Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ build/

# Build directory for out-of-tree builds
/build
/bin
/lib
/include

# Emacs backup files
*~
36 changes: 27 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
cmake_minimum_required(VERSION 3.14.0)

project(stdlib Fortran)
enable_testing()

include(${CMAKE_SOURCE_DIR}/cmake/stdlib.cmake)
# Add our local modules to the module path
if(NOT CMAKE_MODULE_PATH)
set(CMAKE_MODULE_PATH)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think line 10 should move to line 8 as

set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")


# Include the preprocessor options for stdlib
include(${CMAKE_MODULE_PATH}/stdlib.cmake)

# GNUInstallDirs is used to install libraries into correct locations
# on all platforms.
include(GNUInstallDirs)

# Setup the Fortran cmake environment
# Sets up the flags for compiling shared libraries or static libraries, and returns the libType parameter.
include("${CMAKE_MODULE_PATH}/FortranEnvironment.cmake")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for " quotes here



# --- compiler options
if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU)
add_compile_options(-fimplicit-none)
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
add_compile_options(-warn declarations)
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL PGI)
add_compile_options(-Mdclchk)
endif()
#if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU)
# add_compile_options(-fimplicit-none)
#elseif(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
# add_compile_options(-warn declarations)
#elseif(CMAKE_Fortran_COMPILER_ID STREQUAL PGI)
# add_compile_options(-Mdclchk)
#endif()

# --- compiler feature checks
include(CheckFortranSourceCompiles)
Expand All @@ -27,7 +44,8 @@ endif()
# --- find preprocessor
find_program(FYPP fypp)
if(NOT FYPP)
message(FATAL_ERROR "Preprocessor fypp not found!")
message(FATAL_ERROR "Preprocessor fypp not found!\n"
"fypp is a python package and can be installed via, 'pip install fypp'")
endif()

add_subdirectory(src)
118 changes: 118 additions & 0 deletions cmake/FortranEnvironment.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# ================================
# CMAKE Script for setting up the fortran compiling and linking flags for different operating systems and compilers

# Call this cmake file from your project's CMakeLists.txt using 'include(/path/to/FortranEnvironment.cmake)'

# ++++++++++++++++++++++++++++++++


enable_language(Fortran)

option (BUILD_SHARED_LIBS "Shared or static libraries" ON)
Copy link
Member

@scivision scivision May 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default shared libs don't work in general for Fortran compilers like Intel on Windows


# Check if linux
if(UNIX AND NOT APPLE)
set(LINUX TRUE)
endif()


# ================================
# Default the Build type to RELEASE
# ================================
# Make sure the build type is uppercase
string(TOUPPER "${CMAKE_BUILD_TYPE}" BT)

if(BT STREQUAL "RELEASE")
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING
"Choose the type of build, options are DEBUG, or RELEASE."
FORCE)
elseif(BT STREQUAL "DEBUG")
set(CMAKE_BUILD_TYPE DEBUG CACHE STRING
"Choose the type of build, options are DEBUG, or RELEASE."
FORCE)
elseif(NOT BT)
set(CMAKE_BUILD_TYPE DEBUG CACHE STRING
"Choose the type of build, options are DEBUG, or RELEASE."
FORCE)
message(STATUS "CMAKE_BUILD_TYPE not given, defaulting to DEBUG.")
else()
message(FATAL_ERROR "CMAKE_BUILD_TYPE not valid, choices are DEBUG, or RELEASE.")
endif(BT STREQUAL "RELEASE")

# ++++++++++++++++++++++++++++++++

# ================================
# Find the openmp package and add compiler-specific flags
# ================================
find_package(OpenMP)
if(OPENMP_FOUND)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these two lines should be like

string(APPEND CMAKE_Fortran_FLAGS " ${OpenMP_Fortran_FLAGS}")

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()
# ++++++++++++++++++++++++++++++++

# ================================
# Set gfortran compile flags
# ================================
message("\n")
if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
include(${CMAKE_MODULE_PATH}/gfortran_flags.cmake)

# ================================
# Set INTEL compile flags
# ================================
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Intel")
include(${CMAKE_MODULE_PATH}/intel_flags.cmake)

elseif(CMAKE_Fortran_COMILER_ID MATCHES "PGI")
message(FATAL_ERROR "Need to define flags for PGI")

endif()

# ================================
# Set the output directories for compiled libraries and module files.
# Paths are relative to the build folder where you call cmake
# ================================
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/../lib) # Static library location
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make it clear these lines are creating side effects (creating artifacts outside of the build directory) would it be possible to do like:

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good point. I think, it is generally not a nice idea to create anything outside of the build folder (not even in the source folder), unless the user explicitly asks for it. So, why not something like

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/_install/lib)

and the user can override it, in case it should be put somewhere else.

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/../lib) # Shared library location
# Place module files in specific include folder
set(CMAKE_Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/../include)
# Place executables in bin
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/../bin)
INCLUDE_DIRECTORIES(${CMAKE_Fortran_MODULE_DIRECTORY})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

early in the Fortran stdlib development it was noted, and in general for modern CMake, we typically like to use per-target target_include_directories(foo PRIVATE ...) Unless this was decided to be changed for this project


# ++++++++++++++++++++++++++++++++

# ================================
# Display information to the user
# ================================
message("Using compiler type ${CMAKE_Fortran_COMPILER}\n"
"If you need to change the compiler\n"
"Use -DCMAKE_Fortran_COMPILER=<Path to compiler>\n")

message("Build type is ${CMAKE_BUILD_TYPE}\n"
"If you need to change the build type\n"
"Use -DCMAKE_BUILD_TYPE=[DEBUG RELEASE]\n")

if(${CMAKE_BUILD_TYPE} STREQUAL "RELEASE")
message("Using the following compile flags \n"
"${CMAKE_Fortran_FLAGS_RELEASE}\n")
elseif(${CMAKE_BUILD_TYPE} STREQUAL "DEBUG")
message("Using the following compile flags \n"
"${CMAKE_Fortran_FLAGS_DEBUG}\n")
endif()

if(BUILD_SHARED_LIBS)
message("Building with -DBUILD_SHARED_LIBS=ON")
else()
message("Building with -DBUILD_SHARED_LIBS=OFF")
endif()
message("Using the following library link flags \n"
"${CMAKE_SHARED_LINKER_FLAGS}\n")
message("Using the following program link flags \n"
"${CMAKE_EXE_LINKER_FLAGS}\n")

message("'make install' will install to ${CMAKE_INSTALL_PREFIX}")
message("To change the install directory\n"
"Use -DCMAKE_INSTALL_PREFIX:PATH=/path/to/install/to\n")

88 changes: 88 additions & 0 deletions cmake/gfortran_flags.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# ================================
# Set gfortran compile flags
# ================================
message(STATUS "Getting gfortran flags")

# Set flags for all build types
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -std=f2008ts -cpp -ffree-line-length-none -fall-intrinsics")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-fstd=f2008ts is a deprecated flag. In general I've found there are bugs in Gfortran that makes these standard flags problematic (e.g. Gfortran 9.3.0 has -fstd bugs that make lots of spurious warnings).

Is it better to not use -fstd except if the builder specifies them on the CMake command line?


# ================================
# Set GFORTRAN flags for a SHARED library
# ================================
if(BUILD_SHARED_LIBS)
# Add any shared library related stuff here
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -shared -fpic")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's preferable to use CMake POSITION_INDEPENDENT_CODE


if(LINUX OR APPLE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if(UNIX)

# Taken from: https://cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH
# use, i.e. don't skip the full RPATH for the build tree
set(CMAKE_SKIP_BUILD_RPATH FALSE)

# when building, don't use the install RPATH already
# (but later on when installing)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)

set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")

# add the automatically determined parts of the RPATH
# which point to directories outside the build tree to the install RPATH
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

# the RPATH to be used when installing, but only if it's not a system directory
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir)
if("${isSystemDir}" STREQUAL "-1")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
endif("${isSystemDir}" STREQUAL "-1")
endif()

# ================================
# Set GFORTRAN flags for a STATIC library
# ================================
else()
# Static build options
if(APPLE)
# gcc on OS X defaults to the dynamic quadmath library instead of the static
# NOTE: LIBRARY_PATH environment variable must be properly defined for the
# current compiler or find_library(quadmath) will return the static
# system version of libquadmath.a
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
find_library(LIB_QUADMATH quadmath)

if ("${LIB_QUADMATH}" STREQUAL "LIB_QUADMATH-NOTFOUND")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if(NOT LIB_QUADMATH)

string(CONCAT quadmath_error "\
Could not find the quadmath library. \n \
You might need to add to or create the environment variable CMAKE_LIBRARY_PATH. \n \
i.e. export CMAKE_LIBRARY_PATH=$CMAKE_LIBRARY_PATH:/path/to/gfortran/folder/lib \n \
You can find which folder contains libquadmath.a/so by typing 'gcc -### -Xlinker -v 2>&1 | grep LIBRARY' or perhaps 'readlink gcc' \n \
Search through those folders and libquadmath should be in a 'lib' folder. That path is what should be added to CMAKE_LIBRARY_PATH' \n \
Make sure that gcc is the GNU compiler and not OSX's clang compiler by typing 'gcc --version' \n")
message(FATAL_ERROR ${quadmath_error})
else()
endif()

message(STATUS "quadmath library path: ${LIB_QUADMATH}")


# TODO: The addition of '-lgcc_s.1' is a messy fix for libgcc_s.1.dylib
# not being properly included as an indirect dependency of
# libquadmath.a. This is a brittle hack that needs to be fixed.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgfortran -static-libgcc -lgfortran -lgcc -lgcc_s.1 -lSystem -nodefaultlibs ${LIB_QUADMATH}")

# Apple's ar and ranlib commands toss out 'no symbols' warnings
# The following two lines quiets those warnings
set(CMAKE_Fortran_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_Fortran_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
elseif(WIN32)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgfortran -static-libgcc")
elseif(${LINUX})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgfortran -static-libgcc -lgfortran -lgcc")
endif()
endif()

set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3 -funroll-all-loops -finline-functions")
set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -O0 -fbacktrace -fbounds-check -Waliasing -Wampersand -Wconversion -Wsurprising -Wc-binding-type -Wintrinsics-std -Wtabs -Wintrinsic-shadow -Wline-truncation -Wtarget-lifetime -Wreal-q-constant")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string(APPEND CMAKE_Fortran_FLAGS_DEBUG " ....")


if(APPLE)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fno-underscoring")
endif()
33 changes: 33 additions & 0 deletions cmake/intel_flags.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

message(STATUS "Getting ifort flags")

if(WIN32)
set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -nologo -fpp -O3 -heap-arrays1024 -QaxCORE-AVX2,CORE-AVX-I,AVX,SSE4.2,SSSE3 -Qipo -fp:fast=2 -Qdiag-disable:remark -Qmkl")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally CMake handles these flags fine specifically for Intel compiler, including on Windows. What about older CPUs? I typically use for Intel compiler -march=native or /arch:native instead of all these flags.

Note: For Gfortran, -march=native does not work in general, -mtune=native should be used instead.

set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -nologo -fpp -g -Od -heap-arrays1024 -traceback -CB -Qfp-stack-check -Qmkl -warn:all -warn:nounused")
endif()

if(${LINUX})
if(BUILD_SHARED_LIBS)
# Add any shared library related stuff here
else()
# see: https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/753635
# a better alternative is to use "-static-intel" which allows for dynamic system libraries
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-intel")
endif()

set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3 -axCORE-AVX2,CORE-AVX-I,AVX,SSE4.2,SSSE3 -no-prec-div -fp-model fast=2")
set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -O0 -g -traceback -CB -fp-stack-check -gen-interfaces -warn interfaces")
endif()

if(APPLE)
if(BUILD_SHARED_LIBS)
# Add any shared library related stuff here
else()
# see: https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/753635
# a better alternative is to use "-static-intel" which allows for dynamic system libraries
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-intel")
endif()

set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3 -axCORE-AVX2,CORE-AVX-I,AVX,SSE4.2,SSSE3 -no-prec-div -fp-model fast=2")
set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -O0 -g -traceback -CB -fp-stack-check -gen-interfaces -warn interfaces")
endif()
26 changes: 13 additions & 13 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ set(SRC

add_library(fortran_stdlib ${SRC})

set(LIB_MOD_DIR ${CMAKE_CURRENT_BINARY_DIR}/mod_files/)
set_target_properties(fortran_stdlib PROPERTIES
Fortran_MODULE_DIRECTORY ${LIB_MOD_DIR})
target_include_directories(fortran_stdlib PUBLIC
$<BUILD_INTERFACE:${LIB_MOD_DIR}>
$<INSTALL_INTERFACE:include>
)
#set(LIB_MOD_DIR ${CMAKE_CURRENT_BINARY_DIR}/mod_files/)
#set_target_properties(fortran_stdlib PROPERTIES
# Fortran_MODULE_DIRECTORY ${LIB_MOD_DIR})
#target_include_directories(fortran_stdlib PUBLIC
# $<BUILD_INTERFACE:${LIB_MOD_DIR}>
# $<INSTALL_INTERFACE:include>
#)

if(f18errorstop)
target_sources(fortran_stdlib PRIVATE f18estop.f90)
Expand All @@ -49,9 +49,9 @@ endif()

add_subdirectory(tests)

install(TARGETS fortran_stdlib
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
)
install(DIRECTORY ${LIB_MOD_DIR} DESTINATION include)
#install(TARGETS fortran_stdlib
# RUNTIME DESTINATION bin
# ARCHIVE DESTINATION lib
# LIBRARY DESTINATION lib
# )
#install(DIRECTORY ${LIB_MOD_DIR} DESTINATION include)