Skip to content

Fix build on modern toolchains (GCC 10+/15 C23, Clang, -fno-common) - #82

Open
ptudor wants to merge 4 commits into
PhirePhly:masterfrom
ptudor:gcc15-build-fixes
Open

Fix build on modern toolchains (GCC 10+/15 C23, Clang, -fno-common)#82
ptudor wants to merge 4 commits into
PhirePhly:masterfrom
ptudor:gcc15-build-fixes

Conversation

@ptudor

@ptudor ptudor commented Jun 24, 2026

Copy link
Copy Markdown

What

aprx doesn't build out of the box on current C toolchains. This series fixes four independent issues so that a clean ./configure && make succeeds on contemporary GCC, Clang, and cross-build systems. Each commit is one issue:

  1. ttyreader: ANSI prototype for aprx_cfmakeraw() — the K&R definition leaves the 2nd parameter implicit-int. GCC 14, GCC 15 and Clang 19 promote -Wimplicit-int to an error by default, and C23 (GCC 15's default -std=gnu23) removes K&R definitions outright.
  2. interface: rename local boolbool/true/false are keywords in C23, so the parser's int bool; locals are a syntax error under GCC 15's default.
  3. -fno-common multiple definitions — GCC 10+ and Clang 11+ default to -fno-common. aprx.h defines the pthread globals aprsis_thread/pthr_attrs without extern (so every translation unit that includes it emits its own copy), and now is defined in both timercmp.c and aprx-stat.c. Linking then fails with multiple definition of .... The fix declares the shared globals extern in aprx.h — exactly as is already done for the monotonic tick clock — and keeps a single owner for each. Behaviour is unchanged. This one bites every current compiler.
  4. Link via $(CC)Makefile.in sets LD=@CC@ and links with $(LD), so a default build links through the compiler driver. Build systems that set LD to the real linker on the make command line (OpenWrt, Buildroot, Yocto, ...) override that, and the link then runs ld directly and fails with ld: unrecognized option '-pthread'. Linking a threaded C program via the compiler driver is the portable, conventional form; it is a no-op for a default build where LD already expands to the compiler.

Tested — pristine master vs this branch

I built pristine master and then this branch on five platforms. "master build" = does upstream master compile+link as-is; "patched" = does this branch build and does aprx -V run.

Platform Compiler master build fix(es) it needed patched
Debian 12 (bookworm) GCC 12.2 FAIL (link) #3 builds, -V OK
Debian 13 (trixie) GCC 14.2 FAIL (compile + link) #1, #3 builds, -V OK
Fedora 43 GCC 15.2 FAIL (compile + link) #1, #2, #3 builds, -V OK
FreeBSD 15.0 Clang 19.1 FAIL (compile + link) #1, #3 builds, -V OK
OpenWrt (ramips/mt7620, musl) GCC 15.2 cross FAIL #1, #2, #3, #4 builds, packaged + flashed

#3 breaks every platform. #1 breaks everything except GCC 12 (where implicit-int is still only a warning). #2 fires only where the compiler defaults to C23 (GCC 15). #4 fires only where the build system overrides LD (the OpenWrt cross build). Each commit is independent and can be taken on its own.

Out of scope (kept downstream)

Building against a musl sysroot additionally needs the kernel-AX.25 path (<netax25/ax25.h>) gated out, because musl ships no AX.25 headers. That is an environmental change — it would disable AX.25 on a normal glibc host that has libax25 — so it is kept in the downstream (OpenWrt) packaging rather than here. In the five builds above the AX.25 code path is exercised normally: the three glibc/Linux hosts have the AX.25 headers installed, and on FreeBSD PF_AX25 is undefined so aprx compiles that path out on its own.

ptudor added 4 commits June 24, 2026 15:32
C23 (the GCC 15 default, -std=gnu23) removes support for old K&R function
definitions, so the K&R definition of aprx_cfmakeraw() no longer compiles:

    ttyreader.c: error: old-style function definition

Convert it to a prototype. The second parameter was implicitly int under
K&R rules; spell that out as 'int f'.
In C23 'bool', 'true' and 'false' are keywords (no <stdbool.h> needed), so
the interface.c config parser's 'int bool;' locals are a syntax error under
the GCC 15 default of -std=gnu23:

    interface.c: error: expected identifier or '(' before 'bool'

Rename the locals to 'boolval'.
Since GCC 10 (and Clang 11) the compiler defaults to -fno-common, so a
file-scope tentative definition emits a real symbol in every translation
unit that sees it, instead of being merged into one common symbol at link
time. aprx has three globals that relied on the old -fcommon merging:

  * aprx.h defines the pthread globals 'aprsis_thread' and 'pthr_attrs'
    without 'extern', so every .c that includes it gets its own copy;
    netresolver.c also defines a second real 'pthr_attrs'.
  * the wall-clock 'struct timeval now' is defined in both timercmp.c and
    aprx-stat.c, which link together into aprx-stat.

Linking then fails with e.g.:

    multiple definition of `aprsis_thread'; aprx.o: first defined here
    multiple definition of `now'; aprx-stat.o: first defined here

Declare the shared globals 'extern' in aprx.h (as is already done for the
monotonic 'tick' clock) and keep exactly one real definition of each:
aprsis_thread and pthr_attrs in aprsis.c, now in timercmp.c (which is linked
into both programs). Behaviour is unchanged -- one shared object per symbol,
exactly as the merged common symbol used to be.
Makefile.in sets LD=@cc@ and links the programs with $(LD), so a default
build links through the compiler driver. But build systems that set LD to
the real linker on the make command line (OpenWrt, Buildroot, Yocto, ...)
override that assignment, and the link then runs e.g. 'ld' directly:

    ld: unrecognized option '-pthread'

-pthread (and -fuse-ld=...) are compiler-driver options, not linker
options; a threaded C program must be linked via the compiler so the driver
adds the C runtime and translates -pthread. Use $(CC) for the two final
link rules, which is the portable, conventional form and a no-op for a
default build where LD already expands to the compiler.
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.

1 participant