curl-curl/.github/workflows/macos.yml
Viktor Szakats 66ad54e46b
cmake: add CURL_DROP_UNUSED option to reduce binary sizes
To enable known linker options dropping unused, dead, code and data from
the executables built.

Useful to reduce binary sizes for curl, libcurl shared lib and apps
linking static libcurl. It's effective on both "unity" and non-unity
builds. Aligning "unity" build sizes with default, non-unity ones.

Supported platforms: Apple, MSVC, llvm/clang and GCC on all tested
platforms: Linux, BSDs, Windows, MSYS2/Cygwin, Android, MS-DOS.

Notes:
- Static libraries grow 20-30% with non-Apple toolchains.
  This effect is controlled by separate, optional compiler flags on
  non-Apple. This patch enables them automatically for public binaries
  (libcurl and curl tool), and leaves them off for internal/test ones.
- MSVC enables this option by default for 'Release' configurations.
  The curl build option has no effect on it.
- Observed effect on VS2010 is negligible. VS2012+ is recommended.
- Works with LTO, Fil-C.
- No observed/conclusive effect on build speed.
- On Windows with clang/gcc (mingw-w64/MSYS2/Cygwin) it also enables
  `-fno-asynchronous-unwind-tables` as a workaround to make
  the toolchain options actually work.
  Ref: https://sourceware.org/bugzilla/show_bug.cgi?id=11539
  Thanks-to: Andarwinux

Also:
- GHA: enable in Linux and MinGW jobs to test it. Size changes:

  - linux aws-lc H3:
    curl: 2000000 -> 1937152, libcurl.a: 2065724 -> 2716532 bytes
  - macos clang HTTP-only:
    curl: 1364376 -> 128799 bytes, libcurl.a: unchanged
  - macos llvm MultiSSL:
    curl: 410056 -> 405720, libcurl.dylib: 1350336 -> 1348480 bytes
  - mingw schannel c-ares U:
    curl: 1588736 -> 1507328, libcurl-d.a: 3322040 -> 3884746 bytes
    bld: 34 -> 35MB

- GHA: enable in MSVC and Apple jobs to reduce disk footprint, with no
  obvious downside. Size changes:

  - AppVeyor CI VS2019:
    curl: 2339840 -> 1295872, libcurl-d.dll: 3155968 -> 1900544 bytes
    bld: 161 -> 97MB
  - AppVeyor CI VS2022 clang-cl:
    curl: 2933248 -> 2332160, libcurl-d.lib: 4762688 -> 5511330 bytes
    bld: 133 -> 121MB
  - AppVeyor CI VS2022 HTTP-only:
    curl: 3514368 -> 2177024, libcurl-d.lib: 2538420 -> 3151740 bytes
    bld: 137 -> 83MB
  - GHA intel:
    curl: 2629120 -> 2023424, libcurl-d.lib: 4366652 -> 5350670 bytes
    bld: 86 -> 69MB
  - GHA arm64:
    curl: 2832896 -> 2063872, libcurl-d.lib: 4690616 -> 5597250 bytes
    bld: 82 -> 66MB

Refs:
https://maskray.me/blog/2021-02-28-linker-garbage-collection
https://web.archive.org/web/20110811230637/msdn.microsoft.com/en-us/library/bxwfs976.aspx (VS2010)
https://learn.microsoft.com/cpp/build/reference/opt-optimizations
https://learn.microsoft.com/cpp/build/reference/gy-enable-function-level-linking

Closes #20357
2026-01-22 17:08:20 +01:00

708 lines
33 KiB
YAML

# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
#
# SPDX-License-Identifier: curl
name: 'macOS'
'on':
push:
branches:
- master
- '*/ci'
paths-ignore:
- '**/*.md'
- '.circleci/**'
- 'appveyor.*'
- 'Dockerfile'
- 'projects/**'
pull_request:
branches:
- master
paths-ignore:
- '**/*.md'
- '.circleci/**'
- 'appveyor.*'
- 'Dockerfile'
- 'projects/**'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
permissions: {}
# Deprecated Apple APIs and the macos-version-min value required to avoid
# deprecation warnings with llvm/clang:
#
# - 10.7 Lion (2011) - GSS
# - 10.9 Mavericks (2013) - LDAP
#
env:
CURL_CI: github
CURL_TEST_MIN: 1700
MAKEFLAGS: -j 4
LDFLAGS: -w # suppress 'object file was built for newer macOS version than being linked' warnings
jobs:
ios:
name: "iOS, ${{ (matrix.build.generator && format('CM-{0}', matrix.build.generator)) || (matrix.build.generate && 'CM' || 'AM' )}} ${{ matrix.build.name }} arm64"
runs-on: macos-latest
timeout-minutes: 10
env:
DEVELOPER_DIR: "/Applications/Xcode${{ matrix.build.xcode && format('_{0}', matrix.build.xcode) || '' }}.app/Contents/Developer"
CC: 'clang'
LDFLAGS: ''
MATRIX_BUILD: ${{ matrix.build.generate && 'cmake' || 'autotools' }}
MATRIX_OPTIONS: ${{ matrix.build.options }}
# renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com
LIBRESSL_VERSION: 4.2.1
strategy:
fail-fast: false
matrix:
build:
- name: 'libressl'
install_steps: libressl
configure: --with-openssl=/Users/runner/libressl --without-libpsl
- name: 'libressl'
install_steps: libressl
# FIXME: Could not make OPENSSL_ROOT_DIR work. CMake seems to prepend sysroot to it.
generate: >-
-DCMAKE_BUILD_TYPE=Release -DCMAKE_UNITY_BUILD_BATCH_SIZE=50
-DOPENSSL_INCLUDE_DIR=/Users/runner/libressl/include
-DOPENSSL_SSL_LIBRARY=/Users/runner/libressl/lib/libssl.a
-DOPENSSL_CRYPTO_LIBRARY=/Users/runner/libressl/lib/libcrypto.a
-DCURL_USE_LIBPSL=OFF
- name: 'libressl'
install_steps: libressl
generator: Xcode
xcode: '' # default Xcode. Set it once to silence actionlint.
options: --config Debug
generate: >-
-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=OFF
-DMACOSX_BUNDLE_GUI_IDENTIFIER=se.curl
-DOPENSSL_INCLUDE_DIR=/Users/runner/libressl/include
-DOPENSSL_SSL_LIBRARY=/Users/runner/libressl/lib/libssl.a
-DOPENSSL_CRYPTO_LIBRARY=/Users/runner/libressl/lib/libcrypto.a
-DCURL_USE_LIBPSL=OFF
steps:
- name: 'brew install'
if: ${{ matrix.build.configure }}
timeout-minutes: 5
run: |
# shellcheck disable=SC2181,SC2034
while [[ $? == 0 ]]; do for i in 1 2 3; do if brew update && brew install automake libtool; then break 2; else echo Error: wait to try again; sleep 10; fi; done; false Too many retries; done
- name: 'toolchain versions'
run: |
command -v "${CC}"; "${CC}" --version || true
xcodebuild -version || true
xcodebuild -sdk -version | grep '^Path:' || true
xcrun --sdk iphoneos --show-sdk-path 2>/dev/null || true
xcrun --sdk iphoneos --show-sdk-version || true
echo '::group::compiler defaults'; echo 'int main(void) {}' | "${CC}" -v -x c -; echo '::endgroup::'
echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::'
echo '::group::brew packages installed'; ls -l /opt/homebrew/opt; echo '::endgroup::'
- name: 'cache libressl'
if: ${{ contains(matrix.build.install_steps, 'libressl') }}
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
id: cache-libressl
env:
cache-name: cache-libressl
with:
path: ~/libressl
key: iOS-${{ env.cache-name }}-${{ env.LIBRESSL_VERSION }}
- name: 'build libressl'
if: ${{ contains(matrix.build.install_steps, 'libressl') && steps.cache-libressl.outputs.cache-hit != 'true' }}
run: |
curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 60 --retry 3 --retry-connrefused \
--location "https://github.com/libressl/portable/releases/download/v${LIBRESSL_VERSION}/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz
cd "libressl-${LIBRESSL_VERSION}"
cmake -B . -G Ninja \
-DCMAKE_INSTALL_PREFIX=/Users/runner/libressl \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DBUILD_SHARED_LIBS=OFF \
-DLIBRESSL_APPS=OFF \
-DLIBRESSL_TESTS=OFF
cmake --build .
cmake --install . --verbose
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: 'autoreconf'
if: ${{ matrix.build.configure }}
run: autoreconf -fi
- name: 'configure'
env:
MATRIX_CONFIGURE: '${{ matrix.build.configure }}'
MATRIX_GENERATE: '${{ matrix.build.generate }}'
MATRIX_GENERATOR: '${{ matrix.build.generator }}'
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos
[ -n "${MATRIX_GENERATOR}" ] && options="-G ${MATRIX_GENERATOR}"
cmake -B bld -G Ninja -D_CURL_PREFILL=ON \
-DCMAKE_UNITY_BUILD=ON -DCURL_DROP_UNUSED=ON -DCURL_WERROR=ON \
-DCMAKE_SYSTEM_NAME=iOS \
-DUSE_APPLE_IDN=ON \
${MATRIX_GENERATE} ${options}
else
mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror \
--disable-dependency-tracking --enable-option-checking=fatal \
CFLAGS="-isysroot $(xcrun --sdk iphoneos --show-sdk-path 2>/dev/null)" \
--host=aarch64-apple-darwin \
--with-apple-idn \
${MATRIX_CONFIGURE}
fi
- name: 'configure log'
if: ${{ !cancelled() }}
run: cat bld/config.log bld/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true
- name: 'curl_config.h'
run: |
echo '::group::raw'; cat bld/lib/curl_config.h || true; echo '::endgroup::'
grep -F '#define' bld/lib/curl_config.h | sort || true
- name: 'build'
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --build bld ${MATRIX_OPTIONS} --parallel 4 --verbose
else
make -C bld V=1
fi
- name: 'curl info'
run: |
find . -type f \( -name curl -o -name '*.dylib' -o -name '*.a' \) -print0 | xargs -0 file --
find . -type f \( -name curl -o -name '*.dylib' -o -name '*.a' \) -print0 | xargs -0 stat -f '%10z bytes: %N' --
- name: 'build tests'
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --build bld ${MATRIX_OPTIONS} --parallel 4 --target testdeps --verbose
else
make -C bld V=1 -C tests
fi
- name: 'build examples'
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --build bld ${MATRIX_OPTIONS} --parallel 4 --target curl-examples-build --verbose
else
make -C bld examples V=1
fi
macos:
name: "${{ matrix.build.generate && 'CM' || 'AM' }} ${{ matrix.build.compiler }} ${{ matrix.build.name }}"
runs-on: macos-15
timeout-minutes: 15
env:
DEVELOPER_DIR: "/Applications/Xcode${{ matrix.build.xcode && format('_{0}', matrix.build.xcode) || '' }}.app/Contents/Developer"
CC: '${{ matrix.build.compiler }}'
MATRIX_BUILD: ${{ matrix.build.generate && 'cmake' || 'autotools' }}
MATRIX_COMPILER: '${{ matrix.build.compiler }}'
MATRIX_INSTALL: '${{ matrix.build.install }}'
MATRIX_INSTALL_STEPS: '${{ matrix.build.install_steps }}'
MATRIX_MACOS_VERSION_MIN: '${{ matrix.build.macos-version-min }}'
strategy:
fail-fast: false
matrix:
build:
- name: '!ssl !debug brotli zstd'
compiler: gcc-13
configure: --without-ssl --with-brotli --with-zstd --with-apple-idn
tflags: '--min=1450'
xcode: '' # default Xcode. Set it once to silence actionlint.
- name: '!ssl libssh2 AppleIDN'
compiler: clang
generate: -DENABLE_DEBUG=ON -DCURL_USE_LIBSSH2=ON -DUSE_APPLE_IDN=ON -DCURL_ENABLE_SSL=OFF -DCURL_BROTLI=OFF -DCURL_ZSTD=OFF
tflags: '--min=1550'
- name: 'OpenSSL libssh c-ares'
compiler: clang
install: libssh
configure: --enable-debug --with-libssh --with-openssl=/opt/homebrew/opt/openssl --enable-ares --with-fish-functions-dir --with-zsh-functions-dir
- name: 'OpenSSL libssh'
compiler: llvm@18
install: libssh libnghttp3
generate: -DENABLE_DEBUG=ON -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_BROTLI=OFF -DCURL_ZSTD=OFF
- name: '!ssl c-ares'
compiler: clang
configure: --enable-debug --enable-ares --without-ssl
tflags: '--min=1500'
- name: '!ssl HTTP-only'
compiler: clang
tflags: '--min=930'
generate: >-
-DENABLE_DEBUG=ON
-DCURL_ENABLE_SSL=OFF -DHTTP_ONLY=ON -DCURL_DISABLE_WEBSOCKETS=ON
-DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_ALTSVC=ON -DENABLE_UNIX_SOCKETS=OFF
-DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=OFF -DUSE_NGHTTP2=OFF
-DCURL_USE_GSSAPI=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DUSE_LIBRTMP=OFF
-DCURL_BROTLI=OFF -DCURL_ZLIB=OFF -DCURL_ZSTD=OFF
-DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF
macos-version-min: '10.15' # Catalina (2019)
- name: 'LibreSSL !ldap +examples'
compiler: clang
install: libressl
install_steps: pytest
generate: -DENABLE_DEBUG=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/libressl -DCURL_DISABLE_LDAP=ON -DCURL_BROTLI=OFF -DCURL_ZSTD=OFF -DCURL_USE_LIBSSH2=OFF
- name: 'OpenSSL 10.15 C89'
compiler: clang
install: libnghttp3 libngtcp2
install_steps: pytest
generate: -DENABLE_DEBUG=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DUSE_NGTCP2=ON -DCURL_BROTLI=OFF -DCURL_ZSTD=OFF -DCURL_USE_LIBSSH2=OFF -DCMAKE_C_STANDARD=90
macos-version-min: '10.15'
- name: 'OpenSSL SecTrust'
compiler: clang
install: libnghttp3 libngtcp2
install_steps: pytest
configure: --enable-debug --with-openssl=/opt/homebrew/opt/openssl --with-ngtcp2 --with-apple-sectrust
- name: 'OpenSSL event-based'
compiler: clang
generate: -DENABLE_DEBUG=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_BROTLI=OFF -DCURL_ZSTD=OFF -DCURL_USE_LIBSSH2=OFF
tflags: '--test-event --min=1300'
- name: 'OpenSSL gsasl rtmp AppleIDN SecTrust +examples'
compiler: clang
install: libnghttp3 libngtcp2 gsasl rtmpdump
generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_NGTCP2=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DUSE_APPLE_SECTRUST=ON
- name: 'MultiSSL AppleIDN clang-tidy +examples'
compiler: clang
install: llvm gnutls nettle libressl krb5 mbedtls gsasl rustls-ffi rtmpdump libssh fish
install_steps: clang-tidy skiprun
chkprefill: _chkprefill
generate: >-
-DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/libressl -DCURL_DEFAULT_SSL_BACKEND=openssl
-DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DENABLE_ARES=ON -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON
-DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON -DUSE_APPLE_IDN=ON -DUSE_SSLS_EXPORT=ON
-DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/krb5
-DCURL_BROTLI=ON -DCURL_ZSTD=ON
-DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy
-DCURL_COMPLETION_FISH=ON -DCURL_COMPLETION_ZSH=ON
- name: 'HTTP/3 clang-tidy'
compiler: clang
install: llvm libnghttp3 libngtcp2 openldap krb5
install_steps: clang-tidy skipall
generate: >-
-DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DUSE_NGTCP2=ON
-DLDAP_INCLUDE_DIR=/opt/homebrew/opt/openldap/include -DLDAP_LIBRARY=/opt/homebrew/opt/openldap/lib/libldap.dylib -DLDAP_LBER_LIBRARY=/opt/homebrew/opt/openldap/lib/liblber.dylib
-DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/krb5
-DCURL_BROTLI=ON -DCURL_ZSTD=ON
-DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy
- name: 'LibreSSL openldap krb5 c-ares +examples'
compiler: clang
install: libressl krb5 openldap
generate: -DENABLE_DEBUG=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/libressl -DENABLE_ARES=ON -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/krb5 -DLDAP_INCLUDE_DIR=/opt/homebrew/opt/openldap/include -DLDAP_LIBRARY=/opt/homebrew/opt/openldap/lib/libldap.dylib -DLDAP_LBER_LIBRARY=/opt/homebrew/opt/openldap/lib/liblber.dylib
- name: 'wolfSSL !ldap brotli zstd'
compiler: clang
install: brotli wolfssl zstd
install_steps: pytest
generate: -DCURL_USE_WOLFSSL=ON -DCURL_DISABLE_LDAP=ON -DUSE_ECH=ON
- name: 'mbedTLS !ldap brotli zstd MultiSSL AppleIDN'
compiler: llvm@18
install: brotli mbedtls zstd
install_steps: codeset-test
generate: -DCURL_USE_MBEDTLS=ON -DCURL_DISABLE_LDAP=ON -DCURL_DEFAULT_SSL_BACKEND=mbedtls -DCURL_USE_OPENSSL=ON -DUSE_APPLE_IDN=ON
- name: 'GnuTLS !ldap krb5 +examples'
compiler: clang
install: gnutls nettle krb5
generate: -DENABLE_DEBUG=ON -DCURL_USE_GNUTLS=ON -DCURL_USE_OPENSSL=OFF -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/krb5 -DCURL_DISABLE_LDAP=ON -DUSE_SSLS_EXPORT=ON
- name: 'aws-lc'
compiler: gcc-13
install: aws-lc
generate: -DENABLE_DEBUG=ON -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/aws-lc -DUSE_ECH=ON -DCURL_DISABLE_LDAP=ON -DUSE_SSLS_EXPORT=ON
- name: 'Rustls'
compiler: clang
install: rustls-ffi
generate: -DENABLE_DEBUG=ON -DCURL_USE_RUSTLS=ON -DUSE_ECH=ON -DCURL_DISABLE_LDAP=ON
tflags: '--min=1650'
- name: 'OpenSSL torture 1'
compiler: clang
install: libnghttp3
install_steps: torture
generate: -DENABLE_DEBUG=ON -DBUILD_SHARED_LIBS=OFF -DENABLE_THREADED_RESOLVER=OFF -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl
tflags: '-t --shallow=25 --min=480 1 to 500'
- name: 'OpenSSL torture 2'
compiler: clang
install: libnghttp3
install_steps: torture
generate: -DENABLE_DEBUG=ON -DBUILD_SHARED_LIBS=OFF -DENABLE_THREADED_RESOLVER=OFF -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl
tflags: '-t --shallow=25 --min=730 501 to 1250'
- name: 'OpenSSL torture 3'
compiler: clang
install: libnghttp3
install_steps: torture
generate: -DENABLE_DEBUG=ON -DBUILD_SHARED_LIBS=OFF -DENABLE_THREADED_RESOLVER=OFF -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl
tflags: '-t --shallow=25 --min=628 1251 to 9999'
steps:
- name: 'brew install'
timeout-minutes: 5
# Run this command with retries because of spurious failures seen
# while running the tests, for example
# https://github.com/curl/curl/runs/4095721123?check_suite_focus=true
env:
INSTALL_PACKAGES: >-
${{ matrix.build.generate && 'ninja' || 'automake libtool' }}
${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'nghttp2 stunnel' || '' }}
${{ contains(matrix.build.install_steps, 'pytest') && 'caddy httpd vsftpd' || '' }}
run: |
echo pkgconf libpsl libssh2 ${INSTALL_PACKAGES} ${MATRIX_INSTALL} | xargs -Ix -n1 echo brew '"x"' > /tmp/Brewfile
# shellcheck disable=SC2181,SC2034
while [[ $? == 0 ]]; do for i in 1 2 3; do if brew update && brew bundle install --file /tmp/Brewfile; then break 2; else echo Error: wait to try again; sleep 10; fi; done; false Too many retries; done
- name: 'brew unlink openssl'
if: ${{ contains(matrix.build.install, 'aws-lc') || contains(matrix.build.install, 'libressl') }}
run: |
if [ -d /opt/homebrew/include/openssl ]; then
brew unlink openssl
fi
- name: 'toolchain versions'
run: |
[[ "${MATRIX_COMPILER}" = 'llvm'* ]] && CC="$(brew --prefix "${MATRIX_COMPILER}")/bin/clang"
[[ "${MATRIX_COMPILER}" = 'gcc'* ]] && "${CC}" --print-sysroot
command -v "${CC}"; "${CC}" --version || true
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 /opt/homebrew/opt; echo '::endgroup::'
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: 'autoreconf'
if: ${{ matrix.build.configure }}
run: autoreconf -fi
- name: 'configure'
env:
MATRIX_CHKPREFILL: '${{ matrix.build.chkprefill }}'
MATRIX_CONFIGURE: '${{ matrix.build.configure }}'
MATRIX_GENERATE: '${{ matrix.build.generate }}'
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=${sysroot}"
CC+=" --target=$(uname -m)-apple-darwin"
fi
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
for _chkprefill in '' ${MATRIX_CHKPREFILL}; do
options=''
[ -n "${MATRIX_MACOS_VERSION_MIN}" ] && options+=" -DCMAKE_OSX_DEPLOYMENT_TARGET=${MATRIX_MACOS_VERSION_MIN}"
[[ "${MATRIX_INSTALL_STEPS}" = *'pytest'* ]] && options+=' -DVSFTPD=NO' # Skip ~20 tests that stretch run time by 7x on macOS
[ "${_chkprefill}" = '_chkprefill' ] && options+=' -D_CURL_PREFILL=OFF'
cmake -B "bld${_chkprefill}" -G Ninja -D_CURL_PREFILL=ON \
-DCMAKE_INSTALL_PREFIX="$HOME"/curl-install \
-DCMAKE_UNITY_BUILD=ON -DCURL_DROP_UNUSED=ON -DCURL_WERROR=ON \
-DCMAKE_OSX_SYSROOT="${sysroot}" \
-DCMAKE_C_COMPILER_TARGET="$(uname -m | sed 's/arm64/aarch64e/')-apple-darwin$(uname -r)" \
${MATRIX_GENERATE} ${options}
done
if [ -d bld_chkprefill ] && ! diff -u bld/lib/curl_config.h bld_chkprefill/lib/curl_config.h; then
echo '::group::reference configure log'; cat bld_chkprefill/CMakeFiles/CMake*.yaml 2>/dev/null || true; echo '::endgroup::'
false
fi
else
export CFLAGS
if [[ "${MATRIX_COMPILER}" = 'llvm'* ]]; then
options+=" --target=$(uname -m)-apple-darwin"
fi
if [ "${MATRIX_COMPILER}" != 'clang' ]; then
options+=" --with-sysroot=${sysroot}"
CFLAGS+=" --sysroot=${sysroot}"
fi
[ -n "${MATRIX_MACOS_VERSION_MIN}" ] && CFLAGS+=" -mmacosx-version-min=${MATRIX_MACOS_VERSION_MIN}"
[[ "${MATRIX_INSTALL_STEPS}" = *'pytest'* ]] && options+=' --with-test-vsftpd=no' # Skip ~20 tests that stretch run time by 7x on macOS
mkdir bld && cd bld && ../configure --prefix="$PWD"/curl-install --enable-unity --enable-warnings --enable-werror --disable-static \
--disable-dependency-tracking --enable-option-checking=fatal \
--with-libpsl=/opt/homebrew/opt/libpsl \
${MATRIX_CONFIGURE} ${options}
fi
- name: 'configure log'
if: ${{ !cancelled() }}
run: cat bld/config.log bld/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true
- name: 'curl_config.h'
run: |
echo '::group::raw'; cat bld/lib/curl_config.h || true; echo '::endgroup::'
grep -F '#define' bld/lib/curl_config.h | sort || true
- name: 'test configs'
run: grep -H -v '^#' bld/tests/config bld/tests/http/config.ini || true
- name: 'build'
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --build bld --verbose
else
make -C bld V=1
fi
- name: 'curl -V'
run: |
find . -type f \( -name curl -o -name '*.dylib' -o -name '*.a' \) -print0 | xargs -0 file --
find . -type f \( -name curl -o -name '*.dylib' -o -name '*.a' \) -print0 | xargs -0 stat -f '%10z bytes: %N' --
bld/src/curl --disable --version
- name: 'curl install'
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --install bld --strip
else
make -C bld V=1 install
fi
- name: 'build tests'
if: ${{ !contains(matrix.build.install_steps, 'skipall') }}
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --build bld --verbose --target testdeps
else
make -C bld V=1 -C tests
fi
- name: 'install test prereqs'
if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }}
run: |
python3 -m venv ~/venv
~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt
- name: 'run tests'
if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }}
timeout-minutes: ${{ contains(matrix.build.install_steps, 'torture') && 20 || 10 }}
env:
TEST_TARGET: ${{ contains(matrix.build.install_steps, 'torture') && 'test-torture' || 'test-ci' }}
TFLAGS: '${{ matrix.build.tflags }}'
run: |
TFLAGS="-j20 ${TFLAGS}"
if [ "${TEST_TARGET}" != 'test-ci' ]; then
TFLAGS+=' --buildinfo' # only test-ci sets this by default, set it manually for test-torture
fi
source ~/venv/bin/activate
if [[ "${MATRIX_INSTALL_STEPS}" = *'codeset-test'* ]]; then
locale || true
export LC_ALL=C
export LC_CTYPE=C
export LC_NUMERIC=fr_FR.UTF-8
fi
rm -f ~/.curlrc
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --build bld --verbose --target "${TEST_TARGET}"
else
make -C bld V=1 "${TEST_TARGET}"
fi
- name: 'install pytest prereqs'
if: ${{ contains(matrix.build.install_steps, 'pytest') }}
run: |
[ -d ~/venv ] || python3 -m venv ~/venv
~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/http/requirements.txt
- name: 'run pytest'
if: ${{ contains(matrix.build.install_steps, 'pytest') }}
env:
PYTEST_ADDOPTS: '--color=yes'
PYTEST_XDIST_AUTO_NUM_WORKERS: 4
run: |
source ~/venv/bin/activate
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --build bld --verbose --target curl-pytest-ci
else
make -C bld V=1 pytest-ci
fi
- name: 'build examples'
if: ${{ contains(matrix.build.name, '+examples') }}
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --build bld --verbose --target curl-examples-build
else
make -C bld examples V=1
fi
combinations: # Test buildability with host OS, Xcode / SDK, compiler, target-OS, built tool, combinations
name: "${{ matrix.build == 'cmake' && 'CM' || 'AM' }} ${{ matrix.compiler }} ${{ matrix.image }} ${{ matrix.xcode }}"
runs-on: ${{ matrix.image }}
timeout-minutes: 10
env:
DEVELOPER_DIR: "/Applications/Xcode${{ matrix.xcode && format('_{0}', matrix.xcode) || '' }}.app/Contents/Developer"
CC: '${{ matrix.compiler }}'
MATRIX_BUILD: '${{ matrix.build }}'
MATRIX_COMPILER: '${{ matrix.compiler }}'
MATRIX_IMAGE: '${{ matrix.image }}'
MATRIX_MACOS_VERSION_MIN: '${{ matrix.macos-version-min }}'
strategy:
fail-fast: false
matrix:
# Sources:
# https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md
# https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md
# https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md
compiler: [gcc-13, gcc-14, gcc-15, llvm@15, llvm@18, llvm@20, clang]
# Xcode support matrix as of 2025-10, with default macOS SDK versions and OS names, years:
# * = default Xcode on the runner.
# macos-14: 15.0.1, 15.1, 15.2, 15.3,*15.4
# macos-15: 16.0, 16.1, 16.2, 16.3,*16.4, 26.0
# macos-26: 16.4 *26.0
# macOSSDK: 14.0, 14.2, 14.2, 14.4, 14.5, 15.0, 15.1, 15.2, 15.4, 15.5, 26.0
# Sonoma (2023) Sequoia (2024) Tahoe (2025)
# https://github.com/actions/runner-images/tree/main/images/macos
# https://en.wikipedia.org/wiki/MacOS_version_history
image: [macos-14, macos-15, macos-26]
xcode: [''] # default Xcodes
macos-version-min: ['']
build: [autotools, cmake]
exclude:
# Combinations not covered by runner images:
- { image: macos-14, compiler: 'llvm@18' }
- { image: macos-14, compiler: 'llvm@20' }
- { image: macos-15, compiler: 'llvm@15' }
- { image: macos-15, compiler: 'llvm@20' }
- { image: macos-26, compiler: 'llvm@15' }
- { image: macos-26, compiler: 'llvm@18' }
# Covered by the main workflow
- { image: macos-15, compiler: 'gcc-13' }
- { image: macos-15, compiler: 'llvm@18' }
- { image: macos-15, compiler: 'clang' }
# Reduce build combinations, by dropping less interesting ones
- { image: macos-26, compiler: 'gcc-13' }
- { compiler: 'gcc-14' , build: cmake }
# Reduce autotools to just one job that is also build with cmake
- { compiler: 'gcc-13' , build: autotools }
- { compiler: 'gcc-14' , build: autotools }
- { compiler: 'gcc-15' , build: autotools }
- { compiler: 'llvm@15', build: autotools }
- { compiler: 'llvm@18', build: autotools }
- { compiler: 'llvm@20', build: autotools }
- { image: macos-14, build: autotools }
- { image: macos-15, build: autotools }
steps:
- name: 'install autotools'
if: ${{ matrix.build == 'autotools' }}
run: |
# shellcheck disable=SC2181,SC2034
while [[ $? == 0 ]]; do for i in 1 2 3; do if brew update && brew install automake libtool; then break 2; else echo Error: wait to try again; sleep 10; fi; done; false Too many retries; done
- name: 'toolchain versions'
run: |
[[ "${MATRIX_COMPILER}" = 'llvm'* ]] && CC="$(brew --prefix "${MATRIX_COMPILER}")/bin/clang"
[[ "${MATRIX_COMPILER}" = 'gcc'* ]] && "${CC}" --print-sysroot
command -v "${CC}"; "${CC}" --version || true
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::compiler defaults'; echo 'int main(void) {}' | "${CC}" -v -x c -; echo '::endgroup::'
echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::'
echo '::group::brew packages preinstalled'; ls -l /opt/homebrew/opt; echo '::endgroup::'
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: 'autoreconf'
if: ${{ matrix.build == 'autotools' }}
run: autoreconf -fi
- name: 'configure / ${{ matrix.build }}'
run: |
if [ "${MATRIX_COMPILER}" = 'gcc-13' ] && [ "${MATRIX_IMAGE}" = 'macos-15' ]; then
# Ref: https://github.com/Homebrew/homebrew-core/issues/194778#issuecomment-2793243409
/opt/homebrew/opt/gcc@13/libexec/gcc/aarch64-apple-darwin24/13/install-tools/mkheaders
fi
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=${sysroot}"
CC+=" --target=$(uname -m)-apple-darwin"
fi
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
[ -n "${MATRIX_MACOS_VERSION_MIN}" ] && options+=" -DCMAKE_OSX_DEPLOYMENT_TARGET=${MATRIX_MACOS_VERSION_MIN}"
# would pick up nghttp2, libidn2, and libssh2
cmake -B bld -G Ninja -D_CURL_PREFILL=ON \
-DCMAKE_UNITY_BUILD=ON -DCURL_DROP_UNUSED=ON -DCURL_WERROR=ON \
-DCMAKE_OSX_SYSROOT="${sysroot}" \
-DCMAKE_C_COMPILER_TARGET="$(uname -m | sed 's/arm64/aarch64e/')-apple-darwin$(uname -r)" \
-DCMAKE_IGNORE_PREFIX_PATH=/opt/homebrew \
-DBUILD_LIBCURL_DOCS=OFF -DBUILD_MISC_DOCS=OFF -DENABLE_CURL_MANUAL=OFF \
-DCURL_USE_OPENSSL=ON \
-DUSE_NGHTTP2=OFF -DUSE_LIBIDN2=OFF \
-DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF \
-DUSE_APPLE_IDN=ON -DUSE_APPLE_SECTRUST=ON \
${options}
else
export CFLAGS
if [[ "${MATRIX_COMPILER}" = 'llvm'* ]]; then
options+=" --target=$(uname -m)-apple-darwin"
fi
if [ "${MATRIX_COMPILER}" != 'clang' ]; then
options+=" --with-sysroot=${sysroot}"
CFLAGS+=" --sysroot=${sysroot}"
fi
[ -n "${MATRIX_MACOS_VERSION_MIN}" ] && CFLAGS+=" -mmacosx-version-min=${MATRIX_MACOS_VERSION_MIN}"
# would pick up nghttp2, libidn2, but libssh2 is disabled by default
mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror --disable-static \
--disable-dependency-tracking --enable-option-checking=fatal \
--disable-docs --disable-manual \
--with-openssl="$(brew --prefix openssl)" \
--without-nghttp2 --without-libidn2 \
--without-libpsl \
--with-apple-idn --with-apple-sectrust \
${options}
fi
- name: 'configure log'
if: ${{ !cancelled() }}
run: cat bld/config.log bld/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true
- name: 'curl_config.h'
run: |
echo '::group::raw'; cat bld/lib/curl_config.h || true; echo '::endgroup::'
grep -F '#define' bld/lib/curl_config.h | sort || true
- name: 'build / ${{ matrix.build }}'
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
cmake --build bld --verbose
else
make -C bld V=1
fi
- name: 'curl -V'
run: |
find . -type f \( -name curl -o -name '*.dylib' -o -name '*.a' \) -print0 | xargs -0 file --
find . -type f \( -name curl -o -name '*.dylib' -o -name '*.a' \) -print0 | xargs -0 stat -f '%10z bytes: %N' --
bld/src/curl --disable --version