Skip to content

build: fix host toolchain detection on a host whose CC carries flags - #1042

Draft
metaneutrons wants to merge 1 commit into
aros-development-team:masterfrom
metaneutrons:upstream/host-toolchain-detection
Draft

build: fix host toolchain detection on a host whose CC carries flags#1042
metaneutrons wants to merge 1 commit into
aros-development-team:masterfrom
metaneutrons:upstream/host-toolchain-detection

Conversation

@metaneutrons

@metaneutrons metaneutrons commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Two independent faults stop the host side of the build on a current macOS/clang host. Both derive a tool name or flag from another variable, and both are silent — configure reports success and the failure surfaces much later as a missing program.

configure.in derives the host binutils names from $CC_BASE and guards that with a test against "gcc". CC_BASE is a whole command line rather than a program name, because AC_PROG_CC leaves the standard flag it selected in CC (gcc -std=gnu23). Reading configure.in alone makes that look impossible, since CC_BASE=$CC comes before the AC_PROG_CC_STDC call; the generated configure shows why it is not:

4549:     CC="$CC $ac_cv_prog_cc_c23" ;;
4711: CC_BASE=$CC
5192:     if test "$CC_BASE" != "gcc"; then

AC_PROG_CC_STDC has been obsolete since autoconf 2.70 and does nothing here; AC_PROG_CC does the standard detection itself, well before CC_BASE captures the value.

So the guard always takes the non-gcc path, the names come from the command line rather than the program, HOST_AR becomes cr — which is ar's flags — and the build later dies with

gmake[3]: cr: No such file or directory

while configure had reported nothing wrong. Fixed by deriving the program name first, then testing and substituting that.

config/make-autotools.tmpl passes CXXCPP="$(HOST_CPP)" to the autotools ports built for the host. HOST_CPP is the C preprocessor, and a port probing for a C++ one rejects it:

checking how to run the C++ preprocessor... gcc -std=gnu23 -E
configure: error: C++ preprocessor "gcc -std=gnu23 -E" fails sanity check

gmp is the first to hit it. Fixed by deriving CXXCPP from HOST_CXX.

Testing

Tested on darwin-aarch64 building raspi-aarch64.

What decides whether the first fault appears is not the host OS but whether the compiler needs an explicit -std= flag to reach the standard autoconf asks for. clang does, so the flag lands in CC. gcc 15 and newer already default to gnu23, so $ac_cv_prog_cc_c23 stays empty and CC keeps its bare name. That predicts the fault on Linux with an older gcc too, and a second pair of eyes there would be welcome before this is merged. Draft because of that gap, not because the change is unfinished.

Not fixed here

The same pattern sits in three more places, where a tool prefix is prepended to what may be a whole command line rather than a program name:

configure.in:3225   aros_kernel_cpp=${kernel_tool_prefix}${CPP_BASE}
configure.in:3232   aros_kernel_cc=${kernel_tool_prefix}${CC_BASE}
configure.in:3240   aros_kernel_cxx=${kernel_tool_prefix}${CXX_BASE}

With gcc -std=gnu23 those happen to produce a working command. With a path in CC they produce arm-aros-/usr/bin/gcc-13. Left alone deliberately, to keep this change to the two faults that actually break the build.

Note on squashing

The two fixes are logically separate and were developed as separate commits. They are squashed here as one "make the host build work" change; happy to split them if a reviewer prefers one bug per commit.

@metaneutrons

Copy link
Copy Markdown
Contributor Author

Prerequisite for reproducing #1043 and #1044 on a macOS host. Those two are independent of this one in content.

Two independent faults stop the host side of the build on a current
macOS/clang host. Both are in code that derives tool names or flags from
another variable, and both are silent: configure reports success and the
failure surfaces much later as a missing program.

configure.in derives the host binutils names from $CC_BASE, and guards
that derivation with a test against "gcc". CC_BASE is a whole command
line rather than a program name, because AC_PROG_CC leaves the standard
flag it selected in CC - "gcc -std=gnu23", not "gcc". Reading
configure.in alone makes that look impossible, since CC_BASE=$CC comes
before the AC_PROG_CC_STDC call; the generated configure shows why it is
not, with

    CC="$CC $ac_cv_prog_cc_c23"

several hundred lines above CC_BASE=$CC. AC_PROG_CC_STDC has been
obsolete since autoconf 2.70 and does nothing here; AC_PROG_CC does the
standard detection itself.

So the guard always takes the non-gcc path, and the names come out of the
command line rather than the program: HOST_AR becomes "cr", which is ar's
flags, and the build later dies with

    gmake[3]: cr: No such file or directory

while configure had reported no problem at all. Fixed by deriving the
program name first and testing and substituting that.

config/make-autotools.tmpl passes CXXCPP="$(HOST_CPP)" to the autotools
ports built for the host. HOST_CPP is the C preprocessor, and a port that
probes for a C++ preprocessor rejects it:

    checking how to run the C++ preprocessor... gcc -std=gnu23 -E
    configure: error: C++ preprocessor "gcc -std=gnu23 -E" fails sanity check

gmp is the first to hit it. Fixed by deriving CXXCPP from HOST_CXX.

Tested on darwin-aarch64 building raspi-aarch64. What decides whether the
first fault appears is not the host OS but whether the compiler needs an
explicit -std flag to reach the standard autoconf asks for: clang does,
so the flag lands in CC; gcc 15 and newer already default to gnu23, so
$ac_cv_prog_cc_c23 stays empty and CC keeps its bare name. That predicts
the fault on Linux with an older gcc as well, and a second pair of eyes
there would be welcome.
@metaneutrons
metaneutrons force-pushed the upstream/host-toolchain-detection branch from a57718f to 6387704 Compare August 20, 2026 15:21
@Kalamatee

Kalamatee commented Aug 20, 2026

Copy link
Copy Markdown
Member

Thanks for the detailed write-up. The cr: No such file or directory failure is real, and the trace through AC_PROG_CC leaving -std=gnu23 in CC is a genuinely useful find. I think the root cause is a little different from the one described, though, and it points at a smaller fix.

Autoconf already strips the flag for us. AC_PATH_PROG(CC,$CC) (configure.in:150) expands to:

Extract the first word of "$CC", so it can be a program name with args.

set dummy $CC; ac_word=$2
...
CC=$ac_cv_path_CC

So by the time the family detection runs, CC is the resolved path with the flag dropped. That is why the HOST_COMPILER_VERSION probe, which runs "$CC" --version, still works in exactly the scenario described. The flag-free program name that CC_PROG derives by hand is already available as $CC; the patch re-derives it from the older CC_BASE snapshot instead.

The name test is the part that is actually wrong. config/features.in:1591 does the same classification without consulting the compiler's name at all:

COMPILER_VERSION=${CC} --version 2>/dev/null
IS_LLVM_COMPILER=echo "$COMPILER_VERSION" | grep -i -c -E 'LLVM|clang'
if test "$IS_LLVM_COMPILER" -ne "0"; then
IS_GNU_COMPILER=0
fi
if test "$IS_LLVM_COMPILER" -eq "0"; then
IS_GNU_COMPILER=echo "$COMPILER_VERSION" | grep -i -c -E 'gcc'
fi

configure.in already computes HOST_COMPILER_VERSION the same way, and then second-guesses it with test "$CC_BASE" != "gcc". That extra name check is what breaks, and it stays fragile after the patch: CC_PROG is not "gcc" for gcc-13, /usr/bin/gcc-13, cc, or ccache gcc, which yields ccache. On any host whose compiler reports clang, those still take the LLVM branch and still build an llvm-ar name with a bogus suffix.

On HOST_AR becoming cr: the cr is not ar's flags leaking in, it is part of the intended value. configure.in:625 builds it deliberately:

base_ar_name=${HOST_TOOLCHAIN_PREFIX}ar${HOST_TOOLCHAIN_SUFFIX}
AROS_PROG(AR_BASE,$base_ar_name)
aros_host_ar_flags="cr"
aros_host_cmd_ar="$AR_BASE $aros_host_ar_flags"
AROS_PATH_PROG(aros_host_plain_ar,$aros_host_cmd_ar)
aros_host_ar=echo $aros_host_cmd_ar | sed -e "s|$base_ar_name|$aros_host_plain_ar|g"

The target side uses the same convention, where AR is the ar program followed by cr. What goes wrong is that AROS_PROG finds nothing for a garbage base_ar_name, so AR_BASE is empty, the string becomes " cr", and the sed has nothing to substitute.

That also explains the "configure reports success" part, which I think is worth splitting out as its own issue. AROS_REQUIRED (acinclude.m4:9) only rejects an empty value and "no", so " cr" passes the check. It guards every host tool the same way, so any similar mis-derivation will keep surfacing at build time rather than at configure time.

Suggested direction, if it is useful: drop the name-based test and classify purely from HOST_COMPILER_VERSION, as features.in does. The LLVM branch then needs another way to get its suffix, which is the real problem hiding here. Where a program name genuinely is needed, $CC after AC_PATH_PROG already provides it. Tightening AROS_REQUIRED or AROS_PROG to check that the first word is executable would also catch this class of failure while configuring.

Two smaller notes: the configure hunk duplicates the configure.in change by hand, so it would be better regenerated, and the remaining CC_BASE uses at configure.in:3225, 3232 and 3240 mean the stated root cause is still present after the change.

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.

2 participants