diff --git a/.gitignore b/.gitignore index 8a63b480c..72c794cf3 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,9 @@ build/ # Build directory for out-of-tree builds /build +/bin +/lib +/include # Emacs backup files *~ diff --git a/CMakeLists.txt b/CMakeLists.txt index c5a179a52..f0e6aa77a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") + +# 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") + # --- 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) @@ -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) diff --git a/cmake/FortranEnvironment.cmake b/cmake/FortranEnvironment.cmake new file mode 100644 index 000000000..e1ccb9433 --- /dev/null +++ b/cmake/FortranEnvironment.cmake @@ -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) + +# 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}") + 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 +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}) + +# ++++++++++++++++++++++++++++++++ + +# ================================ +# 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=\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") + diff --git a/cmake/gfortran_flags.cmake b/cmake/gfortran_flags.cmake new file mode 100644 index 000000000..703073fae --- /dev/null +++ b/cmake/gfortran_flags.cmake @@ -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") + +# ================================ +# 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") + + if(LINUX OR APPLE) + # 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") + 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 " Scr ") + set(CMAKE_Fortran_ARCHIVE_FINISH " -no_warning_for_no_symbols -c ") + 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") + +if(APPLE) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fno-underscoring") +endif() \ No newline at end of file diff --git a/cmake/intel_flags.cmake b/cmake/intel_flags.cmake new file mode 100644 index 000000000..b15cd97a0 --- /dev/null +++ b/cmake/intel_flags.cmake @@ -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") + 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() \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6b127c0b5..7c4859820 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 - $ - $ -) +#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 +# $ +# $ +#) if(f18errorstop) target_sources(fortran_stdlib PRIVATE f18estop.f90) @@ -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)