Skip to content

Fix build with older avr-gcc: BL must be a constant expression - #877

Open
brubrudsi wants to merge 1 commit into
Yowkees:mainfrom
brubrudsi:fix/bl-constant-expression
Open

Fix build with older avr-gcc: BL must be a constant expression#877
brubrudsi wants to merge 1 commit into
Yowkees:mainfrom
brubrudsi:fix/bl-constant-expression

Conversation

@brubrudsi

Copy link
Copy Markdown

Fixes #803.

Summary

This is not a bug in the firmware's behaviour, and it is not a broken build on your side — it is a toolchain portability issue. The code has shipped fine in v1.3.0–v1.3.2 and builds without complaint in the QMK container used by CI. The one-line change below widens support to distro-packaged AVR toolchains at no cost.

BL is used at file scope, in the keyball initializer:

.pressing_keys = { BL, BL, BL, BL, BL, BL, 0 },

In C, an object with static storage duration must be initialized by a constant expression. A static const char is a read-only object, not a constant expression — unlike in C++, where it would be. So this is a constraint violation that a conforming compiler must diagnose.

Recent GCC folds it as an extension and stays silent. Older avr-gcc does not:

Compiler Result
gcc 13.3.0 (host) accepts, even with -std=c11 -pedantic-errors
avr-gcc 7.3.0 error: initializer element is not constant
avr-gcc 5.4.0 same error (per #803)

This is reachable for anyone building with distro AVR packages instead of the QMK container. On Ubuntu 24.04 the only gcc-avr candidate is 1:7.3.0+Atmel3.7.0-1 — there is no newer version to install — so those users hit it immediately.

Since lib/keyball/keyball.c is shared, it affects every variant (keyball39/44/46/61, one47) and every keymap.

The change

-static const char BL = '\xB0'; // Blank indicator character
+enum { BL = '\xB0' }; // Blank indicator character (must be a constant expression: used in `keyball` initializer below)

An enum constant is a constant expression, so the initializer becomes conforming. I chose enum over #define to keep BL inside the type system rather than introduce a macro into a block of const declarations — but #define BL '\xB0' is equally correct, and it is what the reporter of #803 suggested. Happy to switch if you prefer it.

Why it is safe

BL has three uses and none change behaviour:

  • line 56, the static initializer — the reason for this patch
  • line 496, oled_write_char((layer_state_is(i) ? to_1x(i) : BL), false) — the conditional operator already promoted both arms to int, so this is unchanged
  • lines 615/619, char where = BL; / value = BL;intchar conversion, exactly as before

The value is identical: '\xB0' is an int-typed character constant that narrows to char on assignment the same way the const char object did. AVR's plain char is unsigned, so 0xB0 is representable either way.

Verification

  • Reproduced the original error with avr-gcc 7.3.0 on Ubuntu 24.04.
  • Compiled all three use sites against the patched declaration with avr-gcc -mmcu=atmega32u4 -std=gnu11 -Os -Wall -Wextra: no errors and no new warnings.
  • Confirmed BL still evaluates to 0xB0.
  • CI on this PR builds all five boards × all keymaps, which should confirm no regression on the toolchain you actually use.

There is precedent for accepting build-portability fixes in this area — #816, "Fix compilation error when OLED is disabled".


概要 (Japanese)

これはファームウェアの動作不具合ではなく、またメンテナ側のビルドが壊れているという報告でもありません。ツールチェーンの互換性の問題です。現状のコードは v1.3.0〜v1.3.2 で問題なく動作しており、CI で使われている QMK コンテナでも正常にビルドできます。以下の1行の変更により、ディストリビューション標準の AVR ツールチェーンでもビルドできるようになります。

BLkeyball の初期化子(ファイルスコープ)で使われています。

C 言語では、静的記憶域期間を持つオブジェクトは定数式で初期化しなければなりません。static const char は読み取り専用のオブジェクトであり、定数式ではありません(C++ とは異なります)。したがってこれは制約違反であり、規格に準拠したコンパイラは診断を出す必要があります。

新しい GCC は拡張機能としてこれを受け入れますが、古い avr-gcc は受け入れず error: initializer element is not constant となります。Ubuntu 24.04 では gcc-avr の候補が 1:7.3.0+Atmel3.7.0-1 のみで、これより新しい版を apt で入れることができないため、QMK コンテナを使わずにビルドする利用者はすぐにこの問題に遭遇します。

lib/keyball/keyball.c は共通ファイルのため、すべての機種(keyball39/44/46/61、one47)とすべてのキーマップが対象になります。

変更内容

static const char BLenum { BL = '\xB0' }; に変更しました。列挙定数は定数式なので、初期化子が規格準拠になります。マクロを増やさず型システム内に留めるため enum を選びましたが、#define BL '\xB0' でも同様に正しく#803 の報告者が提案した方法でもあります。そちらがお好みであれば変更します。

安全性

BL の使用箇所は3つあり、いずれも動作は変わりません。56行目の初期化子(本修正の対象)、496行目の条件演算子(元々両辺が int に格上げされているため変化なし)、615/619行目の char への代入(従来どおりの intchar 変換)です。値も 0xB0 のまま変わりません。AVR の char は既定で符号なしのため、いずれの場合も表現可能です。

検証

Ubuntu 24.04 + avr-gcc 7.3.0 でエラーを再現し、修正後は -Wall -Wextra 付きで3箇所すべてが警告なしでコンパイルできることを確認しました。値が 0xB0 のままであることも確認済みです。本 PR の CI で全機種・全キーマップがビルドされるため、実際に使用されているツールチェーンでの非互換がないことも確認できるはずです。

お忙しいところ恐れ入りますが、ご検討いただけますと幸いです。

`BL` is used at file scope in the `keyball` initializer:

    .pressing_keys = { BL, BL, BL, BL, BL, BL, 0 },

In C, an object with static storage duration must be initialized by a
constant expression. A `static const char` is a read-only object, not a
constant expression (unlike in C++), so this is a constraint violation.

Recent GCC folds it as an extension; older avr-gcc does not, and fails
with "error: initializer element is not constant". This affects anyone
building with distro-packaged AVR toolchains rather than the QMK
container -- e.g. Ubuntu 24.04, whose only gcc-avr candidate is
1:7.3.0+Atmel3.7.0-1.

An enum constant is a constant expression, so the initializer becomes
conforming. The value is unchanged (0xB0) and the two other uses of BL
are unaffected.

Fixes Yowkees#803

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error on compilation due to BL character definition

1 participant