cmake linking error on linux using gcc and gfortran

I’m building a program which is mostly Fortran, but includes a C++ interface library. This is a cmake project, and you can even find the specific branch on github here. I’m building on Linux using cmake 3.25.1, gcc and gfortran.

My issue is that there is a cmake option to build with OpenMP. The full CMakeLists.txt for the C++ library is shown below:

#
# Copyright 2016 National Renewable Energy Laboratory
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0")
  cmake_policy(SET CMP0074 NEW)
endif()

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(MPI REQUIRED)
find_package(LibXml2 REQUIRED)
find_package(ZLIB REQUIRED)
find_package(HDF5 REQUIRED COMPONENTS C HL)
find_package(yaml-cpp REQUIRED)

include_directories(${YAML_CPP_INCLUDE_DIRS})
include_directories(${HDF5_INCLUDES})
include_directories(${HDF5_INCLUDE_DIR})
include_directories(${ZLIB_INCLUDES})
include_directories(${LIBXML2_INCLUDE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/modules/openfast-library/src/)
include_directories(${CMAKE_BINARY_DIR}/modules/openfoam/)
include_directories(${CMAKE_BINARY_DIR}/modules/supercontroller/)
include_directories(${MPI_INCLUDE_PATH})

add_library(openfastcpplib
  src/OpenFAST.cpp 
  src/SC.cpp
  $<TARGET_OBJECTS:openfastlib_common_obj>
  $<TARGET_OBJECTS:openfast_prelib_obj>
  $<TARGET_OBJECTS:maplib_obj>
  $<TARGET_OBJECTS:nwtcbaselib_obj> 
  $<TARGET_OBJECTS:nwtcsyslib_obj>
  $<TARGET_OBJECTS:nwtclibs_obj>
  $<TARGET_OBJECTS:ifwlib_obj>
  $<TARGET_OBJECTS:fvwlib_obj>
  $<TARGET_OBJECTS:uaaerolib_obj>
  $<TARGET_OBJECTS:afinfolib_obj>
  $<TARGET_OBJECTS:aeroacoustics_obj>
  $<TARGET_OBJECTS:aerodynlib_obj>
  $<TARGET_OBJECTS:aerodyn14lib_obj>
  $<TARGET_OBJECTS:servodynlib_obj>
  $<TARGET_OBJECTS:elastodynlib_obj>
  $<TARGET_OBJECTS:beamdynlib_obj>
  $<TARGET_OBJECTS:subdynlib_obj>
  $<TARGET_OBJECTS:hydrodynlib_obj>
  $<TARGET_OBJECTS:orcaflexlib_obj>
  $<TARGET_OBJECTS:extptfm_mckflib_obj>
  $<TARGET_OBJECTS:openfoamtypeslib_obj>
  $<TARGET_OBJECTS:foamfastlib_obj>
  $<TARGET_OBJECTS:scdataextypeslib_obj>
  $<TARGET_OBJECTS:scdataexlib_obj>
  $<TARGET_OBJECTS:feamlib_obj>
  $<TARGET_OBJECTS:moordynlib_obj>
  $<TARGET_OBJECTS:icedynlib_obj>
  $<TARGET_OBJECTS:icefloelib_obj>
  $<TARGET_OBJECTS:openfast_postlib_obj>
  $<TARGET_OBJECTS:versioninfolib_obj>
)
set_property(TARGET openfastcpplib PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(openfastcpplib
openfast_prelib_obj
maplib_obj
nwtclibs_obj
nwtcsyslib_obj
nwtcbaselib_obj
ifwlib
fvwlib
uaaerolib
afinfolib
aeroacoustics
aerodynlib
aerodyn14lib
servodynlib
elastodynlib
beamdynlib
subdynlib
hydrodynlib
orcaflexlib
extptfm_mckflib
openfoamtypeslib
foamfastlib
scdataextypeslib
scdataexlib
feamlib
moordynlib
icedynlib
icefloelib
openfast_postlib
versioninfolib
${HDF5_C_LIBRARIES}
${HDF5_HL_LIBRARIES}
${ZLIB_LIBRARIES}
${LIBXML2_LIBRARIES}
${MPI_LIBRARIES}
${CMAKE_DL_LIBS}
)

add_executable(openfastcpp src/FAST_Prog.cpp)
target_link_libraries(openfastcpp openfastcpplib
  ${MPI_LIBRARIES}
  ${YAML_CPP_LIBRARIES}
  ${HDF5_C_LIBRARIES}
  ${HDF5_HL_LIBRARIES}
  ${ZLIB_LIBRARIES}
  ${LIBXML2_LIBRARIES}
  ${CMAKE_DL_LIBS})

if (OPENMP)
  find_package(OpenMP)
  if(OpenMP_CXX_FOUND)
    target_link_libraries(openfastcpplib OpenMP::OpenMP_CXX)
    target_link_libraries(openfastcpp OpenMP::OpenMP_CXX)
  endif()
endif(OPENMP)

if(MPI_COMPILE_FLAGS)
  set_target_properties(openfastcpp PROPERTIES
    COMPILE_FLAGS "${MPI_COMPILE_FLAGS}")
endif(MPI_COMPILE_FLAGS)

if(MPI_LINK_FLAGS)
  set_target_properties(openfastcpp PROPERTIES
    LINK_FLAGS "${MPI_LINK_FLAGS}")
endif(MPI_LINK_FLAGS)

set_property(TARGET openfastcpp PROPERTY LINKER_LANGUAGE CXX)

install(TARGETS openfastcpplib
  EXPORT "${CMAKE_PROJECT_NAME}Libraries"
  RUNTIME DESTINATION lib
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib)

install(FILES
  src/OpenFAST.H src/SC.h
  DESTINATION include)

install(TARGETS openfastcpp
  RUNTIME DESTINATION bin)

It uses the modern OpenMP cmake invocations:

if (OPENMP)
  find_package(OpenMP)
  if(OpenMP_CXX_FOUND)
    target_link_libraries(openfastcpplib OpenMP::OpenMP_CXX)
    target_link_libraries(openfastcpp OpenMP::OpenMP_CXX)
  endif()
endif(OPENMP)

But when I build the program, I receive an error like this:

[ 95%] Linking CXX executable openfast_cpp
cd /home/rcrozier/build/openfast-reos-git/glue-codes/openfast/glue-codes/openfast && /snap/cmake/1210/bin/cmake -E cmake_link_script CMakeFiles/openfast_cpp.dir/link.txt --verbose=1
/bin/c++  -fpic -O3 -DNDEBUG -rdynamic CMakeFiles/openfast_cpp.dir/src/FAST_Prog.cpp.o CMakeFiles/openfast_cpp.dir/src/FastLibAPI.cpp.o -o openfast_cpp  -Wl,-rpath,:::::::::::::: ../../modules/openfast-library/libopenfastlib.a ../../dependencies/src/lapack-build/lib/liblapack.a ../../dependencies/src/lapack-build/lib/libblas.a -ldl -lgfortran -lquadmath 
/bin/ld: ../../modules/openfast-library/libopenfastlib.a(VersionInfo.f90.o): in function `__versioninfo_MOD_dispcompileruntimeinfo._omp_fn.0':
VersionInfo.f90:(.text+0xf): undefined reference to `omp_get_thread_num_'
/bin/ld: VersionInfo.f90:(.text+0x31): undefined reference to `omp_get_num_threads_'
/bin/ld: VersionInfo.f90:(.text+0xf4): undefined reference to `omp_get_max_threads_'
/bin/ld: ../../modules/openfast-library/libopenfastlib.a(VersionInfo.f90.o): in function `__versioninfo_MOD_dispcompileruntimeinfo':
VersionInfo.f90:(.text+0x847): undefined reference to `GOMP_parallel'

If I copy the command, but manually add the -fopenmp option, it seems to work, there is no error message

cd /home/rcrozier/build/openfast-reos-git/glue-codes/openfast/glue-codes/openfast && /snap/cmake/1210/bin/cmake -E cmake_link_script CMakeFiles/openfast_cpp.dir/link.txt --verbose=1
/bin/c++  -fpic -O3 -DNDEBUG -rdynamic CMakeFiles/openfast_cpp.dir/src/FAST_Prog.cpp.o CMakeFiles/openfast_cpp.dir/src/FastLibAPI.cpp.o -o openfast_cpp  -Wl,-rpath,:::::::::::::: ../../modules/openfast-library/libopenfastlib.a ../../dependencies/src/lapack-build/lib/liblapack.a ../../dependencies/src/lapack-build/lib/libblas.a -ldl -lgfortran -lquadmath -fopenmp

So my question is, assuming the -fopenmp is needed, and there is not some other issue I don’t understand, how do I best get the -fopenmp option added by cmake?

I suspect that FindOpenMP needs to learn how to pass the flag cross-compiler for any consuming language. Maybe you should PRIVATE link to OpenMP::OpenMP_CXX and INTERFACE link to OpenMP::OpenMP? Though the lang-free target doesn’t exist…maybe one should to support cross-language usage like this?