From 19d61b2190d2cea8eaae4f8e93cfec3f69bdb525 Mon Sep 17 00:00:00 2001 From: jchristopherson Date: Thu, 14 Aug 2025 12:05:41 -0500 Subject: [PATCH 1/5] Update version info --- CMakeLists.txt | 2 +- fpm.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d87750a..56201b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.24) project( collections LANGUAGES Fortran - VERSION 1.0.3 + VERSION 1.0.4 ) # Utilize the GNU installation structure diff --git a/fpm.toml b/fpm.toml index 192801b..d8d5665 100644 --- a/fpm.toml +++ b/fpm.toml @@ -1,9 +1,9 @@ name = "collections" -version = "1.0.3" +version = "1.0.4" license = "GPL-3.0" author = "Jason Christopherson" maintainer = "Jason Christopherson" -copyright = "Copyright 2022-2024, Jason Christopherson" +copyright = "Copyright 2022-2025, Jason Christopherson" description = "A set of types supporting collections in Fortran." homepage = "https://github.com/jchristopherson/collections" From a54241c4edf7ae84e7d147834084e2a78b12c7be Mon Sep 17 00:00:00 2001 From: jchristopherson Date: Thu, 14 Aug 2025 12:18:12 -0500 Subject: [PATCH 2/5] Clean up cmake scripts --- CMakeLists.txt | 31 +++++------- cmake/helper.cmake | 75 ------------------------------ configure/CMakeLists.txt | 64 ++++++++++++++++++++++--- configure/template.cmake | 5 ++ configure/template.pc | 10 ++++ dependencies/CMakeLists.txt | 4 -- dependencies/ferror/CMakeLists.txt | 18 ------- examples/CMakeLists.txt | 17 +++++-- src/CMakeLists.txt | 61 +++++++++++++++++++++++- test/CMakeLists.txt | 17 +++++-- 10 files changed, 169 insertions(+), 133 deletions(-) delete mode 100644 cmake/helper.cmake create mode 100644 configure/template.cmake create mode 100644 configure/template.pc delete mode 100644 dependencies/CMakeLists.txt delete mode 100644 dependencies/ferror/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 56201b3..ef0b5b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,30 +4,21 @@ project( LANGUAGES Fortran VERSION 1.0.4 ) - -# Utilize the GNU installation structure -include(GNUInstallDirs) - -# Get the macros and functions we'll need -include("${PROJECT_SOURCE_DIR}/cmake/helper.cmake") +set(CMAKE_Fortran_STANDARD 2018) +set(CMAKE_Fortran_STANDARD_REQUIRED TRUE) # Configure everything add_subdirectory(configure) -# Deal with dependencies -add_subdirectory(dependencies) - # Source add_subdirectory(src) -add_fortran_library( - ${PROJECT_NAME} - ${PROJECT_INCLUDE_DIR} - ${CMAKE_INSTALL_INCLUDEDIR} - ${PROJECT_VERSION} - ${PROJECT_VERSION_MAJOR} - ${COLLECTIONS_SOURCES} + +# Installation Instructions +install( + EXPORT ${PROJECT_NAME}-targets + NAMESPACE ${PROJECT_NAME}:: + DESTINATION "${CMAKE_INSALL_LIBDIR}/cmake/${PROJECT_NAME}" ) -link_library(${PROJECT_NAME} ${ferror_LIBRARY} ${ferror_INCLUDE_DIR}) # Testing option(BUILD_TESTING "Build tests") @@ -39,8 +30,8 @@ if (BUILD_TESTING) endif() # Examples -option(BUILD_collections_EXAMPLES "Build examples") -message(STATUS "Build collections examples: ${BUILD_collections_EXAMPLES}") -if (BUILD_collections_EXAMPLES) +option(BUILD_COLLECTIONS_EXAMPLES "Build collections examples") +message(STATUS "Build COLLECTIONS examples: ${BUILD_COLLECTIONS_EXAMPLES}") +if (${BUILD_COLLECTIONS_EXAMPLES}) add_subdirectory(examples) endif() \ No newline at end of file diff --git a/cmake/helper.cmake b/cmake/helper.cmake deleted file mode 100644 index a21692c..0000000 --- a/cmake/helper.cmake +++ /dev/null @@ -1,75 +0,0 @@ -# helper.cmake -# -# A collection of macros and functions making life with CMake and Fortran a -# bit simpler. - -# Use to include and export headers -function(include_headers lib dir install_dir) - target_include_directories( - ${lib} - INTERFACE - $ - $ - ) -endfunction() - -# Use instead of add_library. -function(add_fortran_library lib_name mod_dir include_install_dir version major) - add_library(${lib_name} ${ARGN}) - set_target_properties( - ${lib_name} - PROPERTIES - POSITION_INDEPENDENT_CODE TRUE - OUTPUT_NAME ${lib_name} - VERSION ${version} - SOVERSION ${major} - Fortran_MODULE_DIRECTORY ${include_install_dir} - ) - target_include_directories( - ${lib_name} - PUBLIC - $ - $ - ) -endfunction() - -# Installs the library -function(install_library lib_name lib_install_dir bin_install_dir mod_dir install_dir) - install( - TARGETS ${lib_name} - EXPORT ${lib_name}Targets - RUNTIME DESTINATION ${bin_install_dir} - LIBRARY DESTINATION ${lib_install_dir} - ARCHIVE DESTINATION ${lib_install_dir} - INCLUDES DESTINATION ${install_dir}/include - ) - install( - DIRECTORY ${mod_dir} - DESTINATION ${install_dir} - ) -endfunction() - -# Install the documentation files -function(install_documentation doc_dir install_dir) - install( - DIRECTORY ${doc_dir} - DESTINATION ${install_dir} - ) -endfunction() - -# Links the supplied library -function(link_library targ lib include_dir) - target_link_libraries(${targ} ${lib}) - target_include_directories(${targ} PUBLIC $) -endfunction() - -# ------------------------------------------------------------------------------ -# Helpful Macros -macro(print_all_variables) - message(STATUS "---------- CURRENTLY DEFINED VARIABLES -----------") - get_cmake_property(varNames VARIABLES) - foreach(varName ${varNames}) - message(STATUS ${varName} = ${${varName}}) - endforeach() - message(STATUS "---------- END ----------") -endmacro() diff --git a/configure/CMakeLists.txt b/configure/CMakeLists.txt index f114e3c..3b9639f 100644 --- a/configure/CMakeLists.txt +++ b/configure/CMakeLists.txt @@ -1,6 +1,3 @@ -# Get the macros and functions we'll need -include("${PROJECT_SOURCE_DIR}/cmake/helper.cmake") - # Set a default build type if none was specified if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Release' as none was specified.") @@ -13,11 +10,64 @@ endif() option(BUILD_SHARED_LIBS "Build shared libraries" OFF) # Export all symbols on Windows when building libraries -set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) +SET(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) # Utilize the GNU installation structure include(GNUInstallDirs) -# Locate the local include directory -set(PROJECT_INCLUDE_DIR ${PROJECT_BINARY_DIR}/include) -set(PROJECT_INCLUDE_DIR ${PROJECT_INCLUDE_DIR} PARENT_SCOPE) \ No newline at end of file +# Module directory +if(NOT DEFINED CMAKE_INSTALL_MODULEDIR) + set( + CMAKE_INSTALL_MODULEDIR + "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${CMAKE_Fortran_COMPILER_ID}-${CMAKE_Fortran_COMPILER_VERSION}" + CACHE + STRING + "Directory in prefix to install generated module files" + ) +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE) + +# Export a pkg-config file +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/template.pc" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" + @ONLY +) + +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" +) + +# Export CMake package file +include(CMakePackageConfigHelpers) +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/template.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" +) + +if(BUILD_SHARED_LIBS OR PROJECT_VERSION_MAJOR EQUAL 0) + # Due to the uncertain ABI compatibility of Fortran shared libraries + # limit compatibility for dynamic linking to same minor version. + set(COMPATIBILITY SameMinorVersion) +else() + # Require API compatibility via semantic versioning for static linking. + set(COMPATIBILITY SameMajorVersion) +endif() + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" + VERSION "${PROJECT_VERSION}" + COMPATIBILITY ${COMPATIBILITY} +) + +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" +) diff --git a/configure/template.cmake b/configure/template.cmake new file mode 100644 index 0000000..ffdb09b --- /dev/null +++ b/configure/template.cmake @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +if(NOT TARGET "@PROJECT_NAME@::@PROJECT_NAME@") + include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") +endif() \ No newline at end of file diff --git a/configure/template.pc b/configure/template.pc new file mode 100644 index 0000000..653b13d --- /dev/null +++ b/configure/template.pc @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ +moduledir=${prefix}/@CMAKE_INSTALL_MODULEDIR@ + +Name: @PROJECT_NAME@ +Description: @PROJECT_DESCRIPTION@ +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -l@PROJECT_NAME@ +Cflags: -I${includedir} -I${moduledir} \ No newline at end of file diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt deleted file mode 100644 index 91ec0f3..0000000 --- a/dependencies/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Get FERROR -add_subdirectory(ferror) -set(ferror_LIBRARY ${ferror_LIBRARY} PARENT_SCOPE) -set(ferror_INCLUDE_DIR ${ferror_INCLUDE_DIR} PARENT_SCOPE) \ No newline at end of file diff --git a/dependencies/ferror/CMakeLists.txt b/dependencies/ferror/CMakeLists.txt deleted file mode 100644 index c78fc2c..0000000 --- a/dependencies/ferror/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -include(FetchContent) - -# Fetch the proper content -FetchContent_Declare( - ferror - GIT_REPOSITORY "https://github.com/jchristopherson/ferror" -) -FetchContent_MakeAvailable(ferror) - -set(ferror_INCLUDE_DIR ${ferror_BINARY_DIR}/include) -configure_file( - "${ferror_SOURCE_DIR}/include/ferror.h" - "${ferror_INCLUDE_DIR}/ferror.h" - COPYONLY -) -set(ferror_LIBRARY ferror) -set(ferror_INCLUDE_DIR ${ferror_INCLUDE_DIR} PARENT_SCOPE) -set(ferror_LIBRARY ${ferror_LIBRARY} PARENT_SCOPE) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c3ed6bb..4481e1d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,9 +1,18 @@ -include("${PROJECT_SOURCE_DIR}/cmake/helper.cmake") - # list_example.f90 add_executable(list_example list_example.f90) -link_library(list_example collections ${PROJECT_BINARY_DIR}/include) +target_link_libraries(list_example collections) # linked_list_example.f90 add_executable(linked_list_example linked_list_example.f90) -link_library(linked_list_example collections ${PROJECT_BINARY_DIR}/include) \ No newline at end of file +target_link_libraries(linked_list_example collections) + +if (${BUILD_SHARED_LIBS} AND WIN32) + add_custom_command( + TARGET list_example + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $ + $ + COMMAND_EXPAND_LISTS + ) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 566e0c8..46aa839 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,4 @@ +# Source set(dir ${CMAKE_CURRENT_SOURCE_DIR}) list( APPEND COLLECTIONS_SOURCES @@ -6,4 +7,62 @@ list( ${dir}/collections_list.f90 ${dir}/collections_linked_list.f90 ) -set(COLLECTIONS_SOURCES ${COLLECTIONS_SOURCES} PARENT_SCOPE) + +# Dependencies +include(FetchContent) +find_package(ferror QUIET) +if (NOT ferror_FOUND) + message(STATUS "FERROR could not be found. A reference version will be employed.") + FetchContent_Declare( + ferror + GIT_REPOSITORY "https://github.com/jchristopherson/ferror" + ) + FetchContent_MakeAvailable(ferror) + set(FERROR_LIBRARIES ferror) + set(BUILD_FERROR TRUE) +else() + set(FERROR_LIBRARIES ferror::ferror) + set(BUILD_FERROR FALSE) +endif() + +# Build +add_library(${PROJECT_NAME} ${COLLECTIONS_SOURCES}) +target_link_libraries( + ${PROJECT_NAME} + PUBLIC + ${FERROR_LIBRARIES} +) +set_target_properties( + ${PROJECT_NAME} + PROPERTIES + POSITION_INDEPENDENT_CODE ON + WINDOWS_EXPORT_ALL_SYMBOLS ON +) +set(COLLECTIONS_MOD_DIR ${CMAKE_CURRENT_BINARY_DIR}/mod_files/) +if (NOT EXISTS "${COLLECTIONS_MOD_DIR}") + file(MAKE_DIRECTORY "${COLLECTIONS_MOD_DIR}") +endif() + +set_target_properties( + ${PROJECT_NAME} PROPERTIES + Fortran_MODULE_DIRECTORY ${COLLECTIONS_MOD_DIR} +) +target_include_directories( + ${PROJECT_NAME} PUBLIC + $ + $ +) + +# Install +install( + TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +install(DIRECTORY ${COLLECTIONS_MOD_DIR} DESTINATION ${CMAKE_INSTALL_MODULEDIR}) + +if (${BUILD_FERROR} AND ${BUILD_SHARED_LIBS}) + install(IMPORTED_RUNTIME_ARTIFACTS ${FERROR_LIBRARIES}) +endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6631f8a..3ef526f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,5 +1,3 @@ -include("${PROJECT_SOURCE_DIR}/cmake/helper.cmake") - set(collections_test_sources linked_list_test.f90 list_test.f90 @@ -7,9 +5,20 @@ set(collections_test_sources ) add_executable(collections_test ${collections_test_sources}) -link_library(collections_test ${PROJECT_NAME} ${PROJECT_INCLUDE_DIR}) +target_link_libraries(collections_test collections) add_test( NAME collections_test WORKING_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} COMMAND $ -) \ No newline at end of file +) + +if (${BUILD_SHARED_LIBS} AND WIN32) + add_custom_command( + TARGET collections_test + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $ + $ + COMMAND_EXPAND_LISTS + ) +endif() From a5b3f03065360ab5c833b73e12c3036e1d23d09d Mon Sep 17 00:00:00 2001 From: jchristopherson Date: Thu, 14 Aug 2025 12:19:10 -0500 Subject: [PATCH 3/5] Clean up --- .github/workflows/fpm.yml | 94 +++------------------------------------ 1 file changed, 6 insertions(+), 88 deletions(-) diff --git a/.github/workflows/fpm.yml b/.github/workflows/fpm.yml index 4e76797..a0ec389 100644 --- a/.github/workflows/fpm.yml +++ b/.github/workflows/fpm.yml @@ -8,15 +8,12 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-11] - gcc_v: [10] # Version of GFortran we want to use. + os: [ubuntu-latest] + gcc_v: [12] # Version of GFortran we want to use. include: - os: ubuntu-latest os-arch: linux-x86_64 - - os: macos-11 - os-arch: macos-x86_64 - env: FC: gfortran GCC_V: ${{ matrix.gcc_v }} @@ -25,26 +22,19 @@ jobs: - name: Checkout code uses: actions/checkout@v1 - - name: Install GFortran macOS - if: contains(matrix.os, 'macos') - run: | - ln -s /usr/local/bin/gfortran-${GCC_V} /usr/local/bin/gfortran - which gfortran-${GCC_V} - which gfortran - - name: Install GFortran Linux if: contains(matrix.os, 'ubuntu') run: | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_V} 100 \ --slave /usr/bin/gfortran gfortran /usr/bin/gfortran-${GCC_V} \ --slave /usr/bin/gcov gcov /usr/bin/gcov-${GCC_V} - + - name: Install fpm - uses: fortran-lang/setup-fpm@v3 + uses: fortran-lang/setup-fpm@v5 with: - fpm-version: 'v0.8.2' + fpm-version: 'v0.10.1' - - name: Build FERROR + - name: Build COLLECTIONS run: | gfortran --version fpm build @@ -53,75 +43,3 @@ jobs: run: | gfortran --version fpm test - - msys2-build: - runs-on: windows-latest - defaults: - run: - shell: msys2 {0} - - steps: - - uses: actions/checkout@v2 - - uses: msys2/setup-msys2@v2 - with: - msystem: MINGW64 - update: true - path-type: inherit - install: | - mingw-w64-x86_64-gcc-fortran - mingw-w64-x86_64-fpm - - - name: fpm build - run: | - gfortran --version - fpm --version - fpm build - - - name: fpm test - run: | - fpm test - - intel-build: - runs-on: ubuntu-latest - strategy: - fail-fast: false - - env: - FPM_FC: ifort - FC: ifort - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Add Intel repository (Linux) - run: | - wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list - sudo apt-get update - - - name: Install Intel oneAPI compiler (Linux) - run: | - sudo apt-get install intel-oneapi-compiler-fortran - - - name: Setup Intel oneAPI environment - run: | - source /opt/intel/oneapi/setvars.sh - printenv >> $GITHUB_ENV - - - name: Install fpm - uses: fortran-lang/setup-fpm@v3 - with: - fpm-version: 'v0.8.2' - - - name: fpm build - run: | - ifort --version - fpm --version - fpm build --profile debug --flag "-warn nointerfaces" - - - name: fpm test - run: | - fpm test --profile debug --flag "-warn nointerfaces" \ No newline at end of file From 288061c75d4b7f64d30424e063c8f295401e8f0a Mon Sep 17 00:00:00 2001 From: jchristopherson Date: Thu, 14 Aug 2025 12:20:08 -0500 Subject: [PATCH 4/5] Clean up --- .github/workflows/cmake.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index f31c442..12f654b 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -2,9 +2,9 @@ name: CMake on: push: - branches: [ "master" ] + branches: [ "main" ] pull_request: - branches: [ "master" ] + branches: [ "main" ] env: BUILD_TYPE: Release From c6c3ada0f1b0207253e03e5bae2f4842239312db Mon Sep 17 00:00:00 2001 From: jchristopherson Date: Thu, 14 Aug 2025 12:28:29 -0500 Subject: [PATCH 5/5] Add shared library tests --- .github/workflows/cmake.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 12f654b..a62fae3 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -44,5 +44,15 @@ jobs: run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - name: Test with CMake + working-directory: ${{github.workspace}}/build + run: ctest -C ${{env.BUILD_TYPE}} + + - name: Configure CMake - Shared Library + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_Fortran_COMPILER=${{ env.FC }} -DBUILD_TESTING=TRUE -DBUILD_SHARED_LIBS=TRUE + + - name: Build with CMake - Shared Library + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test with CMake - Shared Library working-directory: ${{github.workspace}}/build run: ctest -C ${{env.BUILD_TYPE}} \ No newline at end of file