From: Viktor Szakats Date: Fri, 8 Nov 2024 00:29:50 +0000 (+0100) Subject: GHA/macos: let gcc dictate the configured Apple SDK X-Git-Tag: curl-8_11_1~106 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4d8ab1f1b8aa069b1567b2d014ca9eace2692f09;p=thirdparty%2Fcurl.git GHA/macos: let gcc dictate the configured Apple SDK As discovered earlier, Homebrew gcc is built against a specific Apple SDK version and doesn't work when matched up with a different version, e.g. the one advertised as default by the macos runner image. Before this patch this was resolved with brute force by zapping the hack-layer gcc component to avoid the bad interference. This worked for us, but it's fragile, accidental and doesn't translate to real-world build environments. Thus, impractical. Avoid this by explicitly selecting the SDK version gcc was built for and meant to be used with, as shown by `gcc --print-sysroot`. It assumes that the gcc binaries preinstalled on the runner images always ship with the SDK version they reference. It also assumes this works with and without `brew update`. Also: - add 4 quick build-only jobs to test all gcc/macos combos. - list SDKs offered via CommandLineTools. Suggested-by: Bo Anderson Ref: https://github.com/Homebrew/homebrew-core/issues/194778#issuecomment-2462764619 Follow-up to c349bd668c91f2484ae21c0f361ddf497143093c #14097 Closes #15518 --- diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 68c44c70f9..40f6602941 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -217,6 +217,7 @@ jobs: xcodebuild -version || true xcrun --sdk macosx --show-sdk-path 2>/dev/null || true xcrun --sdk macosx --show-sdk-version || true + ls -l /Library/Developer/CommandLineTools/SDKs || true echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::' echo '::group::brew packages installed'; ls -l "$(brew --prefix)/opt"; echo '::endgroup::' @@ -226,32 +227,28 @@ jobs: - name: 'configure' run: | + if [[ '${{ matrix.compiler }}' = 'gcc'* ]]; then + sysroot="$("${CC}" --print-sysroot)" # Must match the SDK gcc was built for + else + sysroot="$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" + fi + if [[ '${{ matrix.compiler }}' = 'llvm'* ]]; then CC="$(brew --prefix ${{ matrix.compiler }})/bin/clang" - CC+=" --sysroot=$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" + CC+=" --sysroot=${sysroot}" CC+=" --target=$(uname -m)-apple-darwin" fi - if [[ '${{ matrix.compiler }}' = 'gcc'* ]]; then - libgccdir="$(dirname "$("${CC}" -print-libgcc-file-name)")" - echo '::group::gcc include-fixed details'; find "${libgccdir}/include-fixed" | sort; echo '::endgroup::' - for f in dispatch os AvailabilityInternal.h stdio.h; do - if [ -r "${libgccdir}/include-fixed/${f}" ]; then - echo "Zap gcc hack: '${libgccdir}/include-fixed/${f}'" - mv "${libgccdir}/include-fixed/${f}" "${libgccdir}/include-fixed/${f}-BAK" - fi - done - fi if [ -n '${{ matrix.build.configure }}' ]; then export CFLAGS if [[ '${{ matrix.compiler }}' = 'llvm'* ]]; then options+=" --target=$(uname -m)-apple-darwin" fi - CFLAGS+=' ${{ matrix.build.cflags }}' if [ '${{ matrix.compiler }}' != 'clang' ]; then - options+=" --with-sysroot=$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" - CFLAGS+=" --sysroot=$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" + options+=" --with-sysroot=${sysroot}" + CFLAGS+=" --sysroot=${sysroot}" fi + CFLAGS+=' ${{ matrix.build.cflags }}' CFLAGS+=' -mmacosx-version-min=${{ matrix.build.macos-version-min }}' mkdir bld && cd bld && ../configure --enable-unity --enable-test-bundles --enable-warnings --enable-werror \ --disable-dependency-tracking \ @@ -260,7 +257,7 @@ jobs: else cmake -B bld -G Ninja -DCMAKE_UNITY_BUILD=ON -DCURL_TEST_BUNDLES=ON -DCURL_WERROR=ON \ -DCMAKE_OSX_DEPLOYMENT_TARGET=${{ matrix.build.macos-version-min }} \ - "-DCMAKE_OSX_SYSROOT=$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" \ + "-DCMAKE_OSX_SYSROOT=${sysroot}" \ "-DCMAKE_C_COMPILER_TARGET=$(uname -m | sed 's/arm64/aarch64/')-apple-darwin$(uname -r)" \ ${{ matrix.build.generate }} fi @@ -410,8 +407,7 @@ jobs: # Reduce build combinations, by dropping less interesting ones - { compiler: gcc-12, config: SecureTransport } - { compiler: gcc-13, build: cmake } - - { compiler: gcc-13, image: macos-13 } - - { compiler: gcc-14, config: SecureTransport } + - { compiler: gcc-14, build: autotools } steps: - name: 'install autotools' if: ${{ matrix.build == 'autotools' }} @@ -429,6 +425,7 @@ jobs: xcodebuild -version || true xcrun --sdk macosx --show-sdk-path 2>/dev/null || true xcrun --sdk macosx --show-sdk-version || true + ls -l /Library/Developer/CommandLineTools/SDKs || true echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::' echo '::group::brew packages preinstalled'; ls -l "$(brew --prefix)/opt"; echo '::endgroup::' @@ -438,116 +435,26 @@ jobs: - name: 'configure / ${{ matrix.build }}' run: | + if [[ '${{ matrix.compiler }}' = 'gcc'* ]]; then + sysroot="$("${CC}" --print-sysroot)" # Must match the SDK gcc was built for + else + sysroot="$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" + fi + if [[ '${{ matrix.compiler }}' = 'llvm'* ]]; then CC="$(brew --prefix ${{ matrix.compiler }})/bin/clang" - CC+=" --sysroot=$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" + CC+=" --sysroot=${sysroot}" CC+=" --target=$(uname -m)-apple-darwin" fi - # gcc ships with an `include-fixed` header set, which overrides SDK - # headers with the intent of making them compatible with gcc. The - # source for these headers is: - # https://github.com/gcc-mirror/gcc/tree/master/fixincludes - # with extra Apple-specific patches applied from here for Homebrew: - # https://github.com/iains/gcc-12-branch - # - # They pass through a generator phase at build-time which seems to - # pick the SDK installed on the build machine (maintained by the - # Homebrew project in our case) and patches it according to a set - # of rules in `inclhack.def`. - # - # Homebrew builds and ships different binaries for different macOS - # versions and CPUs, built on machines using the same OS version as - # the target one. Each of these machines have a particular version - # of Apple CommandLineTools with a default SDK version installed with - # them. - # - # Then this binary gets installed onto the end-user machine, - # matching the OS version at the time of installation. - # - # The problem with this approach is that the SDK version picked up - # at gcc build-time has a high chance of being or becoming out of - # sync with actual SDK installed on the end-user machine. This - # can happen after upgrading the OS, Xcode, selecting an SDK version - # manually, or other reasons. - # - # When the SDK versions do not match, the gcc hacks, instead of - # improving compatibility the SDK, are actively _breaking_ - # compatibility, in an unexpected, hard to diagnose way. - # - # The SDK version used for gcc-hacks is not advertised. We can - # extract the major SDK version from the generated gcc-hack header - # files, assuming someone knows what to look for and where. - # - # Basically it also means that the same `gcc-N` Homebrew package - # behaves differently depending on the OS it was built on. Causing - # an explosion of build combination. It may also mean that a minor - # gcc version bump is built against a different SDK version, and due - # to the extra patch for the hack applied by Homebrew, there may - # be extra changes as well. - # - # For GHA runners, it means that the default Xcode + OS combo have - # and SDK mismatch in 8 out of 12 combinations (66%). All fail to - # build, plus one more with matching SDK. This is 9 in total (75%) - # that fail to build out of the box. These are the 3 lucky default - # combinations that worked to build curl: - # macos-14 + Xcode 15.0.1 + gcc-12, gcc-14 - # - # Of all possible valid GHA runner, gcc, manually selected Xcode - # combinations, 40% are broken. - # - # Compared to mainline llvm: llvm ships the same binaries regardless - # of build-OS or environment, it contains no SDK-version-specific - # hacks, and has no 3rd party patches. This still leaves some - # occasional issues, but works much closer to expectations. - # - # Some of these hacks are helpful, in particular for fixing this - # issue via math.h: - # /Applications/Xcode_14.3.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/math.h:53:5: error: #error "Unsupported value of - # 53 | # error "Unsupported value of __FLT_EVAL_METHOD__." - # - # Errors seen in available CI combinations: - # error: two or more data types in declaration specifiers # fatal error: AvailabilityInternalLegacy.h: No such file or directory - # gcc-13 + macos-14 + Xcode 14.3.1 - # error: two or more data types in declaration specifiers - # gcc-13 + macos-12 + Xcode 14.1, 14.2 - # gcc-13 + Xcode 15.0.1, 15.1, 5.2 - # error: expected ';' before 'extern' - # gcc-12, gcc-14 + macos-12 + Xcode 14.1, 14.2 - # error: unknown type name 'dispatch_queue_t' - # gcc-12 + macos-13 + Xcode 15.0.1, 15.1, 15.2 - # error: type defaults to 'int' in declaration of 'DISPATCH_DECL_FACTORY_CLASS_SWIFT' [-Wimplicit-int] - # gcc-14 macos-13 Xcode 15.0.1, 15.1, 15.2 - # error: unknown type name 'FILE' - # Xcode 16.0 - # - # Unbreak Homebrew gcc builds by moving problematic SDK header overlay - # directories/files out of the way: - if [[ '${{ matrix.compiler }}' = 'gcc'* ]]; then - # E.g.: - # $(brew --prefix)/Cellar/gcc@11/11.4.0/lib/gcc/11/gcc/aarch64-apple-darwin23/11/include-fixed - # $(brew --prefix)/Cellar/gcc@11/11.4.0/lib/gcc/11/gcc/x86_64-apple-darwin21/11/include-fixed - # $(brew --prefix)/Cellar/gcc/14.1.0_1/lib/gcc/14/gcc/x86_64-apple-darwin21/14/include-fixed - libgccdir="$(dirname "$("${CC}" -print-libgcc-file-name)")" - echo '::group::gcc include-fixed details'; find "${libgccdir}/include-fixed" | sort; echo '::endgroup::' - patch_out='dispatch os AvailabilityInternal.h' - patch_out+=' stdio.h' # for Xcode 16 error: unknown type name 'FILE' - for f in ${patch_out}; do - if [ -r "${libgccdir}/include-fixed/${f}" ]; then - echo "Zap gcc hack: '${libgccdir}/include-fixed/${f}'" - mv "${libgccdir}/include-fixed/${f}" "${libgccdir}/include-fixed/${f}-BAK" - fi - done - fi - if [ '${{ matrix.build }}' = 'autotools' ]; then export CFLAGS if [[ '${{ matrix.compiler }}' = 'llvm'* ]]; then options+=" --target=$(uname -m)-apple-darwin" fi if [ '${{ matrix.compiler }}' != 'clang' ]; then - options+=" --with-sysroot=$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" - CFLAGS+=" --sysroot=$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" + options+=" --with-sysroot=${sysroot}" + CFLAGS+=" --sysroot=${sysroot}" fi [ '${{ matrix.config }}' = 'OpenSSL' ] && options+=" --with-openssl=$(brew --prefix openssl)" [ '${{ matrix.config }}' = 'SecureTransport' ] && options+=' --with-secure-transport' @@ -565,7 +472,7 @@ jobs: # would pick up nghttp2, libidn2, and libssh2 cmake -B bld -DCMAKE_UNITY_BUILD=ON -DCURL_TEST_BUNDLES=ON -DCURL_WERROR=ON \ -DCMAKE_OSX_DEPLOYMENT_TARGET=${{ matrix.macos-version-min }} \ - "-DCMAKE_OSX_SYSROOT=$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" \ + "-DCMAKE_OSX_SYSROOT=${sysroot}" \ "-DCMAKE_C_COMPILER_TARGET=$(uname -m | sed 's/arm64/aarch64/')-apple-darwin$(uname -r)" \ "-DCMAKE_IGNORE_PREFIX_PATH=$(brew --prefix)" \ -DBUILD_LIBCURL_DOCS=OFF -DBUILD_MISC_DOCS=OFF -DENABLE_CURL_MANUAL=OFF \