Dummy PCM compilation on an Apple Silicon Mac
Contents
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/gccand/usr/bin/cpprun) - 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'sbld.cfgfalls back to plaincpp, which is Apple clang's preprocessor on macOS. With-P -traditionalthis worked for the no-physics build. Thecpp-16workaround on the XIOS page is for the##macros in XIOS's own Fortran interface, not for the gcm. -
%C_COMPILER gccruns/usr/bin/gcc, which on macOS is Apple clang, not GNU gcc. - Harmless warning:
ld: warning: ignoring duplicate libraries: '-lnetcdf'. It appears becausenc-config --libsandnf-config --flibsboth list-lnetcdf.