Search code examples
c++cmakemakefilecompiler-errorsfortran

Linking Fortran library as CMake subdirectory to another subdirectory


I have a project with a directory structure that looks like this

└── Project/
    ├── build/
    │   ├── common/
    │   ├── case/
    │   └── case2/
    ├── common/
    │   ├── CMakeLists.txt
    │   └── Mod*.F90
    ├── examples/
    │   ├── case/
    │   │   ├── CMakeLists.txt
    │   │   ├── exe1.F90
    │   │   └── exe2.F90
    │   └── case2/
    │       ├── exe3.F90
    │       └── exe4.F90
    └── CMakeLists.txt

I'm writing a CMakeLists.txt to compile the project. I want to be able to run make common and make case on each case inside Project/build separately, so my build directory should look like that, but I'm having trouble implementing this version. Currently, only trying to handle Projects/case and will extend it once that works.

This is the part of Project/CMakeLists.txt that handles that. I've been trying to follow this

add_subdirectory(common)
install(TARGETS common LIBRARY DESTINATION "bin")

add_subdirectory(examples/case case)

This is Project/common/CMakeLists.txt:

file(GLOB common_F90s "*.F90")
add_library(common "${common_F90s}")
target_include_directories(common PRIVATE ${PETSC_INCLUDE_DIRS} ${NETCDF_INCLUDE})
target_link_libraries(common PRIVATE ${PETSC_LINK_LIBRARIES} ${SPHPK_LIB} ${FFTW_LIB} ${NETCDF_LIB})

And this is Project/examples/case:

file(GLOB case_F90s "*.F90")
cmake_print_variables(case_F90s)

foreach(F90_filepath ${case_F90s})
    get_filename_component(file_target ${F90_filepath} NAME_WE)
    add_executable(${file_target} ${F90_filepath})
    cmake_print_variables(file_target)

    target_include_directories(${file_target} PRIVATE ${PETSC_INCLUDE_DIRS})
    target_link_libraries(${file_target} PRIVATE common ${PETSC_LINK_LIBRARIES})
    message("HERE")
endforeach()

Executing make in Project/build makes common successfully, but results in a similar error for all of the case F90 files of not being able to find common modules. Also, make common works but not make case for some reason.

[ 90%] Building Fortran object CMakeFiles/initcond.dir/examples/case/initcond.F90.o
~Project/examples/case/initcond.F90:4:7:

    4 |   use ModDataTypes
      |       1
Fatal Error: Cannot open module file 'moddatatypes.mod' for reading at (1): No such file or directory
compilation terminated.
make[2]: *** [CMakeFiles/initcond.dir/examples/case/initcond.F90.o] Error 1
make[1]: *** [CMakeFiles/initcond.dir/all] Error 2

This old version with no nested CMakeLists.txt works for Projects/case, but I can't make cases individually. Any ideas on how to resolve this?

# build common
file(GLOB common_F90s "common/*.F90")
add_library(common "${common_F90s}")
target_include_directories(common PRIVATE ${PETSC_INCLUDE_DIRS} ${NETCDF_INCLUDE})
target_link_libraries(common PRIVATE ${PETSC_LINK_LIBRARIES} ${SPHPK_LIB} ${FFTW_LIB} ${NETCDF_LIB})

file(GLOB case_F90s "examples/case/*.F90")

foreach(F90_filepath ${case_F90s})
    get_filename_component(file_target ${F90_filepath} NAME_WE)
    add_executable(${file_target} ${F90_filepath})

    target_include_directories(${file_target} PRIVATE ${PETSC_INCLUDE_DIRS})
    target_link_libraries(${file_target} PRIVATE common ${PETSC_LINK_LIBRARIES})
    message("HERE")
endforeach()

I've tried changing this line add_library(common "${common_F90s}") of Project/common/CMakeLists.txt to STATIC or SHARED, but SHARED results in errors and STATIC does not help.


Solution

  • Adding this to my top-level CMake file include_directories("${CMAKE_CURRENT_BINARY_DIR}/common") fixed it.