Skip to content

Instantly share code, notes, and snippets.

@scivision
Last active July 24, 2024 05:21
Show Gist options
  • Save scivision/4585ac57bf08c8a98498752c40416782 to your computer and use it in GitHub Desktop.
Save scivision/4585ac57bf08c8a98498752c40416782 to your computer and use it in GitHub Desktop.
Need capital suffix ".F" or ".F90" for preprocessed Fortran source files
.DUMMY
.dummy

CMake Fortran Introspection

Modern build systems like CMake and Meson introspect Fortran source files to determine the build order of source files. This is vital for Fortran source files using modules and submodules.

Fortran module .mod file files are generated when compiling a Fortran source file. The order of compiling Fortran source files with modules is vital to avoiding build failure due to missing module files.

Fails due to improper build order:

gfortran main.f90 m1.f90 m2.F90

Proper build order (success):

gfortran m1.f90 m2.F90 main.f90

If you change the file extension to m2.f90, the build fails due to the preprocessing not being enabled:

mv m2.F90 m2.f90

gfortran m1.f90 m2.f90 main.f90

This is true on both case sensitive and case insensitive file systems.

Detect case sensitivity of filesystem

c++ -std=c++17 case_sensitive.cpp -o case_sensitive

./case_sensitive
#include <filesystem>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <cstdlib>
void create_empty_file(const std::filesystem::path& path)
{
std::ofstream file(path);
file.close();
}
bool case_sensitive(const std::filesystem::path& path)
{
if (!std::filesystem::is_directory(path))
throw std::invalid_argument("path is not a directory");
const auto p1 = path / ".dummy";
const auto p2 = path / ".DUMMY";
for (const auto& p : {p1, p2})
{
if (!std::filesystem::exists(p))
create_empty_file(p);
}
return !std::filesystem::equivalent(p1, p2);
}
int main(int argc, char* argv[])
{
const std::string in = (argc > 1) ? argv[1] : ".";
const auto p = std::filesystem::weakly_canonical(in);
const auto s = case_sensitive(p);
std::cout << "filesystem under " << p.root_path() << " is case " << (s ? "sensitive" : "insensitive") << "\n";
return EXIT_SUCCESS;
}
cmake_minimum_required(VERSION 3.19)
project(mod LANGUAGES CXX Fortran)
message(STATUS "CMake ${CMAKE_VERSION} ${CMAKE_GENERATOR}")
add_executable(main main.f90 m1.f90 m2.F90)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.1)
set(cxx_ldflags "-lstdc++fs")
endif()
add_executable(case_sensitive case_sensitive.cpp)
target_compile_features(case_sensitive PRIVATE cxx_std_17)
target_link_libraries(case_sensitive PRIVATE ${cxx_ldflags})
file(GENERATE OUTPUT .gitignore CONTENT "*")
module m1
implicit none
contains
pure real function pi()
pi = 4*atan(1.)
end function
end module m1
module m2
#if 0
use, intrinsic :: fake
#endif
use m1, only : pi
implicit none
contains
pure real function twopi()
twopi = 2*pi()
end function
end module
program test
use m2
implicit none
print *, "2pi = ", twopi()
end program
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment