CMake on windows with mingw compilers

Hi,
I am trying to use CMAKE on windows with mingw - gfortran complilers.
Suppose I have a directory structure like this:

main directory:
main.f90 ! main program
CMakeLists.txt
utils ! my modules
build ! where cmake will generate build files

inside utils:

mymod.f90 ! my module
CMakeLists.txt

Now in the main directory CMakeLists.txt

cmake_minimum_required(VERSION 3.0.0)
ENABLE_LANGUAGE(Fortran)

project(first VERSION 1.0.0)

add_subdirectory(utils) 
add_executable(first
first.f90)
target_link_libraries(first PUBLIC utilities)

in the utils CMakeLists.txt

ENABLE_LANGUAGE(Fortran)
add_library(utilities
mymod.f90
)
target_include_directories(utilities PUBLIC include)

When I am trying to build and run using

cmake .. -G "MinGW Makefiles"
mingw32-make.exe first

I am getting the following error:

  2 |     use mymod
      |         1
Fatal Error: Cannot open module file 'mymod.mod' for reading at (1): No such file or directory
compilation terminated.
mingw32-make[3]: *** [CMakeFiles\first.dir\build.make:75: CMakeFiles/first.dir/first.f90.obj] Error 1

Can somebody please tell me how to use CMake with Fortran

Include the following lines for all targets that include Fortran source files (replace <target> with your target name or a variable containing the target name, i.e. utilities):

file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include)
set_property (TARGET <target>
    PROPERTY Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include
)
target_include_directories(<target> PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include)

If a single CMakeLists.txt creates more than one target with Fortran sources you should make sure that include directories are unique. Assuming that the variable libname contains the target name from add_library, the code below is one possible solution:

file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include-${libname})
set_property (TARGET ${libname}
    PROPERTY Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include-${libname}
)
target_include_directories(${libname} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include-${libname})
1 Like

You can have a look at GitHub - fortran-lang/stdlib-cmake-example: Integration of the Fortran standard library in CMake projects which provides a template for using CMake with Fortran and integrating with external projects, like stdlib and test-drive.

The main takeaway is that you explicitly have to define your include directories, this can be done by associating them directly with the target:

I tried to write the CMake files in this project in a way to make them reusable, in the best case you have to only change the project name and version (you can also delete the stdlib / test-drive dependency if you don’t like to use them).

1 Like

Thanks a lot @plevold and @awvwgk .
I am just a beginner in CMake of projects. I really appreciate your deep knowledge and effort. While I wish to understand the fortran-lang/stdlib cmake example that you have posted, please help me with this simple project to start with.
One main directory containing main.f90 file and one subdirectory containing one module file. How to compile and link them together. Once I am able to build this - I will expand my knowledge further into the example that you have posted.
I hope you understand.
Thanks.

The linked repository follows fpm’s structure to layout the project, you have three target:

  1. a library defined in the src/ directory, which is installed and usable by dependent projects
  2. an executable in the app/ directory, which is also installed
  3. a test driver in the test/ directory, for creating unit tests using the test-drive framework

You can simply copy / clone the whole project and adjust these lines to your project specification

If you don’t want stdlib, you can delete the lines here

Any sources you want to compile are added in the CMake file in src/CMakeLists.txt at, make sure to include them there otherwise they will not be built:

Finally there are build and installation instructions in the README at GitHub - fortran-lang/stdlib-cmake-example: Integration of the Fortran standard library in CMake projects, which should show you how to build your new CMake project, try the whole workflow. If you want to run tests, you can also use

ctest --test-dir _build --output-on-failure

The CMake files contain a lot of boilerplate, which I have learned over the years of using CMake. The are apparently important to have a well working CMake project which other people can also use, why we have to write all this stuff ourselves however is beyond me. Don’t worry too much about the target export and stuff like that for the moment.

Also, if you should be sick of CMake at some point, you can simply add a package manifest for the Fortran package manager (fpm.toml) and use the project should build directly with fpm due to the compatible layout. There happens to be a guide on using stdlib and test-drive as dependencies with fpm at Adding dependencies — Fortran Package Manager.

If you have any questions feel free to ask, we are always happy to help.

Really a big thanks @awvwgk .
Is fpm is as robust as cmake on windows ? If yes I would rather try that.
I am asking in the sense that - is fpm able to build and link to projects that are built with linux - on windows ? or in short - is it cross platform ?

I’m using fpm, meson and CMake on Linux, MacOS and Windows, some people also build my software on FreeBSD so the cross-platform setup seems to work regardless of the build system.

There is no clear advice I can give you regarding the build system choice, it depends on what you want to do. For developer productivity I would recommend fpm > meson >> CMake. However, meson and CMake are great if you want to do more than just Fortran, i.e. export a C-API and use it in other non-Fortran libraries. My usual strategy is to have both fpm and meson in my projects, fpm for daily development and meson for deployment and developing “advanced” features (exporting C bindings, shared libraries, Python extension modules, …).

Personally, I think wasting time on build systems is very unproductive, since it is time not spend developing the project, the reality is that building a project is a lot of build system tweaking because all platforms have different quirks, there are build systems which make this easy and other which make it unnecessarily hard. CMake belong in the latter category for me.

3 Likes