From 1974f20472e93203f91a9da87ad24c88f1843e14 Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Wed, 8 Oct 2025 11:36:03 +0200 Subject: [PATCH 1/6] download artifact @v5 --- .github/workflows/CI.yml | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c34573a400..6cbbdc9871 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -210,6 +210,7 @@ jobs: - uses: actions/checkout@v5 - name: Download Artifacts + id: download_windows_artifacts uses: actions/download-artifact@v5 with: path: ${{ github.workspace }} @@ -243,7 +244,25 @@ jobs: - name: Fetch Windows executable shell: msys2 {0} run: | - cp fpm-*/fpm-*-windows-*-gcc-${{ matrix.gcc_v }}.exe ./ci/fpm.exe + set -e + download_path='${{ steps.download_windows_artifacts.outputs.download-path }}' + download_path=${download_path%%$'\n'*} + if [ -z "$download_path" ]; then + echo "download-artifact did not report a download path" >&2 + exit 1 + fi + if command -v cygpath >/dev/null 2>&1; then + posix_path=$(cygpath -u "$download_path") + else + posix_path="$download_path" + fi + exe_path=$(find "$posix_path" -maxdepth 2 -type f -name "fpm-*-windows-*-gcc-${{ matrix.gcc_v }}.exe" | head -n 1) + if [ -z "$exe_path" ]; then + echo "Windows executable not found under $posix_path" >&2 + ls -al "$posix_path" || true + exit 1 + fi + cp "$exe_path" ./ci/fpm.exe - name: Fetch Git for Windows shell: msys2 {0} From d310fd33861dd0bbabf07fa50036b366443c9a88 Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Thu, 9 Oct 2025 08:53:05 +0200 Subject: [PATCH 2/6] CI: macos-13 -> macos-14 --- .github/workflows/CI.yml | 39 ++++++++++++++++++++++---------------- .github/workflows/meta.yml | 4 ++-- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 6cbbdc9871..7af7e12908 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-13, windows-latest] + os: [ubuntu-latest, macos-14, windows-latest] toolchain: - {compiler: gcc, version: 10} - {compiler: gcc, version: 11} @@ -31,7 +31,7 @@ jobs: - {compiler: gcc, version: 15} - {compiler: intel, version: 2025.1} exclude: - - os: macos-13 # No Intel on MacOS anymore since 2024 + - os: macos-14 # No Intel on MacOS anymore since 2024 toolchain: {compiler: intel, version: '2025.1'} - os: windows-latest # Doesn't pass build and tests yet toolchain: {compiler: intel, version: '2025.1'} @@ -45,14 +45,14 @@ jobs: - os: ubuntu-latest os-arch: linux-x86_64 release-flags: --flag '--static -g -fbacktrace -O3' - - os: macos-13 + - os: macos-14 os-arch: macos-x86_64 release-flags: --flag '-g -fbacktrace -O3' - os: windows-latest os-arch: windows-x86_64 release-flags: --flag '--static -g -fbacktrace -O3' exe: .exe - - os: macos-13 + - os: macos-14 toolchain: {compiler: gcc, version: 15} release-flags: --flag '-g -fbacktrace -Og -fcheck=all,no-recursion -Wno-external-argument-mismatch' @@ -71,23 +71,30 @@ jobs: - name: Install fpm uses: fortran-lang/setup-fpm@v7 with: - fpm-version: 'v0.8.0' + fpm-version: 'v0.12.0' - # Backport gfortran shared libraries to version 10 folder. This is necessary because the macOS release of fpm - # 0.10.0 used for bootstrapping has these paths hardcoded in the executable. + # Backport gfortran shared libraries to gcc@12 folder. This is necessary because the macOS x86_64 release + # of fpm v0.12.0 used for bootstrapping was built with gcc@12 and has these paths hardcoded in the executable. + # On ARM64 it runs under Rosetta 2 and needs /usr/local paths. - name: MacOS patch libgfortran - if: contains(matrix.os, 'macos') && !contains(matrix.toolchain.version, '10') + if: contains(matrix.os, 'macos') run: | which gfortran-${{ matrix.toolchain.version }} which gfortran - mkdir /usr/local/opt/gcc@10 - mkdir /usr/local/opt/gcc@10/lib - mkdir /usr/local/opt/gcc@10/lib/gcc - mkdir /usr/local/opt/gcc@10/lib/gcc/10 - mkdir /usr/local/lib/gcc/10 - ln -fs /usr/local/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib /usr/local/opt/gcc@10/lib/gcc/10/libquadmath.0.dylib - ln -fs /usr/local/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib /usr/local/opt/gcc@10/lib/gcc/10/libgfortran.5.dylib - ln -fs /usr/local/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib /usr/local/lib/gcc/10/libgcc_s.1.dylib + BREW_PREFIX=$(brew --prefix) + mkdir -p ${BREW_PREFIX}/opt/gcc@12/lib/gcc/12 + mkdir -p ${BREW_PREFIX}/lib/gcc/12 + ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib ${BREW_PREFIX}/opt/gcc@12/lib/gcc/12/libquadmath.0.dylib + ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib ${BREW_PREFIX}/opt/gcc@12/lib/gcc/12/libgfortran.5.dylib + ln -fs ${BREW_PREFIX}/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib ${BREW_PREFIX}/lib/gcc/12/libgcc_s.1.dylib + # For ARM64 (Apple Silicon): create /usr/local symlinks for x86_64 bootstrap binary running under Rosetta 2 + if [ "${BREW_PREFIX}" != "/usr/local" ]; then + sudo mkdir -p /usr/local/opt/gcc@12/lib/gcc/12 + sudo mkdir -p /usr/local/lib/gcc/12 + sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib /usr/local/opt/gcc@12/lib/gcc/12/libquadmath.0.dylib + sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib /usr/local/opt/gcc@12/lib/gcc/12/libgfortran.5.dylib + sudo ln -fs ${BREW_PREFIX}/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib /usr/local/lib/gcc/12/libgcc_s.1.dylib + fi # gcc and g++ will point to clang/clang++: use versioned alias for fpm - name: MacOS patch C and C++ compilers diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml index 210fd99cf2..2394d20516 100644 --- a/.github/workflows/meta.yml +++ b/.github/workflows/meta.yml @@ -39,10 +39,10 @@ jobs: - os: ubuntu-latest mpi: mpich release-flags: --flag ' -Wno-external-argument-mismatch' - - os: macos-13 + - os: macos-14 mpi: openmpi release-flags: --flag ' -Wno-external-argument-mismatch' - - os: macos-13 + - os: macos-14 mpi: mpich release-flags: --flag ' -Wno-external-argument-mismatch' - os: ubuntu-latest From b734524e0f502e74ccc6e060fafa583ff1fc46be Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Thu, 9 Oct 2025 08:53:05 +0200 Subject: [PATCH 3/6] CI: macos-13 -> macos-14 --- .github/workflows/CI.yml | 32 ++++++++++++++++---------------- .github/workflows/meta.yml | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 6cbbdc9871..b0c9a136c0 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-13, windows-latest] + os: [ubuntu-latest, macos-14, windows-latest] toolchain: - {compiler: gcc, version: 10} - {compiler: gcc, version: 11} @@ -31,7 +31,7 @@ jobs: - {compiler: gcc, version: 15} - {compiler: intel, version: 2025.1} exclude: - - os: macos-13 # No Intel on MacOS anymore since 2024 + - os: macos-14 # No Intel on MacOS anymore since 2024 toolchain: {compiler: intel, version: '2025.1'} - os: windows-latest # Doesn't pass build and tests yet toolchain: {compiler: intel, version: '2025.1'} @@ -45,14 +45,14 @@ jobs: - os: ubuntu-latest os-arch: linux-x86_64 release-flags: --flag '--static -g -fbacktrace -O3' - - os: macos-13 + - os: macos-14 os-arch: macos-x86_64 release-flags: --flag '-g -fbacktrace -O3' - os: windows-latest os-arch: windows-x86_64 release-flags: --flag '--static -g -fbacktrace -O3' exe: .exe - - os: macos-13 + - os: macos-14 toolchain: {compiler: gcc, version: 15} release-flags: --flag '-g -fbacktrace -Og -fcheck=all,no-recursion -Wno-external-argument-mismatch' @@ -71,23 +71,23 @@ jobs: - name: Install fpm uses: fortran-lang/setup-fpm@v7 with: - fpm-version: 'v0.8.0' + fpm-version: 'v0.12.0' - # Backport gfortran shared libraries to version 10 folder. This is necessary because the macOS release of fpm - # 0.10.0 used for bootstrapping has these paths hardcoded in the executable. + # Backport gfortran shared libraries to gcc@12 folder. This is necessary because the macOS x86_64 release + # of fpm v0.12.0 used for bootstrapping was built with gcc@12 and has these paths hardcoded in the executable. + # On ARM64 it runs under Rosetta 2 and needs /usr/local paths. - name: MacOS patch libgfortran - if: contains(matrix.os, 'macos') && !contains(matrix.toolchain.version, '10') + if: contains(matrix.os, 'macos') run: | which gfortran-${{ matrix.toolchain.version }} which gfortran - mkdir /usr/local/opt/gcc@10 - mkdir /usr/local/opt/gcc@10/lib - mkdir /usr/local/opt/gcc@10/lib/gcc - mkdir /usr/local/opt/gcc@10/lib/gcc/10 - mkdir /usr/local/lib/gcc/10 - ln -fs /usr/local/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib /usr/local/opt/gcc@10/lib/gcc/10/libquadmath.0.dylib - ln -fs /usr/local/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib /usr/local/opt/gcc@10/lib/gcc/10/libgfortran.5.dylib - ln -fs /usr/local/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib /usr/local/lib/gcc/10/libgcc_s.1.dylib + BREW_PREFIX=$(brew --prefix) + # x86_64 bootstrap binary expects gcc@12 libraries at /usr/local (runs natively on x86_64, under Rosetta 2 on ARM64) + sudo mkdir -p /usr/local/opt/gcc@12/lib/gcc/12 + sudo mkdir -p /usr/local/lib/gcc/12 + sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib /usr/local/opt/gcc@12/lib/gcc/12/libquadmath.0.dylib + sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib /usr/local/opt/gcc@12/lib/gcc/12/libgfortran.5.dylib + sudo ln -fs ${BREW_PREFIX}/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib /usr/local/lib/gcc/12/libgcc_s.1.dylib # gcc and g++ will point to clang/clang++: use versioned alias for fpm - name: MacOS patch C and C++ compilers diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml index 210fd99cf2..2394d20516 100644 --- a/.github/workflows/meta.yml +++ b/.github/workflows/meta.yml @@ -39,10 +39,10 @@ jobs: - os: ubuntu-latest mpi: mpich release-flags: --flag ' -Wno-external-argument-mismatch' - - os: macos-13 + - os: macos-14 mpi: openmpi release-flags: --flag ' -Wno-external-argument-mismatch' - - os: macos-13 + - os: macos-14 mpi: mpich release-flags: --flag ' -Wno-external-argument-mismatch' - os: ubuntu-latest From c651d513ad438e24f05595bb36cd03e974ab1b7b Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Sun, 12 Oct 2025 10:50:48 +0200 Subject: [PATCH 4/6] query libgfortran/libquadmath from fpm directly --- .github/workflows/CI.yml | 47 ++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b0c9a136c0..8e5104d3e7 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -69,12 +69,13 @@ jobs: # Phase 1: Bootstrap fpm with existing version - name: Install fpm - uses: fortran-lang/setup-fpm@v7 + uses: fortran-lang/setup-fpm@v8 with: fpm-version: 'v0.12.0' - # Backport gfortran shared libraries to gcc@12 folder. This is necessary because the macOS x86_64 release - # of fpm v0.12.0 used for bootstrapping was built with gcc@12 and has these paths hardcoded in the executable. + # Backport gfortran shared libraries to the paths expected by the bootstrap fpm binary. + # The macOS x86_64 release used for bootstrapping has hardcoded library paths from the gcc version + # it was built with. Query those paths using otool and create symlinks to the current gcc version. # On ARM64 it runs under Rosetta 2 and needs /usr/local paths. - name: MacOS patch libgfortran if: contains(matrix.os, 'macos') @@ -82,12 +83,40 @@ jobs: which gfortran-${{ matrix.toolchain.version }} which gfortran BREW_PREFIX=$(brew --prefix) - # x86_64 bootstrap binary expects gcc@12 libraries at /usr/local (runs natively on x86_64, under Rosetta 2 on ARM64) - sudo mkdir -p /usr/local/opt/gcc@12/lib/gcc/12 - sudo mkdir -p /usr/local/lib/gcc/12 - sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib /usr/local/opt/gcc@12/lib/gcc/12/libquadmath.0.dylib - sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib /usr/local/opt/gcc@12/lib/gcc/12/libgfortran.5.dylib - sudo ln -fs ${BREW_PREFIX}/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib /usr/local/lib/gcc/12/libgcc_s.1.dylib + + # Query the actual library paths that fpm expects + echo "Checking library dependencies of fpm bootstrap binary..." + otool -L $(which fpm) + + # Extract the expected libgfortran path and create the target directory + LIBGFORTRAN_PATH=$(otool -L $(which fpm) | grep libgfortran | awk '{print $1}' | head -n 1) + if [ -n "$LIBGFORTRAN_PATH" ]; then + TARGET_DIR=$(dirname "$LIBGFORTRAN_PATH") + echo "Creating directory: $TARGET_DIR" + sudo mkdir -p "$TARGET_DIR" + echo "Linking libgfortran from ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib to $LIBGFORTRAN_PATH" + sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib "$LIBGFORTRAN_PATH" + fi + + # Extract the expected libquadmath path and create the target directory + LIBQUADMATH_PATH=$(otool -L $(which fpm) | grep libquadmath | awk '{print $1}' | head -n 1) + if [ -n "$LIBQUADMATH_PATH" ]; then + TARGET_DIR=$(dirname "$LIBQUADMATH_PATH") + echo "Creating directory: $TARGET_DIR" + sudo mkdir -p "$TARGET_DIR" + echo "Linking libquadmath from ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib to $LIBQUADMATH_PATH" + sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib "$LIBQUADMATH_PATH" + fi + + # Extract the expected libgcc_s path and create the target directory + LIBGCC_PATH=$(otool -L $(which fpm) | grep libgcc_s | awk '{print $1}' | head -n 1) + if [ -n "$LIBGCC_PATH" ]; then + TARGET_DIR=$(dirname "$LIBGCC_PATH") + echo "Creating directory: $TARGET_DIR" + sudo mkdir -p "$TARGET_DIR" + echo "Linking libgcc_s from ${BREW_PREFIX}/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib to $LIBGCC_PATH" + sudo ln -fs ${BREW_PREFIX}/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib "$LIBGCC_PATH" + fi # gcc and g++ will point to clang/clang++: use versioned alias for fpm - name: MacOS patch C and C++ compilers From 15b5d5014c41906589f43475d138d7d5e935a38d Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Sun, 12 Oct 2025 10:59:34 +0200 Subject: [PATCH 5/6] deprecate gcc-10 on macos-14 --- .github/workflows/CI.yml | 63 ++++++++++++++++++----- .github/workflows/meta.yml | 102 ++++++++++++++++++++++++++++++------- 2 files changed, 134 insertions(+), 31 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 8e5104d3e7..56241a3fc0 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -33,6 +33,8 @@ jobs: exclude: - os: macos-14 # No Intel on MacOS anymore since 2024 toolchain: {compiler: intel, version: '2025.1'} + - os: macos-14 # gcc@10 not available on macos-14 (ARM64) + toolchain: {compiler: gcc, version: 10} - os: windows-latest # Doesn't pass build and tests yet toolchain: {compiler: intel, version: '2025.1'} - os: windows-latest # gcc 14 not available on Windows yet @@ -75,7 +77,7 @@ jobs: # Backport gfortran shared libraries to the paths expected by the bootstrap fpm binary. # The macOS x86_64 release used for bootstrapping has hardcoded library paths from the gcc version - # it was built with. Query those paths using otool and create symlinks to the current gcc version. + # it was built with. If the versions match, skip this step. Otherwise, create symlinks. # On ARM64 it runs under Rosetta 2 and needs /usr/local paths. - name: MacOS patch libgfortran if: contains(matrix.os, 'macos') @@ -88,34 +90,69 @@ jobs: echo "Checking library dependencies of fpm bootstrap binary..." otool -L $(which fpm) - # Extract the expected libgfortran path and create the target directory + # Extract the gcc version from the bootstrap binary's library paths + BOOTSTRAP_GCC_VERSION=$(otool -L $(which fpm) | grep -o 'gcc@[0-9]\+' | head -n 1 | cut -d@ -f2) + if [ -z "$BOOTSTRAP_GCC_VERSION" ]; then + # Try alternative pattern: /lib/gcc/13/ -> extract 13 + BOOTSTRAP_GCC_VERSION=$(otool -L $(which fpm) | grep libgfortran | grep -o '/lib/gcc/[0-9]\+/' | grep -o '[0-9]\+' | head -n 1) + fi + + echo "Bootstrap fpm built with gcc@$BOOTSTRAP_GCC_VERSION" + echo "Current toolchain: gcc@${{ matrix.toolchain.version }}" + + if [ "$BOOTSTRAP_GCC_VERSION" == "${{ matrix.toolchain.version }}" ]; then + echo "✓ Bootstrap gcc version matches current toolchain - no patching needed" + exit 0 + fi + + echo "⚠ Version mismatch detected - creating compatibility symlinks..." + + # Find the actual Cellar path by following the symlink + if [ -L "${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}" ]; then + GCC_CELLAR_PATH=$(cd -P "${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}" && pwd) + else + GCC_CELLAR_PATH="${BREW_PREFIX}/Cellar/gcc@${{ matrix.toolchain.version }}"/* + fi + echo "GCC Cellar path: $GCC_CELLAR_PATH" + + # Find the actual library files + CURRENT_GFORTRAN=$(find "$GCC_CELLAR_PATH"/lib/gcc/${{ matrix.toolchain.version }} -name "libgfortran.*.dylib" 2>/dev/null | head -n 1) + CURRENT_QUADMATH=$(find "$GCC_CELLAR_PATH"/lib/gcc/${{ matrix.toolchain.version }} -name "libquadmath.*.dylib" 2>/dev/null | head -n 1) + CURRENT_GCC_S=$(find "$GCC_CELLAR_PATH"/lib/gcc/${{ matrix.toolchain.version }} -name "libgcc_s.*.dylib" 2>/dev/null | head -n 1) + + echo "Current gcc@${{ matrix.toolchain.version }} libraries:" + echo " libgfortran: $CURRENT_GFORTRAN" + echo " libquadmath: $CURRENT_QUADMATH" + echo " libgcc_s: $CURRENT_GCC_S" + + # Extract the expected libgfortran path and create symlink LIBGFORTRAN_PATH=$(otool -L $(which fpm) | grep libgfortran | awk '{print $1}' | head -n 1) - if [ -n "$LIBGFORTRAN_PATH" ]; then + if [ -n "$LIBGFORTRAN_PATH" ] && [ -n "$CURRENT_GFORTRAN" ]; then TARGET_DIR=$(dirname "$LIBGFORTRAN_PATH") echo "Creating directory: $TARGET_DIR" sudo mkdir -p "$TARGET_DIR" - echo "Linking libgfortran from ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib to $LIBGFORTRAN_PATH" - sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib "$LIBGFORTRAN_PATH" + echo "Linking $CURRENT_GFORTRAN to $LIBGFORTRAN_PATH" + sudo ln -fs "$CURRENT_GFORTRAN" "$LIBGFORTRAN_PATH" fi - # Extract the expected libquadmath path and create the target directory + # Extract the expected libquadmath path and create symlink LIBQUADMATH_PATH=$(otool -L $(which fpm) | grep libquadmath | awk '{print $1}' | head -n 1) - if [ -n "$LIBQUADMATH_PATH" ]; then + if [ -n "$LIBQUADMATH_PATH" ] && [ -n "$CURRENT_QUADMATH" ]; then TARGET_DIR=$(dirname "$LIBQUADMATH_PATH") echo "Creating directory: $TARGET_DIR" sudo mkdir -p "$TARGET_DIR" - echo "Linking libquadmath from ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib to $LIBQUADMATH_PATH" - sudo ln -fs ${BREW_PREFIX}/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib "$LIBQUADMATH_PATH" + echo "Linking $CURRENT_QUADMATH to $LIBQUADMATH_PATH" + sudo ln -fs "$CURRENT_QUADMATH" "$LIBQUADMATH_PATH" fi - # Extract the expected libgcc_s path and create the target directory + # Extract the expected libgcc_s path and create symlink LIBGCC_PATH=$(otool -L $(which fpm) | grep libgcc_s | awk '{print $1}' | head -n 1) - if [ -n "$LIBGCC_PATH" ]; then + if [ -n "$LIBGCC_PATH" ] && [ -n "$CURRENT_GCC_S" ]; then TARGET_DIR=$(dirname "$LIBGCC_PATH") echo "Creating directory: $TARGET_DIR" sudo mkdir -p "$TARGET_DIR" - echo "Linking libgcc_s from ${BREW_PREFIX}/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib to $LIBGCC_PATH" - sudo ln -fs ${BREW_PREFIX}/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib "$LIBGCC_PATH" + echo "Linking $CURRENT_GCC_S to $LIBGCC_PATH" + sudo ln -fs "$CURRENT_GCC_S" "$LIBGCC_PATH" fi # gcc and g++ will point to clang/clang++: use versioned alias for fpm diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml index 2394d20516..fa54d23040 100644 --- a/.github/workflows/meta.yml +++ b/.github/workflows/meta.yml @@ -208,7 +208,8 @@ jobs: # Only install gcc if not already available which gfortran-${{ env.GCC_V }} || brew install gcc@${{ env.GCC_V }} which gfortran-${{ env.GCC_V }} - which gfortran || ln -s /usr/local/bin/gfortran-${{ env.GCC_V }} /usr/local/bin/gfortran + BREW_PREFIX=$(brew --prefix) + which gfortran || ln -s ${BREW_PREFIX}/bin/gfortran-${{ env.GCC_V }} ${BREW_PREFIX}/bin/gfortran - name: (macOS) Install homebrew MPICH if: contains(matrix.mpi,'mpich') && contains(matrix.os,'macos') @@ -231,26 +232,91 @@ jobs: brew install netcdf brew install netcdf-fortran - - name: (macOS) Patch gfortran paths - if: contains(matrix.os,'macos') - run: | - # Backport gfortran shared libraries to version 10 folder. This is necessary because all macOS releases of fpm - # have these paths hardcoded in the executable (no PIC?). Current bootstrap version 0.8.0 has gcc-10 - mkdir /usr/local/opt/gcc@10 - mkdir /usr/local/opt/gcc@10/lib - mkdir /usr/local/opt/gcc@10/lib/gcc - mkdir /usr/local/opt/gcc@10/lib/gcc/10 - mkdir /usr/local/lib/gcc/10 - ln -fs /usr/local/opt/gcc@${{ env.GCC_V }}/lib/gcc/${{ env.GCC_V }}/libquadmath.0.dylib /usr/local/opt/gcc@10/lib/gcc/10/libquadmath.0.dylib - ln -fs /usr/local/opt/gcc@${{ env.GCC_V }}/lib/gcc/${{ env.GCC_V }}/libgfortran.5.dylib /usr/local/opt/gcc@10/lib/gcc/10/libgfortran.5.dylib - # Newer gcc versions use libgcc_s.1.1.dylib - ln -fs /usr/local/lib/gcc/${{ env.GCC_V }}/libgcc_s.1.dylib /usr/local/lib/gcc/10/libgcc_s.1.dylib || ln -fs /usr/local/lib/gcc/${{ env.GCC_V }}/libgcc_s.1.1.dylib /usr/local/lib/gcc/10/libgcc_s.1.dylib - # Phase 1: Bootstrap fpm with existing version - name: Install fpm - uses: fortran-lang/setup-fpm@v7 + uses: fortran-lang/setup-fpm@v8 with: - fpm-version: 'v0.8.0' + fpm-version: 'v0.12.0' + + # Backport gfortran shared libraries to the paths expected by the bootstrap fpm binary. + # The macOS x86_64 release used for bootstrapping has hardcoded library paths from the gcc version + # it was built with. If the versions match, skip this step. Otherwise, create symlinks. + # On ARM64 it runs under Rosetta 2 and needs /usr/local paths. + - name: MacOS patch libgfortran + if: contains(matrix.os, 'macos') + run: | + which gfortran-${{ env.GCC_V }} + which gfortran || true + BREW_PREFIX=$(brew --prefix) + + # Query the actual library paths that fpm expects + echo "Checking library dependencies of fpm bootstrap binary..." + otool -L $(which fpm) + + # Extract the gcc version from the bootstrap binary's library paths + BOOTSTRAP_GCC_VERSION=$(otool -L $(which fpm) | grep -o 'gcc@[0-9]\+' | head -n 1 | cut -d@ -f2) + if [ -z "$BOOTSTRAP_GCC_VERSION" ]; then + # Try alternative pattern: /lib/gcc/13/ -> extract 13 + BOOTSTRAP_GCC_VERSION=$(otool -L $(which fpm) | grep libgfortran | grep -o '/lib/gcc/[0-9]\+/' | grep -o '[0-9]\+' | head -n 1) + fi + + echo "Bootstrap fpm built with gcc@$BOOTSTRAP_GCC_VERSION" + echo "Current toolchain: gcc@${{ env.GCC_V }}" + + if [ "$BOOTSTRAP_GCC_VERSION" == "${{ env.GCC_V }}" ]; then + echo "✓ Bootstrap gcc version matches current toolchain - no patching needed" + exit 0 + fi + + echo "⚠ Version mismatch detected - creating compatibility symlinks..." + + # Find the actual Cellar path by following the symlink + if [ -L "${BREW_PREFIX}/opt/gcc@${{ env.GCC_V }}" ]; then + GCC_CELLAR_PATH=$(cd -P "${BREW_PREFIX}/opt/gcc@${{ env.GCC_V }}" && pwd) + else + GCC_CELLAR_PATH="${BREW_PREFIX}/Cellar/gcc@${{ env.GCC_V }}"/* + fi + echo "GCC Cellar path: $GCC_CELLAR_PATH" + + # Find the actual library files + CURRENT_GFORTRAN=$(find "$GCC_CELLAR_PATH"/lib/gcc/${{ env.GCC_V }} -name "libgfortran.*.dylib" 2>/dev/null | head -n 1) + CURRENT_QUADMATH=$(find "$GCC_CELLAR_PATH"/lib/gcc/${{ env.GCC_V }} -name "libquadmath.*.dylib" 2>/dev/null | head -n 1) + CURRENT_GCC_S=$(find "$GCC_CELLAR_PATH"/lib/gcc/${{ env.GCC_V }} -name "libgcc_s.*.dylib" 2>/dev/null | head -n 1) + + echo "Current gcc@${{ env.GCC_V }} libraries:" + echo " libgfortran: $CURRENT_GFORTRAN" + echo " libquadmath: $CURRENT_QUADMATH" + echo " libgcc_s: $CURRENT_GCC_S" + + # Extract the expected libgfortran path and create symlink + LIBGFORTRAN_PATH=$(otool -L $(which fpm) | grep libgfortran | awk '{print $1}' | head -n 1) + if [ -n "$LIBGFORTRAN_PATH" ] && [ -n "$CURRENT_GFORTRAN" ]; then + TARGET_DIR=$(dirname "$LIBGFORTRAN_PATH") + echo "Creating directory: $TARGET_DIR" + sudo mkdir -p "$TARGET_DIR" + echo "Linking $CURRENT_GFORTRAN to $LIBGFORTRAN_PATH" + sudo ln -fs "$CURRENT_GFORTRAN" "$LIBGFORTRAN_PATH" + fi + + # Extract the expected libquadmath path and create symlink + LIBQUADMATH_PATH=$(otool -L $(which fpm) | grep libquadmath | awk '{print $1}' | head -n 1) + if [ -n "$LIBQUADMATH_PATH" ] && [ -n "$CURRENT_QUADMATH" ]; then + TARGET_DIR=$(dirname "$LIBQUADMATH_PATH") + echo "Creating directory: $TARGET_DIR" + sudo mkdir -p "$TARGET_DIR" + echo "Linking $CURRENT_QUADMATH to $LIBQUADMATH_PATH" + sudo ln -fs "$CURRENT_QUADMATH" "$LIBQUADMATH_PATH" + fi + + # Extract the expected libgcc_s path and create symlink + LIBGCC_PATH=$(otool -L $(which fpm) | grep libgcc_s | awk '{print $1}' | head -n 1) + if [ -n "$LIBGCC_PATH" ] && [ -n "$CURRENT_GCC_S" ]; then + TARGET_DIR=$(dirname "$LIBGCC_PATH") + echo "Creating directory: $TARGET_DIR" + sudo mkdir -p "$TARGET_DIR" + echo "Linking $CURRENT_GCC_S to $LIBGCC_PATH" + sudo ln -fs "$CURRENT_GCC_S" "$LIBGCC_PATH" + fi - name: Remove fpm from path shell: bash From 11e1a6e450ef6f329f602056cc2ef404ea890315 Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Mon, 13 Oct 2025 10:27:45 +0200 Subject: [PATCH 6/6] Update .github/workflows/CI.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 56241a3fc0..87e68e222e 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -312,7 +312,7 @@ jobs: run: | set -e download_path='${{ steps.download_windows_artifacts.outputs.download-path }}' - download_path=${download_path%%$'\n'*} + download_path=$(printf '%s\n' "$download_path" | head -n1) if [ -z "$download_path" ]; then echo "download-artifact did not report a download path" >&2 exit 1