CMake and MPI Fortran: CMake doesn't see it

All,

This is a weird one. So for reasons unknown to me, when I’m building Open MPI with NAG Fortran and Clang on my MacBook, I need to do it as a static library. I know, I know…I don’t like that either, but even MPICH forces me to.

So, fine, I build Open MPI and then I test it:

❯ mpifort -V
NAG Fortran Compiler Release 7.0(Yurakucho) Build 7066
Product NPMI670NA for Apple Intel Mac OSX 64-bit
Copyright 1990-2020 The Numerical Algorithms Group Ltd., Oxford, U.K.
❯ mpifort -fpp -o helloWorld.mpi2.exe helloWorld.mpi2.F90
NAG Fortran Compiler Release 7.0(Yurakucho) Build 7066
Warning: helloWorld.mpi2.F90, line 42: Unused local variable MY_COMPILER_VERSION
[NAG Fortran Compiler normal termination, 1 warning]
❯ mpirun -np 4 ./helloWorld.mpi2.exe
MPI Version: 3.1
MPI Library Version: Open MPI v4.1.2, package: Open MPI mathomp4@gs614-mchi-L248.ndc.nasa.gov Distribution, ident: 4.1.2, repo rev: v4.1.2, Nov 24, 2021
Process    0 of    4 is on gs614-mchi-L248.ndc.nasa.gov
Process    1 of    4 is on gs614-mchi-L248.ndc.nasa.gov
Process    2 of    4 is on gs614-mchi-L248.ndc.nasa.gov
Process    3 of    4 is on gs614-mchi-L248.ndc.nasa.gov

It builds, it runs. Now, I make a simple CMakeLists.txt:

cmake_minimum_required(VERSION 3.22)
project(test VERSION 1.0.0 LANGUAGES Fortran)

find_package(MPI REQUIRED)
add_executable(helloWorld.mpi2.exe helloWorld.mpi2.F90)
target_link_libraries(helloWorld.mpi2.exe MPI::MPI_Fortran)

if(CMAKE_Fortran_COMPILER_ID MATCHES "NAG")
  add_compile_options(-fpp)
endif()

And…

❯ cmake --version
cmake version 3.22.1

CMake suite maintained and supported by Kitware (kitware.com/cmake).
❯ cmake -B build-NAG
-- The Fortran compiler identification is NAG 7.0.7066
-- Detecting NAG Fortran directory
-- Detecting NAG Fortran directory - /Users/mathomp4/installed/Core/nag/7.0_7066/lib/NAG_Fortran
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Check for working Fortran compiler: /Users/mathomp4/installed/Core/nag/7.0_7066/bin/nagfor - skipped
-- Could NOT find MPI_Fortran (missing: MPI_Fortran_WORKS)
CMake Error at /Users/mathomp4/.homebrew/brew/Cellar/cmake/3.22.1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find MPI (missing: MPI_Fortran_FOUND)
Call Stack (most recent call first):
  /Users/mathomp4/.homebrew/brew/Cellar/cmake/3.22.1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:594 (_FPHSA_FAILURE_MESSAGE)
  /Users/mathomp4/.homebrew/brew/Cellar/cmake/3.22.1/share/cmake/Modules/FindMPI.cmake:1830 (find_package_handle_standard_args)
  CMakeLists.txt:4 (find_package)


-- Configuring incomplete, errors occurred!
See also "/Users/mathomp4/F90Files/OpenMPINag/build-NAG/CMakeFiles/CMakeOutput.log".
See also "/Users/mathomp4/F90Files/OpenMPINag/build-NAG/CMakeFiles/CMakeError.log".

So…huh. I’m not sure how to solve this. I mean, mpifort does work, I just used it with the exact same file. Is this because I built the library as static?

Can you try changing your find_package call to find_package(MPI COMPONENTS Fortran REQUIRED) as the FindMPI documentation suggests (indirectly)?

@vre Leads to the same error:

cmake_minimum_required(VERSION 3.22)
project(test VERSION 1.0.0 LANGUAGES Fortran)

#find_package(MPI REQUIRED)
find_package(MPI COMPONENTS Fortran REQUIRED)
add_executable(helloWorld.mpi2.exe helloWorld.mpi2.F90)
target_link_libraries(helloWorld.mpi2.exe MPI::MPI_Fortran)

if(CMAKE_Fortran_COMPILER_ID MATCHES "NAG")
  add_compile_options(-fpp -mismatch_all)
endif()
❯ cmake -B build-NAG-components
-- The Fortran compiler identification is NAG 7.0.7066
-- Detecting NAG Fortran directory
-- Detecting NAG Fortran directory - /Users/mathomp4/installed/Core/nag/7.0_7066/lib/NAG_Fortran
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Check for working Fortran compiler: /Users/mathomp4/installed/Core/nag/7.0_7066/bin/nagfor - skipped
-- Could NOT find MPI_Fortran (missing: MPI_Fortran_WORKS)
CMake Error at /Users/mathomp4/.homebrew/brew/Cellar/cmake/3.22.1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find MPI (missing: MPI_Fortran_FOUND Fortran)
Call Stack (most recent call first):
  /Users/mathomp4/.homebrew/brew/Cellar/cmake/3.22.1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:594 (_FPHSA_FAILURE_MESSAGE)
  /Users/mathomp4/.homebrew/brew/Cellar/cmake/3.22.1/share/cmake/Modules/FindMPI.cmake:1830 (find_package_handle_standard_args)
  CMakeLists.txt:5 (find_package)


-- Configuring incomplete, errors occurred!
See also "/Users/mathomp4/F90Files/OpenMPINag/build-NAG-components/CMakeFiles/CMakeOutput.log".
See also "/Users/mathomp4/F90Files/OpenMPINag/build-NAG-components/CMakeFiles/CMakeError.log".

That said, in case it helps anyone, here are the CMakeOutput.log and CMakeError.log files

CMakeOutput.log (9.8 KB)
CMakeError.log (142.0 KB)

Well, staring at those error files I do see:

Linking Fortran executable cmTC_0369a
/Users/mathomp4/.homebrew/brew/Cellar/cmake/3.22.1/bin/cmake -E cmake_link_script CMakeFiles/cmTC_0369a.dir/link.txt --verbose=1
/Users/mathomp4/installed/Core/nag/7.0_7066/bin/nagfor -Wl,-flat_namespace CMakeFiles/cmTC_0369a.dir/test_mpi.f90.o -o cmTC_0369a  /Users/mathomp4/insta
lled/Compiler/nag-7.0_7066/openmpi/4.1.2/lib/libmpi_usempi.a /Users/mathomp4/installed/Compiler/nag-7.0_7066/openmpi/4.1.2/lib/libmpi_mpifh.a /Users/mat
homp4/installed/Compiler/nag-7.0_7066/openmpi/4.1.2/lib/libmpi.a /Users/mathomp4/installed/Compiler/nag-7.0_7066/openmpi/4.1.2/lib/libopen-rte.a /Users/
mathomp4/installed/Compiler/nag-7.0_7066/openmpi/4.1.2/lib/libopen-pal.a /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/
SDKs/MacOSX12.1.sdk/usr/lib/libm.tbd /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/usr/lib/libz.tbd

NAG Fortran Compiler Release 7.0(Yurakucho) Build 7066
Error: Unrecognised file suffix .tbd

So, huh. it’s like CMake is somehow “expanding” out the mpifort -show line:

/Users/mathomp4/installed/Core/nag/7.0_7066/bin/nagfor -I/Users/mathomp4/installed/Compiler/nag-7.0_7066/openmpi/4.1.2/include -Wl,-flat_namespace -I/Users/mathomp4/installed/Compiler/nag-7.0_7066/openmpi/4.1.2/lib -L/Users/mathomp4/installed/Compiler/nag-7.0_7066/openmpi/4.1.2/lib -lmpi_usempi -lmpi_mpifh -lmpi -lopen-rte -lopen-pal -lm -lz

and unfortunately on macOS, libm and libz are not libm.a and libz.a but libm.tbd and libz.tbd. Oof.

It looks like the NAG compiler needs to learn about the .tbd stub linker files instead of choking on them. Is there a newer NAG release you could use? Does running the compiler manually work? If so, figuring out where those arguments are coming from would be useful.

@ben.boeckel Yes, running mpifort against helloworld or whatever is just fine as you can see above. I’ll gladly run any commands to help suss things out but my try with --verbose flags wasn’t too…verbose.

mpifort is not a Fortran compiler, but a wrapper around one provided by the MPI implementation. CMake generally prefers to run compilers directly (because wrappers can do…funny things). Can the NAG compiler be taught about the .tbd suffix? If not, changing your Fortran compiler to be mpifort may be the best solution until NAG updates their macOS support.

Interesting. I guess that does work:

❯ cmake -B build-NAG-mpifort -DCMAKE_Fortran_COMPILER=mpifort
-- The Fortran compiler identification is NAG 7.0.7066
-- Detecting NAG Fortran directory
-- Detecting NAG Fortran directory - /Users/mathomp4/installed/Core/nag/7.0_7066/lib/NAG_Fortran
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Check for working Fortran compiler: /Users/mathomp4/installed/Compiler/nag-7.0_7066/openmpi/4.1.2/bin/mpifort - skipped
-- Found MPI_Fortran: /Users/mathomp4/installed/Compiler/nag-7.0_7066/openmpi/4.1.2/bin/mpifort (found version "3.1")
-- Found MPI: TRUE (found version "3.1") found components: Fortran
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/mathomp4/F90Files/OpenMPINag/build-NAG-mpifort

Hmmm. My guess is though this could cause some issues in our system…though maybe not. We used to always build our code with mpifort say, but CMake let us move away from that so we are no longer compiling non-MPI code with mpi wrappers (which caused fun at run time).

Still, I’ll try contacting NAG Support about the .tbd files. It probably is something they’ll need to know about if supporting macOS. I’ll try out “use mpifort” for full build

An update! I think I figured out why I couldn’t build Open MPI as a shared library with NAG anymore. It’s an exciting annoying tale, but since I wildly prefer shared-library Open MPI over static, this might be a moot point.

I mean, NAG still needs to support .tbd files, but I’m not sure I’ll be able to convince them how.

For now, I’ll mark @ben.boeckel 's response as a “solution” so that this is marked as solved.

If they want to support linking the stubs on macOS, they’ll need to. I doubt that NAG has its own linker, but if it does, they’re basically (AFAIK) stubs that say “this is provided by Apple, so Trust Us™”. If they don’t have a linker of their own, whatever filter they have just needs to let .tbd arguments through the same as .dylib arguments.

Taking a look at the files, they are YAML documents with the relevant information needed:

  • target triples supported
  • symbols exported
  • location on an Apple system
  • version info

So it’s probably easier than extracting that info from a Mach-O binary anyways.

If CMake wants to support the NAG Fortran Compiler, it needs to use that compiler’s documented interface to the linker.

nagfor, the NAG Fortran Compiler driver, uses gcc as the linker. An option is passed to the linking invocation of gcc with -Wl,option.

For gcc to pass options to the linker, gcc also uses -Wl,option.

So, the invocation of nagfor should be -Wl,-Wl,option.

For example:

Command Line

mpif90 -Wl,-Wl,/path/to/libz.tbd ring_usempi.f90

Also, if you are faced with a tool that wrongly throws unsupported options to nagfor, the solution is a bit more work (if you can’t/won’t fix the tool): You write a wrapper program (I write mine in Fortran, but python/shell/C/etc are options) that reads all the arguments, filters out the unsupported ones, constructs new ones depending on your need, and then calls the nagfor driver with the corrected arguments. You could even intercept the diagnostics output by nagfor, log all options and sources given during a build, and even modify the exit status of your wrapper driver.

Oh, if that’s the case, then CMake can learn that I think. @brad.king, would it be suitable to special case .tbd files for the NAGFortran compiler linker arguments? Or is this something we should wrap every library argument in?

1 Like

Is Modules/Compiler/NAG-Fortran.cmake perhaps missing code like this?

See [Getting Started with the NAG® Fortran Compiler | nag] for trying out the Compiler with a trial licence.