Dummy PCM compilation on an Apple Silicon Mac

From Planets
Jump to: navigation, search

Compiling the Dummy PCM (LMDZ.COMMON, no physics) on Apple Silicon with XIOS

This page provides the LMDZ.COMMON arch files needed to build the dynamical core with no physics (-p nophys), MPI and XIOS output, on macOS with Homebrew gfortran and Homebrew Open MPI. It assumes XIOS has already been built with the CLANG_MACOSX arch files, as described on the XIOS compilation page (XIOS on an Apple Silicon Mac.

The one setting that differs from the stock arch-gfortran files is the C++ library in XIOS_LIB and discussed below for the interested reader - the background section.

Tested environment

  • macOS 26 (Darwin 25.6.0), Apple Silicon (arm64)
  • GNU Fortran 16.2.0 (Homebrew), installed as gfortran
  • Apple clang 21 (also what /usr/bin/gcc and /usr/bin/cpp run)
  • Open MPI 5.0.11 (Homebrew)
  • netCDF-C and netCDF-Fortran compiled from source against Open MPI, installed in /opt/parallel-netcdf
  • XIOS built with --arch CLANG_MACOSX (C++ compiled by clang against libc++)

Directory layout

The .path file finds IOIPSL and XIOS relative to the LMDZ.COMMON directory, so the three directories must sit side by side:

trunk/
  IOIPSL/
  LMDZ.COMMON/
  XIOS/

Arch files

Create these two files in LMDZ.COMMON/arch/. No .env file is needed: makelmdz_fcm uses an empty one if it is missing.

arch/arch-CLANG_MACOSX.fcm

%COMPILER            mpif90
%LINK                mpif90
%AR                  ar
%MAKE                make
%FPP_FLAGS           -P -traditional
%CPP_FLAGS           -P
%CPP_DEF             LAPACK
%FPP_DEF             NC_DOUBLE
%BASE_FFLAGS         -c -fdefault-real-8 -fdefault-double-8 -ffree-line-length-none -fno-align-commons -fallow-argument-mismatch -fcray-pointer
%PROD_FFLAGS         -O3
%DEV_FFLAGS          -O
%DEBUG_FFLAGS        -ffpe-trap=invalid,zero,overflow -fbounds-check -g3 -O0 -fstack-protector-all -finit-real=snan -fbacktrace
%C_COMPILER          gcc
%C_OPTIM             -O3
%MPI_FFLAGS
%OMP_FFLAGS
%BASE_LD
%MPI_LD
%OMP_LD

arch/arch-CLANG_MACOSX.path

nc-config and nf-config must be on your PATH.

ROOT=$PWD

NETCDF_INCDIR="$(nc-config --cflags) $(nf-config --fflags)"
NETCDF_LIBDIR="$(nc-config --libs) $(nf-config --flibs)"
NETCDF_LIB=""

IOIPSL_INCDIR="-I$ROOT/../IOIPSL/inc"
IOIPSL_LIBDIR="-L$ROOT/../IOIPSL/lib"
IOIPSL_LIB="-lioipsl"

XIOS_INCDIR="-I$ROOT/../XIOS/inc"
XIOS_LIBDIR="-L$ROOT/../XIOS/lib"
XIOS_LIB="-lxios -lc++"

Building

From the LMDZ.COMMON directory:

./makelmdz_fcm -arch CLANG_MACOSX -parallel mpi -io xios -d 32x32x12 -p nophys gcm

A successful build produces bin/gcm_32x32x12_phynophys_para.e.

Background: which C++ library libxios.a needs

Symptom with the stock setting

The stock gfortran arch files use XIOS_LIB="-lxios -lstdc++". With that setting, all Fortran sources compile, and then the final link fails with hundreds of undefined C++ symbols coming from libxios.a:

Undefined symbols for architecture arm64:
  "std::__1::regex_error::regex_error(std::__1::regex_constants::error_type)", referenced from:
      ... in libxios.a[366](server.o)
  "vtable for std::__1::basic_ios<char, std::__1::char_traits<char>>", referenced from:
      xios::CException::CException() in libxios.a[90](exception.o)
  ...
ld: symbol(s) not found for architecture arm64
collect2: error: ld returned 1 exit status

Two compilers, two C++ standard libraries

Two different toolchains build the pieces of this model:

Component Wrapper Underlying compiler C++ standard library
XIOS (C++ core) mpiCC Apple clang libc++ (LLVM), linked with -lc++
LMDZ (Fortran) mpif90 Homebrew gfortran none (GCC Fortran runtime)

mpiCC is not a separate C++ wrapper here. macOS filesystems are case-insensitive by default, so mpiCC and mpicc cannot both exist. Homebrew's Open MPI makes /opt/homebrew/bin/mpiCC a symlink to the C wrapper mpicc, which calls Apple clang:

$ mpiCC --showme
clang -I/opt/homebrew/Cellar/open-mpi/5.0.11/include -L/opt/homebrew/Cellar/open-mpi/5.0.11/lib -lmpi

clang compiles the XIOS .cpp files as C++, because it picks the language from the file extension. Unless it is given -stdlib=libstdc++, it compiles them against libc++, LLVM's C++ standard library. libc++ puts its symbols in the inline namespace std::__1::, which is why every missing symbol in the error starts with std::__1::.

GCC's g++ uses a different library, libstdc++ (-lstdc++), with its own symbol names such as std::__cxx11::. The two libraries are not interchangeable at link time: an object compiled against libc++ can only be linked with libc++.

The gcm is linked by mpif90 (gfortran), and gfortran does not add any C++ library on its own. The C++ library that libxios.a needs must be named in XIOS_LIB. -lstdc++ is right only when XIOS was compiled with g++. Here it was compiled with clang, so the linker looked for std::__1:: symbols in libstdc++, found none, and failed.

The XIOS arch file already makes the same choice for the XIOS executables:

%CCOMPILER      mpiCC
%LINKER         mpif90
%BASE_LD        -lc++

Fix

In arch/arch-CLANG_MACOSX.path:

- XIOS_LIB="-lxios -lstdc++"
+ XIOS_LIB="-lxios -lc++"

Checking which library your libxios.a needs

From LMDZ.COMMON:

nm -C ../XIOS/lib/libxios.a | grep -m1 'std::__1::'      # match -> libc++    (-lc++)
nm -C ../XIOS/lib/libxios.a | grep -m1 'std::__cxx11::'  # match -> libstdc++ (-lstdc++)

The rule: XIOS_LIB must name the same C++ library that compiled XIOS. If you rebuild XIOS with GCC's g++ instead, switch back to -lstdc++. One way to do that rebuild is to set %CCOMPILER mpicxx in the XIOS arch file and export OMPI_CXX=g++-16. Setting OMPI_CXX has no effect on mpiCC, because mpiCC is really mpicc, which reads OMPI_CC.

Other notes

  • Preprocessor. Unlike the XIOS build, this arch file does not set %FPP, so LMDZ.COMMON's bld.cfg falls back to plain cpp, which is Apple clang's preprocessor on macOS. With -P -traditional this worked for the no-physics build. The cpp-16 workaround on the XIOS page is for the ## macros in XIOS's own Fortran interface, not for the gcm.
  • %C_COMPILER gcc runs /usr/bin/gcc, which on macOS is Apple clang, not GNU gcc.
  • Harmless warning: ld: warning: ignoring duplicate libraries: '-lnetcdf'. It appears because nc-config --libs and nf-config --flibs both list -lnetcdf.