From d4924b8be4fda930e270aeebe054ca172a456e4e Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Tue, 28 Feb 2023 16:59:05 -0700 Subject: [PATCH 1/6] Updates for testing and installation CMake logic --- CMakeLists.txt | 81 ++++++++++++++++++++++++++++---- cmake/Log-config.cmake.in | 7 +++ cmake/develop_dependencies.cmake | 7 ++- cmake/release_dependencies.cmake | 6 ++- cmake/unit_testing.cmake | 5 +- src/Log/test/CMakeLists.txt | 4 +- 6 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 cmake/Log-config.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 972cc13..dfdf220 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,16 @@ # Preamble ######################################################################## +set(subproject OFF) +if(DEFINED PROJECT_NAME) + set(subproject ON) +endif() + cmake_minimum_required( VERSION 3.14 ) project( Log LANGUAGES CXX ) + ######################################################################## # Project-wide setup ######################################################################## @@ -13,8 +19,15 @@ project( Log LANGUAGES CXX ) set( CMAKE_CXX_STANDARD 17 ) set( CMAKE_CXX_STANDARD_REQUIRED YES ) -option( Log_unit_tests +include(CTest) +include(CMakeDependentOption) + +cmake_dependent_option( Log_unit_tests "Compile the Log unit tests and integrate with ctest" ON + BUILD_TESTING AND NOT ${subproject} +) +option( Log_installation + "Install Log" ON ) option( strict_compile "Treat all warnings as errors." ON @@ -31,7 +44,6 @@ set( debug_flags "-O0" "-g" ) # Dependencies ######################################################################## -set( SPDLOG_BUILD_TESTING CACHE BOOL OFF ) set( REPOSITORIES "release" CACHE STRING "Options for where to fetch repositories: develop, release, local" @@ -52,14 +64,25 @@ endif() ######################################################################## # Project targets ######################################################################## +include(GNUInstallDirs) + +string( CONCAT prefix + "$" + "$" +) add_library( Log INTERFACE ) -target_include_directories( Log INTERFACE src/ ) -target_link_libraries( Log - INTERFACE catch-adapter - INTERFACE spdlog - ) + +target_include_directories( Log INTERFACE ${prefix} ) + +# treat spdlog specially due to mixed namespace usage +if (TARGET spdlog::spdlog) + target_link_libraries(Log INTERFACE spdlog::spdlog) +else() + target_link_libraries(Log INTERFACE spdlog) +endif() + ####################################################################### @@ -69,8 +92,50 @@ target_link_libraries( Log if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) # unit testing - if( Log_unit_tests ) + if( ${Log_unit_tests} ) include( cmake/unit_testing.cmake ) endif() endif() +####################################################################### +# Installation +####################################################################### + +if(Log_installation) + include(CMakePackageConfigHelpers) + + install(TARGETS Log EXPORT Log-targets + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ) + + install(EXPORT Log-targets + FILE "Log-targets.cmake" + DESTINATION share/cmake/Log + ) + + configure_package_config_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Log-config.cmake.in + ${CMAKE_BINARY_DIR}/Log-config.cmake + INSTALL_DESTINATION share/cmake/Log + ) + + install(DIRECTORY src/ + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILES_MATCHING PATTERN "*.hpp" + PATTERN "*test*" EXCLUDE + ) + + install(FILES + "${PROJECT_BINARY_DIR}/Log-config.cmake" + DESTINATION share/cmake/Log + ) + + if(NOT subproject) + set(CPACK_PACKAGE_VENDOR "Los Alamos National Laboratory") + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") + include(CPack) + endif() +endif() + diff --git a/cmake/Log-config.cmake.in b/cmake/Log-config.cmake.in new file mode 100644 index 0000000..32508ab --- /dev/null +++ b/cmake/Log-config.cmake.in @@ -0,0 +1,7 @@ +include(CMakeFindDependencyMacro) + +if (NOT TARGET spdlog::spdlog) + find_dependency(spdlog) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/Log-targets.cmake") \ No newline at end of file diff --git a/cmake/develop_dependencies.cmake b/cmake/develop_dependencies.cmake index bfcd945..8d856aa 100644 --- a/cmake/develop_dependencies.cmake +++ b/cmake/develop_dependencies.cmake @@ -15,12 +15,17 @@ FetchContent_Declare( spdlog GIT_REPOSITORY https://github.com/gabime/spdlog GIT_TAG a51b4856377a71f81b6d74b9af459305c4c644f8 ) +set( SPDLOG_BUILD_TESTING CACHE BOOL OFF ) ####################################################################### # Load dependencies ####################################################################### FetchContent_MakeAvailable( - catch-adapter spdlog ) + +if (${Log_unit_tests}) + FetchContent_MakeAvailable(catch-adapter) +endif() + diff --git a/cmake/release_dependencies.cmake b/cmake/release_dependencies.cmake index d29a720..6586750 100644 --- a/cmake/release_dependencies.cmake +++ b/cmake/release_dependencies.cmake @@ -9,6 +9,7 @@ FetchContent_Declare( spdlog GIT_REPOSITORY https://github.com/gabime/spdlog GIT_TAG a51b4856377a71f81b6d74b9af459305c4c644f8 ) +set( SPDLOG_BUILD_TESTING CACHE BOOL OFF ) FetchContent_Declare( catch-adapter GIT_REPOSITORY https://github.com/njoy/catch-adapter @@ -21,5 +22,8 @@ FetchContent_Declare( catch-adapter FetchContent_MakeAvailable( spdlog - catch-adapter ) + +if (${Log_unit_tests}) + FetchContent_MakeAvailable(catch-adapter) +endif() diff --git a/cmake/unit_testing.cmake b/cmake/unit_testing.cmake index e4e770a..4b807f7 100644 --- a/cmake/unit_testing.cmake +++ b/cmake/unit_testing.cmake @@ -3,8 +3,11 @@ ####################################################################### message( STATUS "Adding Log unit testing" ) -enable_testing() +add_library( Log_testing INTERFACE ) +target_link_libraries( Log_testing INTERFACE Log ) + +target_link_libraries(Log_testing INTERFACE catch-adapter) ####################################################################### # Unit testing directories diff --git a/src/Log/test/CMakeLists.txt b/src/Log/test/CMakeLists.txt index ee72c94..e1505fb 100644 --- a/src/Log/test/CMakeLists.txt +++ b/src/Log/test/CMakeLists.txt @@ -10,5 +10,5 @@ $<$:${${PREFIX}_link_time_optimization_flags}> $<$:${${PREFIX}_nonportable_optimization_flags}>> ${CXX_appended_flags} ${Log_appended_flags} ) -target_link_libraries( Log.test PUBLIC Log ) -add_test( NAME Log COMMAND Log.test ) \ No newline at end of file +target_link_libraries( Log.test PUBLIC Log_testing ) +add_test( NAME Log COMMAND Log.test ) From 1ee1d470451d309b572ef42b4baa29179fa8f6cc Mon Sep 17 00:00:00 2001 From: Timothy Patrick Burke Date: Tue, 28 Feb 2023 17:01:37 -0700 Subject: [PATCH 2/6] Squashed '.cmake/' content from commit 2ae392c git-subtree-dir: .cmake git-subtree-split: 2ae392c94ec567693f55dd491e1f8bb3e763b53e --- .gitignore | 3 + Backports/X11.cmake | 27 + Backports/X11/CheckFunctionExists.c | 28 + Backports/X11/CheckFunctionExists.cmake | 99 ++++ Backports/X11/CheckLibraryExists.cmake | 86 +++ Backports/X11/FindPackageMessage.cmake | 48 ++ Backports/X11/FindX11.cmake | 519 ++++++++++++++++++ CMakeDependentCacheVar.cmake | 50 ++ CMakeDependentSelection.cmake | 78 +++ DelegatingCacheVariable.cmake | 76 +++ DelegatingOption.cmake | 72 +++ DelegatingSelection.cmake | 97 ++++ DependencyInjection.cmake | 29 + DependencyInjection/add_executable.cmake | 14 + DependencyInjection/add_library.cmake | 14 + DependentDelegatingCacheVariable.cmake | 117 ++++ DependentDelegatingOption.cmake | 115 ++++ DependentDelegatingSelection.cmake | 119 ++++ Fortran.cmake | 32 ++ Fortran/BackslashEscape.cmake | 43 ++ Fortran/BackslashEscape/GNU.cmake | 8 + Fortran/BackslashEscape/Intel.cmake | 14 + Fortran/BackslashEscape/IntelLLVM.cmake | 14 + Fortran/BackslashEscape/PGI.cmake | 10 + Fortran/Backtrace.cmake | 43 ++ Fortran/Backtrace/GNU.cmake | 10 + Fortran/Backtrace/Intel.cmake | 14 + Fortran/Backtrace/IntelLLVM.cmake | 14 + Fortran/Backtrace/PGI.cmake | 10 + Fortran/Exceptions.cmake | 32 ++ Fortran/Exceptions/GNU.cmake | 10 + Fortran/Exceptions/Intel.cmake | 10 + Fortran/Exceptions/IntelLLVM.cmake | 10 + Fortran/Exceptions/README.md | 17 + Fortran/Integer.cmake | 69 +++ Fortran/Integer/GNU.cmake | 22 + Fortran/Integer/Intel.cmake | 28 + Fortran/Integer/IntelLLVM.cmake | 30 + Fortran/Integer/PGI.cmake | 22 + Fortran/LongLines.cmake | 29 + Fortran/LongLines/GNU.cmake | 8 + Fortran/ModuleDirectory.cmake | 60 ++ Fortran/README.md | 46 ++ Fortran/Real.cmake | 69 +++ Fortran/Real/GNU.cmake | 22 + Fortran/Real/Intel.cmake | 27 + Fortran/Real/IntelLLVM.cmake | 30 + Fortran/Real/PGI.cmake | 24 + Fortran/StackArraySizeLimit.cmake | 58 ++ Fortran/StackArraySizeLimit/GNU.cmake | 10 + Fortran/StackArraySizeLimit/Intel.cmake | 12 + Fortran/StackArraySizeLimit/IntelLLVM.cmake | 12 + Fortran/StackArraySizeLimit/PGI.cmake | 4 + Fortran/Standard.cmake | 47 ++ Fortran/Standard/GNU.cmake | 16 + Fortran/Standard/Intel.cmake | 19 + Fortran/Standard/IntelLLVM.cmake | 18 + Fortran/StandardCompliance.cmake | 41 ++ Fortran/StandardCompliance/GNU.cmake | 7 + Fortran/StandardCompliance/Intel.cmake | 12 + Fortran/StandardCompliance/IntelLLVM.cmake | 19 + Fortran/StandardCompliance/PGI.cmake | 7 + FortranPreProcess.cmake | 30 + FortranPreProcess/FortranPreProcess.cmake | 71 +++ FortranPreProcess/filename.cmake | 7 + FortranPreProcess/fpp.pl | 358 ++++++++++++ FortranPreProcess/target_sources.cmake | 36 ++ FunctionExtension.cmake | 35 ++ FunctionExtension/add_executable.cmake | 10 + FunctionExtension/add_library.cmake | 10 + FunctionExtension/backup.cmake | 7 + FunctionExtension/call.cmake | 12 + FunctionExtension/decrement.cmake | 3 + FunctionExtension/find_package.cmake | 29 + FunctionExtension/increment.cmake | 3 + FunctionExtension/pop.cmake | 8 + FunctionExtension/push.cmake | 8 + FunctionExtension/set_property.cmake | 10 + FunctionExtension/set_target_properties.cmake | 10 + FunctionExtension/target_sources.cmake | 10 + GeneratedSources.cmake | 29 + GeneratedSources/README.md | 47 ++ GeneratedSources/target_sources.cmake | 45 ++ GeneratedSources/trap.cmake | 14 + Git/Submodule/Packages.cmake | 33 ++ Git/Submodule/Packages/README.md | 257 +++++++++ .../Packages/README/git-submodules-101.md | 235 ++++++++ Git/Submodule/Packages/check_version.cmake | 138 +++++ Git/Submodule/Packages/configuration.cmake | 66 +++ Git/Submodule/Packages/find_package.cmake | 241 ++++++++ Git/Submodule/Packages/init.cmake | 50 ++ Git/Submodule/Packages/list.cmake | 432 +++++++++++++++ Git/Submodule/Packages/options.cmake | 63 +++ Git/Submodule/Packages/package.cmake | 112 ++++ Git/Submodule/Packages/update.cmake | 99 ++++ Intel.cmake | 22 + Intel/FloatingPoint/Model.cmake | 99 ++++ Intel/FloatingPoint/Speculation.cmake | 99 ++++ Intel/Fortran/Assumptions.cmake | 73 +++ IntelLLVM.cmake | 22 + IntelLLVM/FloatingPoint/Model.cmake | 99 ++++ IntelLLVM/FloatingPoint/Speculation.cmake | 99 ++++ IntelLLVM/Fortran/Assumptions.cmake | 73 +++ LICENSE | 33 ++ LinkOptions/StackSize.cmake | 40 ++ LinkOptions/StackSize/GNU.cmake | 21 + LinkOptions/StackSize/Intel.cmake | 23 + LinkOptions/StackSize/IntelLLVM.cmake | 23 + LinkOptions/StackSize/LLVM.cmake | 30 + LinkOptions/StackSize/MSVC.cmake | 11 + LinkOptions/StackSize/PGI.cmake | 20 + ListBinaryDir.cmake | 40 ++ README.md | 72 +++ Sanitizers.cmake | 46 ++ Sanitizers/configuration.cmake | 75 +++ Selection.cmake | 103 ++++ Warnings.cmake | 129 +++++ Warnings/C.cmake | 16 + Warnings/C/GNU.cmake | 19 + Warnings/C/Intel.cmake | 24 + Warnings/C/IntelLLVM.cmake | 24 + Warnings/C/LLVM.cmake | 22 + Warnings/C/MSVC.cmake | 15 + Warnings/CUDA.cmake | 6 + Warnings/CUDA/NVIDIA.cmake | 12 + Warnings/CXX.cmake | 17 + Warnings/CXX/GNU.cmake | 20 + Warnings/CXX/Intel.cmake | 24 + Warnings/CXX/IntelLLVM.cmake | 24 + Warnings/CXX/LLVM.cmake | 24 + Warnings/CXX/MSVC.cmake | 15 + Warnings/Fortran.cmake | 14 + Warnings/Fortran/GNU.cmake | 19 + Warnings/Fortran/Intel.cmake | 28 + Warnings/Fortran/IntelLLVM.cmake | 28 + config.cmake | 41 ++ documentation/function-extension.md | 51 ++ shacl-config.cmake | 33 ++ shacl_FetchContent.cmake | 190 +++++++ shacl_FetchContent/README.md | 98 ++++ shacl_FetchContent/directory_git_info.cmake | 53 ++ shacl_FetchContent/relative_git_url.cmake | 45 ++ tests/Backports/CMakeLists.txt | 1 + tests/Backports/X11/CMakeLists.txt | 11 + tests/CMakeLists.txt | 49 ++ tests/DelegatingCacheVariable/CMakeLists.txt | 47 ++ tests/DelegatingOption/CMakeLists.txt | 31 ++ tests/DelegatingSelection/CMakeLists.txt | 33 ++ tests/DependencyInjection/CMakeLists.txt | 17 + tests/DependencyInjection/exe_injected.cmake | 3 + tests/DependencyInjection/exe_main.cpp | 5 + tests/DependencyInjection/lib.cpp | 4 + tests/DependencyInjection/lib_injected.cmake | 3 + .../CMakeLists.txt | 54 ++ .../DependentDelegatingOption/CMakeLists.txt | 50 ++ .../CMakeLists.txt | 54 ++ tests/Fortran/BackslashEscape/CMakeLists.txt | 55 ++ .../use_backslash_escape.F90.in | 4 + .../use_no_backslash_escape.F90.in | 4 + tests/Fortran/Backtrace/CMakeLists.txt | 45 ++ tests/Fortran/Backtrace/backtrace.f90.in | 3 + tests/Fortran/CMakeLists.txt | 10 + tests/Fortran/Exceptions/CMakeLists.txt | 12 + tests/Fortran/Exceptions/a.f90 | 11 + tests/Fortran/Exceptions/b.cpp | 10 + tests/Fortran/Integer/CMakeLists.txt | 23 + tests/Fortran/Integer/test.F90 | 19 + tests/Fortran/Integer/test.c | 12 + tests/Fortran/Integer/test.cpp | 12 + tests/Fortran/LongLines/CMakeLists.txt | 19 + tests/Fortran/LongLines/longlines.f90.in | 3 + tests/Fortran/ModuleDirectory/CMakeLists.txt | 21 + .../ModuleDirectory/check_exists.cmake | 3 + tests/Fortran/ModuleDirectory/test_mod.F90 | 13 + tests/Fortran/Real/CMakeLists.txt | 23 + tests/Fortran/Real/test.F90 | 19 + tests/Fortran/Real/test.c | 12 + tests/Fortran/Real/test.cpp | 12 + .../StackArraySizeLimit/CMakeLists.txt | 23 + .../use_temp_arrays.F90.in | 5 + tests/Fortran/Standard/CMakeLists.txt | 48 ++ tests/Fortran/Standard/use_standard.f90.in | 3 + .../Fortran/StandardCompliance/CMakeLists.txt | 23 + .../use_fortran_standard_adherence.F90.in | 5 + tests/FortranPreProcess/CMakeLists.txt | 19 + tests/FortranPreProcess/fprepro_defines.F90 | 5 + tests/FortranPreProcess/fprepro_includes.F90 | 8 + tests/FortranPreProcess/fprepro_includes.inc | 8 + tests/FunctionExtension/CMakeLists.txt | 7 + tests/FunctionExtension/call/CMakeLists.txt | 33 ++ .../integrated_features/CMakeLists.txt | 10 + .../integrated_features/test_source.cpp | 1 + .../FunctionExtension/push_pop/CMakeLists.txt | 140 +++++ .../set_property/CMakeLists.txt | 20 + .../set_target_properties/CMakeLists.txt | 23 + tests/GeneratedSources/CMakeLists.txt | 1 + .../target_sources/CMakeLists.txt | 29 + .../GeneratedSources/target_sources/bar.c.in | 1 + .../GeneratedSources/target_sources/foo.c.in | 1 + .../subdirectory/CMakeLists.txt | 7 + .../target_sources/subdirectory/foo.c.in | 1 + tests/GeneratedSources/target_sources/test1 | 1 + tests/GeneratedSources/target_sources/test2 | 1 + tests/Git/Submodule/Packages/CMakeLists.txt | 24 + tests/Intel/CMakeLists.txt | 3 + tests/Intel/FPModel/CMakeLists.txt | 64 +++ tests/Intel/FPModel/use_intel_fp_model.F90.in | 4 + tests/Intel/FPModel/use_intel_fp_model.c.in | 7 + tests/Intel/FPModel/use_intel_fp_model.cpp.in | 7 + tests/Intel/FPSpeculation/CMakeLists.txt | 65 +++ .../use_intel_fp_speculation.F90.in | 4 + .../use_intel_fp_speculation.c.in | 7 + .../use_intel_fp_speculation.cpp.in | 7 + tests/Intel/FortranAssumptions/CMakeLists.txt | 28 + .../FortranAssumptions/assumptions.f90.in | 3 + .../FortranStandardAdherence/CMakeLists.txt | 26 + .../FortranStandardAdherence/adherence.f90.in | 3 + tests/LinkOptions/CMakeLists.txt | 1 + tests/LinkOptions/StackSize/CMakeLists.txt | 25 + tests/LinkOptions/StackSize/use_stack_size.c | 1 + .../LinkOptions/StackSize/use_stack_size.cpp | 1 + .../LinkOptions/StackSize/use_stack_size.f90 | 6 + tests/Sanitizers/CMakeLists.txt | 20 + tests/Sanitizers/trigger_asan.cpp | 17 + tests/Sanitizers/trigger_msan.cpp | 20 + tests/Sanitizers/trigger_tsan.cpp | 33 ++ tests/Sanitizers/trigger_ubsan.cpp | 19 + tests/Warnings/CMakeLists.txt | 222 ++++++++ tests/Warnings/warnings.c.in | 6 + tests/Warnings/warnings.cpp.in | 5 + tests/Warnings/warnings.cu.in | 5 + tests/Warnings/warnings.f90.in | 4 + tests/shacl_FetchContent/CMakeLists.txt | 29 + tests/shacl_FetchContent/dependencies.cmake | 24 + 234 files changed, 9102 insertions(+) create mode 100644 .gitignore create mode 100644 Backports/X11.cmake create mode 100644 Backports/X11/CheckFunctionExists.c create mode 100644 Backports/X11/CheckFunctionExists.cmake create mode 100644 Backports/X11/CheckLibraryExists.cmake create mode 100644 Backports/X11/FindPackageMessage.cmake create mode 100644 Backports/X11/FindX11.cmake create mode 100644 CMakeDependentCacheVar.cmake create mode 100644 CMakeDependentSelection.cmake create mode 100644 DelegatingCacheVariable.cmake create mode 100644 DelegatingOption.cmake create mode 100644 DelegatingSelection.cmake create mode 100644 DependencyInjection.cmake create mode 100644 DependencyInjection/add_executable.cmake create mode 100644 DependencyInjection/add_library.cmake create mode 100644 DependentDelegatingCacheVariable.cmake create mode 100644 DependentDelegatingOption.cmake create mode 100644 DependentDelegatingSelection.cmake create mode 100644 Fortran.cmake create mode 100644 Fortran/BackslashEscape.cmake create mode 100644 Fortran/BackslashEscape/GNU.cmake create mode 100644 Fortran/BackslashEscape/Intel.cmake create mode 100644 Fortran/BackslashEscape/IntelLLVM.cmake create mode 100644 Fortran/BackslashEscape/PGI.cmake create mode 100644 Fortran/Backtrace.cmake create mode 100644 Fortran/Backtrace/GNU.cmake create mode 100644 Fortran/Backtrace/Intel.cmake create mode 100644 Fortran/Backtrace/IntelLLVM.cmake create mode 100644 Fortran/Backtrace/PGI.cmake create mode 100644 Fortran/Exceptions.cmake create mode 100644 Fortran/Exceptions/GNU.cmake create mode 100644 Fortran/Exceptions/Intel.cmake create mode 100644 Fortran/Exceptions/IntelLLVM.cmake create mode 100644 Fortran/Exceptions/README.md create mode 100644 Fortran/Integer.cmake create mode 100644 Fortran/Integer/GNU.cmake create mode 100644 Fortran/Integer/Intel.cmake create mode 100644 Fortran/Integer/IntelLLVM.cmake create mode 100644 Fortran/Integer/PGI.cmake create mode 100644 Fortran/LongLines.cmake create mode 100644 Fortran/LongLines/GNU.cmake create mode 100644 Fortran/ModuleDirectory.cmake create mode 100644 Fortran/README.md create mode 100644 Fortran/Real.cmake create mode 100644 Fortran/Real/GNU.cmake create mode 100644 Fortran/Real/Intel.cmake create mode 100644 Fortran/Real/IntelLLVM.cmake create mode 100644 Fortran/Real/PGI.cmake create mode 100644 Fortran/StackArraySizeLimit.cmake create mode 100644 Fortran/StackArraySizeLimit/GNU.cmake create mode 100644 Fortran/StackArraySizeLimit/Intel.cmake create mode 100644 Fortran/StackArraySizeLimit/IntelLLVM.cmake create mode 100644 Fortran/StackArraySizeLimit/PGI.cmake create mode 100644 Fortran/Standard.cmake create mode 100644 Fortran/Standard/GNU.cmake create mode 100644 Fortran/Standard/Intel.cmake create mode 100644 Fortran/Standard/IntelLLVM.cmake create mode 100644 Fortran/StandardCompliance.cmake create mode 100644 Fortran/StandardCompliance/GNU.cmake create mode 100644 Fortran/StandardCompliance/Intel.cmake create mode 100644 Fortran/StandardCompliance/IntelLLVM.cmake create mode 100644 Fortran/StandardCompliance/PGI.cmake create mode 100644 FortranPreProcess.cmake create mode 100644 FortranPreProcess/FortranPreProcess.cmake create mode 100644 FortranPreProcess/filename.cmake create mode 100755 FortranPreProcess/fpp.pl create mode 100644 FortranPreProcess/target_sources.cmake create mode 100644 FunctionExtension.cmake create mode 100644 FunctionExtension/add_executable.cmake create mode 100644 FunctionExtension/add_library.cmake create mode 100644 FunctionExtension/backup.cmake create mode 100644 FunctionExtension/call.cmake create mode 100644 FunctionExtension/decrement.cmake create mode 100644 FunctionExtension/find_package.cmake create mode 100644 FunctionExtension/increment.cmake create mode 100644 FunctionExtension/pop.cmake create mode 100644 FunctionExtension/push.cmake create mode 100644 FunctionExtension/set_property.cmake create mode 100644 FunctionExtension/set_target_properties.cmake create mode 100644 FunctionExtension/target_sources.cmake create mode 100644 GeneratedSources.cmake create mode 100644 GeneratedSources/README.md create mode 100644 GeneratedSources/target_sources.cmake create mode 100644 GeneratedSources/trap.cmake create mode 100644 Git/Submodule/Packages.cmake create mode 100644 Git/Submodule/Packages/README.md create mode 100644 Git/Submodule/Packages/README/git-submodules-101.md create mode 100644 Git/Submodule/Packages/check_version.cmake create mode 100644 Git/Submodule/Packages/configuration.cmake create mode 100644 Git/Submodule/Packages/find_package.cmake create mode 100644 Git/Submodule/Packages/init.cmake create mode 100644 Git/Submodule/Packages/list.cmake create mode 100644 Git/Submodule/Packages/options.cmake create mode 100644 Git/Submodule/Packages/package.cmake create mode 100644 Git/Submodule/Packages/update.cmake create mode 100644 Intel.cmake create mode 100644 Intel/FloatingPoint/Model.cmake create mode 100644 Intel/FloatingPoint/Speculation.cmake create mode 100644 Intel/Fortran/Assumptions.cmake create mode 100644 IntelLLVM.cmake create mode 100644 IntelLLVM/FloatingPoint/Model.cmake create mode 100644 IntelLLVM/FloatingPoint/Speculation.cmake create mode 100644 IntelLLVM/Fortran/Assumptions.cmake create mode 100644 LICENSE create mode 100644 LinkOptions/StackSize.cmake create mode 100644 LinkOptions/StackSize/GNU.cmake create mode 100644 LinkOptions/StackSize/Intel.cmake create mode 100644 LinkOptions/StackSize/IntelLLVM.cmake create mode 100644 LinkOptions/StackSize/LLVM.cmake create mode 100644 LinkOptions/StackSize/MSVC.cmake create mode 100644 LinkOptions/StackSize/PGI.cmake create mode 100644 ListBinaryDir.cmake create mode 100644 README.md create mode 100644 Sanitizers.cmake create mode 100644 Sanitizers/configuration.cmake create mode 100644 Selection.cmake create mode 100644 Warnings.cmake create mode 100644 Warnings/C.cmake create mode 100644 Warnings/C/GNU.cmake create mode 100644 Warnings/C/Intel.cmake create mode 100644 Warnings/C/IntelLLVM.cmake create mode 100644 Warnings/C/LLVM.cmake create mode 100644 Warnings/C/MSVC.cmake create mode 100644 Warnings/CUDA.cmake create mode 100644 Warnings/CUDA/NVIDIA.cmake create mode 100644 Warnings/CXX.cmake create mode 100644 Warnings/CXX/GNU.cmake create mode 100644 Warnings/CXX/Intel.cmake create mode 100644 Warnings/CXX/IntelLLVM.cmake create mode 100644 Warnings/CXX/LLVM.cmake create mode 100644 Warnings/CXX/MSVC.cmake create mode 100644 Warnings/Fortran.cmake create mode 100644 Warnings/Fortran/GNU.cmake create mode 100644 Warnings/Fortran/Intel.cmake create mode 100644 Warnings/Fortran/IntelLLVM.cmake create mode 100644 config.cmake create mode 100644 documentation/function-extension.md create mode 100644 shacl-config.cmake create mode 100644 shacl_FetchContent.cmake create mode 100644 shacl_FetchContent/README.md create mode 100644 shacl_FetchContent/directory_git_info.cmake create mode 100644 shacl_FetchContent/relative_git_url.cmake create mode 100644 tests/Backports/CMakeLists.txt create mode 100644 tests/Backports/X11/CMakeLists.txt create mode 100644 tests/CMakeLists.txt create mode 100644 tests/DelegatingCacheVariable/CMakeLists.txt create mode 100644 tests/DelegatingOption/CMakeLists.txt create mode 100644 tests/DelegatingSelection/CMakeLists.txt create mode 100644 tests/DependencyInjection/CMakeLists.txt create mode 100644 tests/DependencyInjection/exe_injected.cmake create mode 100644 tests/DependencyInjection/exe_main.cpp create mode 100644 tests/DependencyInjection/lib.cpp create mode 100644 tests/DependencyInjection/lib_injected.cmake create mode 100644 tests/DependentDelegatingCacheVariable/CMakeLists.txt create mode 100644 tests/DependentDelegatingOption/CMakeLists.txt create mode 100644 tests/DependentDelegatingSelection/CMakeLists.txt create mode 100644 tests/Fortran/BackslashEscape/CMakeLists.txt create mode 100644 tests/Fortran/BackslashEscape/use_backslash_escape.F90.in create mode 100644 tests/Fortran/BackslashEscape/use_no_backslash_escape.F90.in create mode 100644 tests/Fortran/Backtrace/CMakeLists.txt create mode 100644 tests/Fortran/Backtrace/backtrace.f90.in create mode 100644 tests/Fortran/CMakeLists.txt create mode 100644 tests/Fortran/Exceptions/CMakeLists.txt create mode 100644 tests/Fortran/Exceptions/a.f90 create mode 100644 tests/Fortran/Exceptions/b.cpp create mode 100644 tests/Fortran/Integer/CMakeLists.txt create mode 100644 tests/Fortran/Integer/test.F90 create mode 100644 tests/Fortran/Integer/test.c create mode 100644 tests/Fortran/Integer/test.cpp create mode 100644 tests/Fortran/LongLines/CMakeLists.txt create mode 100644 tests/Fortran/LongLines/longlines.f90.in create mode 100644 tests/Fortran/ModuleDirectory/CMakeLists.txt create mode 100644 tests/Fortran/ModuleDirectory/check_exists.cmake create mode 100644 tests/Fortran/ModuleDirectory/test_mod.F90 create mode 100644 tests/Fortran/Real/CMakeLists.txt create mode 100644 tests/Fortran/Real/test.F90 create mode 100644 tests/Fortran/Real/test.c create mode 100644 tests/Fortran/Real/test.cpp create mode 100644 tests/Fortran/StackArraySizeLimit/CMakeLists.txt create mode 100644 tests/Fortran/StackArraySizeLimit/use_temp_arrays.F90.in create mode 100644 tests/Fortran/Standard/CMakeLists.txt create mode 100644 tests/Fortran/Standard/use_standard.f90.in create mode 100644 tests/Fortran/StandardCompliance/CMakeLists.txt create mode 100644 tests/Fortran/StandardCompliance/use_fortran_standard_adherence.F90.in create mode 100644 tests/FortranPreProcess/CMakeLists.txt create mode 100644 tests/FortranPreProcess/fprepro_defines.F90 create mode 100644 tests/FortranPreProcess/fprepro_includes.F90 create mode 100644 tests/FortranPreProcess/fprepro_includes.inc create mode 100644 tests/FunctionExtension/CMakeLists.txt create mode 100644 tests/FunctionExtension/call/CMakeLists.txt create mode 100644 tests/FunctionExtension/integrated_features/CMakeLists.txt create mode 100644 tests/FunctionExtension/integrated_features/test_source.cpp create mode 100644 tests/FunctionExtension/push_pop/CMakeLists.txt create mode 100644 tests/FunctionExtension/set_property/CMakeLists.txt create mode 100644 tests/FunctionExtension/set_target_properties/CMakeLists.txt create mode 100644 tests/GeneratedSources/CMakeLists.txt create mode 100644 tests/GeneratedSources/target_sources/CMakeLists.txt create mode 100644 tests/GeneratedSources/target_sources/bar.c.in create mode 100644 tests/GeneratedSources/target_sources/foo.c.in create mode 100644 tests/GeneratedSources/target_sources/subdirectory/CMakeLists.txt create mode 100644 tests/GeneratedSources/target_sources/subdirectory/foo.c.in create mode 100644 tests/GeneratedSources/target_sources/test1 create mode 100644 tests/GeneratedSources/target_sources/test2 create mode 100644 tests/Git/Submodule/Packages/CMakeLists.txt create mode 100644 tests/Intel/CMakeLists.txt create mode 100644 tests/Intel/FPModel/CMakeLists.txt create mode 100644 tests/Intel/FPModel/use_intel_fp_model.F90.in create mode 100644 tests/Intel/FPModel/use_intel_fp_model.c.in create mode 100644 tests/Intel/FPModel/use_intel_fp_model.cpp.in create mode 100644 tests/Intel/FPSpeculation/CMakeLists.txt create mode 100644 tests/Intel/FPSpeculation/use_intel_fp_speculation.F90.in create mode 100644 tests/Intel/FPSpeculation/use_intel_fp_speculation.c.in create mode 100644 tests/Intel/FPSpeculation/use_intel_fp_speculation.cpp.in create mode 100644 tests/Intel/FortranAssumptions/CMakeLists.txt create mode 100644 tests/Intel/FortranAssumptions/assumptions.f90.in create mode 100644 tests/Intel/FortranStandardAdherence/CMakeLists.txt create mode 100644 tests/Intel/FortranStandardAdherence/adherence.f90.in create mode 100644 tests/LinkOptions/CMakeLists.txt create mode 100644 tests/LinkOptions/StackSize/CMakeLists.txt create mode 100644 tests/LinkOptions/StackSize/use_stack_size.c create mode 100644 tests/LinkOptions/StackSize/use_stack_size.cpp create mode 100644 tests/LinkOptions/StackSize/use_stack_size.f90 create mode 100644 tests/Sanitizers/CMakeLists.txt create mode 100644 tests/Sanitizers/trigger_asan.cpp create mode 100644 tests/Sanitizers/trigger_msan.cpp create mode 100644 tests/Sanitizers/trigger_tsan.cpp create mode 100644 tests/Sanitizers/trigger_ubsan.cpp create mode 100644 tests/Warnings/CMakeLists.txt create mode 100644 tests/Warnings/warnings.c.in create mode 100644 tests/Warnings/warnings.cpp.in create mode 100644 tests/Warnings/warnings.cu.in create mode 100644 tests/Warnings/warnings.f90.in create mode 100644 tests/shacl_FetchContent/CMakeLists.txt create mode 100644 tests/shacl_FetchContent/dependencies.cmake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a8fbb21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.sw? +*~ +*.bak diff --git a/Backports/X11.cmake b/Backports/X11.cmake new file mode 100644 index 0000000..070bae0 --- /dev/null +++ b/Backports/X11.cmake @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") + +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Backports/X11" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Backports/X11") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Backports) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/X11" + DESTINATION share/cmake/shacl/.cmake/Backports) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/X11") diff --git a/Backports/X11/CheckFunctionExists.c b/Backports/X11/CheckFunctionExists.c new file mode 100644 index 0000000..224e340 --- /dev/null +++ b/Backports/X11/CheckFunctionExists.c @@ -0,0 +1,28 @@ +#ifdef CHECK_FUNCTION_EXISTS + +#ifdef __cplusplus +extern "C" +#endif + char + CHECK_FUNCTION_EXISTS(void); +#ifdef __CLASSIC_C__ +int main() +{ + int ac; + char* av[]; +#else +int main(int ac, char* av[]) +{ +#endif + CHECK_FUNCTION_EXISTS(); + if (ac > 1000) { + return *av[0]; + } + return 0; +} + +#else /* CHECK_FUNCTION_EXISTS */ + +#error "CHECK_FUNCTION_EXISTS has to specify the function" + +#endif /* CHECK_FUNCTION_EXISTS */ diff --git a/Backports/X11/CheckFunctionExists.cmake b/Backports/X11/CheckFunctionExists.cmake new file mode 100644 index 0000000..9dd0599 --- /dev/null +++ b/Backports/X11/CheckFunctionExists.cmake @@ -0,0 +1,99 @@ +cmake_minimum_required(VERSION 3.12.1) +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# CheckFunctionExists +# ------------------- +# +# Check if a C function can be linked:: +# +# check_function_exists( ) +# +# Check that the ```` is provided by libraries on the system and store +# the result in a ````. ```` will be created as an internal +# cache variable. +# +# The following variables may be set before calling this macro to modify the +# way the check is run: +# +# :: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories +# CMAKE_REQUIRED_LIBRARIES = list of libraries to link +# CMAKE_REQUIRED_QUIET = execute quietly without messages +# +# .. note:: +# +# Prefer using :Module:`CheckSymbolExists` instead of this module, +# for the following reasons: +# +# * ``check_function_exists()`` can't detect functions that are inlined +# in headers or specified as a macro. +# +# * ``check_function_exists()`` can't detect anything in the 32-bit +# versions of the Win32 API, because of a mismatch in calling conventions. +# +# * ``check_function_exists()`` only verifies linking, it does not verify +# that the function is declared in system headers. + +macro(CHECK_FUNCTION_EXISTS FUNCTION VARIABLE) + if(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}") + set(MACRO_CHECK_FUNCTION_DEFINITIONS + "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${FUNCTION}") + endif() + if(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + else() + set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES) + endif() + if(CMAKE_REQUIRED_INCLUDES) + set(CHECK_FUNCTION_EXISTS_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + else() + set(CHECK_FUNCTION_EXISTS_ADD_INCLUDES) + endif() + + if(CMAKE_C_COMPILER_LOADED) + set(_cfe_source ${CMAKE_ROOT}/Modules/CheckFunctionExists.c) + elseif(CMAKE_CXX_COMPILER_LOADED) + set(_cfe_source ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckFunctionExists/CheckFunctionExists.cxx) + configure_file(${CMAKE_ROOT}/Modules/CheckFunctionExists.c "${_cfe_source}" COPYONLY) + else() + message(FATAL_ERROR "CHECK_FUNCTION_EXISTS needs either C or CXX language enabled") + endif() + + try_compile(${VARIABLE} + ${CMAKE_BINARY_DIR} + ${_cfe_source} + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + ${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + "${CHECK_FUNCTION_EXISTS_ADD_INCLUDES}" + OUTPUT_VARIABLE OUTPUT) + unset(_cfe_source) + + if(${VARIABLE}) + set(${VARIABLE} 1 CACHE INTERNAL "Have function ${FUNCTION}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${FUNCTION} - found") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the function ${FUNCTION} exists passed with the following output:\n" + "${OUTPUT}\n\n") + else() + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${FUNCTION} - not found") + endif() + set(${VARIABLE} "" CACHE INTERNAL "Have function ${FUNCTION}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the function ${FUNCTION} exists failed with the following output:\n" + "${OUTPUT}\n\n") + endif() + endif() +endmacro() diff --git a/Backports/X11/CheckLibraryExists.cmake b/Backports/X11/CheckLibraryExists.cmake new file mode 100644 index 0000000..5708367 --- /dev/null +++ b/Backports/X11/CheckLibraryExists.cmake @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.12.1) +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# CheckLibraryExists +# ------------------ +# +# Check if the function exists. +# +# CHECK_LIBRARY_EXISTS (LIBRARY FUNCTION LOCATION VARIABLE) +# +# :: +# +# LIBRARY - the name of the library you are looking for +# FUNCTION - the name of the function +# LOCATION - location where the library should be found +# VARIABLE - variable to store the result +# Will be created as an internal cache variable. +# +# +# +# The following variables may be set before calling this macro to modify +# the way the check is run: +# +# :: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_LIBRARIES = list of libraries to link +# CMAKE_REQUIRED_QUIET = execute quietly without messages + +macro(CHECK_LIBRARY_EXISTS LIBRARY FUNCTION LOCATION VARIABLE) + if(NOT DEFINED "${VARIABLE}") + set(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION + "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${FUNCTION} in ${LIBRARY}") + endif() + set(CHECK_LIBRARY_EXISTS_LIBRARIES ${LIBRARY}) + if(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_LIBRARY_EXISTS_LIBRARIES + ${CHECK_LIBRARY_EXISTS_LIBRARIES} ${CMAKE_REQUIRED_LIBRARIES}) + endif() + + if(CMAKE_C_COMPILER_LOADED) + set(_cle_source ${CMAKE_ROOT}/Modules/CheckFunctionExists.c) + elseif(CMAKE_CXX_COMPILER_LOADED) + set(_cle_source ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckLibraryExists/CheckFunctionExists.cxx) + configure_file(${CMAKE_ROOT}/Modules/CheckFunctionExists.c "${_cle_source}" COPYONLY) + else() + message(FATAL_ERROR "CHECK_FUNCTION_EXISTS needs either C or CXX language enabled") + endif() + + try_compile(${VARIABLE} + ${CMAKE_BINARY_DIR} + ${_cle_source} + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + LINK_LIBRARIES ${CHECK_LIBRARY_EXISTS_LIBRARIES} + CMAKE_FLAGS + -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION} + -DLINK_DIRECTORIES:STRING=${LOCATION} + OUTPUT_VARIABLE OUTPUT) + unset(_cle_source) + + if(${VARIABLE}) + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${FUNCTION} in ${LIBRARY} - found") + endif() + set(${VARIABLE} 1 CACHE INTERNAL "Have library ${LIBRARY}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the function ${FUNCTION} exists in the ${LIBRARY} " + "passed with the following output:\n" + "${OUTPUT}\n\n") + else() + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${FUNCTION} in ${LIBRARY} - not found") + endif() + set(${VARIABLE} "" CACHE INTERNAL "Have library ${LIBRARY}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the function ${FUNCTION} exists in the ${LIBRARY} " + "failed with the following output:\n" + "${OUTPUT}\n\n") + endif() + endif() +endmacro() diff --git a/Backports/X11/FindPackageMessage.cmake b/Backports/X11/FindPackageMessage.cmake new file mode 100644 index 0000000..ca7750d --- /dev/null +++ b/Backports/X11/FindPackageMessage.cmake @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 3.12.1) +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindPackageMessage +# ------------------ +# +# +# +# FIND_PACKAGE_MESSAGE( "message for user" "find result details") +# +# This macro is intended to be used in FindXXX.cmake modules files. It +# will print a message once for each unique find result. This is useful +# for telling the user where a package was found. The first argument +# specifies the name (XXX) of the package. The second argument +# specifies the message to display. The third argument lists details +# about the find result so that if they change the message will be +# displayed again. The macro also obeys the QUIET argument to the +# find_package command. +# +# Example: +# +# :: +# +# if(X11_FOUND) +# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}" +# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") +# else() +# ... +# endif() + +function(FIND_PACKAGE_MESSAGE pkg msg details) + # Avoid printing a message repeatedly for the same find result. + if(NOT ${pkg}_FIND_QUIETLY) + string(REPLACE "\n" "" details "${details}") + set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) + if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") + # The message has not yet been printed. + message(STATUS "${msg}") + + # Save the find details in the cache to avoid printing the same + # message again. + set("${DETAILS_VAR}" "${details}" + CACHE INTERNAL "Details about finding ${pkg}") + endif() + endif() +endfunction() diff --git a/Backports/X11/FindX11.cmake b/Backports/X11/FindX11.cmake new file mode 100644 index 0000000..dc1a59d --- /dev/null +++ b/Backports/X11/FindX11.cmake @@ -0,0 +1,519 @@ +cmake_minimum_required(VERSION 3.12.1) +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindX11 +# ------- +# +# Find X11 installation +# +# Try to find X11 on UNIX systems. The following values are defined +# +# :: +# +# X11_FOUND - True if X11 is available +# X11_INCLUDE_DIR - include directories to use X11 +# X11_LIBRARIES - link against these to use X11 +# +# and also the following more fine grained variables: +# +# :: +# +# X11_ICE_INCLUDE_PATH, X11_ICE_LIB, X11_ICE_FOUND +# X11_SM_INCLUDE_PATH, X11_SM_LIB, X11_SM_FOUND +# X11_X11_INCLUDE_PATH, X11_X11_LIB +# X11_Xaccessrules_INCLUDE_PATH, X11_Xaccess_FOUND +# X11_Xaccessstr_INCLUDE_PATH, X11_Xaccess_FOUND +# X11_Xau_INCLUDE_PATH, X11_Xau_LIB, X11_Xau_FOUND +# X11_Xcomposite_INCLUDE_PATH, X11_Xcomposite_LIB, X11_Xcomposite_FOUND +# X11_Xcursor_INCLUDE_PATH, X11_Xcursor_LIB, X11_Xcursor_FOUND +# X11_Xdamage_INCLUDE_PATH, X11_Xdamage_LIB, X11_Xdamage_FOUND +# X11_Xdmcp_INCLUDE_PATH, X11_Xdmcp_LIB, X11_Xdmcp_FOUND +# X11_Xext_LIB, X11_Xext_FOUND +# X11_dpms_INCLUDE_PATH, (in X11_Xext_LIB), X11_dpms_FOUND +# X11_XShm_INCLUDE_PATH, (in X11_Xext_LIB), X11_XShm_FOUND +# X11_Xshape_INCLUDE_PATH, (in X11_Xext_LIB), X11_Xshape_FOUND +# X11_xf86misc_INCLUDE_PATH, X11_Xxf86misc_LIB, X11_xf86misc_FOUND +# X11_xf86vmode_INCLUDE_PATH, X11_Xxf86vm_LIB X11_xf86vmode_FOUND +# X11_Xfixes_INCLUDE_PATH, X11_Xfixes_LIB, X11_Xfixes_FOUND +# X11_Xft_INCLUDE_PATH, X11_Xft_LIB, X11_Xft_FOUND +# X11_Xi_INCLUDE_PATH, X11_Xi_LIB, X11_Xi_FOUND +# X11_Xinerama_INCLUDE_PATH, X11_Xinerama_LIB, X11_Xinerama_FOUND +# X11_Xinput_INCLUDE_PATH, X11_Xinput_LIB, X11_Xinput_FOUND +# X11_Xkb_INCLUDE_PATH, X11_Xkb_FOUND +# X11_Xkblib_INCLUDE_PATH, X11_Xkb_FOUND +# X11_Xkbfile_INCLUDE_PATH, X11_Xkbfile_LIB, X11_Xkbfile_FOUND +# X11_Xmu_INCLUDE_PATH, X11_Xmu_LIB, X11_Xmu_FOUND +# X11_Xpm_INCLUDE_PATH, X11_Xpm_LIB, X11_Xpm_FOUND +# X11_XTest_INCLUDE_PATH, X11_XTest_LIB, X11_XTest_FOUND +# X11_Xrandr_INCLUDE_PATH, X11_Xrandr_LIB, X11_Xrandr_FOUND +# X11_Xrender_INCLUDE_PATH, X11_Xrender_LIB, X11_Xrender_FOUND +# X11_Xscreensaver_INCLUDE_PATH, X11_Xscreensaver_LIB, X11_Xscreensaver_FOUND +# X11_Xt_INCLUDE_PATH, X11_Xt_LIB, X11_Xt_FOUND +# X11_Xutil_INCLUDE_PATH, X11_Xutil_FOUND +# X11_Xv_INCLUDE_PATH, X11_Xv_LIB, X11_Xv_FOUND +# X11_XSync_INCLUDE_PATH, (in X11_Xext_LIB), X11_XSync_FOUND + + +set( X11_FOUND 0 ) + +list(APPEND X11_INC_SEARCH_PATH ${X11_ROOT}/include) +list(APPEND X11_LIB_SEARCH_PATH ${X11_ROOT}/lib) +list(APPEND X11_LIB_SEARCH_PATH ${X11_ROOT}/lib64) + +if (UNIX) + # X11 is never a framework and some header files may be + # found in tcl on the mac + set(CMAKE_FIND_FRAMEWORK_SAVE ${CMAKE_FIND_FRAMEWORK}) + set(CMAKE_FIND_FRAMEWORK NEVER) + set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) + set(CMAKE_REQUIRED_QUIET ${X11_FIND_QUIETLY}) + list(APPEND X11_INC_SEARCH_PATH + /usr/pkg/xorg/include + /usr/X11R6/include + /usr/X11R7/include + /usr/include/X11 + /usr/openwin/include + /usr/openwin/share/include + /opt/graphics/OpenGL/include + /opt/X11/include + ) + + list(APPEND X11_LIB_SEARCH_PATH + /usr/pkg/xorg/lib + /usr/X11R6/lib + /usr/X11R7/lib + /usr/openwin/lib + /opt/X11/lib + ) +endif() + +find_path(X11_X11_INCLUDE_PATH X11/X.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xlib_INCLUDE_PATH X11/Xlib.h ${X11_INC_SEARCH_PATH}) + +# Look for includes; keep the list sorted by name of the cmake *_INCLUDE_PATH +# variable (which doesn't need to match the include file name). + +# Solaris lacks XKBrules.h, so we should skip kxkbd there. +find_path(X11_ICE_INCLUDE_PATH X11/ICE/ICE.h ${X11_INC_SEARCH_PATH}) +find_path(X11_SM_INCLUDE_PATH X11/SM/SM.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xaccessrules_INCLUDE_PATH X11/extensions/XKBrules.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xaccessstr_INCLUDE_PATH X11/extensions/XKBstr.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xau_INCLUDE_PATH X11/Xauth.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xcomposite_INCLUDE_PATH X11/extensions/Xcomposite.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xcursor_INCLUDE_PATH X11/Xcursor/Xcursor.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xdamage_INCLUDE_PATH X11/extensions/Xdamage.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xdmcp_INCLUDE_PATH X11/Xdmcp.h ${X11_INC_SEARCH_PATH}) +find_path(X11_dpms_INCLUDE_PATH X11/extensions/dpms.h ${X11_INC_SEARCH_PATH}) +find_path(X11_xf86misc_INCLUDE_PATH X11/extensions/xf86misc.h ${X11_INC_SEARCH_PATH}) +find_path(X11_xf86vmode_INCLUDE_PATH X11/extensions/xf86vmode.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xfixes_INCLUDE_PATH X11/extensions/Xfixes.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xft_INCLUDE_PATH X11/Xft/Xft.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xi_INCLUDE_PATH X11/extensions/XInput.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xinerama_INCLUDE_PATH X11/extensions/Xinerama.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xinput_INCLUDE_PATH X11/extensions/XInput.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xkb_INCLUDE_PATH X11/extensions/XKB.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xkblib_INCLUDE_PATH X11/XKBlib.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xkbfile_INCLUDE_PATH X11/extensions/XKBfile.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xmu_INCLUDE_PATH X11/Xmu/Xmu.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xpm_INCLUDE_PATH X11/xpm.h ${X11_INC_SEARCH_PATH}) +find_path(X11_XTest_INCLUDE_PATH X11/extensions/XTest.h ${X11_INC_SEARCH_PATH}) +find_path(X11_XShm_INCLUDE_PATH X11/extensions/XShm.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xrandr_INCLUDE_PATH X11/extensions/Xrandr.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xrender_INCLUDE_PATH X11/extensions/Xrender.h ${X11_INC_SEARCH_PATH}) +find_path(X11_XRes_INCLUDE_PATH X11/extensions/XRes.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xscreensaver_INCLUDE_PATH X11/extensions/scrnsaver.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xshape_INCLUDE_PATH X11/extensions/shape.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xutil_INCLUDE_PATH X11/Xutil.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xt_INCLUDE_PATH X11/Intrinsic.h ${X11_INC_SEARCH_PATH}) +find_path(X11_Xv_INCLUDE_PATH X11/extensions/Xvlib.h ${X11_INC_SEARCH_PATH}) +find_path(X11_XSync_INCLUDE_PATH X11/extensions/sync.h ${X11_INC_SEARCH_PATH}) + + +find_library(X11_X11_LIB X11 ${X11_LIB_SEARCH_PATH}) + +# Find additional X libraries. Keep list sorted by library name. +find_library(X11_ICE_LIB ICE ${X11_LIB_SEARCH_PATH}) +find_library(X11_SM_LIB SM ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xau_LIB Xau ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xcomposite_LIB Xcomposite ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xcursor_LIB Xcursor ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xdamage_LIB Xdamage ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xdmcp_LIB Xdmcp ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xext_LIB Xext ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xfixes_LIB Xfixes ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xft_LIB Xft ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xi_LIB Xi ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xinerama_LIB Xinerama ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xinput_LIB Xi ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xkbfile_LIB xkbfile ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xmu_LIB Xmu ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xpm_LIB Xpm ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xrandr_LIB Xrandr ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xrender_LIB Xrender ${X11_LIB_SEARCH_PATH}) +find_library(X11_XRes_LIB XRes ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xscreensaver_LIB Xss ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xt_LIB Xt ${X11_LIB_SEARCH_PATH}) +find_library(X11_XTest_LIB Xtst ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xv_LIB Xv ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xxf86misc_LIB Xxf86misc ${X11_LIB_SEARCH_PATH}) +find_library(X11_Xxf86vm_LIB Xxf86vm ${X11_LIB_SEARCH_PATH}) + +set(X11_LIBRARY_DIR "") +if(X11_X11_LIB) + get_filename_component(X11_LIBRARY_DIR ${X11_X11_LIB} PATH) +endif() + +set(X11_INCLUDE_DIR) # start with empty list +if(X11_X11_INCLUDE_PATH) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_X11_INCLUDE_PATH}) +endif() + +if(X11_Xlib_INCLUDE_PATH) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xlib_INCLUDE_PATH}) +endif() + +if(X11_Xutil_INCLUDE_PATH) + set(X11_Xutil_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xutil_INCLUDE_PATH}) +endif() + +if(X11_Xshape_INCLUDE_PATH) + set(X11_Xshape_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xshape_INCLUDE_PATH}) +endif() + +set(X11_LIBRARIES) # start with empty list +if(X11_X11_LIB) + set(X11_LIBRARIES ${X11_LIBRARIES} ${X11_X11_LIB}) +endif() + +if(X11_Xext_LIB) + set(X11_Xext_FOUND TRUE) + set(X11_LIBRARIES ${X11_LIBRARIES} ${X11_Xext_LIB}) +endif() + +if(X11_Xt_LIB AND X11_Xt_INCLUDE_PATH) + set(X11_Xt_FOUND TRUE) +endif() + +if(X11_Xft_LIB AND X11_Xft_INCLUDE_PATH) + set(X11_Xft_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xft_INCLUDE_PATH}) +endif() + +if(X11_Xv_LIB AND X11_Xv_INCLUDE_PATH) + set(X11_Xv_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xv_INCLUDE_PATH}) +endif() + +if (X11_Xau_LIB AND X11_Xau_INCLUDE_PATH) + set(X11_Xau_FOUND TRUE) +endif () + +if (X11_Xdmcp_INCLUDE_PATH AND X11_Xdmcp_LIB) + set(X11_Xdmcp_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xdmcp_INCLUDE_PATH}) +endif () + +if (X11_Xaccessrules_INCLUDE_PATH AND X11_Xaccessstr_INCLUDE_PATH) + set(X11_Xaccess_FOUND TRUE) + set(X11_Xaccess_INCLUDE_PATH ${X11_Xaccessstr_INCLUDE_PATH}) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xaccess_INCLUDE_PATH}) +endif () + +if (X11_Xpm_INCLUDE_PATH AND X11_Xpm_LIB) + set(X11_Xpm_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xpm_INCLUDE_PATH}) +endif () + +if (X11_Xcomposite_INCLUDE_PATH AND X11_Xcomposite_LIB) + set(X11_Xcomposite_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xcomposite_INCLUDE_PATH}) +endif () + +if (X11_Xdamage_INCLUDE_PATH AND X11_Xdamage_LIB) + set(X11_Xdamage_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xdamage_INCLUDE_PATH}) +endif () + +if (X11_XShm_INCLUDE_PATH) + set(X11_XShm_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_XShm_INCLUDE_PATH}) +endif () + +if (X11_XTest_INCLUDE_PATH AND X11_XTest_LIB) + set(X11_XTest_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_XTest_INCLUDE_PATH}) +endif () + +if (X11_Xi_INCLUDE_PATH AND X11_Xi_LIB) + set(X11_Xi_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xi_INCLUDE_PATH}) +endif () + +if (X11_Xinerama_INCLUDE_PATH AND X11_Xinerama_LIB) + set(X11_Xinerama_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xinerama_INCLUDE_PATH}) +endif () + +if (X11_Xfixes_INCLUDE_PATH AND X11_Xfixes_LIB) + set(X11_Xfixes_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xfixes_INCLUDE_PATH}) +endif () + +if (X11_Xrender_INCLUDE_PATH AND X11_Xrender_LIB) + set(X11_Xrender_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xrender_INCLUDE_PATH}) +endif () + +if (X11_XRes_INCLUDE_PATH AND X11_XRes_LIB) + set(X11_XRes_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_XRes_INCLUDE_PATH}) +endif () + +if (X11_Xrandr_INCLUDE_PATH AND X11_Xrandr_LIB) + set(X11_Xrandr_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xrandr_INCLUDE_PATH}) +endif () + +if (X11_xf86misc_INCLUDE_PATH AND X11_Xxf86misc_LIB) + set(X11_xf86misc_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_xf86misc_INCLUDE_PATH}) +endif () + +if (X11_xf86vmode_INCLUDE_PATH AND X11_Xxf86vm_LIB) + set(X11_xf86vmode_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_xf86vmode_INCLUDE_PATH}) +endif () + +if (X11_Xcursor_INCLUDE_PATH AND X11_Xcursor_LIB) + set(X11_Xcursor_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xcursor_INCLUDE_PATH}) +endif () + +if (X11_Xscreensaver_INCLUDE_PATH AND X11_Xscreensaver_LIB) + set(X11_Xscreensaver_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xscreensaver_INCLUDE_PATH}) +endif () + +if (X11_dpms_INCLUDE_PATH) + set(X11_dpms_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_dpms_INCLUDE_PATH}) +endif () + +if (X11_Xkb_INCLUDE_PATH AND X11_Xkblib_INCLUDE_PATH AND X11_Xlib_INCLUDE_PATH) + set(X11_Xkb_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xkb_INCLUDE_PATH} ) +endif () + +if (X11_Xkbfile_INCLUDE_PATH AND X11_Xkbfile_LIB AND X11_Xlib_INCLUDE_PATH) + set(X11_Xkbfile_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xkbfile_INCLUDE_PATH} ) +endif () + +if (X11_Xmu_INCLUDE_PATH AND X11_Xmu_LIB) + set(X11_Xmu_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xmu_INCLUDE_PATH}) +endif () + +if (X11_Xinput_INCLUDE_PATH AND X11_Xinput_LIB) + set(X11_Xinput_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_Xinput_INCLUDE_PATH}) +endif () + +if (X11_XSync_INCLUDE_PATH) + set(X11_XSync_FOUND TRUE) + set(X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${X11_XSync_INCLUDE_PATH}) +endif () + +if(X11_ICE_LIB AND X11_ICE_INCLUDE_PATH) + set(X11_ICE_FOUND TRUE) +endif() + +if(X11_SM_LIB AND X11_SM_INCLUDE_PATH) + set(X11_SM_FOUND TRUE) +endif() + +# Most of the X11 headers will be in the same directories, avoid +# creating a huge list of duplicates. +if (X11_INCLUDE_DIR) + list(REMOVE_DUPLICATES X11_INCLUDE_DIR) +endif () + +# Deprecated variable for backwards compatibility with CMake 1.4 +if (X11_X11_INCLUDE_PATH AND X11_LIBRARIES) + set(X11_FOUND 1) +endif () + +if(X11_FOUND) + include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake) + + # Translated from an autoconf-generated configure script. + # See libs.m4 in autoconf's m4 directory. + if($ENV{ISC} MATCHES "^yes$") + set(X11_X_EXTRA_LIBS -lnsl_s -linet) + else() + set(X11_X_EXTRA_LIBS "") + + # See if XOpenDisplay in X11 works by itself. + CHECK_LIBRARY_EXISTS("${X11_LIBRARIES}" "XOpenDisplay" "${X11_LIBRARY_DIR}" X11_LIB_X11_SOLO) + if(NOT X11_LIB_X11_SOLO) + # Find library needed for dnet_ntoa. + CHECK_LIBRARY_EXISTS("dnet" "dnet_ntoa" "" X11_LIB_DNET_HAS_DNET_NTOA) + if (X11_LIB_DNET_HAS_DNET_NTOA) + set (X11_X_EXTRA_LIBS ${X11_X_EXTRA_LIBS} -ldnet) + else () + CHECK_LIBRARY_EXISTS("dnet_stub" "dnet_ntoa" "" X11_LIB_DNET_STUB_HAS_DNET_NTOA) + if (X11_LIB_DNET_STUB_HAS_DNET_NTOA) + set (X11_X_EXTRA_LIBS ${X11_X_EXTRA_LIBS} -ldnet_stub) + endif () + endif () + endif() + + # Find library needed for gethostbyname. + CHECK_FUNCTION_EXISTS("gethostbyname" CMAKE_HAVE_GETHOSTBYNAME) + if(NOT CMAKE_HAVE_GETHOSTBYNAME) + CHECK_LIBRARY_EXISTS("nsl" "gethostbyname" "" CMAKE_LIB_NSL_HAS_GETHOSTBYNAME) + if (CMAKE_LIB_NSL_HAS_GETHOSTBYNAME) + set (X11_X_EXTRA_LIBS ${X11_X_EXTRA_LIBS} -lnsl) + else () + CHECK_LIBRARY_EXISTS("bsd" "gethostbyname" "" CMAKE_LIB_BSD_HAS_GETHOSTBYNAME) + if (CMAKE_LIB_BSD_HAS_GETHOSTBYNAME) + set (X11_X_EXTRA_LIBS ${X11_X_EXTRA_LIBS} -lbsd) + endif () + endif () + endif() + + # Find library needed for connect. + CHECK_FUNCTION_EXISTS("connect" CMAKE_HAVE_CONNECT) + if(NOT CMAKE_HAVE_CONNECT) + CHECK_LIBRARY_EXISTS("socket" "connect" "" CMAKE_LIB_SOCKET_HAS_CONNECT) + if (CMAKE_LIB_SOCKET_HAS_CONNECT) + set (X11_X_EXTRA_LIBS -lsocket ${X11_X_EXTRA_LIBS}) + endif () + endif() + + # Find library needed for remove. + CHECK_FUNCTION_EXISTS("remove" CMAKE_HAVE_REMOVE) + if(NOT CMAKE_HAVE_REMOVE) + CHECK_LIBRARY_EXISTS("posix" "remove" "" CMAKE_LIB_POSIX_HAS_REMOVE) + if (CMAKE_LIB_POSIX_HAS_REMOVE) + set (X11_X_EXTRA_LIBS ${X11_X_EXTRA_LIBS} -lposix) + endif () + endif() + + # Find library needed for shmat. + CHECK_FUNCTION_EXISTS("shmat" CMAKE_HAVE_SHMAT) + if(NOT CMAKE_HAVE_SHMAT) + CHECK_LIBRARY_EXISTS("ipc" "shmat" "" CMAKE_LIB_IPS_HAS_SHMAT) + if (CMAKE_LIB_IPS_HAS_SHMAT) + set (X11_X_EXTRA_LIBS ${X11_X_EXTRA_LIBS} -lipc) + endif () + endif() + endif() + + if (X11_ICE_FOUND) + CHECK_LIBRARY_EXISTS("ICE" "IceConnectionNumber" "${X11_LIBRARY_DIR}" + CMAKE_LIB_ICE_HAS_ICECONNECTIONNUMBER) + if(CMAKE_LIB_ICE_HAS_ICECONNECTIONNUMBER) + set (X11_X_PRE_LIBS ${X11_ICE_LIB}) + if(X11_SM_LIB) + set (X11_X_PRE_LIBS ${X11_SM_LIB} ${X11_X_PRE_LIBS}) + endif() + endif() + endif () + + # Build the final list of libraries. + set(X11_LIBRARIES ${X11_X_PRE_LIBS} ${X11_LIBRARIES} ${X11_X_EXTRA_LIBS}) + + if(NOT TARGET X11::X11) + add_library(X11::X11 INTERFACE IMPORTED) + set_property(TARGET X11::X11 PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${X11_INCLUDE_DIR}) + set_property(TARGET X11::X11 PROPERTY + INTERFACE_LINK_LIBRARIES ${X11_LIBRARIES}) + endif() + + include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) + FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}" + "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") +endif () + +mark_as_advanced( + X11_X11_INCLUDE_PATH + X11_X11_LIB + X11_Xext_LIB + X11_Xau_LIB + X11_Xau_INCLUDE_PATH + X11_Xlib_INCLUDE_PATH + X11_Xutil_INCLUDE_PATH + X11_Xcomposite_INCLUDE_PATH + X11_Xcomposite_LIB + X11_Xaccess_INCLUDE_PATH + X11_Xfixes_LIB + X11_Xfixes_INCLUDE_PATH + X11_Xrandr_LIB + X11_Xrandr_INCLUDE_PATH + X11_Xdamage_LIB + X11_Xdamage_INCLUDE_PATH + X11_Xrender_LIB + X11_Xrender_INCLUDE_PATH + X11_XRes_LIB + X11_XRes_INCLUDE_PATH + X11_Xxf86misc_LIB + X11_xf86misc_INCLUDE_PATH + X11_Xxf86vm_LIB + X11_xf86vmode_INCLUDE_PATH + X11_Xi_LIB + X11_Xi_INCLUDE_PATH + X11_Xinerama_LIB + X11_Xinerama_INCLUDE_PATH + X11_XTest_LIB + X11_XTest_INCLUDE_PATH + X11_Xcursor_LIB + X11_Xcursor_INCLUDE_PATH + X11_dpms_INCLUDE_PATH + X11_Xt_LIB + X11_Xt_INCLUDE_PATH + X11_Xdmcp_LIB + X11_LIBRARIES + X11_Xaccessrules_INCLUDE_PATH + X11_Xaccessstr_INCLUDE_PATH + X11_Xdmcp_INCLUDE_PATH + X11_Xkb_INCLUDE_PATH + X11_Xkblib_INCLUDE_PATH + X11_Xkbfile_INCLUDE_PATH + X11_Xkbfile_LIB + X11_Xmu_INCLUDE_PATH + X11_Xmu_LIB + X11_Xscreensaver_INCLUDE_PATH + X11_Xscreensaver_LIB + X11_Xpm_INCLUDE_PATH + X11_Xpm_LIB + X11_Xinput_LIB + X11_Xinput_INCLUDE_PATH + X11_Xft_LIB + X11_Xft_INCLUDE_PATH + X11_Xshape_INCLUDE_PATH + X11_Xv_LIB + X11_Xv_INCLUDE_PATH + X11_XShm_INCLUDE_PATH + X11_ICE_LIB + X11_ICE_INCLUDE_PATH + X11_SM_LIB + X11_SM_INCLUDE_PATH + X11_XSync_INCLUDE_PATH) + +set(CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK_SAVE}) +set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) + +if( NOT X11_FOUND ) + if (X11_FIND_REQUIRED) + message(FATAL_ERROR "Could not find X11") + else () + message(STATUS "Could not find X11") + endif () +endif () diff --git a/CMakeDependentCacheVar.cmake b/CMakeDependentCacheVar.cmake new file mode 100644 index 0000000..47d0a2a --- /dev/null +++ b/CMakeDependentCacheVar.cmake @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "CMakeDependentCacheVar" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "CMakeDependentCacheVar") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +function(CMAKE_DEPENDENT_CACHE_VAR variable type docstring default conditions force) + set(type_list FILEPATH PATH STRING BOOL INTERNAL) + list(FIND type_list ${type} type_found) + if( type_found LESS 0 ) + message("CMAKE_DEPENDENT_CACHE_VAR error: variable type") + message(FATAL_ERROR + "'${type}' must be one of FILEPATH, PATH, STRING, BOOL, or INTERNAL") + endif() + + set(${variable}_AVAILABLE TRUE) + foreach(condition ${conditions}) + string(REGEX REPLACE " +" ";" + CMAKE_DEPENDENT_VARIABLE_DEP "${condition}") + if(${CMAKE_DEPENDENT_VARIABLE_DEP}) + else() + set(${variable}_AVAILABLE FALSE) + endif() + endforeach() + + if(${variable}_AVAILABLE) + set(${variable} "${default}" CACHE "${type}" "${docstring}") + set(${variable} "${${variable}}" CACHE "${type}" "${docstring}" FORCE) + else() + if(DEFINED ${variable}) + set(${variable} "${${variable}}" CACHE INTERNAL "${docstring}") + endif() + set(${variable} "${force}" PARENT_SCOPE) + endif() +endfunction() diff --git a/CMakeDependentSelection.cmake b/CMakeDependentSelection.cmake new file mode 100644 index 0000000..4a92757 --- /dev/null +++ b/CMakeDependentSelection.cmake @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "CMakeDependentSelection" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "CMakeDependentSelection") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include(Selection) + +include_guard(GLOBAL) +function(CMAKE_DEPENDENT_SELECTION variable docstring) + cmake_parse_arguments(${variable}_selection + "" "DEFAULT;CONDITION" OPTIONS ${ARGN}) + + if(NOT DEFINED ${variable}_selection_OPTIONS) + message(FATAL_ERROR + "CMAKE_DEPENDENT_SELECTION invoked without 'OPTIONS' keyword") + endif() + + if(NOT DEFINED ${variable}_selection_CONDITION) + message(FATAL_ERROR + "CMAKE_DEPENDENT_SELECTION invoked without 'CONDITION' keyword") + endif() + + if(NOT DEFINED ${variable}_selection_UNPARSED_ARGUMENTS) + message(FATAL_ERROR + "CMAKE_DEPENDENT_SELECTION invoked without fallback value") + else() + list(GET ${variable}_selection_UNPARSED_ARGUMENTS "0" + ${variable}_selection_fallback) + list(REMOVE_AT ${variable}_selection_UNPARSED_ARGUMENTS "0") + if(${variable}_selection_UNPARSED_ARGUMENTS) + message("CMAKE_DEPENDENT_SELECTION called with unparsed arguments") + message(FATAL_ERROR "unparsed arguments: ${${variable}_selection_UNPARSED_ARGUMENTS}") + endif() + endif() + + set(${variable}_selection_AVAILABLE TRUE) + foreach(condition ${${variable}_selection_CONDITION}) + string(REGEX REPLACE " +" ";" condition "${condition}") + if(${condition}) + else() + set(${variable}_selection_AVAILABLE FALSE) + endif() + endforeach() + + if(${variable}_selection_AVAILABLE) + if(DEFINED ${variable}_selection_DEFAULT) + selection(${variable} + DOCSTRING "${docstring}" + DEFAULT "${${variable}_selection_DEFAULT}" + OPTIONS "${${variable}_selection_OPTIONS}") + else() + selection(${variable} + DOCSTRING "${docstring}" + OPTIONS "${${variable}_selection_OPTIONS}") + endif() + set(${variable} "${${variable}}" CACHE STRING "${docstring}" FORCE) + else() + if(DEFINED ${variable}) + set(${variable} "${${variable}}" CACHE INTERNAL "${docstring}") + endif() + set(${variable} "${${variable}_selection_fallback}" PARENT_SCOPE) + endif() +endfunction() diff --git a/DelegatingCacheVariable.cmake b/DelegatingCacheVariable.cmake new file mode 100644 index 0000000..c289219 --- /dev/null +++ b/DelegatingCacheVariable.cmake @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "DelegatingCacheVariable" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "DelegatingCacheVariable") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +function(delegating_cache_variable variable) + set(OPTIONS) + set(UNARY_ARGUMENTS TYPE DEFAULT DOCSTRING) + set(VARIADIC_ARGUMENTS) + + set(arguments) + foreach(argument IN LISTS ARGN) + if(argument STREQUAL "" # argument empty string + OR argument MATCHES ".*[ ].*" # argument with embedded whitespace + OR argument MATCHES ".*[;].*" # argument list + OR argument MATCHES ".*\".*") # argument with embedded quotation + list(APPEND arguments "\"${argument}\"") + else() + list(APPEND arguments "${argument}") + endif() + endforeach() + + cmake_parse_arguments(dcv + "${OPTIONS}" + "${UNARY_ARGUMENTS}" + "${VARIADIC_ARGUMENTS}" ${arguments}) + + if(NOT DEFINED dcv_DEFAULT) + message(FATAL_ERROR + "delegating_cache_variable invoked without 'DEFAULT' argument") + endif() + + if(NOT DEFINED dcv_TYPE) + message(FATAL_ERROR + "delegating_cache_variable invoked without 'TYPE' argument") + endif() + + set(valid_types FILEPATH PATH STRING BOOL INTERNAL) + if(NOT dcv_TYPE IN_LIST valid_types) + message("delegating_cache_variable error") + message("TYPE argument value: ${dcv_TYPE}") + message(FATAL_ERROR + "TYPE argument must be one of FILEPATH, PATH, STRING, BOOL, or INTERNAL") + endif() + + if(dcv_DOCSTRING) + string(CONCAT docstring + "${dcv_DOCSTRING}\n" + "When set to 'default', this variable assumes the value of ${dcv_DEFAULT} ('${${dcv_DEFAULT}}')") + else() + string(CONCAT docstring + "When set to 'default', this variable assumes the value of ${dcv_DEFAULT} ('${${dcv_DEFAULT}}')") + endif() + + set(${variable} "default" CACHE ${dcv_TYPE} "${docstring}") + + if(${variable} STREQUAL "default") + set(${variable} "${${dcv_DEFAULT}}" PARENT_SCOPE) + endif() +endfunction() diff --git a/DelegatingOption.cmake b/DelegatingOption.cmake new file mode 100644 index 0000000..59bffbc --- /dev/null +++ b/DelegatingOption.cmake @@ -0,0 +1,72 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") + +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "DelegatingOption" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "DelegatingOption") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +function(delegating_option variable) + set(OPTIONS) + set(UNARY_ARGUMENTS DEFAULT DOCSTRING) + set(VARIADIC_ARGUMENTS) + + set(arguments) + foreach(argument IN LISTS ARGN) + if(argument STREQUAL "" # argument empty string + OR argument MATCHES ".*[ ].*" # argument with embedded whitespace + OR argument MATCHES ".*[;].*" # argument list + OR argument MATCHES ".*\".*") # argument with embedded quotation + list(APPEND arguments "\"${argument}\"") + else() + list(APPEND arguments "${argument}") + endif() + endforeach() + + cmake_parse_arguments(do + "${OPTIONS}" + "${UNARY_ARGUMENTS}" + "${VARIADIC_ARGUMENTS}" ${arguments}) + + if(NOT DEFINED do_DEFAULT) + message(FATAL_ERROR + "delegating_option invoked without 'DEFAULT' argument") + endif() + + if(do_DOCSTRING) + if(do_DOCSTRING MATCHES "\"(.*)\"") + set(do_DOCSTRING "${CMAKE_MATCH_1}") + endif() + string(CONCAT docstring + "${do_DOCSTRING}\n" + "When set to 'default', this variable assumes the value of ${do_DEFAULT} (${${do_DEFAULT}})") + else() + string(CONCAT docstring + "When set to 'default', this variable assumes the value of ${do_DEFAULT} (${${do_DEFAULT}})") + endif() + + set(${variable} "default" CACHE STRING "${docstring}") + set_property(CACHE ${variable} PROPERTY HELPSTRING "${docstring}") + set_property(CACHE ${variable} PROPERTY STRINGS default ON OFF) + if(${variable} STREQUAL "default") + if(${do_DEFAULT}) + set(${variable} ON PARENT_SCOPE) + else() + set(${variable} OFF PARENT_SCOPE) + endif() + endif() +endfunction() diff --git a/DelegatingSelection.cmake b/DelegatingSelection.cmake new file mode 100644 index 0000000..9bb86da --- /dev/null +++ b/DelegatingSelection.cmake @@ -0,0 +1,97 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "DelegatingSelection" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "DelegatingSelection") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +function(delegating_selection variable) + set(OPTIONS) + set(UNARY_ARGUMENTS DEFAULT DOCSTRING) + set(VARIADIC_ARGUMENTS OPTIONS) + + set(arguments) + foreach(argument IN LISTS ARGN) + if(argument MATCHES ".*[ ].*" + OR argument MATCHES ".*[;].*" # argument list + OR argument MATCHES "\".*\"") # quoted argument + list(APPEND arguments "\"${argument}\"") + elseif(argument STREQUAL "") + list(APPEND arguments "\"\"") + else() + list(APPEND arguments "${argument}") + endif() + endforeach() + + cmake_parse_arguments(ds + "${OPTIONS}" + "${UNARY_ARGUMENTS}" + "${VARIADIC_ARGUMENTS}" ${arguments}) + + if(NOT DEFINED ds_DEFAULT) + message(FATAL_ERROR + "delegating_selection invoked without 'DEFAULT' argument") + endif() + + if(NOT DEFINED ds_OPTIONS) + message(FATAL_ERROR "selection invoked without 'OPTIONS' keyword") + endif() + + set(options "default") + foreach(option IN LISTS ds_OPTIONS) + if(option MATCHES "\"(.*)\"") + set(option "${CMAKE_MATCH_1}") + endif() + + list(APPEND options "${option}") + endforeach() + + if(ds_DOCSTRING) + if(ds_DOCSTRING MATCHES "\"(.*)\"") + set(ds_DOCSTRING "${CMAKE_MATCH_1}") + endif() + string(CONCAT docstring + "${ds_DOCSTRING}\n" + "When set to 'default', this variable assumes the value of ${ds_DEFAULT} ('${${ds_DEFAULT}}')") + else() + string(CONCAT docstring + "When set to 'default', this variable assumes the value of ${ds_DEFAULT} ('${${ds_DEFAULT}}')") + endif() + + if(NOT DEFINED ds_OPTIONS) + message(FATAL_ERROR "selection invoked without 'OPTIONS' keyword") + endif() + + set(${variable} "default" CACHE STRING "${docstring}") + set_property(CACHE ${variable} PROPERTY STRINGS "${options}") + set_property(CACHE ${variable} PROPERTY HELPSTRING "${docstring}") + + if(${variable} STREQUAL "default") + set(${variable} "${${ds_DEFAULT}}") + endif() + + if(NOT ${variable} IN_LIST options) + message("${variable} set to ${${variable}}") + set(error_message "${variable} must be one of:") + foreach(option_string IN LISTS options) + string(CONCAT error_message "${error_message}\n" " ${option_string}") + endforeach() + message(FATAL_ERROR "${error_message}") + endif() + + set(${variable} "${${variable}}" PARENT_SCOPE) +endfunction() diff --git a/DependencyInjection.cmake b/DependencyInjection.cmake new file mode 100644 index 0000000..4c9b4cd --- /dev/null +++ b/DependencyInjection.cmake @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "DependencyInjection" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "DependencyInjection") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/DependencyInjection" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include(FunctionExtension) + +include_guard(GLOBAL) +include(DependencyInjection/add_executable) +include(DependencyInjection/add_library) diff --git a/DependencyInjection/add_executable.cmake b/DependencyInjection/add_executable.cmake new file mode 100644 index 0000000..d2d34d5 --- /dev/null +++ b/DependencyInjection/add_executable.cmake @@ -0,0 +1,14 @@ +backup(add_executable) + +macro(add_executable target_) + push(scl.DependencyInjection.target) + set(scl.DependencyInjection.target ${target_}) + + previous_add_executable(${target_} "${ARGN}") + + foreach(inc IN LISTS ${scl.DependencyInjection.target}.injections) + include(${inc}) + endforeach() + + pop(scl.DependencyInjection.target) +endmacro() diff --git a/DependencyInjection/add_library.cmake b/DependencyInjection/add_library.cmake new file mode 100644 index 0000000..841fe35 --- /dev/null +++ b/DependencyInjection/add_library.cmake @@ -0,0 +1,14 @@ +backup(add_library) + +macro(add_library target_) + push(scl.DependencyInjection.target) + set(scl.DependencyInjection.target ${target_}) + + previous_add_library(${target_} "${ARGN}") + + foreach(inc IN LISTS ${scl.DependencyInjection.target}.injections) + include(${inc}) + endforeach() + + pop(scl.DependencyInjection.target) +endmacro() diff --git a/DependentDelegatingCacheVariable.cmake b/DependentDelegatingCacheVariable.cmake new file mode 100644 index 0000000..b50a947 --- /dev/null +++ b/DependentDelegatingCacheVariable.cmake @@ -0,0 +1,117 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "DependentDelegatingCacheVariable" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "DependentDelegatingCacheVariable") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +function(dependent_delegating_cache_variable variable) + set(OPTIONS) + set(UNARY_ARGUMENTS DEFAULT TYPE DOCSTRING) + set(VARIADIC_ARGUMENTS CONDITION FALLBACK) + + set(arguments) + foreach(argument IN LISTS ARGN) + if(argument STREQUAL "" # argument empty string + OR argument MATCHES ".*[ ].*" # argument with embedded whitespace + OR argument MATCHES ".*[;].*" # argument list + OR argument MATCHES ".*\".*") # argument with embedded quotation + list(APPEND arguments "\"${argument}\"") + else() + list(APPEND arguments "${argument}") + endif() + endforeach() + + cmake_parse_arguments(ddcv + "${OPTIONS}" + "${UNARY_ARGUMENTS}" + "${VARIADIC_ARGUMENTS}" ${arguments}) + + if(NOT DEFINED ddcv_DEFAULT) + message(FATAL_ERROR + "dependent_delegating_cache_variable invoked without 'DEFAULT' argument") + endif() + + if(NOT DEFINED ddcv_TYPE) + message(FATAL_ERROR + "dependent_delegating_cache_variable invoked without 'TYPE' argument") + endif() + + set(valid_types FILEPATH PATH STRING BOOL INTERNAL) + if(NOT ddcv_TYPE IN_LIST valid_types) + message("dependent_delegating_cache_variable error") + message("TYPE argument value: ${ddcv_TYPE}") + message(FATAL_ERROR + "TYPE argument must be one of FILEPATH, PATH, STRING, BOOL, or INTERNAL") + endif() + + if(ddcv_DOCSTRING) + string(CONCAT docstring + "${ddcv_DOCSTRING}\n" + "When set to 'default', ${variable} assumes the value of ${ddcv_DEFAULT}") + else() + string(CONCAT docstring + "When set to 'default', ${variable} assumes the value of ${ddcv_DEFAULT}") + endif() + + if(NOT DEFINED ddcv_CONDITION) + message(FATAL_ERROR + "dependent_delegating_cache_variable invoked without 'CONDITION' argument") + endif() + + if(NOT DEFINED ddcv_FALLBACK) + message(FATAL_ERROR + "dependent_delegating_cache_variable invoked without 'FALLBACK' argument") + endif() + + if(DEFINED ddcv_UNPARSED_ARGUMENTS) + message(FATAL_ERROR + "dependent_delegating_cache_variable invoked with unrecognized arguments: ${dcv_UNPARSED_ARGUMENTS}") + endif() + + set(available TRUE) + foreach(condition IN LISTS ddcv_CONDITION) + if(condition MATCHES "\"(.*)\"") + set(condition "${CMAKE_MATCH_1}") + endif() + string(REGEX REPLACE " +" ";" condition "${condition}") + if(${condition}) + else() + set(available FALSE) + break() + endif() + endforeach() + + get_property(variable.set GLOBAL PROPERTY "${variable}.set" SET) + + if(${available}) + if(NOT variable.set) + set(${variable} "default" CACHE "${ddcv_TYPE}" "${docstring}") + set(${variable} "${${variable}}" CACHE "${ddcv_TYPE}" "${docstring}" FORCE) + endif() + if(${variable} STREQUAL "default") + set(${variable} "${${ddcv_DEFAULT}}" PARENT_SCOPE) + endif() + else() + if(DEFINED ${variable}) + set(${variable} "${${variable}}" CACHE INTERNAL "${docstring}") + else(NOT variable.set) + set(${variable} "default" CACHE INTERNAL "${docstring}") + endif() + set(${variable} "${ddcv_FALLBACK}" PARENT_SCOPE) + endif() +endfunction() diff --git a/DependentDelegatingOption.cmake b/DependentDelegatingOption.cmake new file mode 100644 index 0000000..6f85235 --- /dev/null +++ b/DependentDelegatingOption.cmake @@ -0,0 +1,115 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "DependentDelegatingOption" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "DependentDelegatingOption") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +function(dependent_delegating_option variable) + set(OPTIONS) + set(UNARY_ARGUMENTS DEFAULT DOCSTRING FALLBACK) + set(VARIADIC_ARGUMENTS CONDITION) + + set(arguments) + foreach(argument IN LISTS ARGN) + if(argument STREQUAL "" # argument empty string + OR argument MATCHES ".*[ ].*" # argument with embedded whitespace + OR argument MATCHES ".*[;].*" # argument list + OR argument MATCHES ".*\".*") # argument with embedded quotation + list(APPEND arguments "\"${argument}\"") + else() + list(APPEND arguments "${argument}") + endif() + endforeach() + + cmake_parse_arguments(ddo + "${OPTIONS}" + "${UNARY_ARGUMENTS}" + "${VARIADIC_ARGUMENTS}" ${arguments}) + + if(NOT DEFINED ddo_DEFAULT) + message(FATAL_ERROR + "dependent_delegating_option invoked without 'DEFAULT' argument") + endif() + if(ddo_DEFAULT MATCHES "\"(.*)\"") + set(ddo_DEFAULT "${CMAKE_MATCH_1}") + endif() + + if(ddo_DOCSTRING) + if(ddo_DOCSTRING MATCHES "\"(.*)\"") + set(ddo_DOCSTRING "${CMAKE_MATCH_1}") + endif() + string(CONCAT docstring + "${ddo_DOCSTRING}\n" + "When set to 'default', ${variable} assumes the value of ${ddo_DEFAULT}") + else() + string(CONCAT docstring + "When set to 'default', ${variable} assumes the value of ${ddo_DEFAULT}") + endif() + + if(NOT DEFINED ddo_CONDITION) + message(FATAL_ERROR + "dependent_delegating_option invoked without 'CONDITION' argument") + endif() + + if(NOT DEFINED ddo_FALLBACK) + message(FATAL_ERROR + "dependent_delegating_option invoked without 'FALLBACK' argument") + endif() + if(ddo_FALLBACK MATCHES "\"(.*)\"") + set(ddo_FALLBACK "${CMAKE_MATCH_1}") + endif() + + set(available TRUE) + foreach(condition IN LISTS ddo_CONDITION) + if(condition MATCHES "\"(.*)\"") + set(condition "${CMAKE_MATCH_1}") + endif() + string(REGEX REPLACE " +" ";" condition "${condition}") + if(${condition}) + else() + set(available FALSE) + break() + endif() + endforeach() + + get_property(variable.set GLOBAL PROPERTY "${variable}.set" SET) + + if(available) + if(NOT variable.set) + set(${variable} "default" CACHE STRING "${docstring}") + set(${variable} "${${variable}}" CACHE STRING "${docstring}" FORCE) + set_property(CACHE ${variable} PROPERTY STRINGS default ON OFF) + endif() + if(${variable} STREQUAL "default") + if(${ddo_DEFAULT}) + set(${variable} ON PARENT_SCOPE) + else() + set(${variable} OFF PARENT_SCOPE) + endif() + endif() + else() + if(DEFINED ${variable}) + set(${variable} "${${variable}}" CACHE INTERNAL "${docstring}") + else(NOT variable.set) + set(${variable} "default" CACHE INTERNAL "${docstring}") + endif() + set(${variable} "${ddo_FALLBACK}" PARENT_SCOPE) + endif() + + set_property(GLOBAL PROPERTY "${variable}.set" "") +endfunction() diff --git a/DependentDelegatingSelection.cmake b/DependentDelegatingSelection.cmake new file mode 100644 index 0000000..f935b85 --- /dev/null +++ b/DependentDelegatingSelection.cmake @@ -0,0 +1,119 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "DependentDelegatingSelection" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "DependentDelegatingSelection") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +function(dependent_delegating_selection variable) + set(OPTIONS) + set(UNARY_ARGUMENTS DEFAULT DOCSTRING) + set(VARIADIC_ARGUMENTS OPTIONS CONDITION FALLBACK) + + set(arguments) + foreach(argument IN LISTS ARGN) + if(argument STREQUAL "" # argument empty string + OR argument MATCHES ".*[ ].*" # argument with embedded whitespace + OR argument MATCHES ".*[;].*" # argument list + OR argument MATCHES ".*\".*") # argument with embedded quotation + list(APPEND arguments "\"${argument}\"") + else() + list(APPEND arguments "${argument}") + endif() + endforeach() + + cmake_parse_arguments(dds + "${OPTIONS}" + "${UNARY_ARGUMENTS}" + "${VARIADIC_ARGUMENTS}" ${arguments}) + + if(NOT DEFINED dds_DEFAULT) + message(FATAL_ERROR + "dependent_delegating_selection invoked without 'DEFAULT' argument") + endif() + + if(dds_DOCSTRING) + string(CONCAT docstring + "${dds_DOCSTRING}\n" + "When set to 'default', ${variable} assumes the value of ${dds_DEFAULT}") + else() + string(CONCAT docstring + "When set to 'default', ${variable} assumes the value of ${dds_DEFAULT}") + endif() + + if(NOT DEFINED dds_CONDITION) + message(FATAL_ERROR + "dependent_delegating_selection invoked without 'CONDITION' argument") + endif() + + if(NOT DEFINED dds_FALLBACK) + message(FATAL_ERROR + "dependent_delegating_selection invoked without 'FALLBACK' argument") + endif() + + if(NOT DEFINED dds_OPTIONS) + message(FATAL_ERROR "dependent_delegating_selection invoked without 'OPTIONS' keyword") + endif() + + set(available TRUE) + foreach(condition IN LISTS dds_CONDITION) + if(condition MATCHES "\"(.*)\"") + set(condition "${CMAKE_MATCH_1}") + endif() + string(REGEX REPLACE " +" ";" condition "${condition}") + if(${condition}) + else() + set(available FALSE) + break() + endif() + endforeach() + + set(options "default;${dds_OPTIONS}") + + get_property(variable.set GLOBAL PROPERTY "${variable}.set" SET) + + if(${available}) + if(NOT variable.set) + set(${variable} "default" CACHE STRING "${docstring}") + set(${variable} "${${variable}}" CACHE STRING "${docstring}" FORCE) + set_property(CACHE ${variable} PROPERTY STRINGS ${options}) + endif() + if(${variable} STREQUAL "default") + set(${variable} "${${dds_DEFAULT}}") + endif() + else() + if(DEFINED ${variable}) + set(${variable} "${${variable}}" CACHE INTERNAL "${docstring}") + else(NOT variable.set) + set(${variable} "default" CACHE INTERNAL "${docstring}") + endif() + set(${variable} "${dds_FALLBACK}") + endif() + + set_property(GLOBAL PROPERTY "${variable}.set" "") + + if(NOT ${variable} IN_LIST options) + message("${variable} set to ${${variable}}") + set(error_message "${variable} must be one of:") + foreach(option_string IN LISTS options) + string(CONCAT error_message "${error_message}\n" " ${option_string}") + endforeach() + message(FATAL_ERROR "${error_message}") + endif() + + set(${variable} "${${variable}}" PARENT_SCOPE) +endfunction() diff --git a/Fortran.cmake b/Fortran.cmake new file mode 100644 index 0000000..0a4ff9e --- /dev/null +++ b/Fortran.cmake @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY shacl.cmake.installed_modules "Fortran") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + + install( + FILES "${CMAKE_CURRENT_LIST_DIR}/README.md" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include(Fortran/BackslashEscape) +include(Fortran/Backtrace) +include(Fortran/Exceptions) +include(Fortran/Integer) +include(Fortran/ModuleDirectory) +include(Fortran/Real) +include(Fortran/StackArraySizeLimit) +include(Fortran/Standard) +include(Fortran/StandardCompliance) diff --git a/Fortran/BackslashEscape.cmake b/Fortran/BackslashEscape.cmake new file mode 100644 index 0000000..703e69c --- /dev/null +++ b/Fortran/BackslashEscape.cmake @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") + +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/BackslashEscape" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/BackslashEscape") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/BackslashEscape" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +enable_language(Fortran) + +define_property(TARGET PROPERTY Fortran_BACKSLASH_ESCAPE +BRIEF_DOCS +"Allow for C-style backslash escape characters when reading and writing strings" +FULL_DOCS +"The behavior runs contrary to the Fortran Standard specification, but never the +less is a common vendor extension. This behavior defaults to OFF.") + +add_library(shacl::cmake::Fortran::BackslashEscape INTERFACE IMPORTED GLOBAL) +set_property(TARGET shacl::cmake::Fortran::BackslashEscape + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Fortran_BACKSLASH_ESCAPE) + +include(Fortran/BackslashEscape/GNU) +include(Fortran/BackslashEscape/Intel) +include(Fortran/BackslashEscape/IntelLLVM) +include(Fortran/BackslashEscape/PGI) diff --git a/Fortran/BackslashEscape/GNU.cmake b/Fortran/BackslashEscape/GNU.cmake new file mode 100644 index 0000000..2da0c1b --- /dev/null +++ b/Fortran/BackslashEscape/GNU.cmake @@ -0,0 +1,8 @@ +string(CONCAT shacl.cmake.Fortran.BackslashEscape.generator + "$<$:" + "$<$>:-fbackslash>>") + +target_compile_options(shacl::cmake::Fortran::BackslashEscape INTERFACE + ${shacl.cmake.Fortran.BackslashEscape.generator}) + +unset(shacl.cmake.Fortran.BackslashEscape.generator) diff --git a/Fortran/BackslashEscape/Intel.cmake b/Fortran/BackslashEscape/Intel.cmake new file mode 100644 index 0000000..2e94ab4 --- /dev/null +++ b/Fortran/BackslashEscape/Intel.cmake @@ -0,0 +1,14 @@ +string(CONCAT shacl.cmake.Fortran.BackslashEscape.generator + "$<$:" + "$>" + ",$" + ",/assume$<1::>bscc" + ",SHELL:-assume bscc>" + ",$" + ",/assume$<1::>nobscc" + ",SHELL:-assume nobscc>>>") + +target_compile_options(shacl::cmake::Fortran::BackslashEscape INTERFACE + ${shacl.cmake.Fortran.BackslashEscape.generator}) + +unset(shacl.cmake.Fortran.BackslashEscape.generator) diff --git a/Fortran/BackslashEscape/IntelLLVM.cmake b/Fortran/BackslashEscape/IntelLLVM.cmake new file mode 100644 index 0000000..7d834c7 --- /dev/null +++ b/Fortran/BackslashEscape/IntelLLVM.cmake @@ -0,0 +1,14 @@ +string(CONCAT shacl.cmake.Fortran.BackslashEscape.generator + "$<$:" + "$>" + ",$" + ",/assume$<1::>bscc" + ",SHELL:-assume bscc>" + ",$" + ",/assume$<1::>nobscc" + ",SHELL:-assume nobscc>>>") + +target_compile_options(shacl::cmake::Fortran::BackslashEscape INTERFACE + ${shacl.cmake.Fortran.BackslashEscape.generator}) + +unset(shacl.cmake.Fortran.BackslashEscape.generator) diff --git a/Fortran/BackslashEscape/PGI.cmake b/Fortran/BackslashEscape/PGI.cmake new file mode 100644 index 0000000..17e3dc3 --- /dev/null +++ b/Fortran/BackslashEscape/PGI.cmake @@ -0,0 +1,10 @@ +string(CONCAT shacl.cmake.Fortran.BackslashEscape.generator + "$<$:" + "$>" + ",-Mbackslash" + ",-Mnobackslash>>") + +target_compile_options(shacl::cmake::Fortran::BackslashEscape INTERFACE + ${shacl.cmake.Fortran.BackslashEscape.generator}) + +unset(shacl.cmake.Fortran.BackslashEscape.generator) diff --git a/Fortran/Backtrace.cmake b/Fortran/Backtrace.cmake new file mode 100644 index 0000000..ffbcc1b --- /dev/null +++ b/Fortran/Backtrace.cmake @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/Backtrace" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/Backtrace") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/Backtrace" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +enable_language(Fortran) + +define_property(TARGET PROPERTY Fortran_BACKTRACE +BRIEF_DOCS +"Toggle backtrace information in Fortran programs" +FULL_DOCS +"This functionality is not universally supported amongst Fortran +compilers. This property provides an interface to that functionality +if available.") + +add_library(shacl::cmake::Fortran::Backtrace INTERFACE IMPORTED GLOBAL) +set_property(TARGET shacl::cmake::Fortran::Backtrace + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL Fortran_BACKTRACE) + +include(Fortran/Backtrace/Intel) +include(Fortran/Backtrace/IntelLLVM) +include(Fortran/Backtrace/PGI) +include(Fortran/Backtrace/GNU) diff --git a/Fortran/Backtrace/GNU.cmake b/Fortran/Backtrace/GNU.cmake new file mode 100644 index 0000000..7d4b6f2 --- /dev/null +++ b/Fortran/Backtrace/GNU.cmake @@ -0,0 +1,10 @@ +string(CONCAT shacl.cmake.Fortran.Backtrace.generator + "$<$:" + "$>" + ",-fbacktrace" + ",-fno-backtrace>>") + +target_compile_options(shacl::cmake::Fortran::Backtrace INTERFACE + ${shacl.cmake.Fortran.Backtrace.generator}) + +unset(shacl.cmake.Fortran.Backtrace.generator) diff --git a/Fortran/Backtrace/Intel.cmake b/Fortran/Backtrace/Intel.cmake new file mode 100644 index 0000000..fb23801 --- /dev/null +++ b/Fortran/Backtrace/Intel.cmake @@ -0,0 +1,14 @@ +string(CONCAT shacl.cmake.Fortran.Backtrace.generator + "$<$:" + "$>" + ",$" + ",/traceback" + ",-traceback>" + ",$" + ",/notraceback" + ",-notraceback>>>") + +target_compile_options(shacl::cmake::Fortran::Backtrace INTERFACE + ${shacl.cmake.Fortran.Backtrace.generator}) + +unset(shacl.cmake.Fortran.Backtrace.generator) diff --git a/Fortran/Backtrace/IntelLLVM.cmake b/Fortran/Backtrace/IntelLLVM.cmake new file mode 100644 index 0000000..cefb689 --- /dev/null +++ b/Fortran/Backtrace/IntelLLVM.cmake @@ -0,0 +1,14 @@ +string(CONCAT shacl.cmake.Fortran.Backtrace.generator + "$<$:" + "$>" + ",$" + ",/traceback" + ",-traceback>" + ",$" + ",/notraceback" + ",-notraceback>>>") + +target_compile_options(shacl::cmake::Fortran::Backtrace INTERFACE + ${shacl.cmake.Fortran.Backtrace.generator}) + +unset(shacl.cmake.Fortran.Backtrace.generator) diff --git a/Fortran/Backtrace/PGI.cmake b/Fortran/Backtrace/PGI.cmake new file mode 100644 index 0000000..5d07bd4 --- /dev/null +++ b/Fortran/Backtrace/PGI.cmake @@ -0,0 +1,10 @@ +string(CONCAT shacl.cmake.Fortran.Backtrace.generator + "$<$:" + "$>" + ",-traceback" + ",-notraceback>>") + +target_compile_options(shacl::cmake::Fortran::Backtrace INTERFACE + ${shacl.cmake.Fortran.Backtrace.generator}) + +unset(shacl.cmake.Fortran.Backtrace.generator) diff --git a/Fortran/Exceptions.cmake b/Fortran/Exceptions.cmake new file mode 100644 index 0000000..c46c57c --- /dev/null +++ b/Fortran/Exceptions.cmake @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.13.0) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/Exceptions" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/Exceptions") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/Exceptions" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +enable_language(Fortran) + +add_library(shacl::cmake::Fortran::Exceptions INTERFACE IMPORTED GLOBAL) + +include(Fortran/Exceptions/GNU) +include(Fortran/Exceptions/Intel) +include(Fortran/Exceptions/IntelLLVM) diff --git a/Fortran/Exceptions/GNU.cmake b/Fortran/Exceptions/GNU.cmake new file mode 100644 index 0000000..16cc28d --- /dev/null +++ b/Fortran/Exceptions/GNU.cmake @@ -0,0 +1,10 @@ +string(CONCAT shacl.cmake.Fortran.Exceptions.generator + "$<$,Fortran>" + ",$" + ",$>:" + "-Wl,-keep_dwarf_unwind>") + +target_link_options(shacl::cmake::Fortran::Exceptions INTERFACE + ${shacl.cmake.Fortran.Exceptions.generator}) + +unset(shacl.cmake.Fortran.Exceptions.generator) diff --git a/Fortran/Exceptions/Intel.cmake b/Fortran/Exceptions/Intel.cmake new file mode 100644 index 0000000..6a3b70c --- /dev/null +++ b/Fortran/Exceptions/Intel.cmake @@ -0,0 +1,10 @@ +string(CONCAT shacl.cmake.Fortran.Exceptions.generator + "$<$,Fortran>" + ",$" + ",$>:" + "-Wl,-keep_dwarf_unwind>") + +target_link_options(shacl::cmake::Fortran::Exceptions INTERFACE + ${shacl.cmake.Fortran.Exceptions.generator}) + +unset(shacl.cmake.Fortran.Exceptions.generator) diff --git a/Fortran/Exceptions/IntelLLVM.cmake b/Fortran/Exceptions/IntelLLVM.cmake new file mode 100644 index 0000000..67079fe --- /dev/null +++ b/Fortran/Exceptions/IntelLLVM.cmake @@ -0,0 +1,10 @@ +string(CONCAT shacl.cmake.Fortran.Exceptions.generator + "$<$,Fortran>" + ",$" + ",$>:" + "-Wl,-keep_dwarf_unwind>") + +target_link_options(shacl::cmake::Fortran::Exceptions INTERFACE + ${shacl.cmake.Fortran.Exceptions.generator}) + +unset(shacl.cmake.Fortran.Exceptions.generator) diff --git a/Fortran/Exceptions/README.md b/Fortran/Exceptions/README.md new file mode 100644 index 0000000..5c38825 --- /dev/null +++ b/Fortran/Exceptions/README.md @@ -0,0 +1,17 @@ +## shacl::cmake::Fortran::Exceptions + +Fortran has no notion of language level exceptions. As such, on some platforms +(notably macOS), a Fortran compiler may choose to suppress the generation of the +linker synthesized stack unwind information commonly used to implement exception +handling in other languages. For a project composed entirely of Fortran +components, this is not an unreasonable optimization to make. + +However, for multi-language projects, where one or more component langauges rely +on exception handling (such as C++ or Objective C), this behavior effectively +renders exceptions un-catchable. + +This module provides an interface target which, when linked against an +executable or shared library targets, ensures the necessary stack unwinding +information is retained, even when linking with a Fortran compiler. See the +module test [directory](../../tests/Fortran/Exceptions/) for example usage. + diff --git a/Fortran/Integer.cmake b/Fortran/Integer.cmake new file mode 100644 index 0000000..d4fa803 --- /dev/null +++ b/Fortran/Integer.cmake @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.12.1) + +if(NOT TARGET shacl::cmake::Fortran::Integer::detail) + add_library(shacl::cmake::Fortran::Integer::detail INTERFACE IMPORTED GLOBAL) + target_compile_definitions(shacl::cmake::Fortran::Integer::detail INTERFACE + $<$,4>:F90_INT_4BYTE> + $<$,8>:F90_INT_8BYTE>) + set_property(TARGET shacl::cmake::Fortran::Integer::detail + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Fortran_INTEGER_SIZE_BYTES) +endif() + +if(DEFINED CMAKE_C_COMPILER) + if(NOT TARGET shacl::cmake::Fortran::Integer_C) + add_library(shacl::cmake::Fortran::Integer_C INTERFACE IMPORTED GLOBAL) + target_link_libraries(shacl::cmake::Fortran::Integer_C + INTERFACE shacl::cmake::Fortran::Integer::detail) + endif() +endif() + +if(DEFINED CMAKE_CXX_COMPILER) + if(NOT TARGET shacl::cmake::Fortran::Integer_CXX) + add_library(shacl::cmake::Fortran::Integer_CXX INTERFACE IMPORTED GLOBAL) + target_link_libraries(shacl::cmake::Fortran::Integer_CXX + INTERFACE shacl::cmake::Fortran::Integer::detail) + endif() +endif() + +if(DEFINED CMAKE_Fortran_COMPILER) + if(NOT TARGET shacl::cmake::Fortran::Integer_Fortran) + add_library(shacl::cmake::Fortran::Integer_Fortran INTERFACE IMPORTED GLOBAL) + target_link_libraries(shacl::cmake::Fortran::Integer_Fortran + INTERFACE shacl::cmake::Fortran::Integer::detail) + endif() +endif() + +include(Fortran/Integer/GNU) +include(Fortran/Integer/Intel) +include(Fortran/Integer/IntelLLVM) +include(Fortran/Integer/PGI) + +include_guard(DIRECTORY) +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/Integer" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/Integer") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/Integer" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY Fortran_INTEGER_SIZE_BYTES +BRIEF_DOCS +"The size of the default Fortran integer in bytes" +FULL_DOCS +"This property specifies the size (in bytes) of the default Fortran integer, +e.g., in the expression 'integer :: i' where no kind is given") diff --git a/Fortran/Integer/GNU.cmake b/Fortran/Integer/GNU.cmake new file mode 100644 index 0000000..23a9e43 --- /dev/null +++ b/Fortran/Integer/GNU.cmake @@ -0,0 +1,22 @@ +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +string(CONCAT shacl.cmake.Fortran.Integer.generator + "$<$:" + "$<$,8>:" + "-fdefault-integer-8>>") + +target_compile_options(shacl::cmake::Fortran::Integer_Fortran INTERFACE + ${shacl.cmake.Fortran.Integer.generator}) + +string(CONCAT shacl.cmake.Fortran.Integer.generator + "$<$:" + "$<$>>:" + "F90_INT_4BYTE>>") + +target_compile_definitions(shacl::cmake::Fortran::Integer::detail INTERFACE + ${shacl.cmake.Fortran.Integer.generator}) + +unset(shacl.cmake.Fortran.Integer.generator) diff --git a/Fortran/Integer/Intel.cmake b/Fortran/Integer/Intel.cmake new file mode 100644 index 0000000..d88aa6b --- /dev/null +++ b/Fortran/Integer/Intel.cmake @@ -0,0 +1,28 @@ +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +string(CONCAT shacl.cmake.Fortran.Integer.generator + "$<$:" + "$<$>:" + "$<$,8>:-i8>>" + "$<$:" + "$<$,4>:" + "/integer-size$<1::>32>" + "$<$,8>:" + "/integer-size$<1::>64>>>") + +target_compile_options(shacl::cmake::Fortran::Integer_Fortran INTERFACE + ${shacl.cmake.Fortran.Integer.generator}) + +string(CONCAT shacl.cmake.Fortran.Integer.generator + "$<$:" + "$<$>>:" + "F90_INT_4BYTE>>") + +target_compile_definitions(shacl::cmake::Fortran::Integer::detail INTERFACE + ${shacl.cmake.Fortran.Integer.generator}) + +unset(shacl.cmake.Fortran.Integer.generator) + diff --git a/Fortran/Integer/IntelLLVM.cmake b/Fortran/Integer/IntelLLVM.cmake new file mode 100644 index 0000000..268edfe --- /dev/null +++ b/Fortran/Integer/IntelLLVM.cmake @@ -0,0 +1,30 @@ +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +string(CONCAT shacl.cmake.Fortran.Integer.generator + "$<$:" + "$<$>:" + "$<$,4>:" + "SHELL:-integer-size 32>" + "$<$,8>:" + "SHELL:-integer-size 64>>" + "$<$:" + "$<$,4>:" + "/integer-size$<1::>32>" + "$<$,8>:" + "/integer-size$<1::>64>>>") + +target_compile_options(shacl::cmake::Fortran::Integer_Fortran INTERFACE + ${shacl.cmake.Fortran.Integer.generator}) + +string(CONCAT shacl.cmake.Fortran.Integer.generator + "$<$:" + "$<$>>:" + "F90_INT_4BYTE>>") + +target_compile_definitions(shacl::cmake::Fortran::Integer::detail INTERFACE + ${shacl.cmake.Fortran.Integer.generator}) + +unset(shacl.cmake.Fortran.Integer.generator) diff --git a/Fortran/Integer/PGI.cmake b/Fortran/Integer/PGI.cmake new file mode 100644 index 0000000..78ca1dd --- /dev/null +++ b/Fortran/Integer/PGI.cmake @@ -0,0 +1,22 @@ +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +string(CONCAT shacl.cmake.Fortran.Integer.generator + "$<$:" + "$<$,4>:-i4>" + "$<$,8>:-i8>>") + +target_compile_options(shacl::cmake::Fortran::Integer_Fortran INTERFACE + ${shacl.cmake.Fortran.Integer.generator}) + +string(CONCAT shacl.cmake.Fortran.Integer.generator + "$<$:" + "$<$>>:" + "F90_INT_4BYTE>>") + +target_compile_definitions(shacl::cmake::Fortran::Integer::detail INTERFACE + ${shacl.cmake.Fortran.Integer.generator}) + +unset(shacl.cmake.Fortran.Integer.generator) diff --git a/Fortran/LongLines.cmake b/Fortran/LongLines.cmake new file mode 100644 index 0000000..dde85fb --- /dev/null +++ b/Fortran/LongLines.cmake @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.10.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/LongLines" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/LongLines") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/LongLines" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +enable_language(Fortran) +add_library(shacl::cmake::Fortran::LongLines INTERFACE IMPORTED GLOBAL) + +include(Fortran/LongLines/GNU) diff --git a/Fortran/LongLines/GNU.cmake b/Fortran/LongLines/GNU.cmake new file mode 100644 index 0000000..b740c82 --- /dev/null +++ b/Fortran/LongLines/GNU.cmake @@ -0,0 +1,8 @@ +string(CONCAT shacl.cmake.Fortran.LongLines.generator + "$<$:" + "-ffree-line-length-none;>") + +target_compile_options(shacl::cmake::Fortran::LongLines INTERFACE + ${shacl.cmake.Fortran.LongLines.generator}) + +unset(shacl.cmake.Fortran.LongLines.generator) diff --git a/Fortran/ModuleDirectory.cmake b/Fortran/ModuleDirectory.cmake new file mode 100644 index 0000000..8dc3177 --- /dev/null +++ b/Fortran/ModuleDirectory.cmake @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/ModuleDirectory" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/ModuleDirectory") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +include(CMakeParseArguments) + +function(target_Fortran_module_directory target linkage) + set(OPTIONS) + set(UNARY_ARGUMENTS BUILD_INTERFACE INSTALL_INTERFACE) + set(VARIADIC_ARGUMENTS) + cmake_parse_arguments(target_Fortran_module_directory + "${OPTIONS}" + "${UNARY_ARGUMENTS}" + "${VARIADIC_ARGUMENTS}" ${ARGN}) + + if(NOT target_Fortran_module_directory_BUILD_INTERFACE) + message(FATAL_ERROR "target_Fortran_module_directory on target \"${target}\" missing BUILD_INTERFACE argument") + endif() + + file(MAKE_DIRECTORY "${target_Fortran_module_directory_BUILD_INTERFACE}") + + set(multiconfig_suffix "") + if(CMAKE_CONFIGURATION_TYPES) + foreach(CONFIGURATION_TYPE IN LISTS CMAKE_CONFIGURATION_TYPES) + file(MAKE_DIRECTORY "${target_Fortran_module_directory_BUILD_INTERFACE}/${CONFIGURATION_TYPE}") + endforeach() + set(multiconfig_suffix "/$") + endif() + + target_include_directories("${target}" "${linkage}" + $) + set_target_properties("${target}" PROPERTIES + Fortran_MODULE_DIRECTORY ${target_Fortran_module_directory_BUILD_INTERFACE}) + + if(target_Fortran_module_directory_INSTALL_INTERFACE) + target_include_directories("${target}" "${linkage}" + $) + + install( + DIRECTORY "${target_Fortran_module_directory_BUILD_INTERFACE}${multiconfig_suffix}/" + DESTINATION "${target_Fortran_module_directory_INSTALL_INTERFACE}") + endif() +endfunction() diff --git a/Fortran/README.md b/Fortran/README.md new file mode 100644 index 0000000..fe5b043 --- /dev/null +++ b/Fortran/README.md @@ -0,0 +1,46 @@ +shacl::cmake::Fortran +============= + +This directory provides a number of utilities for working with Fortran-based +projects in CMake. + ++ [`shacl::cmake::Fortran::BackslashEscape`](./BackslashEscape/README.md) +This module provides a target and related target property which allows +a client to explicitly opt-in or opt-out of the common vendor extension to +support the backslash escape character in Fortran strings in a compiler +independent manner. + ++ [`shacl::cmake::Fortran::Backtrace`](./Backtrace/README.md) +This module provides a target which allows a client to, in a +compiler independent manner, compile Fortran executables such an execution +backtrace is provided when execution fails. + ++ [`shacl::cmake::Fortran::Integer`](./Integer/README.md) +This module provides a target and related target property which allows +a client to specify the size of default `integer` variables in Fortran code +in a compiler independent manner. + ++ [`shacl::cmake::Fortran::ModuleDirectory`](./ModuleDirectry/README.md) +This module provides a function which associates a Fortran target with a +directory for storing compiled Fortran module files. + ++ [`shacl::cmake::Fortran::Real`](./Real/README.md)n +This module provides a target and related target property which allows +a client to specify the size of default `real` variables in Fortran code +in a compiler independent manner. + ++ [`shacl::cmake::Fortran::StackArraySizeLimit`](./StackArraySizeLimit/README.md) +This module provides a target and related target property which allows +a client to establish a maximum size for stack allocated automatic arrays +in a compiler independent manner. Arrays larger than this threshold fallback +to a vendor-defined memory strategy. + ++ [`shacl::cmake::Fortran::Standard`](./Standard/README.md) +This module provides a target and related target property which allows a client +to specify a Fortran Standard in a compiler independent manner (for vendors +which support multiple standards) + ++ [`shacl::cmake::Fortran::StandardCompliance`](./StandardCompliance/README.md) +This module provides a target which suppresses vendor extensions in Fortran +code. This target it useful when writing Fortran which must be portable between +compiler vendors. diff --git a/Fortran/Real.cmake b/Fortran/Real.cmake new file mode 100644 index 0000000..d23e6b8 --- /dev/null +++ b/Fortran/Real.cmake @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.12.1) + +if(NOT TARGET shacl::cmake::Fortran::Real::detail) + add_library(shacl::cmake::Fortran::Real::detail INTERFACE IMPORTED GLOBAL) + target_compile_definitions(shacl::cmake::Fortran::Real::detail INTERFACE + $<$,4>:F90_REAL_4BYTE> + $<$,8>:F90_REAL_8BYTE>) + set_property(TARGET shacl::cmake::Fortran::Real::detail + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Fortran_REAL_SIZE_BYTES) +endif() + +if(DEFINED CMAKE_C_COMPILER) + if(NOT TARGET shacl::cmake::Fortran::Real_C) + add_library(shacl::cmake::Fortran::Real_C INTERFACE IMPORTED GLOBAL) + target_link_libraries(shacl::cmake::Fortran::Real_C + INTERFACE shacl::cmake::Fortran::Real::detail) + endif() +endif() + +if(DEFINED CMAKE_CXX_COMPILER) + if(NOT TARGET shacl::cmake::Fortran::Real_CXX) + add_library(shacl::cmake::Fortran::Real_CXX INTERFACE IMPORTED GLOBAL) + target_link_libraries(shacl::cmake::Fortran::Real_CXX + INTERFACE shacl::cmake::Fortran::Real::detail) + endif() +endif() + +if(DEFINED CMAKE_Fortran_COMPILER) + if(NOT TARGET shacl::cmake::Fortran::Real_Fortran) + add_library(shacl::cmake::Fortran::Real_Fortran INTERFACE IMPORTED GLOBAL) + target_link_libraries(shacl::cmake::Fortran::Real_Fortran + INTERFACE shacl::cmake::Fortran::Real::detail) + endif() +endif() + +include(Fortran/Real/GNU) +include(Fortran/Real/Intel) +include(Fortran/Real/IntelLLVM) +include(Fortran/Real/PGI) + +include_guard(DIRECTORY) +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/Real" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/Real") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/Real" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY Fortran_REAL_SIZE_BYTES +BRIEF_DOCS +"The size of the default Fortran real in bytes" +FULL_DOCS +"This property specifies the size (in bytes) of the default Fortran real, e.g., +in the expression 'real :: r' where no kind is given") diff --git a/Fortran/Real/GNU.cmake b/Fortran/Real/GNU.cmake new file mode 100644 index 0000000..01d0f82 --- /dev/null +++ b/Fortran/Real/GNU.cmake @@ -0,0 +1,22 @@ +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +string(CONCAT shacl.cmake.Fortran.Real.generator + "$<$:" + "$<$,8>:" + "-fdefault-real-8;-fdefault-double-8>>") + +target_compile_options(shacl::cmake::Fortran::Real_Fortran INTERFACE + ${shacl.cmake.Fortran.Real.generator}) + +string(CONCAT shacl.cmake.Fortran.Real.generator + "$<$:" + "$<$>>:" + "F90_REAL_4BYTE>>") + +target_compile_definitions(shacl::cmake::Fortran::Real::detail INTERFACE + ${shacl.cmake.Fortran.Real.generator}) + +unset(shacl.cmake.Fortran.Real.generator) diff --git a/Fortran/Real/Intel.cmake b/Fortran/Real/Intel.cmake new file mode 100644 index 0000000..3c3d17a --- /dev/null +++ b/Fortran/Real/Intel.cmake @@ -0,0 +1,27 @@ +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +string(CONCAT shacl.cmake.Fortran.Real.generator + "$<$:" + "$<$>:" + "$<$,8>:-r8>>" + "$<$:" + "$<$,4>:" + "/real-size$<1::>32>" + "$<$,8>:" + "/real-size$<1::>64>>>") + +target_compile_options(shacl::cmake::Fortran::Real_Fortran INTERFACE + ${shacl.cmake.Fortran.Real.generator}) + +string(CONCAT shacl.cmake.Fortran.Real.generator + "$<$:" + "$<$>>:" + "F90_REAL_4BYTE>>") + +target_compile_definitions(shacl::cmake::Fortran::Real::detail INTERFACE + ${shacl.cmake.Fortran.Real.generator}) + +unset(shacl.cmake.Fortran.Real.generator) diff --git a/Fortran/Real/IntelLLVM.cmake b/Fortran/Real/IntelLLVM.cmake new file mode 100644 index 0000000..d254c4c --- /dev/null +++ b/Fortran/Real/IntelLLVM.cmake @@ -0,0 +1,30 @@ +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +string(CONCAT shacl.cmake.Fortran.Real.generator + "$<$:" + "$<$>:" + "$<$,4>:" + "SHELL:-real-size 32>" + "$<$,8>:" + "SHELL:-real-size 64>>" + "$<$:" + "$<$,4>:" + "/real-size$<1::>32>" + "$<$,8>:" + "/real-size$<1::>64>>>") + +target_compile_options(shacl::cmake::Fortran::Real_Fortran INTERFACE + ${shacl.cmake.Fortran.Real.generator}) + +string(CONCAT shacl.cmake.Fortran.Real.generator + "$<$:" + "$<$>>:" + "F90_REAL_4BYTE>>") + +target_compile_definitions(shacl::cmake::Fortran::Real::detail INTERFACE + ${shacl.cmake.Fortran.Real.generator}) + +unset(shacl.cmake.Fortran.Real.generator) diff --git a/Fortran/Real/PGI.cmake b/Fortran/Real/PGI.cmake new file mode 100644 index 0000000..d4fbe3e --- /dev/null +++ b/Fortran/Real/PGI.cmake @@ -0,0 +1,24 @@ +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +string(CONCAT shacl.cmake.Fortran.Real.generator + "$<$:" + "$<$,4>:-r4>" + "$<$,8>:-r8>>" +) + +target_compile_options(shacl::cmake::Fortran::Real_Fortran INTERFACE + ${shacl.cmake.Fortran.Real.generator}) + +string(CONCAT shacl.cmake.Fortran.Real.generator + "$<$:" + "$<$>>:" + "F90_REAL_4BYTE>>" +) + +target_compile_definitions(shacl::cmake::Fortran::Real::detail INTERFACE + ${shacl.cmake.Fortran.Real.generator}) + +unset(shacl.cmake.Fortran.Real.generator) diff --git a/Fortran/StackArraySizeLimit.cmake b/Fortran/StackArraySizeLimit.cmake new file mode 100644 index 0000000..11b145c --- /dev/null +++ b/Fortran/StackArraySizeLimit.cmake @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/StackArraySizeLimit" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/StackArraySizeLimit") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/StackArraySizeLimit" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY Fortran_STACK_ARRAY_SIZE_LIMIT +BRIEF_DOCS +"A integer size limit (in kilobytes) above which arrays should not be stack allocated" +FULL_DOCS +"This behavior varies widely between Fortran compilers. + +In the case of Intel ifort/ifx, automatic and temporary arrays which exceed this +limit are allocated on the heap. This is the ideal behavior. + +On GNU gfortran (at least in version 9.0 and earlier) any stack allocated +variable which exceeds this limit are allocated in static storage. As this value +is specified in kilobytes, most primitive and user-defined data-types will be +excluded from this behavior for non-zero Fortran_STACK_ARRAY_SIZE_LIMIT values. +That said, the use of static storage for these arrays is not thread-safe in the +absense of other constructs (e.g. thread private). + +In the case of the PGI compiler, this option is only available in a coarse-grain +form; either all automatic and temporary arrays are stack-allocated or none are. +As such, the value of Fortran_STACK_ARRAY_SIZE_LIMIT is irrelevant for this +compiler; this flag is dispatched based on whether the +Fortran_STACK_ARRAY_SIZE_LIMIT is defined on a target linking to the +shacl::cmake::Fortran::StackArraySizeLimit target.") + +add_library(shacl::cmake::Fortran::StackArraySizeLimit INTERFACE IMPORTED GLOBAL) + +include(Fortran/StackArraySizeLimit/GNU) +include(Fortran/StackArraySizeLimit/Intel) +include(Fortran/StackArraySizeLimit/IntelLLVM) +include(Fortran/StackArraySizeLimit/PGI) diff --git a/Fortran/StackArraySizeLimit/GNU.cmake b/Fortran/StackArraySizeLimit/GNU.cmake new file mode 100644 index 0000000..c3181e3 --- /dev/null +++ b/Fortran/StackArraySizeLimit/GNU.cmake @@ -0,0 +1,10 @@ +string(CONCAT shacl.cmake.Fortran.StackArraySizeLimit.generator + "$<$:" + "$<$>:" + "-fmax-stack-var-size=" + "$000>>") + +target_compile_options(shacl::cmake::Fortran::StackArraySizeLimit INTERFACE + ${shacl.cmake.Fortran.StackArraySizeLimit.generator}) + +unset(shacl.cmake.Fortran.StackArraySizeLimit.generator) diff --git a/Fortran/StackArraySizeLimit/Intel.cmake b/Fortran/StackArraySizeLimit/Intel.cmake new file mode 100644 index 0000000..52534c6 --- /dev/null +++ b/Fortran/StackArraySizeLimit/Intel.cmake @@ -0,0 +1,12 @@ +string(CONCAT shacl.cmake.Fortran.StackArraySizeLimit.generator + "$<$:" + "$<$>:" + "$" + ",/heap-arrays$<1::>" + ",-heap-arrays;>" + "$>>") + +target_compile_options(shacl::cmake::Fortran::StackArraySizeLimit INTERFACE + ${shacl.cmake.Fortran.StackArraySizeLimit.generator}) + +unset(shacl.cmake.Fortran.StackArraySizeLimit.generator) diff --git a/Fortran/StackArraySizeLimit/IntelLLVM.cmake b/Fortran/StackArraySizeLimit/IntelLLVM.cmake new file mode 100644 index 0000000..6778930 --- /dev/null +++ b/Fortran/StackArraySizeLimit/IntelLLVM.cmake @@ -0,0 +1,12 @@ +string(CONCAT shacl.cmake.Fortran.StackArraySizeLimit.generator + "$<$:" + "$<$>:" + "$" + ",/heap-arrays$<1::>" + ",-heap-arrays;>" + "$>>") + +target_compile_options(shacl::cmake::Fortran::StackArraySizeLimit INTERFACE + ${shacl.cmake.Fortran.StackArraySizeLimit.generator}) + +unset(shacl.cmake.Fortran.StackArraySizeLimit.generator) diff --git a/Fortran/StackArraySizeLimit/PGI.cmake b/Fortran/StackArraySizeLimit/PGI.cmake new file mode 100644 index 0000000..13902c0 --- /dev/null +++ b/Fortran/StackArraySizeLimit/PGI.cmake @@ -0,0 +1,4 @@ +target_compile_options(shacl::cmake::Fortran::StackArraySizeLimit INTERFACE + "$<$:" + "$<$>:" + "-Mnostack_arrays>>") diff --git a/Fortran/Standard.cmake b/Fortran/Standard.cmake new file mode 100644 index 0000000..1ad772b --- /dev/null +++ b/Fortran/Standard.cmake @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/Standard" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/Standard") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/Standard" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +if(NOT CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY Fortran_STANDARD +BRIEF_DOCS +"The Fortran standard whose features are requested to build this target." +FULL_DOCS +"This property specifies the Fortran standard whose features are requested to + build this target. For some compilers, this results in adding a flag such as + -std=f2003 to the compile line. For compilers that have no notion of a + standard level, such as PGI, this has no effect. + + Supported values are 95, 2003, 2008, and 2018") + +add_library(shacl::cmake::Fortran::Standard INTERFACE IMPORTED GLOBAL) +set_property(TARGET shacl::cmake::Fortran::Standard + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Fortran_STANDARD) + +include(Fortran/Standard/GNU) +include(Fortran/Standard/Intel) +include(Fortran/Standard/IntelLLVM) diff --git a/Fortran/Standard/GNU.cmake b/Fortran/Standard/GNU.cmake new file mode 100644 index 0000000..d08d84b --- /dev/null +++ b/Fortran/Standard/GNU.cmake @@ -0,0 +1,16 @@ +string(CONCAT shacl.cmake.Fortran.Standard.generator + "$<$,95>:f95>" + "$<$,2003>:f2003>" + "$<$,2008>:f2008>" + "$<$,2018>:" + "$,f2008ts,f2018>>") + +string(CONCAT shacl.cmake.Fortran.Standard.generator + "$<$>" + ",$>:" + "-std=${shacl.cmake.Fortran.Standard.generator}>") + +target_compile_options(shacl::cmake::Fortran::Standard INTERFACE + ${shacl.cmake.Fortran.Standard.generator}) + +unset(shacl.cmake.Fortran.Standard.generator) diff --git a/Fortran/Standard/Intel.cmake b/Fortran/Standard/Intel.cmake new file mode 100644 index 0000000..365a516 --- /dev/null +++ b/Fortran/Standard/Intel.cmake @@ -0,0 +1,19 @@ +string(CONCAT shacl.cmake.Fortran.Standard.generator + "$<$,95>:f95>" + "$<$,2003>:f03>" + "$<$,2008>:f08>" + "$<$,2018>:" + "$,f15,f18>>") + +string(CONCAT shacl.cmake.Fortran.Standard.generator + "$<$>" + ",$>:" + "$" + ",/stand$<1::>" + ",-stand=>" + "${shacl.cmake.Fortran.Standard.generator}>") + +target_compile_options(shacl::cmake::Fortran::Standard INTERFACE + ${shacl.cmake.Fortran.Standard.generator}) + +unset(shacl.cmake.Fortran.Standard.generator) diff --git a/Fortran/Standard/IntelLLVM.cmake b/Fortran/Standard/IntelLLVM.cmake new file mode 100644 index 0000000..533c670 --- /dev/null +++ b/Fortran/Standard/IntelLLVM.cmake @@ -0,0 +1,18 @@ +string(CONCAT shacl.cmake.Fortran.Standard.generator + "$<$,95>:f95>" + "$<$,2003>:f03>" + "$<$,2008>:f08>" + "$<$,2018>:f18>") + +string(CONCAT shacl.cmake.Fortran.Standard.generator + "$<$>" + ",$>:" + "$" + ",/stand$<1::>" + ",-stand=>" + "${shacl.cmake.Fortran.Standard.generator}>") + +target_compile_options(shacl::cmake::Fortran::Standard INTERFACE + ${shacl.cmake.Fortran.Standard.generator}) + +unset(shacl.cmake.Fortran.Standard.generator) diff --git a/Fortran/StandardCompliance.cmake b/Fortran/StandardCompliance.cmake new file mode 100644 index 0000000..83dd85f --- /dev/null +++ b/Fortran/StandardCompliance.cmake @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Fortran/StandardCompliance" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Fortran/StandardCompliance") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Fortran) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/StandardCompliance" + DESTINATION share/cmake/shacl/.cmake/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include(Fortran/BackslashEscape) + +include_guard(GLOBAL) +enable_language(Fortran) + +add_library(shacl::cmake::Fortran::StandardCompliance INTERFACE IMPORTED GLOBAL) + +target_link_libraries(shacl::cmake::Fortran::StandardCompliance INTERFACE + shacl::cmake::Fortran::BackslashEscape) + +set_target_properties(shacl::cmake::Fortran::StandardCompliance PROPERTIES + INTERFACE_Fortran_BACKSLASH_ESCAPE OFF) + +include(Fortran/StandardCompliance/GNU) +include(Fortran/StandardCompliance/Intel) +include(Fortran/StandardCompliance/IntelLLVM) +include(Fortran/StandardCompliance/PGI) diff --git a/Fortran/StandardCompliance/GNU.cmake b/Fortran/StandardCompliance/GNU.cmake new file mode 100644 index 0000000..af4fb0d --- /dev/null +++ b/Fortran/StandardCompliance/GNU.cmake @@ -0,0 +1,7 @@ +string(CONCAT shacl.cmake.Fortran.StandardCompliance.generator + "$<$:-pedantic-errors>") + +target_compile_options(shacl::cmake::Fortran::StandardCompliance INTERFACE + ${shacl.cmake.Fortran.StandardCompliance.generator}) + +unset(shacl.cmake.Fortran.StandardCompliance.generator) diff --git a/Fortran/StandardCompliance/Intel.cmake b/Fortran/StandardCompliance/Intel.cmake new file mode 100644 index 0000000..9a9903d --- /dev/null +++ b/Fortran/StandardCompliance/Intel.cmake @@ -0,0 +1,12 @@ +string(CONCAT shacl.cmake.Fortran.StandardCompliance.generator + "$<$:" + "$" + ",/standard-semantics" + ";/assume$<1::>nostd_mod_proc_name" + ",-standard-semantics" + ";SHELL:-assume nostd_mod_proc_name>>") + +target_compile_options(shacl::cmake::Fortran::StandardCompliance + INTERFACE ${shacl.cmake.Fortran.StandardCompliance.generator}) + +unset(shacl.cmake.Fortran.StandardCompliance.generator) diff --git a/Fortran/StandardCompliance/IntelLLVM.cmake b/Fortran/StandardCompliance/IntelLLVM.cmake new file mode 100644 index 0000000..a036d2e --- /dev/null +++ b/Fortran/StandardCompliance/IntelLLVM.cmake @@ -0,0 +1,19 @@ +# Notes: +# fpscomp logicals does not work on ifx 2022.1.0 but the flag can be removed +# from here once it does. +# std_mod_proc_name breaks linking of almost all Fortran -> C bindings. + +string(CONCAT shacl.cmake.Fortran.StandardCompliance.generator + "$<$:" + "$" + ",/standard-semantics" + ";/assume$<1::>nostd_mod_proc_name" + ";/fpscomp$<1::>none" + ",-standard-semantics" + ";SHELL:-assume nostd_mod_proc_name" + ";SHELL:-fpscomp none>>") + +target_compile_options(shacl::cmake::Fortran::StandardCompliance + INTERFACE ${shacl.cmake.Fortran.StandardCompliance.generator}) + +unset(shacl.cmake.Fortran.StandardCompliance.generator) diff --git a/Fortran/StandardCompliance/PGI.cmake b/Fortran/StandardCompliance/PGI.cmake new file mode 100644 index 0000000..5eb5a90 --- /dev/null +++ b/Fortran/StandardCompliance/PGI.cmake @@ -0,0 +1,7 @@ +string(CONCAT shacl.cmake.Fortran.StandardCompliance.generator + "$<$:-Mstandard>") + +target_compile_options(shacl::cmake::Fortran::StandardCompliance INTERFACE + ${shacl.cmake.Fortran.StandardCompliance.generator}) + +unset(shacl.cmake.Fortran.StandardCompliance.generator) diff --git a/FortranPreProcess.cmake b/FortranPreProcess.cmake new file mode 100644 index 0000000..425b5b0 --- /dev/null +++ b/FortranPreProcess.cmake @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "FortranPreProcess" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "FortranPreProcess") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/FortranPreProcess" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include(GeneratedSources) + +include_guard(GLOBAL) +include(FortranPreProcess/FortranPreProcess) +include(FortranPreProcess/filename) +include(FortranPreProcess/target_sources) diff --git a/FortranPreProcess/FortranPreProcess.cmake b/FortranPreProcess/FortranPreProcess.cmake new file mode 100644 index 0000000..fdb3aff --- /dev/null +++ b/FortranPreProcess/FortranPreProcess.cmake @@ -0,0 +1,71 @@ +find_package(Perl REQUIRED) + +include_guard(GLOBAL) + +set( + FPP_PATH "${CMAKE_CURRENT_LIST_DIR}/fpp.pl" + CACHE STRING "path to Fortran preprocessor script") + +function(FortranPreProcess infile outfile) + set(working_directory "${CMAKE_CURRENT_SOURCE_DIR}") + foreach(arg ${ARGN}) + if(arg STREQUAL "DEFINE") + set(keyword "DEFINE") + elseif(arg STREQUAL "UNDEFINE") + set(keyword "UNDEFINE") + elseif(arg STREQUAL "MACROS") + set(keyword "MACROS") + list(APPEND FPP_ARGS "-macros") + elseif(arg STREQUAL "NOMACROS") + set(keyword "NOMACROS") + list(APPEND FPP_ARGS "-nomacros") + elseif(arg STREQUAL "BLANKS") + set(keyword "BLANKS") + list(APPEND FPP_ARGS "-blanks") + elseif(arg STREQUAL "NOBLANKS") + set(keyword "NOBLANKS") + list(APPEND FPP_ARGS "-noblanks") + elseif(arg STREQUAL "WORKING_DIRECTORY") + set(keyword "WORKING_DIRECTORY") + elseif(arg STREQUAL "INCLUDE") + set(keyword "INCLUDE") + elseif(arg STREQUAL "SUFFIX") + message(STATUS "INVOCATION: FortranPreProcess(${ARGV})") + message(FATAL_ERROR "FortranPreProcessor -suffix option not supported") + else() + if(keyword STREQUAL "DEFINE") + set(-D) + if(arg MATCHES "[$]<.*>$") + list(APPEND FPP_ARGS "$<$:-D$>") + else() + list(APPEND FPP_ARGS "-D${arg}") + endif() + elseif(keyword STREQUAL "UNDEFINE") + if(arg MATCHES "[$]<.*>$") + list(APPEND FPP_ARGS "$<$:-U$>") + else() + list(APPEND FPP_ARGS "-U${arg}") + endif() + elseif(keyword STREQUAL "WORKING_DIRECTORY") + set(working_directory ${arg}) + elseif(keyword STREQUAL "INCLUDE") + set(-I) + if(arg MATCHES "[$]<.*>$") + list(APPEND FPP_ARGS "$<$:-I$>") + else() + list(APPEND FPP_ARGS "-I${arg}") + endif() + else() + message(STATUS "INVOCATION: FortranPreProcess(${ARGV})") + message(FATAL_ERROR "unknown FortranPreProcess keyword ${arg}") + endif() + endif() + endforeach() + + add_custom_command( + OUTPUT "${outfile}" + COMMAND "${PERL_EXECUTABLE}" "${FPP_PATH}" ${FPP_ARGS} -o "${outfile}" -- "${infile}" + DEPENDS "${infile}" + WORKING_DIRECTORY "${working_directory}") + +endfunction(FortranPreProcess) diff --git a/FortranPreProcess/filename.cmake b/FortranPreProcess/filename.cmake new file mode 100644 index 0000000..e0e338b --- /dev/null +++ b/FortranPreProcess/filename.cmake @@ -0,0 +1,7 @@ +function(FortranPreProcess_filename input output) + get_filename_component(directory "${input}" DIRECTORY) + get_filename_component(root "${input}" NAME_WE) + get_filename_component(old_extension "${input}" EXT) + string(TOLOWER ${old_extension} new_extension) + set(${output} "${directory}${root}${new_extension}" PARENT_SCOPE) +endfunction() diff --git a/FortranPreProcess/fpp.pl b/FortranPreProcess/fpp.pl new file mode 100755 index 0000000..ce8edaf --- /dev/null +++ b/FortranPreProcess/fpp.pl @@ -0,0 +1,358 @@ +#!/usr/bin/perl +######################################################################## +# Copyright Triad National Security, LLC/LANL/DOE - see LICENSE file +# +# fpp -- preprocessor for fortran files +# +# History: +# 1992-12-12 - fbb, initial version for ANL Vim code +# 2001-06-06 - fbb, initial version for MCNP5 +# 2010-06-06 - fbb, mods for MCNP6 +# 2014-01-07 - fbb, bug fix for pattern matching in arg processing +# (for -I,-o,-s,-e) - must match start of pattern. +# 2014-01-15 - fbb, mods for templating +#....................................................................... +# +# Handles these constructs: +# +# #ifdef DEF +# #else +# #endif +# +# #ifndef DEF +# #else +# #endif +# +# #define DEF +# +# #undef DEF +# +# #include "F" +# +# #if defined(DEF1) op defined(DEF2) op ... +# #else +# #endif +# where "op" is |, &, ||, && +# and "defined()" may be preceded with "!" +# +# Substitutions for variables defined as -Dvar=value, +# (only if macro substitution is on (-F or -macros), +# on by default in MCNP5 build system, off for MCNP6.) +# +# These preprocessor constructs are ignored: +# #include +# #include 'file' +# #include file +# #elif +# #if [anything other than "defined()...." ] +# +# Long fpp preprocessor lines may be continued on successive lines by using a +# backslash ("\") as the last character. The continuation lines should NOT +# include a "#" character at their beginning. +# +# Templating (added 2013-12-20, fbb) +# +# #FPP_TEMPLATE_BEGIN +# #FPP_TEMPLATE = a1; a2; a3; ...; aN +# #FPP_TEMPLATE = b1; b2; b3; ...; bN +# +# all coding here (after other fpp processing) is replicated N times, +# with substitutions for , , etc. +# the keys, , etc., should be \w+ (alphanumeric, underscore) +# only, without blanks, and are case-sensitive. The <> delimiters +# are required. +# the subsititutions are separated by semicolons, hence could be any +# character string not containing semicolons. Do not include a +# trailing semicolon on the last entry in a list. +# fpp template constructs cannot be nested within a single file, but +# may contain other preprocessor constructs, or may be enclosed +# within other constructs (eg, #ifdef's). +# +# #FPP_TEMPLATE_END +#....................................................................... +# +# Usage: +# +# fpp [-Dopt] [-Dopt=val] [-Uopt] [-I file] [-o outfile] +# [-F] [-macros] [-nomacros] [-blanks] [-noblanks] +# [-s suffix] [-noblanks] [--] files +# +# * optional spaces or quotes allowed after -D, -U, -I, or -o +# +# * reads from stdin if no files listed on cmd line +# ***not for Win32*** +# +# * -I specifies an include-directory, can be repeated +# If include-file begins with "/" it is used, +# otherwise, check ".", then include-dirs (in cmdline order) +# +# * For MCNP5, +# MACRO EXPANSION SHOULD ALWAYS BE PERFORMED. +# The default value for $macro_substitute should be 1. +# ForMCNP6, +# MACRO EXPANSION IN SOURCE CODING IS NOT PERFORMED +# UNLESS THE -F OPTION IS SPECIFIED (change: 11/9/2004) +# The default value for $macro_substitute should be 0. +# +# -macros turns on macro substitution, equivalent to -F +# -nomacros turns off macro substitution +# +# * these options are ignored: -P, -E, -eP +# +# * if "-o file" not supplied, writes to stdout +# +# * if "-s suffix" supplied, writes to file with suffix extension. +# example: -s .i90 puts output into file.i90 +# +# +# * -noblanks indicates that blank lines should NOT +# be output for # lines or deleted lines +# +# For MCNP5, -noblanks is the default, +# set $blanks=0 +# For MCNP6, blank lines SHOULD be output, +# set $blanks=1 +# +######################################################################## +$verbose = 0; +# +# MCNP6 defaults: -nomacros -blanks + $macro_substitute = 0; + $blanks = 1; +# MCNP5 defaults: -macros -noblanks +# $macro_substitute = 1; +# $blanks = 0; +# +##### get args +# +push @INCS, '.'; +while( $arg = shift @ARGV ) { + if( $arg eq '-v' ) { $verbose=1; } + elsif( $arg eq '-D' ) { $defs{ shift(@ARGV) } = 1; } + elsif( $arg =~ /^-D(\S+)=(.+)$/ ) { $defs{$1} = 1; $subs{$1} = "$2"; } + elsif( $arg =~ /^-D(\S+)$/ ) { $defs{$1} = 1; } + elsif( $arg eq '-U' ) { delete $defs{ shift(@ARGV) }; } + elsif( $arg =~ /^-U(\S+)$/ ) { delete $defs{$1}; } + elsif( $arg eq '-I' ) { push @INCS, shift(@ARGV); } + elsif( $arg =~ /^-I(\S+)/ ) { push @INCS, $1; } + elsif( $arg eq '-o' ) { $OUT = shift(@ARGV); } + elsif( $arg =~ /^-o(\S+)/ ) { $OUT = $1; } + elsif( $arg eq '-s' ) { $EXT = shift(@ARGV); } + elsif( $arg =~ /^-s(\S+)/ ) { $EXT = $1; } + elsif( $arg eq '-F' ) { $macro_substitute=1; } + elsif( $arg eq '-macros' ) { $macro_substitute=1; } + elsif( $arg eq '-nomacros' ) { $macro_substitute=0; } + elsif( $arg eq '-noblanks' ) { $blanks = 0; } + elsif( $arg eq '-blanks' ) { $blanks = 1; } + elsif( $arg eq '-P' ) { ; } + elsif( $arg eq '-E' ) { ; } + elsif( $arg eq '-e' ) { shift(@ARGV); } + elsif( $arg =~ /^-e\S+/ ) { ; } + elsif( $arg eq '--' ) { last; } + elsif( $arg eq '-pthread' ) { ; } #problem with OpenMPI on Yellowrail + else { unshift(@ARGV,$arg); last; } +} +if( !@ARGV ) { unshift(@ARGV,'-'); } +if( $verbose ) { + foreach $k (keys(%defs)) { + if( $defs{$k} ) { + if( $subs{$k} ) { print STDERR " .......defined: $k\n";} + else { print STDERR " .......defined: $k= $subs{$k}\n";} + } + else { print STDERR " ...not defined: $k\n"; } + } + print STDERR " ....macro_subs= $macro_substitute\n"; + print STDERR " ........blanks= $blanks\n"; + print STDERR " ..include dirs: @INCS\n"; + print STDERR " ...output file: $OUT\n"; + print STDERR " .........files: @ARGV\n"; +} +if( $OUT && $EXT ) { die("$0: can't use both -o and -s\n"); } +# +##### redirect output to file, stdout by default +# +if( $OUT ) { + open( OUT, ">$OUT") || die("$0: can't open $OUT\n"); + *STDOUT = *OUT; +} +# +##### process each file from command line +# +foreach $F (@ARGV) { + + if( $EXT ) { + $i = rindex($F,'.'); + if( $i==-1 ) { $G = $F.$EXT; } + else { $G = substr($F,0,$i).$EXT; } + open( OUT, ">$G") || die("$0: can't open $G\n"); + *STDOUT = *OUT; + } + open( F, "<$F" ) || die("$0: can't open $F\n"); + + &process_file( *F, 1, 1, 0 ); + + close(F); + close(OUT) if $EXT; +} +close(OUT) if $OUT; +exit; +# +##### recursive sub, to process lines in current file +# +sub process_file { + local( *F ) = $_[0]; ### current filehandle + my( $ok ) = $_[1]; ### t/f, outer condition for print + my( $def ) = $_[2]; ### t/f, active def, for current level + my( $level) = $_[3]; ### int, current level in recursion + my( $newok, $newdef, $G, $dir, $dstr ); + my( @template_name, @template_subs ); + my( @template_repl, @template_junk ); + my( $template_count,$template_copies, $n, $t ); + my( $ftplate_file ) = "fpp_temp_file_for_template_$$-$level.txt"; + local( *G, *FTPLATE, *STDOUT_PREVIOUS ); + + $newok = $ok && $def; + $level++; + + while( ) { + + # pick up continuation lines for #directives + if( /^\s*#/ ) { + while( substr($_,-2,1) eq "\\" ) { $_ = substr($_,0,-2).; } + } + + if( /^\s*#\s*include\s+"([^"]+)"/ ) { + print "\n" if $blanks; + next unless $newok; + $G = $1; + if( $G =~ m(^[^/]) ) { + foreach $dir (@INCS) { + if( -r $dir.'/'.$G ) { $G = $dir.'/'.$G; last; } + } + } + open( G, "<$G") || die("$0: can't open $G\n"); + &process_file( *G, $newok, $def, $level ); + close(G); + } + elsif( /^\s*#\s*define\s+(\w+)\s*$/ ) { + print "\n" if $blanks; + $defs{$1} = 1 if $newok; + } + elsif( /^\s*#\s*define\s+(\w+)\s+(.+)/ ) { + print "\n" if $blanks; + $defs{$1} = "$2" if $newok; + } + elsif( /^\s*#\s*undef\s+(\w+)/ ) { + print "\n" if $blanks; + $defs{$1} = '' if $newok; + $subs{$1} = '' if $newok; + } + elsif( /^\s*#\s*ifdef\s+(\w+)/ ) { + print "\n" if $blanks; + $newdef = $defs{$1}; + &process_file( *F, $newok, $newdef, $level ); + } + elsif( /^\s*#\s*ifndef\s+(\w+)/ ) { + print "\n" if $blanks; + $newdef = ! $defs{$1}; + &process_file( *F, $newok, $newdef, $level ); + } + elsif( /^\s*#if\s+(!?\s*defined\(.*)/ ) { + print "\n" if $blanks; + $dstr = $1; + $dstr =~ s/defined\(\s*(\w+)\s*\)/\$defs\{\1\}/go; + $newdef = eval $dstr; + &process_file( *F, $newok, $newdef, $level ); + } + elsif( /^\s*#if\s+\((!?\s*defined\(.*)\)/ ) { + print "\n" if $blanks; + $dstr = $1; + $dstr =~ s/defined\(\s*(\w+)\s*\)/\$defs\{\1\}/go; + $newdef = eval $dstr; + &process_file( *F, $newok, $newdef, $level ); + } + elsif( /^\s*#\s*endif/ ) { + print "\n" if $blanks; + return; + } + elsif( /^\s*#\s*else/ ) { + print "\n" if $blanks; + $newok = $ok && ! $def; + } + elsif( /^\s*#\s*include/ ) { + # ignore #include statements lines + #print "\n"; + my $temp = $_; + chomp $temp; + print STDERR "\nPreprocessor warning: ignoring stmt: $temp"; + } + + elsif( /^\s*#\s*FPP_TEMPLATE_BEGIN/ ) { + # switch stdout to scratch file + *STDOUT_PREVIOUS = *STDOUT; + open( FTPLATE, ">$ftplate_file" ); + *STDOUT = *FTPLATE; + $template_count = 0; + undef @template_name; + undef @template_subs; + undef @template_junk; + undef @template_repl; + } + elsif( /^\s*#\s*FPP_TEMPLATE\s+<(\w+)>\s*=\s*(.*)$/ ) { + $template_name[$template_count] = $1; + $template_subs[$template_count] = $2; + $template_count++; + } + elsif( /^\s*#\s*FPP_TEMPLATE_END/ ) { + close(*FTPLATE); + # switch stdout back + *STDOUT = *STDOUT_PREVIOUS; + @template_junk = split( /;\s*/, $template_subs[0] ); + $template_copies = @template_junk; + for( $t=0; $t<$template_copies; $t++ ) { + for( $n=0; $n<$template_count; $n++ ) { + @template_junk = split( /;\s*/, $template_subs[$n] ); + $template_repl[$n] = $template_junk[$t]; + } + open( FTPLATE, "<$ftplate_file" ); + while( ) { + for( $n=0; $n<$template_count; $n++ ) { + s/<$template_name[$n]>/$template_repl[$n]/g; + } + print; + } + close(FTPLATE); + } + unlink $ftplate_file; + } + + elsif( /^\s*#\s*if/ || /^\s*#\s*elif/ + || /^\s*#\s*include/ || /^\s*#\s*line/ + || /^\s*#\s*error/ || /^\s*#\s*cpu/ + || /^\s*#\s*system/ || /^\s*#\s*assert/ + || /^\s*#\s*unassert/ || /^\s*#\s*ident/ + || /^\s*#\s*pragma/ || /^\s*#\s*elseif/ ) { + # error stop if any of these show up. + # any other lines starting with # are printed (if $newok) + print STDERR "Error: unsupported preproc stmt: $_\n"; + exit 1; + } + elsif( $newok ) { + + if( $macro_substitute ) { + # macro substitution + foreach $k (keys(%subs)) { + $val = $subs{$k}; + s/(^|\W)$k(\W|$)/\1${val}\2/; + } + } + + print; + } + else { + print "\n" if $blanks; + } + } +} + +exit; diff --git a/FortranPreProcess/target_sources.cmake b/FortranPreProcess/target_sources.cmake new file mode 100644 index 0000000..87c656f --- /dev/null +++ b/FortranPreProcess/target_sources.cmake @@ -0,0 +1,36 @@ +backup(target_sources) + +function(target_sources target tag linkage) + if(NOT tag STREQUAL "PREPROCESS") + previous_target_sources(${ARGV}) + return() + endif() + + foreach(arg IN LISTS ARGN) + if(arg STREQUAL "PUBLIC" + OR arg STREQUAL "PRIVATE" + OR arg STREQUAL "INTERFACE") + set(linkage ${arg}) + else() + if(NOT "${arg}" MATCHES ".*\.F([0-9][0-9])?$") + previous_target_sources(${target} PREPROCESS ${linkage} "${arg}") + return() + endif() + + file(RELATIVE_PATH path "${CMAKE_CURRENT_LIST_DIR}" "${arg}") + get_filename_component(directory "${path}" DIRECTORY) + file(MAKE_DIRECTORY "${LIST_BINARY_DIR}/${directory}") + + FortranPreProcess_filename("${path}" preprocessed_path) + + FortranPreProcess( + "${CMAKE_CURRENT_LIST_DIR}/${path}" + "${LIST_BINARY_DIR}/${preprocessed_path}" + DEFINE $ + INCLUDE $) + + previous_target_sources(${target} GENERATED ${linkage} + "${LIST_BINARY_DIR}/${preprocessed_path}") + endif() + endforeach() +endfunction() diff --git a/FunctionExtension.cmake b/FunctionExtension.cmake new file mode 100644 index 0000000..7b40d87 --- /dev/null +++ b/FunctionExtension.cmake @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "FunctionExtension" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "FunctionExtension") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/FunctionExtension" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +include(FunctionExtension/push) +include(FunctionExtension/pop) +include(FunctionExtension/call) +include(FunctionExtension/backup) +include(FunctionExtension/add_library) +include(FunctionExtension/add_executable) +include(FunctionExtension/set_property) +include(FunctionExtension/set_target_properties) +include(FunctionExtension/target_sources) +include(FunctionExtension/find_package) diff --git a/FunctionExtension/add_executable.cmake b/FunctionExtension/add_executable.cmake new file mode 100644 index 0000000..0d42ae8 --- /dev/null +++ b/FunctionExtension/add_executable.cmake @@ -0,0 +1,10 @@ +macro(previous_add_executable) + if(NOT previous_add_executable_fn) + set(previous_add_executable_fn add_executable) + endif() + + push(previous_add_executable_fn) + set(previous_add_executable_fn _${previous_add_executable_fn}) + call(${previous_add_executable_fn} "${ARGN}") + pop(previous_add_executable_fn) +endmacro() diff --git a/FunctionExtension/add_library.cmake b/FunctionExtension/add_library.cmake new file mode 100644 index 0000000..bbb85c7 --- /dev/null +++ b/FunctionExtension/add_library.cmake @@ -0,0 +1,10 @@ +macro(previous_add_library) + if(NOT previous_add_library_fn) + set(previous_add_library_fn add_library) + endif() + + push(previous_add_library_fn) + set(previous_add_library_fn _${previous_add_library_fn}) + call(${previous_add_library_fn} "${ARGN}") + pop(previous_add_library_fn) +endmacro() diff --git a/FunctionExtension/backup.cmake b/FunctionExtension/backup.cmake new file mode 100644 index 0000000..41cf39e --- /dev/null +++ b/FunctionExtension/backup.cmake @@ -0,0 +1,7 @@ +macro(backup func) + if(COMMAND _${func}) + backup(_${func}) + endif() + macro(_${func}) + endmacro() +endmacro() diff --git a/FunctionExtension/call.cmake b/FunctionExtension/call.cmake new file mode 100644 index 0000000..35836c6 --- /dev/null +++ b/FunctionExtension/call.cmake @@ -0,0 +1,12 @@ +macro(call function_name) + push(indirection_file) + set(indirection_file "${CMAKE_CURRENT_BINARY_DIR}/indirection") + while(EXISTS "${indirection_file}.cmake") + set(indirection_file "${indirection_file}_") + endwhile() + set(indirection_file "${indirection_file}.cmake") + file(WRITE "${indirection_file}" "${function_name}(${ARGN})") + include("${indirection_file}") + file(REMOVE "${indirection_file}") + pop(indirection_file) +endmacro() diff --git a/FunctionExtension/decrement.cmake b/FunctionExtension/decrement.cmake new file mode 100644 index 0000000..40aeece --- /dev/null +++ b/FunctionExtension/decrement.cmake @@ -0,0 +1,3 @@ +macro(decrement n) + MATH(EXPR ${n} "${${n}}-1") +endmacro() diff --git a/FunctionExtension/find_package.cmake b/FunctionExtension/find_package.cmake new file mode 100644 index 0000000..af002fe --- /dev/null +++ b/FunctionExtension/find_package.cmake @@ -0,0 +1,29 @@ +macro(previous_find_package) + push(arguments_modified) + set(arguments_modified FALSE) + + if(NOT previous_find_package_fn) + set(previous_find_package_fn find_package) + endif() + + push(previous_find_package_fn) + + if(NOT find_package_args STREQUAL "${ARGN}") + set(previous_find_package_fn find_package) + push(find_package_args) + set(find_package_args "${ARGN}") + set(arguments_modified TRUE) + set(previous_find_package_fn find_package) + else() + set(previous_find_package_fn _${previous_find_package_fn}) + endif() + + call(${previous_find_package_fn} ${ARGN}) + + if(arguments_modified) + pop(find_package_args) + endif() + + pop(arguments_modified) + pop(previous_find_package_fn) +endmacro() diff --git a/FunctionExtension/increment.cmake b/FunctionExtension/increment.cmake new file mode 100644 index 0000000..a77b426 --- /dev/null +++ b/FunctionExtension/increment.cmake @@ -0,0 +1,3 @@ +macro(increment n) + MATH(EXPR ${n} "${${n}}+1") +endmacro() diff --git a/FunctionExtension/pop.cmake b/FunctionExtension/pop.cmake new file mode 100644 index 0000000..2e8e89a --- /dev/null +++ b/FunctionExtension/pop.cmake @@ -0,0 +1,8 @@ +macro(pop variable_name) + if(DEFINED _${variable_name}) + set(${variable_name} "${_${variable_name}}") + pop(_${variable_name}) + else() + unset(${variable_name}) + endif() +endmacro() diff --git a/FunctionExtension/push.cmake b/FunctionExtension/push.cmake new file mode 100644 index 0000000..bed1352 --- /dev/null +++ b/FunctionExtension/push.cmake @@ -0,0 +1,8 @@ +macro(push variable_name) + if(DEFINED ${variable_name}) + if(DEFINED _${variable_name}) + push(_${variable_name}) + endif() + set(_${variable_name} "${${variable_name}}") + endif() +endmacro() diff --git a/FunctionExtension/set_property.cmake b/FunctionExtension/set_property.cmake new file mode 100644 index 0000000..e3f4536 --- /dev/null +++ b/FunctionExtension/set_property.cmake @@ -0,0 +1,10 @@ +macro(previous_set_property) + if(NOT previous_set_property_fn) + set(previous_set_property_fn set_property) + endif() + + push(previous_set_property_fn) + set(previous_set_property_fn _${previous_set_property_fn}) + call(${previous_set_property_fn} ${ARGN}) + pop(previous_set_property_fn) +endmacro() diff --git a/FunctionExtension/set_target_properties.cmake b/FunctionExtension/set_target_properties.cmake new file mode 100644 index 0000000..e88f63e --- /dev/null +++ b/FunctionExtension/set_target_properties.cmake @@ -0,0 +1,10 @@ +macro(previous_set_target_properties) + if(NOT previous_set_target_properties_fn) + set(previous_set_target_properties_fn set_target_properties) + endif() + + push(previous_set_target_properties_fn) + set(previous_set_target_properties_fn _${previous_set_target_properties_fn}) + call(${previous_set_target_properties_fn} ${ARGN}) + pop(previous_set_target_properties_fn) +endmacro() diff --git a/FunctionExtension/target_sources.cmake b/FunctionExtension/target_sources.cmake new file mode 100644 index 0000000..4498bb2 --- /dev/null +++ b/FunctionExtension/target_sources.cmake @@ -0,0 +1,10 @@ +macro(previous_target_sources) + if(NOT previous_target_sources_fn) + set(previous_target_sources_fn target_sources) + endif() + + push(previous_target_sources_fn) + set(previous_target_sources_fn _${previous_target_sources_fn}) + call(${previous_target_sources_fn} ${ARGN}) + pop(previous_target_sources_fn) +endmacro() diff --git a/GeneratedSources.cmake b/GeneratedSources.cmake new file mode 100644 index 0000000..a400a44 --- /dev/null +++ b/GeneratedSources.cmake @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "GeneratedSources" IN_LIST shacl.cmake.installed_modules) + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/GeneratedSources" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include(ListBinaryDir) +include(FunctionExtension) + +include_guard(GLOBAL) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +include(GeneratedSources/target_sources) +include(GeneratedSources/trap) diff --git a/GeneratedSources/README.md b/GeneratedSources/README.md new file mode 100644 index 0000000..ace333b --- /dev/null +++ b/GeneratedSources/README.md @@ -0,0 +1,47 @@ +## the SHACL Generated Sources module + +The intent of this CMake module is improve support for the use of source files +generated during the build step in library and executable targets. While CMake +provides out-of-the-box support for this task, the mechanics are obscure and +difficult to use correctly. + +In this module, the CMake `target_sources` intrinsics are extended to simplify +this process. The implementation of this functionality relies on an undocumented +behavior of CMake. Please see `documentation/function-extension.md` for more +information. + +In addition to the usual signature, this module provides an additional +signature. + +``` + target_sources( + GENERATED + [items1...] + [ [items2...] ...]) +``` + +Note the addition of the `GENERATED` keyword with respect to the traditional +`target_sources`. Adding generated sources using this signature will establish a +[custom target](https://cmake.org/cmake/help/latest/command/add_custom_target.html) +to ensure any +[custom command](https://cmake.org/cmake/help/latest/command/add_custom_command.html) +required to generate argument files (`item1...` and `item2...`) is executed, +even if the argument target was declared in another directory. Moreover, +generated files passed `target_sources` in this fashion are marked as generated +in all parent directories. + +Unfortunately, due to limitations in the `add_custom_target` function (as of the +time of writing) used in the implementation (and unlike the traditional +`target_sources`), generator expressions are not supported. + +These sources are only added to their respective target in the build interface. +If these sources need be available in the install interface, a second +(traditional) call to target sources is necessary, e.g., + +``` +target_sources(myTarget + GENERATED PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/example.hpp) + +target_sources(myTarget + PUBLIC $) +``` diff --git a/GeneratedSources/target_sources.cmake b/GeneratedSources/target_sources.cmake new file mode 100644 index 0000000..6246b89 --- /dev/null +++ b/GeneratedSources/target_sources.cmake @@ -0,0 +1,45 @@ +backup(target_sources) + +function(target_sources target tag linkage) + if(NOT ${tag} STREQUAL "GENERATED") + previous_target_sources(${ARGV}) + return() + endif() + + foreach(entry IN LISTS ARGN) + if(entry STREQUAL "PUBLIC" + OR entry STREQUAL "PRIVATE" + OR entry STREQUAL "INTERFACE") + set(linkage ${entry}) + else() + string(REGEX MATCH ".*[$]<.*>.*" generator_expression ${entry}) + if("${generator_expression}") + message(FATAL_ERROR + "Generator expressions are unavailable in GENERATED target_sources invocations") + endif() + + previous_target_sources(${target} ${linkage} "${entry}") + + get_filename_component(directory "${entry}" DIRECTORY) + get_filename_component(file "${entry}" NAME) + string(REPLACE "." "_" file "${file}") + + file(RELATIVE_PATH relative_path "${PROJECT_BINARY_DIR}" "${directory}") + string(SHA256 path_hash "${relative_path}") + + foreach(index RANGE 7 63) + string(SUBSTRING ${path_hash} 0 ${index} potential_hash) + set(custom_target ${target}.${potential_hash}.${file}) + if(NOT TARGET ${custom_target}) + break() + endif() + endforeach() + + add_custom_target(${custom_target} DEPENDS "${entry}") + set_target_properties(${custom_target} PROPERTIES FOLDER generated) + add_dependencies(${target} ${custom_target}) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.GeneratedSources.list "${entry}") + endif() + endforeach() +endfunction() diff --git a/GeneratedSources/trap.cmake b/GeneratedSources/trap.cmake new file mode 100644 index 0000000..7415d2d --- /dev/null +++ b/GeneratedSources/trap.cmake @@ -0,0 +1,14 @@ +function(shacl_cmake_GeneratedSources_trap _ access _ file) + if(access STREQUAL "MODIFIED_ACCESS" AND file MATCHES ".*CMakeLists[.]txt") + get_property(shacl.cmake.GeneratedSources.list + GLOBAL PROPERTY shacl.cmake.GeneratedSources.list) + + foreach(shacl.cmake.GeneratedSources.entry + IN LISTS shacl.cmake.GeneratedSources.list) + set_source_files_properties("${shacl.cmake.GeneratedSources.entry}" + PROPERTIES GENERATED ON) + endforeach() + endif() +endfunction() + +variable_watch(CMAKE_PARENT_LIST_FILE shacl_cmake_GeneratedSources_trap) diff --git a/Git/Submodule/Packages.cmake b/Git/Submodule/Packages.cmake new file mode 100644 index 0000000..32bb196 --- /dev/null +++ b/Git/Submodule/Packages.cmake @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.12.1) + +include("Git/Submodule/Packages/options") +include("Git/Submodule/Packages/configuration") +include("Git/Submodule/Packages/list") +include("Git/Submodule/Packages/init") +include("Git/Submodule/Packages/update") +include("Git/Submodule/Packages/package") +include("Git/Submodule/Packages/find_package") +include("Git/Submodule/Packages/check_version") +git_submodule_list() + +include_guard(DIRECTORY) +include("${CMAKE_CURRENT_LIST_DIR}/../../config.cmake") + +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Git/Submodule/Packages" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Git/Submodule/Packages") + + install(FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Git/Submodule) + + install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/Packages" + DESTINATION share/cmake/shacl/.cmake/Git/Submodule) + endif() + + unset(shacl.cmake.installed_modules) +endif() + diff --git a/Git/Submodule/Packages/README.md b/Git/Submodule/Packages/README.md new file mode 100644 index 0000000..2c8ba7f --- /dev/null +++ b/Git/Submodule/Packages/README.md @@ -0,0 +1,257 @@ +Git Submodule Packages +===== + +Quickstart +----- + +For the impatient, in order to incorporate this functionality into your CMake +project, add the following lines to your project's highest level +`CMakeLists.txt` before any call to `find_package`. + +```cmake +list(APPEND CMAKE_MODULE_PATH ) +include(Git/Submodule/Packages) +``` + +Thereafter, any call to `find_package` will be submodule-aware. + +Introduction +----- + +The intent of this CMake module to provide a means of managing, recording, +and sharing software dependency usage during software development. This module +leverages the git version control system's 'submodule' feature to express +dependencies between (potentially many layers) of CMake projects. + +For those unfamiliar with Git submodules (or would just appreciate a refresher), +an introduction to the feature is provided in the +[Git Submodules 101](README/git-submodules-101.md) file in the README directory. + +From the perspective of the author of a project CMake description, this module +provides an extension to the intrinsic `find_package` macro, providing +integration to allow git submodules to act as a back-end. + +Goals +----- + +The fundemental goal of this CMake module is to support the use of + ++ a modular repository structure ++ third party dependencies + +where + ++ system administration support is poor ++ external network access is unavailable ++ there exists no internal git hosting service + +Beyond that the module aims to + +1. be easily incorporated into existing projects +1. work within the existing vocabulary of CMake +1. improve software reproducibility +1. fallback gracefully to traditional `find_package` behavior +1. accomodate additional extension to the `find_package` behavior +1. avoid making life harder for the person packaging software + +Controlling Behavior +----- + +This module provides a number of CMake cache variables to tailor the extended +behavior of `find_package`. These cache variables are broken into two +categories: fine-grain and course-grain. + +#### Coarse Grain #### + +Coarse grain variables define the default and package-independent behavior. + +--- + ++ `git.submodule.packages` + + type: boolean + + default: `ON` + + condition: N/A + +This option allows an end user (meaning the person invoking CMake) to opt-out +of the use Git submodule usage in `find_package`. This option is useful for +those interested in packaging software with fixed version dependencies as part +of a larger ecosystem (as is conventional with Debian's `apt`, Red Hat's `dnf`, +or Microsoft's `vcpkg` package managers). + +----- + ++ `git.submodule.packages.cache` + + type: directory path + + default: `${CMAKE_BINARY_DIR}/git-submodule-packages` + + condition: `git.submodule.packages` + +During configuration, `find_package` will lazily clone any requested submodule +packages. This variable specifies a root directory to which any such repository +should be cloned (and later found). Note that this directory is, by default, in +the binary directory. This allows an end user to experiment using multiple build +configurations leveraging different dependency versions. + +This option is labeled as advanced and when `git.submodule.packages` is `OFF`, +this option does not appear in the cache. + +----- + ++ `git.submodule.packages.specification` + + type: file path + + default: N/A + + condition: N/A + +During each configuration, CMake will write a file recording the usage of Git +submodules (see the `git.submodule.packages.specification.output` variable). +These file can later be consumed to reproduce that environment. This variable +is used to specify the path to such a file, which will be used to reproduce +the described environment. + +----- + ++ `git.submodule.packages.specification.output` + + type: file path + + default: `${CMAKE_BINARY_DIR}/git-submodule-packages/specification.cmake` + + condition: `git.submodule.packages` + +During each configuration, CMake will write a file recording the usage of Git +submodules (see the `git.submodule.packages.specification.output` variable). +This includes an absolute url to each submodule remote and a corresponding Git +commit hash. These file can later be consumed to reproduce that environment. +This variable is used to specify the path to write this specification file. + +This option is labeled as advanced and when `git.submodule.packages` is `OFF`, +this option does not appear in the cache. + +----- + ++ `git.submodule.packages.update` + + type: boolean + + default: `ON` + + condition: `git.submodule.packages` + +This controls an aspect of behavior when working with Git submodules with an +associated branch. When `ON`, CMake will fast-forward the cloned dependency +repositories to the HEAD of their respective associated branches. + +This option is labeled as advanced and when `git.submodule.packages` is `OFF`, +this option does not appear in the cache. + +----- + ++ `git.submodule.packages.eager` + + type: boolean + + default: `ON` + + condition: `git.submodule.packages` + +When `ON`, the `find_package` command will eagerly consume dependencies via +Git submodule (when a corresponding submodule is available). When `OFF`, the +`find_package` command will first attempt to find a system installation of the +dependency, falling back to Git submodules only if a system installation could +not be found. + +When `git.submodule.packages` is `OFF`, this option does not appear in the +cache. + +---- + +#### Fine Grain #### + + +Fine grain variables allow users to specify behavior and inspect state on a +package-by-package basis. All fine-grain variables are marked as advanced to +avoid overwhelming newcomers. + +---- + ++ `git.submodule.package.` + + type: boolean + + default: `ON` + + condition: `git.submodule.packages` + +This option allows a user to opt-out of the use of a Git submodule associated +with a particular package. When `git.submodule.packages` is `OFF`, this option +does not appear in the cache. + +---- + ++ `git.submodule.package..branch` + + type: string + + default: see description + + condition: see description + +This string appears in the cache for submodules with an associated branch. This +variable is intended to be read-only and is meant for debugging. When +`git.submodule.packages` or `git.submodule.package.` is `OFF`, +this option does not appear in the cache. + +---- + ++ `git.submodule.package..eager` + + type: enumeration + + default: `default` + + values: `default`, `ON`, `OFF` + + condition: `git.submodule.package.` + +This is a package-specific analog to the `git.submodule.packages.eager` coarse +grain option. When set to default, this option reproduces the value specified in +the coarse grain option. Otherwise, when `ON`, the `find_package` command will +eagerly consume the package via Git submodule. When `OFF`, the `find_package` +command will first attempt to find a system installation of the dependency, +falling back to the Git submodule only if a system installation could not be +found. + +When `git.submodule.packages` or `git.submodule.package.` is +`OFF`, this option does not appear in the cache. + +---- + ++ `git.submodule.package..update` + + type: enumeration + + default: `default` + + values: `default`, `ON`, `OFF` + + condition: see description + +This is a package-specific analog to the `git.submodule.packages.update` coarse +grain option and only appears in the cache when +`git.submodule.package..branch` is populated. When set to default, +this option reproduces the value specified in the coarse grain option. +Otherwise, when `ON`, CMake will fast-forward the cloned dependency repository +to the HEAD of its associated branch. + +When `git.submodule.packages` or `git.submodule.package.` is +`OFF`, this option does not appear in the cache. + +---- + ++ `git.submodule.package..url` + + type: string + + default: see description + + condition: `git.submodule.package.` + +This string appears in the cache for each Git submodule. This variable is +intended to be read-only and is meant for debugging. When +`git.submodule.packages` or `git.submodule.package.` is `OFF`, +this option does not appear in the cache. + +---- + +Implementation +---- + +The implementation of the `find_package` command depends on a CMake developer +feature that allows for the extension and/or overwriting of CMake command. The +use of this functionality for purposes beyond debugging is controversial; +[Daniel Pfeifer](https://gitlab.kitware.com/purpleKarrot) (of +[Effective CMake](https://youtu.be/bsXLMQ6WgIk)) suggests this sort of extension +as a reasonable use of the facility, while +[Craig Scott](https://gitlab.kitware.com/craig.scott) (of +[Professional CMake](https://crascit.com/professional-cmake/)) +[discourages](https://crascit.com/2018/09/14/do-not-redefine-cmake-commands/) +this practice. + +For those siding with Scott, this module also provides an alternative command, +`git_submodule_package` which does not leverage developer features. This +command falls back to `find_package` when the git submodule package +functionality is disabled (via fine-grain or coarse-grain cache variables), but +otherwise does not interoperate with the intrinsic command. diff --git a/Git/Submodule/Packages/README/git-submodules-101.md b/Git/Submodule/Packages/README/git-submodules-101.md new file mode 100644 index 0000000..5e71081 --- /dev/null +++ b/Git/Submodule/Packages/README/git-submodules-101.md @@ -0,0 +1,235 @@ +### Git Submodules 101 ### + +#### Basics ##### + +Git submodules are effectingly a reference from one Git repository to a +particular state of another Git repository. This is reference is represented +in Git using + ++ a commit hash ++ a relative directory path ++ a remote uniform resource identifier (URI) ++ (optionally) an associated branch + +Here, a URI can be + ++ an http/https address ++ an ssh address ++ a file address ++ a relative address + +In the case of a relative address, Git internally computes an absolute address +for the submodule as needed. This is done by taking the submodule url to be +relative to a remote url. By default, the remote considered in the remote +associated with the current branch of the repository in which submodule resides. +In the case that current branch has no associated remote, `origin` is used +instead. + +> Relative URI's can very useful when working with a project leveraging a +> modular repository structure. Here, by modular structure, I mean a project +> which version controls individual components in separate repositories, which +> express interdependencies using git submodules. Using relative URI's for +> (at least) intra-project dependencies allows a project to migrate (or mirror) +> from one repository hosting platform (let's say Atlassian's bitbucket) to +> another platform (say Microsoft's Github) without modifying the submodule +> URIs. + +#### Adding New Submodules #### + +Git submodules are relatively painless to incorporate into a Git reposotory. +Here we consider a simple example adding three submodules. To begin let's +create a empty repository. + +``` +mkdir repo +cd repo +git init +git remote add origin ssh://git@xcp-stash.lanl.gov:7999/project/repo.git +``` + +We'll begin simply. Our first submodule will be Keith O'Hara's +[excellent constexpr math library](https://github.com/kthohr/gcem.git). + +``` +git submodule add https://github.com/kthohr/gcem.git +``` + +This submodule is + ++ associated with the current commit at the HEAD of the repository default +branch (master). ++ cloned into the `gcem` relative directory ++ using an https address referring to Github as a URI ++ not associated with any branch + +------ + +Our second submodule will be Phil Nash's +[excellent unit testing library](https://github.com/catchorg/Catch2.git). +This time, we'll associate the submodule with a branch and explicitly specify +a relative directory. + +``` +git submodule add -b master \ + https://github.com/catchorg/Catch2.git \ + dependencies/Catch2 +``` + +Note the addition of the `-b` argument. This flag indicates that the submodule +should track a branch (in this case, `master`). To summarize, this submodule + ++ associated with the current commit at the HEAD of master. ++ cloned into the `dependencies/Catch2` relative directory ++ using an https address referring to Github as a URI ++ is associated with the `Catch2` master branch + +----- + +Our last submodule will be Niels Lohmann's +[excellent JSON library](https://github.com/nlohmann/json.git). +In this case, in addition to explicitly specifying a relative directory, we'll +use a relative URI. + +``` +git submodule add ../../nlohmann/json.git dependencies/nlohmann_json +``` + +For this clone, this relative URI will be resolved against our demonstration +repostiory's orgin remote URI, i.e. +`ssh://git@xcp-stash.lanl.gov:7999/nlohmann/json.git`. + +> Note that the time of writing a mirror of Lohmann's library is maintained on +> the ADLX bitbucket instance and updated nightly. + +This submodule is + ++ associated with the current commit at the HEAD of the repository default +branch (master). ++ cloned into the `dependencies/nlohmann_json` relative directory ++ using a relative URI ++ not associated with any branch + +#### Updating Submodules #### + +As we've discussed, submodules are effectively a reference to a particular state +of another respository. Provided the upstream repository is still active, the +upstream submodule respository will continue to evolve, introducing additional +functionality, improoving performance, or resolving bugs. If our project is to +take advantage of that work, we need to update the state to which our submodule +refers. + +Let's begin by considering the `nlohmann_json` submodules described in the +previous section. The respository need by initialized, if it isn't already. + +``` +git submodule update --init -- dependencies/nlohmann_json +``` + +Given an initialized submodule, we can update the state to which the submodule +refers much as we would an ordinary Git repository. In this case, we'll update +the `dependencies/nlohmann_json` submodule to refer to the current HEAD of the +master branch of the remote. + +``` +# update the submodule +cd dependencies/nlohmann_json +git checkout master +git pull + +# commit the updated submodule reference +cd ../.. +git add dependencies/nlohmann_json +git commit -m "updated nlohmann_json submodule" +``` + +In the case of submodules which provide an associated branch, this reference +state can also be modified during the initialization. Let's consider the +`dependencies/Catch2` submodule, which specifies `master` as it's associated +branch. + +``` +git submodule update --init --remote -- dependencies/Catch2 +git add dependencies/Catch2 +git commit -m "updated Catch2 submodule" +``` + +For a project with many submodules, updating each individually (with either +procedure) can quickly become quite tedious. Naturally, Git provides facilities +for during these operations in bulk. + +In order to update each submodule with an associated branch, use the following +command: + +``` +git submodule deinit --force --all +git submodule update --init --remote +git commit -am "updated all branch tracking submodules" +``` + +In order to update each submodule (regardless of whether it has an associated +branch) to the head of master, use the following command. + +``` +git submodule deinit --force --all +git submodule update --init +git submodule foreach git checkout origin/master +git commit -am "updated all submodules to HEAD of master" +``` + +#### Inspecting the Submodule State ##### + +In any Git repository hosting submodules, in the highest level directory of the +repository, there should exist a `.gitmodules` file. Consider the following +example extracted from the `shacl::cmake` testing repository: + +``` +[submodule "dependencies/Catch2"] + path = dependencies/Catch2 + url = https://github.com/catchorg/Catch2.git + branch = master +[submodule "dependencies/nlohmann_json"] + path = dependencies/nlohmann_json + url = ../../nlohmann/json.git +``` + +Here we see two submodules. By default submodules are named by using their +respective relative path in the parent repository. There are a number of nested +fields (`path`, `url`, and `branch`) which correspond to components of the +submodule state. Note that, in this example, the `Catch2` submodule has an +associated branch (`master`) while the `nlohmann_json` submodule does not. + +Perceptive readers may have noticed that in the example `.gitmodules` file, +there is no field which corresponds the the associated commit hash for for +either submodule. This is not an oversight; the associated commit hash is not +stored in this file! + +The commit hash can be obtained a few ways. A simple way to query the associated +hash would be to intialize the submodule and query the result repository. Using +Catch2 as an example: + +``` +git submodule update --init -- dependencies/Catch2 +cd dependencies/Catch2 +git rev-parse HEAD +``` + +Sometimes it's useful to query this information without actually initializing +the submodule (e.g. the network is unavailable or the submodule is +time-consuming to clone). Surely we can query the parent repository? This is +information is in fact stored in the parent repository and, we do have access to +it. The submodule commit hash is stored as the index entry associated with the +submodule directory. Taking Catch2 for example: + +``` +git ls-tree HEAD dependencies/Catch2 +``` + +As of the time of writing, on the `shacl::cmake` testing repository, this +command has the following output: + +``` +160000 commit 60b05b20413afe4ad9980e627862474a9b8ba4cd dependencies/Catch2 +``` + +The third field in the output (`60b05b204`...) is the commit hash tracked by +the Catch2 module. diff --git a/Git/Submodule/Packages/check_version.cmake b/Git/Submodule/Packages/check_version.cmake new file mode 100644 index 0000000..77f8b7e --- /dev/null +++ b/Git/Submodule/Packages/check_version.cmake @@ -0,0 +1,138 @@ +macro(Git_Submodule_Packages_check_version) + +get_property(${git.submodule.packages.subject}_VERSION GLOBAL PROPERTY + ${git.submodule.packages.subject}_VERSION SET) + +if(NOT ${git.submodule.packages.subject}_VERSION) + push(CVF_VERSION_) + get_property(CVF_VERSION_ GLOBAL PROPERTY + git.submodule.package.${git.submodule.package.PROJECT_NAME}.CVF_VERSION SET) + if(CVF_VERSION_) + get_property(CVF_VERSION_ GLOBAL PROPERTY + git.submodule.package.${git.submodule.package.PROJECT_NAME}.CVF_VERSION) + set(git.submodule.package.PROJECT_VERSION "${CVF_VERSION_}") + string(REPLACE "." ";" CVF_VERSION_ "${CVF_VERSION_}") + + push(length) + list(LENGTH CVF_VERSION_ length) + list(GET CVF_VERSION_ 0 git.submodule.package.PROJECT_VERSION_MAJOR) + + if(length GREATER "1") + list(GET CVF_VERSION_ 1 git.submodule.package.PROJECT_VERSION_MINOR) + if(length GREATER "2") + list(GET CVF_VERSION_ 2 git.submodule.package.PROJECT_VERSION_PATCH) + if(length GREATER "3") + list(GET CVF_VERSION_ 3 git.submodule.package.PROJECT_VERSION_TWEAK) + endif() + endif() + endif() + pop(length) + endif() + pop(CVF_VERSION_) + + set(${git.submodule.packages.subject}_VERSION + "${git.submodule.package.PROJECT_VERSION}") + set_property(GLOBAL PROPERTY ${git.submodule.packages.subject}_VERSION + "${${git.submodule.packages.subject}_VERSION}") + + set(${git.submodule.packages.subject}_VERSION_MAJOR + "${git.submodule.package.PROJECT_VERSION_MAJOR}") + set_property(GLOBAL PROPERTY ${git.submodule.packages.subject}_VERSION_MAJOR + "${${git.submodule.packages.subject}_VERSION_MAJOR}") + + set(${git.submodule.packages.subject}_VERSION_MINOR + "${git.submodule.package.PROJECT_VERSION_MINOR}") + set_property(GLOBAL PROPERTY ${git.submodule.packages.subject}_VERSION_MINOR + "${${git.submodule.packages.subject}_VERSION_MINOR}") + + set(${git.submodule.packages.subject}_VERSION_PATCH + "${git.submodule.package.PROJECT_VERSION_PATCH}") + set_property(GLOBAL PROPERTY ${git.submodule.packages.subject}_VERSION_PATCH + "${${git.submodule.packages.subject}_VERSION_PATCH}") + + set(${git.submodule.packages.subject}_VERSION_TWEAK + "${git.submodule.package.PROJECT_VERSION_TWEAK}") + set_property(GLOBAL PROPERTY ${git.submodule.packages.subject}_VERSION_TWEAK + "${${git.submodule.packages.subject}_VERSION_TWEAK}") + + pop(git.submodule.package.PROJECT_VERSION) + pop(git.submodule.package.PROJECT_VERSION_MAJOR) + pop(git.submodule.package.PROJECT_VERSION_MINOR) + pop(git.submodule.package.PROJECT_VERSION_PATCH) + pop(git.submodule.package.PROJECT_VERSION_TWEAK) +else() + get_property(${git.submodule.packages.subject}_VERSION GLOBAL PROPERTY + ${git.submodule.packages.subject}_VERSION) + get_property(${git.submodule.packages.subject}_VERSION_MAJOR GLOBAL PROPERTY + ${git.submodule.packages.subject}_VERSION_MAJOR) + get_property(${git.submodule.packages.subject}_VERSION_MINOR GLOBAL PROPERTY + ${git.submodule.packages.subject}_VERSION_MINOR) + get_property(${git.submodule.packages.subject}_VERSION_PATCH GLOBAL PROPERTY + ${git.submodule.packages.subject}_VERSION_PATCH) + get_property(${git.submodule.packages.subject}_VERSION_TWEAK GLOBAL PROPERTY + ${git.submodule.packages.subject}_VERSION_TWEAK) +endif() + +if(PACKAGE_FIND_VERSION) + push(PACKAGE_VERSION_EXACT) + set(PACKAGE_VERSION_EXACT TRUE) + + push(PACKAGE_VERSION_COMPATIBLE) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + + push(CVF_COMPATIBILITY) + get_property(CVF_COMPATIBILITY_ GLOBAL PROPERTY + git.submodule.package.${git.submodule.package.PROJECT_NAME}.CVF_COMPATIBILITY) + + if(NOT ${git.submodule.packages.subject}_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_EXACT FALSE) + if(${git.submodule.packages.subject}_FIND_EXACT) + string(CONCAT message + "${git.submodule.packages.subject} version ${PACKAGE_FIND_VERSION} (exactly) requested\n" + "Found version ${${git.submodule.packages.subject}_VERSION} via submodule\n" + "Please update the ${git.submodule.packages.subject} repository located at: " + "${git.submodule.packages.cache}/${git.submodule.packages.subject}\n") + message(FATAL_ERROR "${message}") + elseif(${git.submodule.packages.subject}_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + string(CONCAT message + "${git.submodule.packages.subject} version ${PACKAGE_FIND_VERSION} requested\n" + "Found version ${${git.submodule.packages.subject}_VERSION} via submodule\n" + "Please update the ${git.submodule.packages.subject} repository located at: " + "${git.submodule.packages.cache}/${git.submodule.packages.subject}\n") + message(FATAL_ERROR "${message}") + elseif(CVF_COMPATIBILITY_ STREQUAL "ExactVersion") + string(CONCAT message + "${git.submodule.packages.subject} version ${PACKAGE_FIND_VERSION} requested\n" + "Found version ${${git.submodule.packages.subject}_VERSION} via submodule\n" + "${git.submodule.packages.subject} only provides compatibility within the same exact version\n" + "Please update the ${git.submodule.packages.subject} repository located at: " + "${git.submodule.packages.cache}/${git.submodule.packages.subject}\n") + message(FATAL_ERROR "${message}") + elseif(CVF_COMPATIBILITY_ STREQUAL "SameMajorVersion") + if(NOT ${git.submodule.packages.subject}_VERSION_MAJOR EQUAL PACKAGE_FIND_VERSION_MAJOR) + string(CONCAT message + "${git.submodule.packages.subject} version ${PACKAGE_FIND_VERSION} requested\n" + "Found version ${${git.submodule.packages.subject}_VERSION} via submodule\n" + "${git.submodule.packages.subject} only provides compatibility within the same major version\n" + "Please update the ${git.submodule.packages.subject} repository located at: " + "${git.submodule.packages.cache}/${git.submodule.packages.subject}\n") + message(FATAL_ERROR "${message}") + endif() + elseif(CVF_COMPATIBILITY_ STREQUAL "SameMinorVersion") + if(NOT ${git.submodule.packages.subject}_VERSION_MINOR EQUAL PACKAGE_FIND_VERSION_MINOR) + string(CONCAT message + "${git.submodule.packages.subject} version ${PACKAGE_FIND_VERSION} requested\n" + "Found version ${${git.submodule.packages.subject}_VERSION} via submodule\n" + "${git.submodule.packages.subject} only provides compatibility within the same minor version\n" + "Please update the ${git.submodule.packages.subject} repository located at: " + "${git.submodule.packages.cache}/${git.submodule.packages.subject}\n") + message(FATAL_ERROR "${message}") + endif() + endif() + endif() + pop(CVF_COMPATIBILITY_) + pop(PACKAGE_VERSION_COMPATIBLE) + pop(PACKAGE_VERSION_EXACT) +endif() + +endmacro() diff --git a/Git/Submodule/Packages/configuration.cmake b/Git/Submodule/Packages/configuration.cmake new file mode 100644 index 0000000..5622097 --- /dev/null +++ b/Git/Submodule/Packages/configuration.cmake @@ -0,0 +1,66 @@ +include_guard(GLOBAL) + +if(git.submodule.packages) + # + # We search for and require git iff git submodule packages are enabled. + # + find_package(Git REQUIRED) + + get_filename_component( + git.submodule.packages.specification_dir + "${git.submodule.packages.specification.output}" + DIRECTORY) + + file(MAKE_DIRECTORY + "${git.submodule.packages.cache}" + "${git.submodule.packages.specification_dir}") + + string(CONCAT git.submodule.packages.specification.content + "option(git.submodule.packages\n" + " \"Enable git submodule support for CMake find_package\" ON)\n" + "\n") + + file(WRITE "${git.submodule.packages.specification.output}" + "${git.submodule.packages.specification.content}") +endif() + +# +# We eavesdrop on a few project-related variables. +# +# When any variables are written to, we cache that value in a corresonding +# (name-mangled) variable in the parent-scope. If that parent-scope is the +# calling context of `find_package` or `git_submodule_package`, these +# variables are leveraged for version checking. +# +macro(git_submodule_packages_2ParentScope var access value) + if("${access}" STREQUAL "MODIFIED_ACCESS") + set(git.submodule.package.${var} "${value}" PARENT_SCOPE) + endif() +endmacro() + +variable_watch(PROJECT_NAME git_submodule_packages_2ParentScope) +variable_watch(PROJECT_VERSION git_submodule_packages_2ParentScope) +variable_watch(PROJECT_VERSION_MAJOR git_submodule_packages_2ParentScope) +variable_watch(PROJECT_VERSION_MINOR git_submodule_packages_2ParentScope) +variable_watch(PROJECT_VERSION_PATCH git_submodule_packages_2ParentScope) +variable_watch(PROJECT_VERSION_TWEAK git_submodule_packages_2ParentScope) + +# +# We also eavesdrop on a few variables written to when invoking +# `write_basic_package_version_file`. +# +# These variables are written to a, respective, project-specific global +# property. These are leveraged for version checking. +# +function(git_submodule_packages_2GlobalProperty var access value) + if("${access}" STREQUAL "MODIFIED_ACCESS") + set_property(GLOBAL PROPERTY git.submodule.package.${PROJECT_NAME}.${var} + "${value}") + endif() +endfunction() + +variable_watch(CVF_COMPATIBILITY git_submodule_packages_2GlobalProperty) +variable_watch(CVF_VERSION git_submodule_packages_2GlobalProperty) + +include(FunctionExtension) +include(DependentDelegatingOption) diff --git a/Git/Submodule/Packages/find_package.cmake b/Git/Submodule/Packages/find_package.cmake new file mode 100644 index 0000000..9c2509e --- /dev/null +++ b/Git/Submodule/Packages/find_package.cmake @@ -0,0 +1,241 @@ +include_guard(GLOBAL) + +backup(find_package) + +macro(find_package name) + # + # git.submodule.package. is dependent on git.submodule.package. Isn't + # the check of the git.submodule.package redundant? + # + # In a perfect world, it would be. Unfortunately, the dispatching + # implementation for dependent options, variables, and selections is based + # on the way directory scope variables shadow and hide cache variables. + # + # A consequence of this trivia is that, should a sibling dependencies include + # a shared dependency, with and without including the Git Submodule Packages + # module, the cache variable will be read by one and the directory variable + # by the other, leading to contradictory paths. + # + if(NOT (git.submodule.packages AND git.submodule.package.${name})) + previous_find_package(${ARGV}) + else() + # + # Used in conjunction with the git_submodule_packages_cache and + # variable_watch. See the Git/Submodule/Packages.cmake for more context. + # + push(git.submodule.packages.subject) + set(git.submodule.packages.subject "${name}") + push(PACKAGE_FIND_VERSION) + push(PACKAGE_FIND_VERSION_MAJOR) + push(PACKAGE_FIND_VERSION_MINOR) + if("${ARGV1}" MATCHES "[0-9]+(\\.[0-9])*") + set(PACKAGE_FIND_VERSION ${ARGV1}) + push(version_list) + string(REPLACE "." ";" version_list "${PACKAGE_FIND_VERSION}") + list(GET version_list 0 PACKAGE_FIND_VERSION_MAJOR) + if(NOT PACKAGE_FIND_VERSION_MAJOR) + set(PACKAGE_FIND_VERSION_MAJOR 0) + endif() + list(GET version_list 1 PACKAGE_FIND_VERSION_MINOR) + if(NOT PACKAGE_FIND_VERSION_MINOR) + set(PACKAGE_FIND_VERSION_MINOR 0) + endif() + pop(version_list) + else() + set(PACKAGE_FIND_VERSION "") + set(PACKAGE_FIND_VERSION_MAJOR "") + set(PACKAGE_FIND_VERSION_MINOR "") + endif() + + push(find_package_options) + set(find_package_options EXACT QUIET REQUIRED) + + push(find_package_singleValueArgs) + set(find_package_singleValueArgs) + + push(find_package_multiValueArgs) + set(find_package_multiValueArgs COMPONENTS OPTIONAL_COMPONENTS) + + push(${name}_FIND_EXACT) + push(${name}_FIND_QUIET) + push(${name}_FIND_REQUIRED) + push(${name}_FIND_COMPONENTS) + push(${name}_FIND_OPTIONAL_COMPONENTS) + + cmake_parse_arguments(${name}_FIND + "${find_package_options}" + "${find_package_singleValueArgs}" + "${find_package_multiValueArgs}" + ${ARGN}) + + pop(find_package_options) + pop(find_package_singleValueArgs) + pop(find_package_multiValueArgs) + + push(${name}_FIND_QUIETLY) + set(${name}_FIND_QUIETLY ${${name}_FIND_QUIET}) + + if(NOT DEFINED git.submodule.packages.quiet.${name}) + set(git.submodule.packages.quiet.${name} ${${name}_FIND_QUIET}) + endif() + + set(${name}_FOUND FALSE) + + push(continue) + set(continue TRUE) + + push(eager) + set(eager "${git.submodule.package.${name}.eager}") + + if(NOT eager) + push(EXACT_ARG) + if(${name}_FIND_EXACT) + set(EXACT_ARG EXACT) + else() + set(EXACT_ARG "") + endif() + + push(COMPONENTS_ARG) + if(${name}_FIND_COMPONENTS) + set(COMPONENTS_ARG COMPONENTS ${${name}_FIND_COMPONENTS}) + else() + set(COMPONENTS_ARG) + endif() + + push(OPTIONAL_COMPONENTS_ARG) + if(${name}_FIND_OPTIONAL_COMPONENTS) + set(OPTIONAL_COMPONENTS_ARG + OPTIONAL_COMPONENTS ${${name}_FIND_OPTIONAL_COMPONENTS}) + else() + set(OPTIONAL_COMPONENTS_ARG) + endif() + + previous_find_package(${name} + ${PACKAGE_FIND_VERSION} ${EXACT_ARG} + QUIET + ${COMPONENTS_ARG} + ${OPTIONAL_CONPONENT_ARG}) + + pop(EXACT_ARG) + pop(COMPONENTS_ARG) + pop(OPTIONAL_COMPONENTS_ARG) + + if(${name}_FOUND) + set(continue FALSE) + endif() + endif() + + if(continue) + push(git.submodule.package.${name}.traversed) + get_property(git.submodule.package.${name}.traversed GLOBAL PROPERTY + git.submodule.package.${name}.traversed) + if(git.submodule.package.${name}.traversed) + set(continue FALSE) + else() + set_property(GLOBAL PROPERTY git.submodule.package.${name}.traversed TRUE) + endif() + + push(git.submodule.package.${name}.traversed.components) + get_property(git.submodule.package.${name}.traversed.components + GLOBAL PROPERTY git.submodule.package.${name}.traversed.components) + + foreach(component IN LISTS ${name}_FIND_COMPONENTS) + if(component IN_LIST git.submodule.package.${name}.traversed.components) + list(REMOVE_ITEM ${name}_FIND_COMPONENTS component) + else() + set_property(GLOBAL APPEND PROPERTY + git.submodule.package.${name}.traversed.components ${component}) + push(${name}_FIND_REQUIRED_${component}) + set(${name}_FIND_REQUIRED_${component} TRUE) + endif() + endforeach() + + if(${name}_FIND_COMPONENTS) + set(continue TRUE) + endif() + + foreach(component IN LISTS ${name}_FIND_OPTIONAL_COMPONENTS) + if(component IN_LIST git.submodule.package.${name}.traversed.components) + list(REMOVE_ITEM ${name}_FIND_OPTIONAL_COMPONENTS component) + else() + set_property(GLOBAL APPEND PROPERTY + git.submodule.package.${name}.traversed.components ${component}) + push(${name}_FIND_REQUIRED_${component}) + set(${name}_FIND_REQUIRED_${component} FALSE) + endif() + endforeach() + + if(${name}_FIND_OPTIONAL_COMPONENTS) + set(continue TRUE) + endif() + + pop(git.submodules.package.${name}.traversed.components) + + if(continue) + if((NOT eager) AND (NOT git.submodule.packages.quiet.${name})) + message(STATUS "Failed to find local installation of ${name}.") + endif() + + if(NOT git.submodule.package.${name}.traversed) + git_submodule_init(${name} ${git.submodule.packages.quiet.${name}}) + git_submodule_update(${name} ${git.submodule.packages.quiet.${name}}) + endif() + + push(ALL_COMPONENTS) + set(ALL_COMPONENTS "") + list(APPEND ALL_COMPONENTS + ${${name}_FIND_COMPONENTS} + ${${name}_FIND_OPTIONAL_COMPONENTS}) + + push(${name}_FIND_COMPONENTS) + set(${name}_FIND_COMPONENTS ${ALL_COMPONENTS}) + pop(ALL_COMPONENTS) + + push(git.submodule.package.PROJECT_VERSION) + push(git.submodule.package.PROJECT_VERSION_MAJOR) + push(git.submodule.package.PROJECT_VERSION_MINOR) + push(git.submodule.package.PROJECT_VERSION_PATCH) + push(git.submodule.package.PROJECT_VERSION_TWEAK) + set(git.submodule.package.PROJECT_VERSION 0.0.0) + set(git.submodule.package.PROJECT_VERSION_MAJOR 0) + set(git.submodule.package.PROJECT_VERSION_MINOR 0) + set(git.submodule.package.PROJECT_VERSION_PATCH 0) + set(git.submodule.package.PROJECT_VERSION_TWEAK 0) + + add_subdirectory( + "${git.submodule.packages.cache}/${name}" + "${CMAKE_CURRENT_BINARY_DIR}/${name}") + + pop(${name}_FIND_COMPONENTS) + + set(${name}_FOUND TRUE) + endif() + + Git_Submodule_Packages_check_version() + pop(git.submodule.package.${name}.traversed) + endif() + + pop(continue) + pop(eager) + + foreach(component IN LISTS ${package}_FIND_COMPONENTS) + pop(${name}_FIND_REQUIRED_{component}) + endforeach() + pop(${name}_FIND_COMPONENTS) + + foreach(component IN LISTS ${package}_FIND_OPTIONAL_COMPONENTS) + pop(${package}_FIND_REQUIRED_{component}) + endforeach() + pop(${name}_FIND_OPTIONAL_COMPONENTS) + + pop(${package}_FIND_QUIETLY) + pop(${package}_FIND_REQUIRED) + pop(${package}_FIND_QUIET) + pop(${package}_FIND_EXACT) + pop(PACKAGE_FIND_VERSION) + pop(PACKAGE_FIND_VERSION_MAJOR) + pop(PACKAGE_FIND_VERSION_MINOR) + pop(git.submodule.packages.subject) + pop(git.submodule.package.${name}.compatibility) + endif() +endmacro() diff --git a/Git/Submodule/Packages/init.cmake b/Git/Submodule/Packages/init.cmake new file mode 100644 index 0000000..2b484ba --- /dev/null +++ b/Git/Submodule/Packages/init.cmake @@ -0,0 +1,50 @@ +include_guard(GLOBAL) + +function(git_submodule_init name) + set(source_dir "${git.submodule.packages.cache}") + set(QUIET ${ARGV1}) + + if(NOT EXISTS "${source_dir}/${name}/.git") + set(url "${git.submodule.package.${name}.url}") + + if(NOT url) + string(REPLACE "NEWLINE" "\n" message "${git.submodule.package.${name}.deferred_error}") + message(FATAL_ERROR "${message}") + endif() + + if(NOT QUIET) + message(STATUS "Cloning ${name} git submodule package...") + endif() + execute_process( + COMMAND "${GIT_EXECUTABLE}" clone "${url}" "${source_dir}/${name}" + OUTPUT_QUIET + RESULT_VARIABLE failure + ERROR_VARIABLE error_output) + + if(failure) + message("Encountered trouble while cloning ${name} git submodule package") + message("clone url: ${url}") + message(FATAL_ERROR "${error_output}") + endif() + + set(commit_hash "${git.submodule.package.${name}.hash.initial}") + if(NOT QUIET) + message(STATUS "Setting ${name} git submodule package to reference state...") + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" reset --hard "${commit_hash}" + WORKING_DIRECTORY "${source_dir}/${name}" + OUTPUT_QUIET + RESULT_VARIABLE failure + ERROR_VARIABLE error_output) + + if(failure) + message("Encountered trouble while checking out commit specified for ${name} git submodule package") + message("Commit hash: ${commit_hash}") + message(FATAL_ERROR "${error_output}") + endif() + + set(git.submodule.package.${name}.updated FALSE CACHE INTERNAL "" FORCE) + endif() +endfunction() diff --git a/Git/Submodule/Packages/list.cmake b/Git/Submodule/Packages/list.cmake new file mode 100644 index 0000000..b5a0401 --- /dev/null +++ b/Git/Submodule/Packages/list.cmake @@ -0,0 +1,432 @@ +include_guard(GLOBAL) + +macro(git_submodule_list) + # ** NOTE ** + # + # Variables which are expected to contain file or directory paths are + # dereferenced within quotes in order to accomodate whitespace characters + # in the path. A frequent offender in this regard are paths including + # the 'Program Files' directory found on the Windows operating system. + # + + # + # As a macro, an variables we define here are visible in the calling scope. + # Moreover, any changes we make to variables here are visible in the calling + # scope. In order to be polite, we cache the previous values of the variables + # used in the macro and restore them upon exit. + # + # So why go through the trouble of using a macro? Here we define a number of + # dependent options, selections, and variables. The implementation of these + # functions assume contingent decision making is in a shared scope. Declaring + # dependent variables in a CMake function would violate this assumption. + # + push(repository.root) + push(repository.branch) + push(repository.remote.name) + push(failure) + push(repository.remotes) + push(path_output) + push(repository.remote.url) + push(output) + push(line) + push(wordlist) + push(submodule.key) + push(truncate_point) + push(submodule.path.relative) + push(submodule.path.absolute) + push(submodule.name) + push(repository.index.entry) + push(submodule.commit_hash) + push(submodule.url) + push(repository.remote.url.prefix) + push(submodule.branch) + + # + # -------------------------------------------------------------------------- + # Step 1: Determine the repository remote url root for use with relative git + # submodule remote urls + # -------------------------------------------------------------------------- + # + + # + # Determine the highest level directory (aka root) of the git repository + # hosting the current source directory. + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" rev-parse --show-toplevel + OUTPUT_VARIABLE repository.root + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT EXISTS "${repository.root}" AND WIN32) + find_program(CYGPATH_EXECUTABLE NAMES cygpath cygpath.exe) + + if(CYGPATH_EXECUTABLE) + execute_process( + COMMAND "${CYGPATH_EXECUTABLE}" -w "${repository.root}" + OUTPUT_VARIABLE repository.root + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + endif() + + if(NOT EXISTS "${repository.root}") + message(FATAL_ERROR + "Could resolve git repository root directory: ${repository.root}") + endif() + + # + # Determine the current branch of the git repository hosting the current + # source directory. + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" rev-parse --abbrev-ref HEAD + OUTPUT_VARIABLE repository.branch + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_STRIP_TRAILING_WHITESPACE) + + # + # Determine the upstream remote name (e.g. origin) of the current branch of + # the git repository hosting the current source directory. This operation can + # fail if the current branch is not currently associated with a branch on the + # remote. + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" config --get branch.${repository.branch}.remote + OUTPUT_VARIABLE repository.remote.name + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE failure + OUTPUT_STRIP_TRAILING_WHITESPACE) + + # + # If the upstream remote name could not be determined by considering the + # corresponding git branch property, we examine the remotes for the repository + # as whole. If 'origin' is found amongst the available remote, it is assumed + # to be the appropriate remote. Otherwise, no remote is assumed. This + # replicates the behavior of git submodules. + # + if(failure) + # + # `git remote` returns a list of remote aliases (one per line). + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" remote + OUTPUT_VARIABLE repository.remotes + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_STRIP_TRAILING_WHITESPACE) + + # + # The output of `git remote` is converted to a cmake list by replacing + # newlines with semicolons (the cmake list's element delimiter character) + # + string(REPLACE "\n" ";" path_output "${repository.remotes}") + + # + # If origin is amongst the reported remote aliases, we declare success + # + if("origin" IN_LIST path_output) + set(repository.remote.name origin) + set(failure OFF) + endif() + endif() + + if(NOT failure) + # + # We query the git config for the url associated with the repository remote + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" config --get remote.${repository.remote.name}.url + OUTPUT_VARIABLE repository.remote.url + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_STRIP_TRAILING_WHITESPACE) + else() + set(repository.remote.url "") + endif() + + # + # -------------------------------------------------------------------------- + # Step 2: Collect a list of the git submodules associated with the repository. + # + # For each submodule, we collect the following information + # + # + name + # + commit hash + # + remote url + # + branch (optional) + # + # Beyond that, for each submodule, we establish variables + # + # + toggling the use of the submodule package + # + toggling eager submodule consumption + # + toggling submodule update mode + # + # -------------------------------------------------------------------------- + # + if(EXISTS "${repository.root}/.gitmodules") + # + # List the entries in the git module file with the phrase 'path' + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" config --file .gitmodules --get-regexp path + WORKING_DIRECTORY "${repository.root}" + OUTPUT_VARIABLE output + OUTPUT_STRIP_TRAILING_WHITESPACE) + + # + # Split the text output on newlines to form a list of lines. + # + string(REPLACE "\n" ";" output "${output}") + + foreach(line IN LISTS output) + # + # Split the line on whitespace. The result is a key-value pair, where + # the key is '.path' and the value is the path relative + # to the repository root directory. + # + string(REPLACE " " ";" wordlist "${line}") + + # + # Get the key and strip the '.path' component of the key to isolate the + # submodule key. + # + # *** NOTE *** + # We assume the submodule name does not embed white space. + # + list(GET wordlist 0 submodule.key) + string(FIND "${submodule.key}" ".path" truncate_point REVERSE) + string(SUBSTRING "${submodule.key}" 0 ${truncate_point} submodule.key) + + # + # We isolate that submodule relative path and construct the submodule + # absolute path + # + list(GET wordlist 1 submodule.path.relative) + set(submodule.path.absolute "${repository.root}/${submodule.path.relative}") + + # + # Only information on submodules that still exist in the repository is + # collected. + # + if (EXISTS "${submodule.path.absolute}") + # + # We recover the submodule project name by taking the last component + # of the submodule directory path. + # + # *** NOTE *** + # We assume the submodule project name does not contain forward slashes. + # + get_filename_component(submodule.name "${submodule.path.absolute}" NAME) + + # + # Provided the user has enabled git submodule packages, a fine-grained + # option allowing the user to opt out on a submodule-by-submodule basis. + # + dependent_delegating_option( + git.submodule.package.${submodule.name} + DOCSTRING "Use dependency submodule for ${submodule.name}" + DEFAULT git.submodule.packages + CONDITION git.submodule.packages + FALLBACK OFF) + + # + # There are potentially many submodule packages, each of which + # establishes multiple options. This can be somewhat overwhelming to + # a casual user when reviewing the cmake-gui or ccmake entry. + # + # Given the defaults have been chosen well, most users should only + # rarely need to consider these customization points. By marking these + # options as advanced, users can opt into the added flexibility (and + # corresponding complexity) as needed, but can generally remain + # blissfully unaware. + # + mark_as_advanced(git.submodule.package.${submodule.name}) + + # + # We collect the submodule commit hash by reviewing the corresponding + # git index entry. + # + # We establish two cache entries, one that stores the commit hash + # tracked by the parent respository and one that reflects the commit + # hash of the current state of the submodule in the binary tree. + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" ls-tree HEAD "${submodule.path.relative}" + WORKING_DIRECTORY "${repository.root}" + OUTPUT_VARIABLE repository.index.entry + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(repository.index.entry) + string(REPLACE " " ";" repository.index.entry "${repository.index.entry}") + string(REPLACE "\t" ";" repository.index.entry "${repository.index.entry}") + list(GET repository.index.entry 2 submodule.commit_hash) + + CMAKE_DEPENDENT_CACHE_VAR( + git.submodule.package.${submodule.name}.hash.initial + STRING + "Initial commit hash tracked by ${submodule.name} git submodule" + "${submodule.commit_hash}" + "git.submodule.package.${submodule.name}" + "") + + CMAKE_DEPENDENT_CACHE_VAR( + git.submodule.package.${submodule.name}.hash + STRING + "Current commit hash tracked by ${submodule.name} git submodule" + "${submodule.commit_hash}" + "git.submodule.package.${submodule.name}" + "") + + mark_as_advanced(git.submodule.package.${submodule.name}.hash.initial) + mark_as_advanced(git.submodule.package.${submodule.name}.hash) + endif() + # + # Collect the url associated with the submodule. + # + # If it is defined to be relative to the host repository, compute an + # absolute address using the repository remote computed in Step 1. If no + # repository remote could determined in Step 1, issue an error and cease + # to process. + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" config --file .gitmodules + --get "${submodule.key}.url" + WORKING_DIRECTORY "${repository.root}" + OUTPUT_VARIABLE submodule.url + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(submodule.url MATCHES "^[.][.][/]") + if(repository.remote.url) + set(repository.remote.url.prefix "${repository.remote.url}") + while(submodule.url MATCHES "^[.][.][/]") + string(FIND "${repository.remote.url.prefix}" "/" truncate_point REVERSE) + string(SUBSTRING "${repository.remote.url.prefix}" + 0 ${truncate_point} repository.remote.url.prefix) + string(SUBSTRING "${submodule.url}" 3 -1 submodule.url) + endwhile() + set(submodule.url "${repository.remote.url.prefix}/${submodule.url}") + else() + set(git.submodule.package.${submodule.name}.deferred_error + "${submodule.name} git submodule has a relative url: ${submodule.url}NEWLINE" + "${PROJECT_NAME} git repository branch, \"${repository.branch}\", does not establish a remoteNEWLINE" + "${PROJECT_NAME} git repository does not provide a remote named \"origin\"") + set(submodule.url "NOT_FOUND") + endif() + endif() + + # + # The repository url is exposed to the user in the cache for + # verification and to allow for the user to modify the value after the + # initial configure. The latter ability allows distinct build trees to + # reference distinct forks of a dependency (each of which may provide + # exclusive content) + # + CMAKE_DEPENDENT_CACHE_VAR( + git.submodule.package.${submodule.name}.url + STRING + "Remote url for ${submodule.name} git submodule" + "${submodule.url}" + "git.submodule.package.${submodule.name}" + "") + + mark_as_advanced(git.submodule.package.${submodule.name}.url) + + # + # We attempt to collect the branch tracked by the submodule. This can + # fail if the submodule doesn't track a branch (obviously). + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" config --file .gitmodules + --get "${submodule.key}.branch" + WORKING_DIRECTORY "${repository.root}" + OUTPUT_VARIABLE submodule.branch + RESULT_VARIABLE failure + OUTPUT_STRIP_TRAILING_WHITESPACE) + + # + # Iff the submodule tracks a branch we expose a cache variable to the + # user along with an update policy. + # + if(NOT failure) + CMAKE_DEPENDENT_CACHE_VAR( + git.submodule.package.${submodule.name}.branch + STRING + "Branch tracked by ${submodule.name} git submodule" + "${submodule.branch}" + "git.submodule.package.${submodule.name}" + "") + + mark_as_advanced(git.submodule.package.${submodule.name}.branch) + + # + # Three update model options are supported + # + # + default + # Fallback to the value specified by 'git.submodule.packages.update' + # cache variable + # + # + ON + # On the initial cmake configuration in which the submodule + # repository cloned, if the submodule tracks a branch, update the + # submodule respository to the HEAD of the branch + # + # + OFF + # Never update a submodule state + # + dependent_delegating_option( + git.submodule.package.${submodule.name}.update + DOCSTRING "${submodule.name} git submodule package configuration-time branch update behavior" + DEFAULT git.submodule.packages.update + CONDITION "git.submodule.package.${submodule.name}.branch" + FALLBACK "OFF") + + mark_as_advanced(git.submodule.package.${submodule.name}.update) + endif() + + # + # Three consumption options are supported for a given git submodule + # package. + # + # + default + # Fall back to the value specified by 'git.submodule.packages.eager' + # cache variable + # + # + ON + # Always use the git submodule package. + # + # + OFF + # Use the git submodule package iff the the package cannot be found + # through the underlying `find_package` utility + # + dependent_delegating_option( + git.submodule.package.${submodule.name}.eager + DOCSTRING "find_package will prefer to consume ${submodule.name} via submodule" + DEFAULT git.submodule.packages.eager + CONDITION "git.submodule.package.${submodule.name}" + FALLBACK "OFF") + + mark_as_advanced(git.submodule.package.${submodule.name}.eager) + endif() + endforeach() + endif() + + pop(repository.root) + pop(repository.branch) + pop(repository.remote.name) + pop(failure) + pop(repository.remotes) + pop(path_output) + pop(repository.remote.url) + pop(output) + pop(line) + pop(wordlist) + pop(submodule.key) + pop(truncate_point) + pop(submodule.path.relative) + pop(submodule.path.absolute) + pop(submodule.name) + pop(repository.index.entry) + pop(submodule.commit_hash) + pop(submodule.url) + pop(repository.remote.url.prefix) + pop(submodule.branch) +endmacro() diff --git a/Git/Submodule/Packages/options.cmake b/Git/Submodule/Packages/options.cmake new file mode 100644 index 0000000..d9fdf42 --- /dev/null +++ b/Git/Submodule/Packages/options.cmake @@ -0,0 +1,63 @@ +include_guard(DIRECTORY) + +include(CMakeDependentOption) +include(CMakeDependentCacheVar) + +# +# This option is intended to allow an end user to opt-out of the use of git +# submodule packages by toggling this option. +# +# Here we use 'end user' to mean the person invoking CMake, rather than a +# project including this module. +# +option(git.submodule.packages "Enable git submodule package support" ON) + +# +# This package supports the use of a file to reproduce previous +# configurations. We refer to these as specification files. +# +# Options in this cmake module are written in such a way that they +# will not override values specified at the command line or through +# a specification file. +# +CMAKE_DEPENDENT_CACHE_VAR(git.submodule.packages.specification + FILEPATH + "Path to consumed git submodule packages specification file" + "" + "git.submodule.packages" "") + +if(git.submodule.packages.specification) + if(NOT EXISTS "${git.submodule.packages.specification}") + message("git.submodule.packages.specification variable defined") + message("specification file path: ${git.submodule.packages.specification}") + message(FATAL_ERROR "No file exists at this path") + endif() + + include("${git.submodule.packages.specification}") +endif() + +CMAKE_DEPENDENT_OPTION(git.submodule.packages.eager + "find_package will prefer to consume dependencies via submodules when available" + ON "git.submodule.packages" OFF) + +CMAKE_DEPENDENT_OPTION(git.submodule.packages.update + "Update to head of branch-tracking submodules on first configuration" + ON "git.submodule.packages" OFF) + +mark_as_advanced(git.submodule.packages.update) + +CMAKE_DEPENDENT_CACHE_VAR(git.submodule.packages.cache + PATH + "Location for git submodule packages directory clones" + "${CMAKE_BINARY_DIR}/git-submodule-packages" + "git.submodule.packages" "") + +mark_as_advanced(git.submodule.packages.cache) + +CMAKE_DEPENDENT_CACHE_VAR(git.submodule.packages.specification.output + FILEPATH + "Location for generated git submodule packages specification file" + "${CMAKE_BINARY_DIR}/git-submodule-packages/specification.cmake" + "git.submodule.packages" "") + +mark_as_advanced(git.submodule.packages.specification.output) diff --git a/Git/Submodule/Packages/package.cmake b/Git/Submodule/Packages/package.cmake new file mode 100644 index 0000000..b09e001 --- /dev/null +++ b/Git/Submodule/Packages/package.cmake @@ -0,0 +1,112 @@ +include_guard(GLOBAL) + +include(ListBinaryDir) + +function(git_submodule_package name) + # + # If the user calls to this function without a corresponding git submodule, + # fail quickly. + # + if(NOT DEFINED git.submodule.package.${name}) + message(INFO "git_submodule_package called on package without a corresponding submodule in the repository") + message(INFO "requested package: ${name}") + message(FATAL_ERROR "No corresponding git submodule") + endif() + + if(NOT (git.submodule.packages AND git.submodule.package.${name})) + find_package(${ARGV}) + return() + endif() + + set(git.submodule.packages.subject "${name}") + if("${ARGV1}" MATCHES "[0-9]+(\\.[0-9])*") + set(PACKAGE_FIND_VERSION ${ARGV1}) + string(REPLACE "." ";" version_list "${PACKAGE_FIND_VERSION}") + list(GET version_list 0 PACKAGE_FIND_VERSION_MAJOR) + if(NOT PACKAGE_FIND_VERSION_MAJOR) + set(PACKAGE_FIND_VERSION_MAJOR 0) + endif() + list(GET version_list 1 PACKAGE_FIND_VERSION_MINOR) + if(NOT PACKAGE_FIND_VERSION_MINOR) + set(PACKAGE_FIND_VERSION_MINOR 0) + endif() + else() + set(PACKAGE_FIND_VERSION "") + set(PACKAGE_FIND_VERSION_MAJOR "") + set(PACKAGE_FIND_VERSION_MINOR "") + endif() + + set(find_package_options EXACT QUIET REQUIRED) + set(find_package_singleValueArgs) + set(find_package_multipleValueArgs COMPONENTS OPTIONAL_COMPONENTS) + + cmake_parse_arguments(${name}_FIND + "${find_package_options}" + "${find_package_singleValueArgs}" + "${find_package_multipleValueArgs}" + ${ARGN}) + + set(${name}_FIND_QUIETLY ${${name}_FIND_QUIET}) + set(continue FALSE) + + get_property(git.submodule.package.${name}.traversed GLOBAL PROPERTY + git.submodule.package.${name}.traversed) + + if(NOT git.submodule.package.${name}.traversed) + set_property(GLOBAL PROPERTY git.submodule.package.${name}.traversed TRUE) + git_submodule_init(${name}) + git_submodule_update(${name}) + set(continue TRUE) + endif() + + get_property(git.submodule.package.${name}.traversed.components + GLOBAL PROPERTY git.submodule.package.${name}.traversed.components) + + foreach(component IN LISTS ${name}_FIND_COMPONENTS) + if(component IN_LIST git.submodule.package.${name}.traversed.components) + list(REMOVE_ITEM ${name}_FIND_COMPONENTS component) + else() + set_property(GLOBAL APPEND PROPERTY + git.submodule.package.${name}.traversed.component ${component}) + set(${name}_FIND_REQUIRED_${component} TRUE) + endif() + endforeach() + + if(${name}_FIND_COMPONENTS) + set(continue TRUE) + endif() + + foreach(component IN LISTS ${name}_FIND_OPTIONAL_COMPONENTS) + if(component IN_LIST git.submodule.${name}.traversed.components) + list(REMOVE_ITEM ${name}_FIND_OPTIONAL_COMPONENTS component) + else() + set_property(GLOBAL APPEND PROPERTY + git.submodule.package.${name}.traversed.component ${component}) + set(${name}_FIND_REQUIRED_${component} FALSE) + endif() + endforeach() + + if(${name}_FIND_OPTIONAL_COMPONENTS) + set(continue TRUE) + endif() + + if(continue) + list(APPEND ${name}_FIND_COMPONENTS ${${name}_FIND_OPTIONAL_COMPONENTS}) + + set(git.submodule.package.PROJECT_VERSION 0.0.0) + set(git.submodule.package.PROJECT_VERSION_MAJOR 0) + set(git.submodule.package.PROJECT_VERSION_MINOR 0) + set(git.submodule.package.PROJECT_VERSION_PATCH 0) + set(git.submodule.package.PROJECT_VERSION_TWEAK 0) + add_subdirectory( + "${git.submodule.packages.cache}/${name}" + "${LIST_BINARY_DIR}/${name}") + endif() + + include(Git/Submodule/Packages/check_version) + + set(${name}_FOUND TRUE PARENT_SCOPE) + set(${name}_VERSION ${${name}_VERSION} PARENT_SCOPE) + set(${name}_VERSION_MAJOR ${${name}_VERSION_MAJOR} PARENT_SCOPE) + set(${name}_VERSION_MINOR ${${name}_VERSION_MINOR} PARENT_SCOPE) +endfunction() diff --git a/Git/Submodule/Packages/update.cmake b/Git/Submodule/Packages/update.cmake new file mode 100644 index 0000000..8bf0cab --- /dev/null +++ b/Git/Submodule/Packages/update.cmake @@ -0,0 +1,99 @@ +include_guard(GLOBAL) + +function(git_submodule_update name) + set(source_dir "${git.submodule.packages.cache}/${name}") + set(url "${git.submodule.package.${name}.url}") + set(QUIET ${ARGV1}) + + if(NOT DEFINED git.submodule.package.${name}.updated) + set(git.submodule.package.${name}.updated "TRUE") + endif() + + if(git.submodule.package.${name}.update + AND NOT git.submodule.package.${name}.updated) + + if(NOT QUIET) + message(STATUS "Fetching ${name} git submodule package upstream content...") + endif() + execute_process( + COMMAND "${GIT_EXECUTABLE}" fetch --tags + WORKING_DIRECTORY "${source_dir}" + OUTPUT_QUIET + RESULT_VARIABLE failure + ERROR_VARIABLE error_output) + + if(failure AND NOT QUIET) + message(WARNING "Encountered trouble while fetching from ${name} git submodule package remote repository\n") + message("${error_output}") + endif() + + set(branch "${git.submodule.package.${name}.branch}") + + if(NOT QUIET) + message(STATUS "Fast forwarding ${name} git submodule package to local HEAD of tracked branch...") + endif() + execute_process( + COMMAND "${GIT_EXECUTABLE}" checkout "${branch}" + WORKING_DIRECTORY "${source_dir}" + OUTPUT_QUIET + RESULT_VARIABLE failure + ERROR_VARIABLE error_output) + + if(failure) + message("Encountered trouble checking out ${name} git reference") + message("reference: ${branch}\n") + message("${error_output}") + message(FATAL_ERROR "Error while updating ${name} git submodule") + endif() + + if(NOT QUIET) + message(STATUS "Incorporating upstream changes to tracked branch...") + endif() + execute_process( + COMMAND "${GIT_EXECUTABLE}" pull + WORKING_DIRECTORY "${source_dir}" + OUTPUT_QUIET + RESULT_VARIABLE failure + ERROR_VARIABLE error_output) + + if(failure AND NOT QUIET) + message(WARNING "Encountered trouble while pulling from ${name} remote repository\n") + message("${error_output}") + endif() + + set(git.submodule.package.${name}.updated TRUE CACHE INTERNAL "" FORCE) + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD + WORKING_DIRECTORY "${source_dir}" + OUTPUT_VARIABLE commit_hash + OUTPUT_STRIP_TRAILING_WHITESPACE) + + set(git.submodule.package.${name}.hash + "${commit_hash}" + CACHE STRING + "Current commit hash tracked by ${name} git submodule" + FORCE) + + string(CONCAT content + "set(git.submodule.package.${name}.url \"${url}\"\n" + " CACHE STRING \"Remote url for ${name} git submodule\"\n" + " FORCE)\n" + "\n" + "set(git.submodule.package.${name}.hash.initial \"${commit_hash}\"\n" + " CACHE STRING \"Initial commit hash tracked by ${name} git submodule\"\n" + " FORCE)\n" + "\n" + "set(git.submodule.package.${name}.update OFF\n" + " CACHE BOOL \"${name} git submodule package configuration-time branch update behavior\"\n" + " FORCE)\n" + "\n" + "set(git.submodule.package.${name}.eager ON\n" + " CACHE STRING \"find_package will prefer to consume ${name} via submodule\"\n" + " FORCE)\n" + "\n") + + set(specification_file "${git.submodule.packages.specification.output}") + file(APPEND "${specification_file}" "${content}") +endfunction() diff --git a/Intel.cmake b/Intel.cmake new file mode 100644 index 0000000..730ae86 --- /dev/null +++ b/Intel.cmake @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Intel" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY shacl.cmake.installed_modules "Intel") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include(Intel/Fortran/Assumptions) +include(Intel/FloatingPoint/Model) +include(Intel/FloatingPoint/Speculation) diff --git a/Intel/FloatingPoint/Model.cmake b/Intel/FloatingPoint/Model.cmake new file mode 100644 index 0000000..3ecad1a --- /dev/null +++ b/Intel/FloatingPoint/Model.cmake @@ -0,0 +1,99 @@ +cmake_minimum_required(VERSION 3.12.1) + +if(DEFINED CMAKE_C_COMPILER) + if(NOT TARGET shacl::cmake::Intel::FloatingPoint::Model_C) + add_library(shacl::cmake::Intel::FloatingPoint::Model_C + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_C_COMPILER_ID STREQUAL "Intel") + set_property(TARGET shacl::cmake::Intel::FloatingPoint::Model_C + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Intel_FLOATING_POINT_MODEL) + endif() + + string(CONCAT shacl.cmake.Intel.FloatingPoint.Model.generator + "$<$>:" + "$<$:" + "$" + ",/fp$<1::>" + ",SHELL:-fp-model >" + "$>>") + + target_compile_options(shacl::cmake::Intel::FloatingPoint::Model_C + INTERFACE ${shacl.cmake.Intel.FloatingPoint.Model.generator}) + endif() +endif() + +if(DEFINED CMAKE_CXX_COMPILER) + if(NOT TARGET shacl::cmake::Intel::FloatingPoint::Model_CXX) + add_library(shacl::cmake::Intel::FloatingPoint::Model_CXX + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + set_property(TARGET shacl::cmake::Intel::FloatingPoint::Model_CXX + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Intel_FLOATING_POINT_MODEL) + endif() + + string(CONCAT shacl.cmake.Intel.FloatingPoint.Model.generator + "$<$>:" + "$<$:" + "$" + ",/fp$<1::>" + ",SHELL:-fp-model >" + "$>>") + + target_compile_options(shacl::cmake::Intel::FloatingPoint::Model_CXX + INTERFACE ${shacl.cmake.Intel.FloatingPoint.Model.generator}) + endif() +endif() + +if(DEFINED CMAKE_Fortran_COMPILER) + if(NOT TARGET shacl::cmake::Intel::FloatingPoint::Model_Fortran) + add_library(shacl::cmake::Intel::FloatingPoint::Model_Fortran + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") + set_property(TARGET shacl::cmake::Intel::FloatingPoint::Model_Fortran + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Intel_FLOATING_POINT_MODEL) + endif() + + string(CONCAT shacl.cmake.Intel.FloatingPoint.Model.generator + "$<$>:" + "$<$:" + "$" + ",/fp$<1::>" + ",SHELL:-fp-model >" + "$>>") + + target_compile_options(shacl::cmake::Intel::FloatingPoint::Model_Fortran + INTERFACE ${shacl.cmake.Intel.FloatingPoint.Model.generator}) + endif() +endif() + +unset(shacl.cmake.Intel.FloatingPoint.Model.generator) + +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Intel/FloatingPoint/Model" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Intel/FloatingPoint/Model") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Intel/FloatingPoint) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY Intel_FLOATING_POINT_MODEL +BRIEF_DOCS +"Intel Fortran floating point model" +FULL_DOCS +"This property specifies the Intel floating-point model to apply. +Options are: precise, fast[=1|2], consistent, strict, source") diff --git a/Intel/FloatingPoint/Speculation.cmake b/Intel/FloatingPoint/Speculation.cmake new file mode 100644 index 0000000..f2095d5 --- /dev/null +++ b/Intel/FloatingPoint/Speculation.cmake @@ -0,0 +1,99 @@ +cmake_minimum_required(VERSION 3.12.1) + +if(DEFINED CMAKE_C_COMPILER) + if(NOT TARGET shacl::cmake::Intel::FloatingPoint::Speculation_C) + add_library(shacl::cmake::Intel::FloatingPoint::Speculation_C + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_C_COMPILER_ID STREQUAL "Intel") + set_property(TARGET shacl::cmake::Intel::FloatingPoint::Speculation_C + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Intel_FLOATING_POINT_SPECULATION) + endif() + + string(CONCAT shacl.cmake.Intel.FloatingPoint.Speculation.generator + "$<$>:" + "$<$:" + "$" + ",/Qfp-speculation$<1::>" + ",SHELL:-fp-speculation >" + "$>>") + + target_compile_options(shacl::cmake::Intel::FloatingPoint::Speculation_C + INTERFACE ${shacl.cmake.Intel.FloatingPoint.Speculation.generator}) + endif() +endif() + +if(DEFINED CMAKE_CXX_COMPILER) + if(NOT TARGET shacl::cmake::Intel::FloatingPoint::Speculation_CXX) + add_library(shacl::cmake::Intel::FloatingPoint::Speculation_CXX + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + set_property(TARGET shacl::cmake::Intel::FloatingPoint::Speculation_CXX + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Intel_FLOATING_POINT_SPECULATION) + endif() + + string(CONCAT shacl.cmake.Intel.FloatingPoint.Speculation.generator + "$<$>:" + "$<$:" + "$" + ",/Qfp-speculation$<1::>" + ",SHELL:-fp-speculation >" + "$>>") + + target_compile_options(shacl::cmake::Intel::FloatingPoint::Speculation_CXX + INTERFACE ${shacl.cmake.Intel.FloatingPoint.Speculation.generator}) + endif() +endif() + +if(DEFINED CMAKE_Fortran_COMPILER) + if(NOT TARGET shacl::cmake::Intel::FloatingPoint::Speculation_Fortran) + add_library(shacl::cmake::Intel::FloatingPoint::Speculation_Fortran + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") + set_property(TARGET shacl::cmake::Intel::FloatingPoint::Speculation_Fortran + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Intel_FLOATING_POINT_SPECULATION) + endif() + + string(CONCAT shacl.cmake.Intel.FloatingPoint.Speculation.generator + "$<$>:" + "$<$:" + "$" + ",/Qfp-speculation$<1::>" + ",SHELL:-fp-speculation >" + "$>>") + + target_compile_options(shacl::cmake::Intel::FloatingPoint::Speculation_Fortran + INTERFACE ${shacl.cmake.Intel.FloatingPoint.Speculation.generator}) + endif() +endif() + +unset(shacl.cmake.Intel.FloatingPoint.Speculation.generator) + +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Intel/FloatingPoint/Speculation" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Intel/FloatingPoint/Speculation") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Intel/FloatingPoint) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY Intel_FLOATING_POINT_SPECULATION +BRIEF_DOCS +"Intel Fortran floating point speculation model" +FULL_DOCS +"This property specifies the Intel floating-point speculation approach. +Options are: fast, safe, strict, off") diff --git a/Intel/Fortran/Assumptions.cmake b/Intel/Fortran/Assumptions.cmake new file mode 100644 index 0000000..bf205c6 --- /dev/null +++ b/Intel/Fortran/Assumptions.cmake @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Intel/Fortran/Assumptions" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Intel/Fortran/Assumptions") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/Intel/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY Intel_Fortran_ENABLED_ASSUMPTIONS +BRIEF_DOCS +"Intel assumption keywords (for Fortran) to ensable" +FULL_DOCS +"This property contains zero or more entries specifying assumption options + used when compiling with the Intel Fortran compiler. Each entry corresponds + to an assumption keyword, e.g., specifying `buffered_io` will add the + `-assume buffered_io` or `/assume:buffered_io` flag as appropriate for + the host platform. + + Multiple entries must be semicolon separated e.g. unused;unused") + +define_property(TARGET PROPERTY Intel_Fortran_DISABLED_ASSUMPTIONS +BRIEF_DOCS +"Intel assumption keywords (for Fortran) to disable" +FULL_DOCS +"This property contains zero or more entries specifying assumption options + used when compiling with the Intel Fortran compiler. Each entry corresponds + to an assumption keyword, e.g., specifying `buffered_io` will add the + `-assume nobuffered_io` or `/assume:nobuffered_io` flag as appropriate for + the host platform. + + Multiple entries must be semicolon separated e.g. unused;unused") + +add_library(shacl::cmake::Intel::Fortran::Assumptions INTERFACE IMPORTED GLOBAL) + +string(CONCAT shacl.cmake.Intel.FortranAssumptions.generator + "$<$" + ",$>>:" + "$" + ",/assume$<1::>" + ",-assume;>" + "$" + ",$>>" + "$<$" + ",$>>:" + "$>" + ",$no" + ",$" + ",/assume$<1::>no" + ",-assume;no>>" + "$" + ",$no>>") + +target_compile_options(shacl::cmake::Intel::Fortran::Assumptions INTERFACE + ${shacl.cmake.Intel.FortranAssumptions.generator}) + +unset(shacl.cmake.Intel.FortranAssumptions.generator) diff --git a/IntelLLVM.cmake b/IntelLLVM.cmake new file mode 100644 index 0000000..087f723 --- /dev/null +++ b/IntelLLVM.cmake @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "IntelLLVM" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY shacl.cmake.installed_modules "IntelLLVM") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include(IntelLLVM/Fortran/Assumptions) +include(IntelLLVM/FloatingPoint/Model) +include(IntelLLVM/FloatingPoint/Speculation) diff --git a/IntelLLVM/FloatingPoint/Model.cmake b/IntelLLVM/FloatingPoint/Model.cmake new file mode 100644 index 0000000..90c7487 --- /dev/null +++ b/IntelLLVM/FloatingPoint/Model.cmake @@ -0,0 +1,99 @@ +cmake_minimum_required(VERSION 3.12.1) + +if(DEFINED CMAKE_C_COMPILER) + if(NOT TARGET shacl::cmake::IntelLLVM::FloatingPoint::Model_C) + add_library(shacl::cmake::IntelLLVM::FloatingPoint::Model_C + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM") + set_property(TARGET shacl::cmake::IntelLLVM::FloatingPoint::Model_C + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING IntelLLVM_FLOATING_POINT_MODEL) + endif() + + string(CONCAT shacl.cmake.IntelLLVM.FloatingPoint.Model.generator + "$<$>:" + "$<$:" + "$" + ",/fp$<1::>" + ",SHELL:-fp-model >" + "$>>") + + target_compile_options(shacl::cmake::IntelLLVM::FloatingPoint::Model_C + INTERFACE ${shacl.cmake.IntelLLVM.FloatingPoint.Model.generator}) + endif() +endif() + +if(DEFINED CMAKE_CXX_COMPILER) + if(NOT TARGET shacl::cmake::IntelLLVM::FloatingPoint::Model_CXX) + add_library(shacl::cmake::IntelLLVM::FloatingPoint::Model_CXX + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") + set_property(TARGET shacl::cmake::IntelLLVM::FloatingPoint::Model_CXX + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING IntelLLVM_FLOATING_POINT_MODEL) + endif() + + string(CONCAT shacl.cmake.IntelLLVM.FloatingPoint.Model.generator + "$<$>:" + "$<$:" + "$" + ",/fp$<1::>" + ",SHELL:-fp-model >" + "$>>") + + target_compile_options(shacl::cmake::IntelLLVM::FloatingPoint::Model_CXX + INTERFACE ${shacl.cmake.IntelLLVM.FloatingPoint.Model.generator}) + endif() +endif() + +if(DEFINED CMAKE_Fortran_COMPILER) + if(NOT TARGET shacl::cmake::IntelLLVM::FloatingPoint::Model_Fortran) + add_library(shacl::cmake::IntelLLVM::FloatingPoint::Model_Fortran + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM") + set_property(TARGET shacl::cmake::IntelLLVM::FloatingPoint::Model_Fortran + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING IntelLLVM_FLOATING_POINT_MODEL) + endif() + + string(CONCAT shacl.cmake.IntelLLVM.FloatingPoint.Model.generator + "$<$>:" + "$<$:" + "$" + ",/fp$<1::>" + ",SHELL:-fp-model >" + "$>>") + + target_compile_options(shacl::cmake::IntelLLVM::FloatingPoint::Model_Fortran + INTERFACE ${shacl.cmake.IntelLLVM.FloatingPoint.Model.generator}) + endif() +endif() + +unset(shacl.cmake.IntelLLVM.FloatingPoint.Model.generator) + +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "IntelLLVM/FloatingPoint/Model" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "IntelLLVM/FloatingPoint/Model") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/IntelLLVM/FloatingPoint) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY IntelLLVM_FLOATING_POINT_MODEL +BRIEF_DOCS +"IntelLLVM Fortran floating point model" +FULL_DOCS +"This property specifies the IntelLLVM floating-point model to apply. +Options are: precise, fast[=1|2], consistent, strict, source") diff --git a/IntelLLVM/FloatingPoint/Speculation.cmake b/IntelLLVM/FloatingPoint/Speculation.cmake new file mode 100644 index 0000000..a01d068 --- /dev/null +++ b/IntelLLVM/FloatingPoint/Speculation.cmake @@ -0,0 +1,99 @@ +cmake_minimum_required(VERSION 3.12.1) + +if(DEFINED CMAKE_C_COMPILER) + if(NOT TARGET shacl::cmake::IntelLLVM::FloatingPoint::Speculation_C) + add_library(shacl::cmake::IntelLLVM::FloatingPoint::Speculation_C + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM") + set_property(TARGET shacl::cmake::IntelLLVM::FloatingPoint::Speculation_C + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING IntelLLVM_FLOATING_POINT_SPECULATION) + endif() + + string(CONCAT shacl.cmake.IntelLLVM.FloatingPoint.Speculation.generator + "$<$>:" + "$<$:" + "$" + ",/Qfp-speculation$<1::>" + ",SHELL:-fp-speculation >" + "$>>") + + target_compile_options(shacl::cmake::IntelLLVM::FloatingPoint::Speculation_C + INTERFACE ${shacl.cmake.IntelLLVM.FloatingPoint.Speculation.generator}) + endif() +endif() + +if(DEFINED CMAKE_CXX_COMPILER) + if(NOT TARGET shacl::cmake::IntelLLVM::FloatingPoint::Speculation_CXX) + add_library(shacl::cmake::IntelLLVM::FloatingPoint::Speculation_CXX + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") + set_property(TARGET shacl::cmake::IntelLLVM::FloatingPoint::Speculation_CXX + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING IntelLLVM_FLOATING_POINT_SPECULATION) + endif() + + string(CONCAT shacl.cmake.IntelLLVM.FloatingPoint.Speculation.generator + "$<$>:" + "$<$:" + "$" + ",/Qfp-speculation$<1::>" + ",SHELL:-fp-speculation >" + "$>>") + + target_compile_options(shacl::cmake::IntelLLVM::FloatingPoint::Speculation_CXX + INTERFACE ${shacl.cmake.IntelLLVM.FloatingPoint.Speculation.generator}) + endif() +endif() + +if(DEFINED CMAKE_Fortran_COMPILER) + if(NOT TARGET shacl::cmake::IntelLLVM::FloatingPoint::Speculation_Fortran) + add_library(shacl::cmake::IntelLLVM::FloatingPoint::Speculation_Fortran + INTERFACE IMPORTED GLOBAL) + + if(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM") + set_property(TARGET shacl::cmake::IntelLLVM::FloatingPoint::Speculation_Fortran + APPEND PROPERTY COMPATIBLE_INTERFACE_STRING IntelLLVM_FLOATING_POINT_SPECULATION) + endif() + + string(CONCAT shacl.cmake.IntelLLVM.FloatingPoint.Speculation.generator + "$<$>:" + "$<$:" + "$" + ",/Qfp-speculation$<1::>" + ",SHELL:-fp-speculation >" + "$>>") + + target_compile_options(shacl::cmake::IntelLLVM::FloatingPoint::Speculation_Fortran + INTERFACE ${shacl.cmake.IntelLLVM.FloatingPoint.Speculation.generator}) + endif() +endif() + +unset(shacl.cmake.IntelLLVM.FloatingPoint.Speculation.generator) + +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "IntelLLVM/FloatingPoint/Speculation" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "IntelLLVM/FloatingPoint/Speculation") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/IntelLLVM/FloatingPoint) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY IntelLLVM_FLOATING_POINT_SPECULATION +BRIEF_DOCS +"IntelLLVM Fortran floating point speculation model" +FULL_DOCS +"This property specifies the IntelLLVM floating-point speculation approach. +Options are: fast, safe, strict, off") diff --git a/IntelLLVM/Fortran/Assumptions.cmake b/IntelLLVM/Fortran/Assumptions.cmake new file mode 100644 index 0000000..6a1a864 --- /dev/null +++ b/IntelLLVM/Fortran/Assumptions.cmake @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "IntelLLVM/Fortran/Assumptions" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "IntelLLVM/Fortran/Assumptions") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/IntelLLVM/Fortran) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +if(NOT DEFINED CMAKE_Fortran_COMPILER) + return() +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY IntelLLVM_Fortran_ENABLED_ASSUMPTIONS +BRIEF_DOCS +"IntelLLVM assumption keywords (for Fortran) to ensable" +FULL_DOCS +"This property contains zero or more entries specifying assumption options + used when compiling with the IntelLLVM Fortran compiler. Each entry corresponds + to an assumption keyword, e.g., specifying `buffered_io` will add the + `-assume buffered_io` or `/assume:buffered_io` flag as appropriate for + the host platform. + + Multiple entries must be semicolon separated e.g. unused;unused") + +define_property(TARGET PROPERTY IntelLLVM_Fortran_DISABLED_ASSUMPTIONS +BRIEF_DOCS +"IntelLLVM assumption keywords (for Fortran) to disable" +FULL_DOCS +"This property contains zero or more entries specifying assumption options + used when compiling with the IntelLLVM Fortran compiler. Each entry corresponds + to an assumption keyword, e.g., specifying `buffered_io` will add the + `-assume nobuffered_io` or `/assume:nobuffered_io` flag as appropriate for + the host platform. + + Multiple entries must be semicolon separated e.g. unused;unused") + +add_library(shacl::cmake::IntelLLVM::Fortran::Assumptions INTERFACE IMPORTED GLOBAL) + +string(CONCAT shacl.cmake.IntelLLVM.FortranAssumptions.generator + "$<$" + ",$>>:" + "$" + ",/assume$<1::>" + ",-assume;>" + "$" + ",$>>" + "$<$" + ",$>>:" + "$>" + ",$no" + ",$" + ",/assume$<1::>no" + ",-assume;no>>" + "$" + ",$no>>") + +target_compile_options(shacl::cmake::IntelLLVM::Fortran::Assumptions INTERFACE + ${shacl.cmake.IntelLLVM.FortranAssumptions.generator}) + +unset(shacl.cmake.IntelLLVM.FortranAssumptions.generator) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..237f5b8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,33 @@ +© (or copyright) 2019. Triad National Security, LLC. All rights reserved. +This program was produced under U.S. Government contract 89233218CNA000001 for Los Alamos +National Laboratory (LANL), which is operated by Triad National Security, LLC for the U.S. +Department of Energy/National Nuclear Security Administration. All rights in the program are +reserved by Triad National Security, LLC, and the U.S. Department of Energy/National Nuclear +Security Administration. The Government is granted for itself and others acting on its behalf a +nonexclusive, paid-up, irrevocable worldwide license in this material to reproduce, prepare +derivative works, distribute copies to the public, perform publicly and display publicly, and to permit +others to do so. + +This program is open source under the BSD-3 License. +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and +the following disclaimer. +2.Redistributions in binary form must reproduce the above copyright notice, this list of conditions +and the following disclaimer in the documentation and/or other materials provided with the +distribution. +3.Neither the name of the copyright holder nor the names of its contributors may be used to endorse +or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LinkOptions/StackSize.cmake b/LinkOptions/StackSize.cmake new file mode 100644 index 0000000..a4ba8c9 --- /dev/null +++ b/LinkOptions/StackSize.cmake @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.13.0) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/../config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "LinkOptions/StackSize" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "LinkOptions/StackSize") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake/LinkOptions) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/StackSize" + DESTINATION share/cmake/shacl/.cmake/LinkOptions) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +define_property(TARGET PROPERTY LINK_STACK_SIZE + BRIEF_DOCS "minimum link-time stack size in bytes to be set by the linker" + FULL_DOCS "minimum link-time stack size in bytes to be set by the linker") + +add_library(shacl::cmake::LinkOptions::StackSize INTERFACE IMPORTED GLOBAL) + +include(CheckLanguage) +check_language(Fortran) + +include(LinkOptions/StackSize/GNU) +include(LinkOptions/StackSize/Intel) +include(LinkOptions/StackSize/IntelLLVM) +include(LinkOptions/StackSize/PGI) +include(LinkOptions/StackSize/LLVM) +include(LinkOptions/StackSize/MSVC) diff --git a/LinkOptions/StackSize/GNU.cmake b/LinkOptions/StackSize/GNU.cmake new file mode 100644 index 0000000..1131c4b --- /dev/null +++ b/LinkOptions/StackSize/GNU.cmake @@ -0,0 +1,21 @@ +string(CONCAT shacl.cmake.LinkOptions.StackSize.generator + "$<$>," + "$>," + "$>," + "$>," + "$>," + "$>>:" + "$<$>:" + "$<$," + "$," + "$>:" + "-Wl$" + "$<$:-stack_size$>" + "$<$," + "$>:--stack$>" + "$>>>") + +target_link_options(shacl::cmake::LinkOptions::StackSize INTERFACE + ${shacl.cmake.LinkOptions.StackSize.generator}) + +unset(shacl.cmake.LinkOptions.StackSize.generator) diff --git a/LinkOptions/StackSize/Intel.cmake b/LinkOptions/StackSize/Intel.cmake new file mode 100644 index 0000000..01816d2 --- /dev/null +++ b/LinkOptions/StackSize/Intel.cmake @@ -0,0 +1,23 @@ +string(CONCAT shacl.cmake.LinkOptions.StackSize.generator + "$<$>," + "$>," + "$>," + "$>," + "$>," + "$>>:" + "$<$>:" + "$<$>:" + "$<$,$>:-Wl$" + "$<$:-stack_size$>" + "$<$:--stack$>" + "$" + ">" + ">" + "$<$:-STACK:$>" + ">" + ">") + +target_link_options(shacl::cmake::LinkOptions::StackSize INTERFACE + ${shacl.cmake.LinkOptions.StackSize.generator}) + +unset(shacl.cmake.LinkOptions.StackSize.generator) diff --git a/LinkOptions/StackSize/IntelLLVM.cmake b/LinkOptions/StackSize/IntelLLVM.cmake new file mode 100644 index 0000000..70da3b3 --- /dev/null +++ b/LinkOptions/StackSize/IntelLLVM.cmake @@ -0,0 +1,23 @@ +string(CONCAT shacl.cmake.LinkOptions.StackSize.generator + "$<$>," + "$>," + "$>," + "$>," + "$>," + "$>>:" + "$<$>:" + "$<$>:" + "$<$,$>:-Wl$" + "$<$:-stack_size$>" + "$<$:--stack$>" + "$" + ">" + ">" + "$<$:-STACK:$>" + ">" + ">") + +target_link_options(shacl::cmake::LinkOptions::StackSize INTERFACE + ${shacl.cmake.LinkOptions.StackSize.generator}) + +unset(shacl.cmake.LinkOptions.StackSize.generator) diff --git a/LinkOptions/StackSize/LLVM.cmake b/LinkOptions/StackSize/LLVM.cmake new file mode 100644 index 0000000..516f882 --- /dev/null +++ b/LinkOptions/StackSize/LLVM.cmake @@ -0,0 +1,30 @@ +string(CONCAT shacl.cmake.LinkOptions.StackSize.generator + "$<$>," + "$" + ">," + "$>," + "$," + "$" + ">" + ">," + "$>," + "$," + "$" + ">" + ">" + ">:" + "$<$>," + "$," + "$" + ">" + ">:-Wl$" + "$<$:-stack_size$>" + "$<$:--stack$>" + "$" + ">" + ">") + +target_link_options(shacl::cmake::LinkOptions::StackSize INTERFACE + ${shacl.cmake.LinkOptions.StackSize.generator}) + +unset(shacl.cmake.LinkOptions.StackSize.generator) diff --git a/LinkOptions/StackSize/MSVC.cmake b/LinkOptions/StackSize/MSVC.cmake new file mode 100644 index 0000000..a227e67 --- /dev/null +++ b/LinkOptions/StackSize/MSVC.cmake @@ -0,0 +1,11 @@ +string(CONCAT shacl.cmake.LinkOptions.StackSize.generator + "$<$>" + ",$>" + ",$>" + ",$>>:" + "$<$:-STACK:$>>") + +target_link_options(shacl::cmake::LinkOptions::StackSize INTERFACE + ${shacl.cmake.LinkOptions.StackSize.generator}) + +unset(shacl.cmake.LinkOptions.StackSize.generator) diff --git a/LinkOptions/StackSize/PGI.cmake b/LinkOptions/StackSize/PGI.cmake new file mode 100644 index 0000000..9898d69 --- /dev/null +++ b/LinkOptions/StackSize/PGI.cmake @@ -0,0 +1,20 @@ +string(CONCAT shacl.cmake.LinkOptions.StackSize.generator + "$<$>," + "$>," + "$>," + "$>," + "$>," + "$>>:" + "$<$>:" + "$<$,$>:-Wl$" + "$<$:-stack_size$>" + "$<$:--stack$>" + "$" + ">" + ">" + ">") + +target_link_options(shacl::cmake::LinkOptions::StackSize INTERFACE + ${shacl.cmake.LinkOptions.StackSize.generator}) + +unset(shacl.cmake.LinkOptions.StackSize.generator) diff --git a/ListBinaryDir.cmake b/ListBinaryDir.cmake new file mode 100644 index 0000000..7754d60 --- /dev/null +++ b/ListBinaryDir.cmake @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "ListBinaryDir" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "ListBinaryDir") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +function(LIST_BINARY_DIR_update variable access) + if(${access} STREQUAL UNKNOWN_READ_ACCESS OR + ${access} STREQUAL READ_ACCESS) + + file(RELATIVE_PATH + relative_path + "${CMAKE_SOURCE_DIR}" + "${CMAKE_CURRENT_LIST_DIR}") + + if(relative_path) + set(LIST_BINARY_DIR "${CMAKE_BINARY_DIR}/${relative_path}" PARENT_SCOPE) + else() + set(LIST_BINARY_DIR "${CMAKE_BINARY_DIR}" PARENT_SCOPE) + endif() + + endif() +endfunction() + +variable_watch(LIST_BINARY_DIR LIST_BINARY_DIR_update) diff --git a/README.md b/README.md new file mode 100644 index 0000000..c0fdc2f --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +# the shacl::cmake module repository + +## Introduction +This repository is intended to act as a shared collection of cmake modules for +use in shacl projects. The intent is that this repository will exist as a git +subtree in host projects. + +## Adding shacl::cmake to an existing git repository + +Given Git v1.7.11 or later, adding another repository as a subtree is a +straight-forward process. To start, ensure the host repository is in a clean +state, i.e., there are no uncommitted modifications to tracked content. + +``` +git status +``` + +If uncommitted modifications to tracked content exist, either record or discard +each modification as appropriate. + ++ recording modifications + +``` +git add ; git commit +``` + ++ discarding modifications + +``` +git checkout -- +``` + +Of course, on a fresh clone, no modifications will exist and this step can be +skipped. + +It's recommended to add the cmake subtree to highest level source directory of +the git repository. Once you've navigated there, the following command will +create a `cmake` directory and populate it with the contents of the master +branch of this repository. + +``` +git subtree add --prefix cmake /shacl/cmake.git master [--squash] +``` + +The `--squash` flag here is important for those who maintain a curated commit +log. Without this flag, the entire commit history of the `shacl::cmake` +repository would be appended to the host project directory. With this flag +specified, the `shacl::cmake` repository commit history is compressed to a +single commit in the host project. In either case, there will also be a merge +commit added to the log. + +## Using shacl::cmake + +Once the `shacl::cmake` subtree has been added to your repository, there's the +matter of exposing it's modules to the host CMake build system generator. +Navigate to the highest level source directory of the host repository and add +the following line to the the `CMakeLists.txt`. + +``` +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +``` + +There after `shacl::cmake` modules are available by way of the CMake `include` +function, e.g., + +``` +include(path/to/module) +``` + +## License + +See [license file.](./LICENSE) diff --git a/Sanitizers.cmake b/Sanitizers.cmake new file mode 100644 index 0000000..8e113e9 --- /dev/null +++ b/Sanitizers.cmake @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.12.1) + +include("${CMAKE_CURRENT_LIST_DIR}/Sanitizers/configuration.cmake") + +get_property(shacl.cmake.sanitizers.languages GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(language IN ITEMS C CXX Fortran) + if(language IN_LIST shacl.cmake.sanitizers.languages) + if(NOT TARGET shacl::cmake::Sanitizers_${language}) + string(CONCAT shacl.cmake.sanitizers.generator + "$<$" + ",$" + ",$>:" + "shacl::cmake::detail::sanitizers>") + + add_library(shacl::cmake::Sanitizers_${language} INTERFACE IMPORTED GLOBAL) + target_link_libraries(shacl::cmake::Sanitizers_${language} INTERFACE + ${shacl.cmake.sanitizers.generator}) + + unset(shacl.cmake.sanitizers.generator) + endif() + endif() +endforeach() +unset(shacl.cmake.sanitizers.languages) + +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Sanitizers" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Sanitizers") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + + install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/Sanitizers" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() diff --git a/Sanitizers/configuration.cmake b/Sanitizers/configuration.cmake new file mode 100644 index 0000000..5344aa0 --- /dev/null +++ b/Sanitizers/configuration.cmake @@ -0,0 +1,75 @@ +include_guard(GLOBAL) +define_property(TARGET PROPERTY asan + BRIEF_DOCS "Enable address sanitizer" + FULL_DOCS "AddressSanitizer (aka ASan) is a tool that detects memory error") + +define_property(TARGET PROPERTY msan + BRIEF_DOCS "Enable memory sanitizer" + FULL_DOCS "MemorySanitizer (aka MSan) is a tool that detects reads from uninitialized memory") + +define_property(TARGET PROPERTY tsan + BRIEF_DOCS "Enable thread sanitizer" + FULL_DOCS "ThreadSanitizer (aka TSan) is a tool that detects data races.") + +define_property(TARGET PROPERTY ubsan + BRIEF_DOCS "Enable undefined behavior sanitizer" + FULL_DOCS "UndefinedBehaviorSanitizer (aka UBSan) is a tool that detects undefined behavior") + +option(shacl.sanitizer.asan.default + "Default address sanitizer behavior (ON/OFF)" OFF) +mark_as_advanced(shacl.sanitizer.asan.default) + +option(shacl.sanitizer.msan.default + "Default memory sanitizer behavior (ON/OFF)" OFF) +mark_as_advanced(shacl.sanitizer.msan.default) + +option(shacl.sanitizer.tsan.default + "Default thread sanitizer behavior (ON/OFF)" OFF) +mark_as_advanced(shacl.sanitizer.tsan.default) + +option(shacl.sanitizer.ubsan.default + "Default undefined behavior sanitizer behavior (ON/OFF)" OFF) +mark_as_advanced(shacl.sanitizer.ubsan.default) + +add_library(shacl::cmake::detail::sanitizers INTERFACE IMPORTED GLOBAL) + +set(shacl.cmake.sanitizers.asan address) +set(shacl.cmake.sanitizers.msan memory) +set(shacl.cmake.sanitizers.tsan thread) +set(shacl.cmake.sanitizers.ubsan undefined) + +foreach(sanitizer IN ITEMS asan msan tsan ubsan) + string(CONCAT shacl.cmake.sanitizers.generator + "${shacl.cmake.sanitizers.generator}" + "$<$>" + ",$>:" + "-fsanitize=${shacl.cmake.sanitizers.${sanitizer}};" + "-fno-omit-frame-pointer;" + "-fno-sanitize-recover=all;>") +endforeach() + +unset(shacl.cmake.sanitizers.asan) +unset(shacl.cmake.sanitizers.msan) +unset(shacl.cmake.sanitizers.tsan) +unset(shacl.cmake.sanitizers.ubsan) + +target_compile_options(shacl::cmake::detail::sanitizers INTERFACE + ${shacl.cmake.sanitizers.generator}) + +target_link_libraries(shacl::cmake::detail::sanitizers INTERFACE + ${shacl.cmake.sanitizers.generator}) + +unset(shacl.cmake.sanitizer.generator) + +set_property(TARGET shacl::cmake::detail::sanitizers + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL asan) + +set_property(TARGET shacl::cmake::detail::sanitizers + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL msan) + +set_property(TARGET shacl::cmake::detail::sanitizers + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL tsan) + +set_property(TARGET shacl::cmake::detail::sanitizers + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL ubsan) + diff --git a/Selection.cmake b/Selection.cmake new file mode 100644 index 0000000..ef42c7d --- /dev/null +++ b/Selection.cmake @@ -0,0 +1,103 @@ +cmake_minimum_required(VERSION 3.12.1) +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Selection" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Selection") + + install( + FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) +function(selection variable) + set(OPTIONS) + set(UNARY_ARGUMENTS DEFAULT DOCSTRING) + set(VARIADIC_ARGUMENTS OPTIONS) + + set(arguments) + set(options) + foreach(argument IN LISTS ARGN) + if(argument STREQUAL "" # argument empty string + OR argument MATCHES ".*[ ].*" # argument with embedded whitespace + OR argument MATCHES ".*[;].*" # argument list + OR argument MATCHES ".*\".*") # argument with embedded quotation + list(APPEND arguments "\"${argument}\"") + else() + list(APPEND arguments "${argument}") + endif() + endforeach() + + cmake_parse_arguments(selection + "${OPTIONS}" + "${UNARY_ARGUMENTS}" + "${VARIADIC_ARGUMENTS}" ${arguments}) + + if(NOT DEFINED selection_OPTIONS) + message(FATAL_ERROR "selection invoked without 'OPTIONS' keyword") + endif() + + if(DEFINED selection_DEFAULT) + if(NOT selection_DEFAULT IN_LIST selection_OPTIONS) + string(CONCAT error_message + "selection invoked with 'DEFAULT' argument not present in 'OPTIONS' list\n" + "DEFAULT: ${selection_DEFAULT}\n\n" + "${variable} must be one of:") + foreach(option IN LISTS selection_OPTIONS) + string(CONCAT error_message "${error_message}\n" " ${option}") + endforeach() + message(FATAL_ERROR "${error_message}") + endif() + + if(selection_DEFAULT MATCHES "\"(.*)\"") + set(selection_DEFAULT "${CMAKE_MATCH_1}") + endif() + else() + set(selection_DEFAULT "" ) + if(NOT "\"\"" IN_LIST selection_OPTIONS) + list(APPEND selection_OPTIONS "\"\"") + endif() + endif() + + if(NOT DEFINED selection_DOCSTRING) + message(FATAL_ERROR + "selection invoked without 'DOCSTRING' argument") + endif() + if(selection_DOCSTRING MATCHES "\"(.*)\"") + set(selection_DOCSTRING "${CMAKE_MATCH_1}") + endif() + + if(DEFINED selection_UNPARSED_ARGUMENTS) + message(FATAL_ERROR + "selection invoked with unrecognized arguments: ${selection_UNPARSED_ARGUMENTS}") + endif() + + foreach(option IN LISTS selection_OPTIONS) + if(option MATCHES "\"(.*)\"") + set(option "${CMAKE_MATCH_1}") + endif() + + set(options "${options};${option}") + endforeach() + + set(${variable} "${selection_DEFAULT}" CACHE STRING ${selection_DOCSTRING}) + set_property(CACHE ${variable} PROPERTY STRINGS "${options}") + + if(NOT ${variable} IN_LIST options) + message("${variable} set to '${${variable}}'") + set(error_message "${variable} must be one of:") + foreach(option IN LISTS options) + string(CONCAT error_message "${error_message}\n" " ${option}") + endforeach() + message(FATAL_ERROR "${error_message}") + endif() +endfunction() diff --git a/Warnings.cmake b/Warnings.cmake new file mode 100644 index 0000000..a3b469d --- /dev/null +++ b/Warnings.cmake @@ -0,0 +1,129 @@ +cmake_minimum_required(VERSION 3.12.1) + +include(Warnings/C) +include(Warnings/CXX) +include(Warnings/Fortran) +include(Warnings/CUDA) + +include_guard(DIRECTORY) + +include("${CMAKE_CURRENT_LIST_DIR}/config.cmake") +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Warnings" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "Warnings") + + install(FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + + install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/Warnings" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + +include_guard(GLOBAL) + +define_property(TARGET PROPERTY WARN_ALL +BRIEF_DOCS +"Use all available warning flags subject to few or no false positives" +FULL_DOCS +"This boolean flag is used to provide a reasonably complete set of flags + for each compiler vendor for each language") + +define_property(TARGET PROPERTY WARN_ERROR +BRIEF_DOCS +"Treat warnings as errors" +FULL_DOCS +"When the boolean property is set, when supported by the compiler in use, + compiler warnings will result in a compilation errors") + +define_property(TARGET PROPERTY GNU_ENABLED_WARNINGS +BRIEF_DOCS +"GNU warning keywords flags" +FULL_DOCS +"This property contains zero or more entries specifying warning options + used when compiling with an GNU compiler. Each entry corresponds to a + warning keyword, e.g., specifying `strict-aliasing` will add the + `-Wstrict-aliasing` flag. + + Multiple entries must be semicolon separated e.g. unused;unused") + +define_property(TARGET PROPERTY GNU_DISABLED_WARNINGS +BRIEF_DOCS +"GNU warning keywords flags" +FULL_DOCS +"This property contains zero or more entries specifying warning options + used when compiling with an GNU compiler. Each entry corresponds to a + warning keyword, e.g., specifying `strict-aliasing` will add the + `-Wno-strict-aliasing` flag. + + Multiple entries must be semicolon separated e.g. unused;unused") + +define_property(TARGET PROPERTY LLVM_ENABLED_WARNINGS +BRIEF_DOCS +"LLVM warning keywords flags" +FULL_DOCS +"This property contains zero or more entries specifying warning options + used when compiling with an LLVM compiler. Each entry corresponds to a + warning keyword, e.g., specifying `strict-aliasing` will add the + `-Wno-strict-aliasing` flag. + + Multiple entries must be semicolon separated e.g. unused;unused") + +define_property(TARGET PROPERTY LLVM_DISABLED_WARNINGS +BRIEF_DOCS +"LLVM warning keywords flags" +FULL_DOCS +"This property contains zero or more entries specifying warning options + used when compiling with an LLVM compiler. Each entry corresponds to a + warning keyword, e.g., specifying `strict-aliasing` will add the + `-Wno-strict-aliasing` flag. + + Multiple entries must be semicolon separated e.g. unused;unused") + +define_property(TARGET PROPERTY MSVC_ENABLED_WARNINGS +BRIEF_DOCS +"MSVC warning keywords flags" +FULL_DOCS +"This property contains zero or more entries specifying warning options + used when compiling with an MSVC compiler. Each entry corresponds to a + warning keyword, e.g., specifying `4326` will add the `/we4326` flag. + + Multiple entries must be semicolon separated e.g. unused;unused") + +define_property(TARGET PROPERTY MSVC_DISABLED_WARNINGS +BRIEF_DOCS +"MSVC warning keywords flags" +FULL_DOCS +"This property contains zero or more entries specifying warning options + used when compiling with an MSVC compiler. Each entry corresponds to a + warning keyword, e.g., specifying `4326` will add the `/wd4326` flag. + + Multiple entries must be semicolon separated e.g. unused;unused") + +define_property(TARGET PROPERTY Intel_ENABLED_WARNINGS +BRIEF_DOCS +"Intel warning keywords flags" +FULL_DOCS +"This property contains zero or more entries specifying warning options + used when compiling with an Intel compiler. Each entry corresponds to a + warning keyword, e.g., specifying `uncalled` will add the `/warn:uncalled` + flag or `-warn uncalled` flag as appropriate for the host platform. + + Multiple entries must be semicolon separated e.g. unused;unused") + +define_property(TARGET PROPERTY Intel_DISABLED_WARNINGS +BRIEF_DOCS +"Intel warning keywords flags" +FULL_DOCS +"This property contains zero or more entries specifying warning options + used when compiling with an Intel compiler. Each entry corresponds to a + warning keyword, e.g., specifying `uncalled` will add the `/warn:no-uncalled` + flag or `-warn no-uncalled` flag as appropriate for the host platform. + + Multiple entries must be semicolon separated e.g. unused;unused") diff --git a/Warnings/C.cmake b/Warnings/C.cmake new file mode 100644 index 0000000..5e0ec0a --- /dev/null +++ b/Warnings/C.cmake @@ -0,0 +1,16 @@ +if(DEFINED CMAKE_C_COMPILER) + if(NOT TARGET shacl::cmake::Warnings_C) + add_library(shacl::cmake::Warnings_C INTERFACE IMPORTED GLOBAL) + include(Warnings/C/GNU) + include(Warnings/C/LLVM) + include(Warnings/C/MSVC) + include(Warnings/C/Intel) + include(Warnings/C/IntelLLVM) + + set_property(TARGET shacl::cmake::Warnings_C + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL WARN_ALL) + + set_property(TARGET shacl::cmake::Warnings_C + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL WARN_ERROR) + endif() +endif() diff --git a/Warnings/C/GNU.cmake b/Warnings/C/GNU.cmake new file mode 100644 index 0000000..23827a9 --- /dev/null +++ b/Warnings/C/GNU.cmake @@ -0,0 +1,19 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:-Werror>;" + "$<$>:" + "-Wall;" + "-Wextra;" + "-Wpedantic;" + "$<$,7.0>:-Wduplicated-branches;>" + "$<$,6.0>:-Wduplicated-cond;>>" + "$<$>:" + "-W$" + ",;-W>;>" + "$<$>:" + "-Wno-$" + ",;-Wno->;>") + +target_compile_options(shacl::cmake::Warnings_C INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/C/Intel.cmake b/Warnings/C/Intel.cmake new file mode 100644 index 0000000..fbc6046 --- /dev/null +++ b/Warnings/C/Intel.cmake @@ -0,0 +1,24 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:" + "$" + ",/WX" + ",-Werror>;>" + "$<$>:" + "$" + ",/W3" + ",-w2>;>" + "$<$>:" + "$" + ",/Qdiag-enable$<1::>" + ",-diag-enable=>" + "$,$>;>" + "$<$>:" + "$" + ",/Qdiag-disable$<1::>" + ",-diag-disable=>" + "$,$>;>") + +target_compile_options(shacl::cmake::Warnings_C INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/C/IntelLLVM.cmake b/Warnings/C/IntelLLVM.cmake new file mode 100644 index 0000000..a237470 --- /dev/null +++ b/Warnings/C/IntelLLVM.cmake @@ -0,0 +1,24 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:" + "$" + ",/WX" + ",-Werror>;>" + "$<$>:" + "$" + ",/Wall" + ",-Wall>;>" + "$<$>:" + "$" + ",/Qdiag-enable$<1::>" + ",-diag-enable=>" + "$,$>;>" + "$<$>:" + "$" + ",/Qdiag-disable$<1::>" + ",-diag-disable=>" + "$,$>;>") + +target_compile_options(shacl::cmake::Warnings_C INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/C/LLVM.cmake b/Warnings/C/LLVM.cmake new file mode 100644 index 0000000..9913d59 --- /dev/null +++ b/Warnings/C/LLVM.cmake @@ -0,0 +1,22 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:-Werror>;" + "$<$>:" + "-Wall;" + "-Wextra;" + "-Wpedantic;" + "-Wassign-enum;" + "-Wbad-function-cast;" + "-Wkeyword-macro;" + "-Wnonportable-system-include-path;" + "-Wsometimes-uninitialized;>" + "$<$>:" + "-W$" + ",;-W>;>" + "$<$>:" + "-Wno-$" + ",;-Wno->;>") + +target_compile_options(shacl::cmake::Warnings_C INTERFACE + $<$,$>:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/C/MSVC.cmake b/Warnings/C/MSVC.cmake new file mode 100644 index 0000000..0542faf --- /dev/null +++ b/Warnings/C/MSVC.cmake @@ -0,0 +1,15 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:/WX;>" + "$<$>:/W4;>" + "$<$>:" + "$<$>>:/W1;>" + "/w1$" + ",;/w1>;>" + "$<$>:" + "/wd$" + ",;/wd>;>") + +target_compile_options(shacl::cmake::Warnings_C INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/CUDA.cmake b/Warnings/CUDA.cmake new file mode 100644 index 0000000..dedb29a --- /dev/null +++ b/Warnings/CUDA.cmake @@ -0,0 +1,6 @@ +if(DEFINED CMAKE_CUDA_COMPILER) + if(NOT TARGET shacl::cmake::Warnings_CUDA) + add_library(shacl::cmake::Warnings_CUDA INTERFACE IMPORTED GLOBAL) + include(Warnings/CUDA/NVIDIA) + endif() +endif() diff --git a/Warnings/CUDA/NVIDIA.cmake b/Warnings/CUDA/NVIDIA.cmake new file mode 100644 index 0000000..41becc6 --- /dev/null +++ b/Warnings/CUDA/NVIDIA.cmake @@ -0,0 +1,12 @@ +string(CONCAT shacl.cmake.Warnings.generator + "-Xcompiler;" + "$>" + ",$>" + # We're assuming at least one flag is passed by the GENEX_EVAL + "$<$:$-Wno-pedantic>") + +target_compile_options(shacl::cmake::Warnings_CUDA INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/CXX.cmake b/Warnings/CXX.cmake new file mode 100644 index 0000000..f0375e4 --- /dev/null +++ b/Warnings/CXX.cmake @@ -0,0 +1,17 @@ +if(DEFINED CMAKE_CXX_COMPILER) + if(NOT TARGET shacl::cmake::Warnings_CXX) + add_library(shacl::cmake::Warnings_CXX INTERFACE IMPORTED GLOBAL) + include(Warnings/CXX/GNU) + include(Warnings/CXX/LLVM) + include(Warnings/CXX/MSVC) + include(Warnings/CXX/Intel) + include(Warnings/CXX/IntelLLVM) + + set_property(TARGET shacl::cmake::Warnings_CXX + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL WARN_ALL) + + set_property(TARGET shacl::cmake::Warnings_CXX + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL WARN_ERROR) + endif() +endif() + diff --git a/Warnings/CXX/GNU.cmake b/Warnings/CXX/GNU.cmake new file mode 100644 index 0000000..77311d3 --- /dev/null +++ b/Warnings/CXX/GNU.cmake @@ -0,0 +1,20 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:-Werror;>" + "$<$>:" + "-Wall;" + "-Wextra;" + "-Wpedantic;" + "-Wsuggest-override;" + "$<$,7.0>:-Wduplicated-branches;>" + "$<$,6.0>:-Wduplicated-cond;>>" + "$<$>:" + "-W$" + ",;-W>;>" + "$<$>:" + "-Wno-$" + ",;-Wno->;>") + +target_compile_options(shacl::cmake::Warnings_CXX INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/CXX/Intel.cmake b/Warnings/CXX/Intel.cmake new file mode 100644 index 0000000..7dfb8ac --- /dev/null +++ b/Warnings/CXX/Intel.cmake @@ -0,0 +1,24 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:" + "$" + ",/WX" + ",-Werror>;>" + "$<$>:" + "$" + ",/W3" + ",-w2>;>" + "$<$>:" + "$" + ",/Qdiag-enable$<1::>" + ",-diag-enable=>" + "$,$>;>" + "$<$>:" + "$" + ",/Qdiag-disable$<1::>" + ",-diag-disable=>" + "$,$>;>") + +target_compile_options(shacl::cmake::Warnings_CXX INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/CXX/IntelLLVM.cmake b/Warnings/CXX/IntelLLVM.cmake new file mode 100644 index 0000000..91d5757 --- /dev/null +++ b/Warnings/CXX/IntelLLVM.cmake @@ -0,0 +1,24 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:" + "$" + ",/WX" + ",-Werror>;>" + "$<$>:" + "$" + ",/Wall" + ",-Wall>;>" + "$<$>:" + "$" + ",/Qdiag-enable$<1::>" + ",-diag-enable=>" + "$,$>;>" + "$<$>:" + "$" + ",/Qdiag-disable$<1::>" + ",-diag-disable=>" + "$,$>;>") + +target_compile_options(shacl::cmake::Warnings_CXX INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/CXX/LLVM.cmake b/Warnings/CXX/LLVM.cmake new file mode 100644 index 0000000..758be7d --- /dev/null +++ b/Warnings/CXX/LLVM.cmake @@ -0,0 +1,24 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:-Werror;>" + "$<$>:" + "-Wall;" + "-Wextra;" + "-Wpedantic;" + "-Wassign-enum;" + "-Wbad-function-cast;" + "-Wkeyword-macro;" + "-Wnonportable-system-include-path;" + "-Wsometimes-uninitialized;" + "-Wnon-virtual-dtor;" + "-Wrange-loop-analysis;>" + "$<$>:" + "-W$" + ",;-W>;>" + "$<$>:" + "-Wno-$" + ",;-Wno->;>") + +target_compile_options(shacl::cmake::Warnings_CXX INTERFACE + $<$,$>:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/CXX/MSVC.cmake b/Warnings/CXX/MSVC.cmake new file mode 100644 index 0000000..0717712 --- /dev/null +++ b/Warnings/CXX/MSVC.cmake @@ -0,0 +1,15 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:/WX;>" + "$<$>:/W4;>" + "$<$>:" + "$<$>>:/W1;>" + "/w1$" + ",;/w1>;>" + "$<$>:" + "/wd$" + ",;/wd>;>") + +target_compile_options(shacl::cmake::Warnings_CXX INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/Fortran.cmake b/Warnings/Fortran.cmake new file mode 100644 index 0000000..5e6e378 --- /dev/null +++ b/Warnings/Fortran.cmake @@ -0,0 +1,14 @@ +if(DEFINED CMAKE_Fortran_COMPILER) + if(NOT TARGET shacl::cmake::Warnings_Fortran) + add_library(shacl::cmake::Warnings_Fortran INTERFACE IMPORTED GLOBAL) + include(Warnings/Fortran/GNU) + include(Warnings/Fortran/Intel) + include(Warnings/Fortran/IntelLLVM) + + set_property(TARGET shacl::cmake::Warnings_Fortran + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL WARN_ALL) + + set_property(TARGET shacl::cmake::Warnings_Fortran + APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL WARN_ERROR) + endif() +endif() diff --git a/Warnings/Fortran/GNU.cmake b/Warnings/Fortran/GNU.cmake new file mode 100644 index 0000000..42e8f96 --- /dev/null +++ b/Warnings/Fortran/GNU.cmake @@ -0,0 +1,19 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:-Werror;>" + "$<$>:" + "-Wall;" + "-Wextra;" + "-Wpedantic;" + "-Wcharacter-truncation;" + "-Wrealloc-lhs;" + "$<$:-Wno-surprising;>" + "-Wuse-without-only;>" + "$<$>:" + "-W$,;-W>;>" + "$<$>:" + "-Wno-$,;-Wno->;>") + +target_compile_options(shacl::cmake::Warnings_Fortran INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/Fortran/Intel.cmake b/Warnings/Fortran/Intel.cmake new file mode 100644 index 0000000..84a3c0b --- /dev/null +++ b/Warnings/Fortran/Intel.cmake @@ -0,0 +1,28 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$" + ",/warn$<1::>" + ",-warn;>") + +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:" + "${shacl.cmake.Warnings.generator}error$stderror>" + "$<$>:" + "$>" + ",$" + ",${shacl.cmake.Warnings.generator}>" + "all>;" + "$<$>:" + "$" + ",/Qdiag-enable$<1::>" + ",-diag-enable=>" + "$,$>;>" + "$<$>:" + "$" + ",/Qdiag-disable$<1::>" + ",-diag-disable=>" + "$,$>;>") + +target_compile_options(shacl::cmake::Warnings_Fortran INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/Warnings/Fortran/IntelLLVM.cmake b/Warnings/Fortran/IntelLLVM.cmake new file mode 100644 index 0000000..005415e --- /dev/null +++ b/Warnings/Fortran/IntelLLVM.cmake @@ -0,0 +1,28 @@ +string(CONCAT shacl.cmake.Warnings.generator + "$" + ",/warn$<1::>" + ",-warn;>") + +string(CONCAT shacl.cmake.Warnings.generator + "$<$>:" + "${shacl.cmake.Warnings.generator}error$stderror>" + "$<$>:" + "$>" + ",$" + ",${shacl.cmake.Warnings.generator}>" + "all>;" + "$<$>:" + "$" + ",/Qdiag-enable$<1::>" + ",-diag-enable=>" + "$,$>;>" + "$<$>:" + "$" + ",/Qdiag-disable$<1::>" + ",-diag-disable=>" + "$,$>;>") + +target_compile_options(shacl::cmake::Warnings_Fortran INTERFACE + $<$:${shacl.cmake.Warnings.generator}>) + +unset(shacl.cmake.Warnings.generator) diff --git a/config.cmake b/config.cmake new file mode 100644 index 0000000..efb983a --- /dev/null +++ b/config.cmake @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.13.0) + +if(NOT CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + set(shacl.cmake.is_subproject TRUE) +else() + set(shacl.cmake.is_subproject FALSE) +endif() + +if(shacl.cmake.is_subproject) + if(NOT DEFINED INSTALL_SUBPROJECTS) + option(INSTALL_SUBPROJECTS + "Perform full installation of subproject dependencies" ON) + endif() +endif() + +include_guard(DIRECTORY) + +if(NOT DEFINED shacl.cmake.installation) + set(shacl.cmake.installation "default" CACHE STRING + "Install to included shacl::cmake modules used by this project. + When set to 'default', shacl::cmake projects will be installed for + the highest level project and refer to the INSTALL_SUBPROJECTS cache + variable in subprojects") + + set_property(CACHE shacl.cmake.installation PROPERTY STRINGS default ON OFF) + mark_as_advanced(shacl.cmake.installation) +endif() + +if(shacl.cmake.installation STREQUAL "default") + if(shacl.cmake.is_subproject) + set(shacl.cmake.install "${INSTALL_SUBPROJECTS}") + else() + set(shacl.cmake.install ON) + endif() +endif() + +include_guard(GLOBAL) +if(shacl.cmake.installation) + install(FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) +endif() diff --git a/documentation/function-extension.md b/documentation/function-extension.md new file mode 100644 index 0000000..76846ed --- /dev/null +++ b/documentation/function-extension.md @@ -0,0 +1,51 @@ +## the SHACL function extension implementation + +In the CMake language, defining a function with the name as an existing +function is permitted. The new definition takes precedence when calling to the +function name, but the previous definition is accessible by way of a modified +name. + +``` + # new definition +_ # previous definition +``` + +By way of this mechanism, the previous functions definition is available to the +new definition allowing for behavior extension without duplication, i.e., +they allow for an (albeit unusual) implementation of the decorator pattern. + +Consider the following example. + +Given a definition of a function `foo` + +``` +function(foo) + message("this message comes from the original definition") +endfunction() +``` + +a function call `foo()` results in + +``` +this message comes from the original definition +``` + +We can redefine the `foo` function in such a way that it refers to +the original definition. + +``` +function(foo) + message("this message comes from the new definition") + _foo() +endfunction() +``` + +Thereafter, we can call `foo()`, just as before, but in this instance the output +has changed + +``` +this message comes from the new definition +this message comes from the original definition +``` + +Here we've augmented or 'decorated' the function. diff --git a/shacl-config.cmake b/shacl-config.cmake new file mode 100644 index 0000000..fa81f25 --- /dev/null +++ b/shacl-config.cmake @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.12.1) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/.cmake") + +if(shacl_FIND_QUIETLY) + set(shacl_FIND_QUIETLY_ARG QUIET) +endif() + +foreach(component IN LISTS shacl_FIND_COMPONENTS) + if(${component} STREQUAL "cmake") + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE) + else() + set(shacl_FOUND FALSE) # (partial) work around for bug in + # find_dependency macro in cmake < 3.15. + # For more information, see: + # https://github.com/Kitware/CMake/commit/37da6af17d0d2cc8b499dc58f74866351e06c288#diff-a8dbf85f500c956187a26a08846639f0 + + find_package(shacl-${component} + ${shacl_FIND_QUIETLY_ARG} + HINTS "${CMAKE_CURRENT_LIST_DIR}/../shacl-${component}") + + if(shacl_FIND_REQUIRED_${component} AND NOT shacl-${component}_FOUND) + string(CONCAT + shacl_NOT_FOUND_MESSAGE + "shacl could not be found because dependency ${component}" + " could not be found.") + set(shacl_FOUND False) + return() + endif() + endif() +endforeach() + +set(shacl_FOUND TRUE) diff --git a/shacl_FetchContent.cmake b/shacl_FetchContent.cmake new file mode 100644 index 0000000..5173f8d --- /dev/null +++ b/shacl_FetchContent.cmake @@ -0,0 +1,190 @@ +include_guard(GLOBAL) + +cmake_minimum_required(VERSION 3.24.0) + +cmake_policy(SET CMP0097 NEW) # Policy for GIT_SUBMODULES with empty arguments - won't download submodules when cloning + +# Turn off searching of CMAKE_INSTALL_PREFIX during calls to find_package +set(CMAKE_FIND_USE_INSTALL_PREFIX OFF CACHE BOOL "Disables find_package searching in CMAKE_INSTALL_PREFIX for dependencies") + +find_package(Git REQUIRED) +include("shacl_FetchContent/relative_git_url") +include("shacl_FetchContent/directory_git_info") + +include(FetchContent) + +# The wrapped FetchContent_MakeAvailable function only adds print statements +# for CMake clone progress and to aid in debugging dependency origins and keep user +# informed when lots of clones are happening +function(shacl_FetchContent_MakeAvailable name) + + # Check if package was already found or if its source directory was specified. + # If so, don't print diagnostic info. + # Note - if a package specifies by hand any of these variables in its cmake + # then the diagnostics may not get printed properly (i.e. pybind11) + FetchContent_GetProperties(${name} POPULATED ${name}_pre_makeavailable_fetched) + if (${name}_FOUND) + set(${name}_pre_makeavailable_found TRUE) + else() + set(${name}_pre_makeavailable_found FALSE) + endif() + + # Check if source directory was specified + # FETCHCONTENT uses upper-case names for some variables + string(TOUPPER ${name} uname) + if("${FETCHCONTENT_SOURCE_DIR_${uname}}" STREQUAL "") + set(sourceDirNotSpecified TRUE) + else() + set(sourceDirNotSpecified FALSE) + endif() + + set(${name}_already_found ${${name}_pre_makeavailable_fetched} OR ${${name}_pre_makeavailable_found}) + + if (${sourceDirNotSpecified} AND NOT (${${name}_already_found}})) + message(STATUS "Finding or fetching and configuring ${name}") + endif() + + FetchContent_MakeAvailable(${name}) + + FetchContent_GetProperties(${name} + SOURCE_DIR ${name}_source_dir + POPULATED ${name}_post_makeavailable_found + ) + + # It's possible that ${name}_post_makeavailable_found is TRUE because the package was found via find_package. + # In that case ${name}_source_dir was not defined. + # If both ${name}_post_makeavailable_found is TRUE and ${name}_source_dir was defined then the package was fetched. + set(${name}_post_makeavailable_found ${${name}_post_makeavailable_found} AND DEFINED ${name}_source_dir) + + if (${name_FOUND}) + if (${${name}_FOUND}) + set(${name}_found_via_find_package TRUE) + else() + set(${name}_found_via_find_package FALSE) + endif() + else() + set(${name}_found_via_find_package FALSE) + endif() + + if (NOT (${${name}_already_found}})) + if( ${${name}_post_makeavailable_found} AND NOT ${${name}_found_via_find_package} ) + message(STATUS "${name} fetched and configured") + # If Git information exists for the source directory then print and save it into cache variables + # This enables printing even when FETCHCONTENT_SOURCE_DIR_${NAME} was defined and is a git repo + cmake_path(APPEND ${name}_source_dir .git OUTPUT_VARIABLE ${name}_git_path) + message(STATUS " ${name} source dir: ${${name}_source_dir}") + if (EXISTS ${${name}_git_path}) + get_git_info_for_directory(${${name}_source_dir} return_url return_hash return_branch) + message(STATUS " ${name} repository: ${return_url}") + message(STATUS " ${name} branch/tag: ${return_branch}") + message(STATUS " ${name} hash: ${return_hash}") + + # Set cache variables and mark them as "ro" to indicate they're read-only + set(shacl_FetchContent.${name}.repository.ro ${return_url} CACHE STRING "The repository of ${name} that was fetched. Read only." FORCE) + set(shacl_FetchContent.${name}.tag.ro ${return_branch} CACHE STRING "The branch/tag of ${name} that was fetched, HEAD if hash was fetched. Read only." FORCE) + set(shacl_FetchContent.${name}.hash.ro ${return_hash} CACHE STRING "The hash of ${name} that was fetched. Read only." FORCE) + mark_as_advanced(shacl_FetchContent.${name}.repository.ro) + mark_as_advanced(shacl_FetchContent.${name}.tag.ro) + mark_as_advanced(shacl_FetchContent.${name}.hash.ro) + else() + message(STATUS " ${name} repository information not available.") + endif() + + elseif (${name}_FOUND) + message(STATUS "${name} found via installation and configured") + message(STATUS " ${name} dir: ${${name}_DIR}") + endif() + endif() + + # recursively call FetchContent_MakeAvailable on all arguments + # otherwise all fetching or finding is done with one call and + # a package-by-package status will not be available + list(LENGTH ARGN argn_len) + if (${argn_len} GREATER 0) + shacl_FetchContent_MakeAvailable(${ARGN}) + endif() + +endfunction() + +# The purpose of the wrapped FetchContent_Declare function is twofold: +# * Enabling relative GIT_REPOSITORY URLs to aid in automated testing or different host servers +# * Adding the appropriate arguments to FetchContent_Declare to avoid finding the dependency from different sources +function(shacl_FetchContent_Declare name) + + # FETCHCONTENT uses upper-case names for some variables + string(TOUPPER ${name} uname) + # Disable automatic post-fetch updates on a reconfigure for each package + set(FETCHCONTENT_UPDATES_DISCONNECTED_${uname} ON CACHE BOOL "Enables UPDATE_DISCONNECTED just for population of ${name}") + + # Option to enable force fetching via configuration + option(shacl_FetchContent.${name}.override_find_package "Force fetch of ${name} instead of first calling find_package" OFF) + + # copy argument list as methods like list(FIND...) don't work on ${ARGV} + set (args ${ARGV}) + + # Find where FIND_PACKAGE_ARGS is present in argument list (-1 if not present) + list(FIND args FIND_PACKAGE_ARGS find_pkg_index) + list(FIND args OVERRIDE_FIND_PACKAGE override_pkg_index) + + # If override_find_package (force fetching) is turned on then always fetch, never find. + # If force fetching then first remove FIND_PACKAGE_ARGS and all of the arguments. + # Then specify OVERRIDE_FIND_PACKAGE to force future calls to find_package to find the fetched version. + # If not force fetching then specify FIND_PACKAGE_ARGS if it wasn't present in the argument list to + # first attempt finding the dependency via a call to find_paackage before trying to fetch it. + # FIND_PACKAGE_ARGS also ensures that if the dependency was fetched then future calls to find_package will find the fetched dependency. + # If OVERRIDE_FIND_PACKAGE was specified in FetchContent_Declare then FIND_PACKAGE_ARGS is not added + if (${shacl_FetchContent.${name}.override_find_package}) + # Ignore everything after FIND_PACKAGE_ARGS + # FIND_PACKAGE_ARGS and its associated args must come at the end of + # the FetchContent_Declare function call so we can safely ignore everything after it + # if ${find_pkg_index} is -1 then arg_subset is equal to args + list(SUBLIST args 0 ${find_pkg_index} arg_subset) + # if OVERRIDE_FIND_PACKAGE is not present then add it + if (${override_pkg_index} EQUAL -1) + list(APPEND arg_subset OVERRIDE_FIND_PACKAGE) + endif() + else() # if not force fetching then call find_package first + set(arg_subset ${args}) + # if FIND_PACKAGE_ARGS is not present and OVERRIDE_FIND_PACKAGE was not specified then add FIND_PACKAGE_ARGS + if (${find_pkg_index} EQUAL -1 AND ${override_pkg_index} EQUAL -1) + list(APPEND arg_subset FIND_PACKAGE_ARGS) + endif() + endif() + + # If the dependency uses a relative path then it uses the same server as the host project. + # This is useful for automated testing with gitlab CI tokens or if repos are hosted on different servers + # e.g. if the project is hosted on github then pull all relative dependencies from github. + + # Find the GIT_REPOSITORY keyword then increment index to point to associated value + list(FIND arg_subset GIT_REPOSITORY git_repository_index) + math(EXPR git_repository_index "${git_repository_index}+1") + list(GET arg_subset ${git_repository_index} git_repository_url) + + # Update the git URL if it was a relative URL, otherwise return it unchanged + get_dependency_url(${git_repository_url} updated_url) + list(REMOVE_AT arg_subset ${git_repository_index}) + list(INSERT arg_subset ${git_repository_index} ${updated_url}) + + FetchContent_Declare(${arg_subset}) + +endfunction() + +# Installation of shacl_FetchContent module +if(shacl.cmake.installation) + get_property( + shacl.cmake.installed_modules GLOBAL PROPERTY shacl.cmake.installed_modules) + + if(NOT "Git/Submodule/Packages" IN_LIST shacl.cmake.installed_modules) + set_property(GLOBAL APPEND PROPERTY + shacl.cmake.installed_modules "shacl_FetchContent") + + install(FILES "${CMAKE_CURRENT_LIST_FILE}" + DESTINATION share/cmake/shacl/.cmake) + + install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/shacl_FetchContent" + DESTINATION share/cmake/shacl/.cmake) + endif() + + unset(shacl.cmake.installed_modules) +endif() + diff --git a/shacl_FetchContent/README.md b/shacl_FetchContent/README.md new file mode 100644 index 0000000..5ae796c --- /dev/null +++ b/shacl_FetchContent/README.md @@ -0,0 +1,98 @@ +shacl FetchContent +===== + +`shacl::cmake`'s FetchContent functions +`shacl_FetchContent_MakeAvailable` and `shacl_FetchContent_Declare` are +thin wrappers on top of the standard CMake 3.24+ implementation of +`FetchContent_Declare` and `FetchContent_MakeAvailable`. +The intent of this CMake module to provide a means of managing, recording, +and sharing software dependency usage during software development. This module +leverages features provided via CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html#fetchcontent) +while adjusting defaults to avoid surprises during code development. + +It provides the FetchContent capabilities for Git repositories with the following adjustments for a dependency with name : + * First tries to find the dependency via `find_package()` by default even if `FIND_PACKAGE_ARGS` was not specified in the call to `shacl_FetchContent_Declare`. + If wasn't found then it will be downloaded via a network connection from the specified `GIT_REPOSITORY`. + * Provides a configure-time variable `shacl.fetchcontent..override_find_package` to toggle force fetching of as though `OVERRIDE_FIND_PACKAGE` was specified. + * Enables relative URLs in the `GIT_REPOSITORY` argument + * Sets the default value of `FETCHCONTENT_UPDATES_DISCONNECTED_` to `ON` + * Prints information about where dependencies were found whether they were found via system install or fetched + +While CMake's FetchContent can be used to fetch things other than git repositories, +`shacl::cmake`'s FetchContent method should only be used when fetching git repositories. + +In order to incorporate this functionality into your CMake project, +add the following lines to your project's highest level `CMakeLists.txt`. + +```cmake +list(APPEND CMAKE_MODULE_PATH path/to/shacl-cmake) +include(shacl_FetchContent) +``` + +As noted in the [main documentation](../README.md), `shacl::cmake` is typically incorporated into projects via a git subtree. + +The following is a list of features and common use cases. +The other arguments to this function have the +[expected behavior of the standard CMake FetchContent functions] +(https://cmake.org/cmake/help/latest/module/FetchContent.html#fetchcontent), which can override the behaviors noted above. + +## Relative URLs +The `shacl_FetchContent_Declare` method enables use of relative URLs in the `GIT_REPOSITORY` argument. +Use of relative URLs relies on the project containing a .git repository with a remote with name "origin". +As an example, if the parent repository's "origin" remote URL is https://github.com/shacl/cmake.git and +`shacl_FetchContent_Declare` function contains `GIT_REPOSITORY ../../shacl/trait.git` then the +`GIT_REPOSITORY` key-value pair will be modified and passed to `FetchContent_Declare` as +`GIT_REPOSITORY https://github.com/shacl/trait.git`. + +## Integration with find_package +Since CMake 3.24, FetchContent can first try finding via a call to `find_package` with arguments +specified after `FIND_PACKAGE_ARGS` in the call to `shacl_FetchContent_Declare`. This is provided directly via +CMake's FetchContent commands. This module simply opts in to by default always call `find_package` first +unless `OVERRIDE_FIND_PACKAGE` is specified in the call to `shacl_FetchContent_Declare`. If `OVERRIDE_FIND_PACKAGE` +is specified then the package is fetched and future calls to `find_package` will find the fetched package. +`shacl_FetchContent` also provides a variable to opt-in to `OVERRIDE_FIND_PACKAGE` at configure time. +If `shacl.fetchcontent..override_find_package` is set to `ON` then it will act as though +`OVERRIDE_FIND_PACKAGE` was specified in `shacl_FetchContent_Declare` and will ignore `FIND_PACKAGE_ARGS` +if it was specified. By default `FetchContent_Declare` does not allow `FIND_PACKAGE_ARGS` to be specified +alongside `OVERRIDE_FIND_PACKAGE`, so this capability is unique to `shacl_FetchContent_Declare`. + + +## Updating or changing checked-out code +There are several ways to change the branch/tag. + +1) Change the `GIT_TAG` entry in the call to `shacl_FetchContent_Declare( ...)` either in the first configure or later configures with `FETCHCONTENT_UPDATES_DISCONNECTED_` set to `OFF`. +2) Navigate into the source directory where was cloned and check out a different branch. This can be done safely if `FETCHCONTENT_UPDATES_DISCONNECTED_` is set to `ON`. +3) Specify `FETCHCONTENT_SOURCE_DIR_=/path/to/source` where is in upper-case. + +The `shacl_FetchContent` module defaults `FETCHCONTENT_UPDATES_DISCONNECTED_` to `ON`. +This enables one to modify the code in the source directory and check out different branches without +the changes being overwritten or a different branch getting checked out. +The default behavior of `FetchContent_Declare` is to set this value to OFF, which on a CMake reconfigure +will check out the branch listed in the `GIT_TAG` argument. +To update the code to what is specified in the build system one can either navigate to 's source +directory and update the code there or set `FETCHCONTENT_UPDATES_DISCONNECTED_` to `OFF` to +have FetchContent update the branch from the git remote. +If `FETCHCONTENT_UPDATES_DISCONNECTED_` is set to `OFF` then one must have a connection available to the git repository remote +even if has been downloaded and is present in the `_deps` directory, otherwise the CMake configure will fail and the code in +the `_deps` directory will be deleted. + +## Viewing what was set during configure +The repository URL, git tag/branch, and git hash are all saved in +read-only CMake cache variables viewable in the CMakeCache.txt file. +The variables are `shacl.fetchcontent..repository.ro`, +`shacl.fetchcontent..tag.ro`, and `shacl.fetchcontent..hash.ro`, respectively. +Changing these variables will not affect the build system and any changes will be overwritten on the following configure. +They are only present to save what was checked out or present during the configure stage. +These variables will be updated after a reconfigure if the branch or commit is changed in the `_deps` directory. +This information will also be printed and cached if `FETCHCONTENT_SOURCE_DIR_` +is specified and the path pointed to by the variable has a git repository (.git directory). + +## Moving downloaded dependencies to a different machine +There are a few steps for moving downloaded dependencies (in the `_deps` directory by default) to a different machine. +This is useful for compilation on off-network machines. +1. Delete the build directories within `_deps` e.g. `rm -rf /path/to/_deps/*build`. +2. Move `_deps` directory to different machine. +3. Either copy `_deps` into the project's build directory or specify `FETCHCONTENT_SOURCE_DIR_` for each repository, pointing to 's respective path in the copied `_deps` directory. +4. If `_deps` was copied into the build directory either configure the project with `FETCHCONTENT_UPDATES_DISCONNECTED_` set to `ON` (default) or `FETCHCONTENT_FULLY_DISCONNECTED` set to `ON`. + +After following these steps the project should successfully configure. diff --git a/shacl_FetchContent/directory_git_info.cmake b/shacl_FetchContent/directory_git_info.cmake new file mode 100644 index 0000000..a1c9912 --- /dev/null +++ b/shacl_FetchContent/directory_git_info.cmake @@ -0,0 +1,53 @@ +include_guard(GLOBAL) +function(get_git_info_for_directory source_dir return_url return_hash return_branch) + + # Get remote url of origin + execute_process( COMMAND "${GIT_EXECUTABLE}" config --get remote.origin.url + WORKING_DIRECTORY "${source_dir}" + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE rc + OUTPUT_VARIABLE output + ERROR_VARIABLE error ) + + if( rc ) + string(CONCAT error_output + "Error encountered while obtaining repository url for fetched content in ${source_dir} \n" + "${output}" + "${error}" + ) + message(FATAL_ERROR "${error_output}") + endif() + + set(${return_url} ${output} PARENT_SCOPE) + + # Get hash of current branch + execute_process( COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD + WORKING_DIRECTORY "${source_dir}" + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE rc + OUTPUT_VARIABLE output + ERROR_VARIABLE error ) + + if( rc ) + string(CONCAT error_output + "Error encountered while obtaining repository url for fetched content in ${source_dir} \n" + "${output}" + "${error}" + ) + message(FATAL_ERROR "${error_output}") + endif() + + set(${return_hash} ${output} PARENT_SCOPE) + + # Get current tag or HEAD if not on a branch or tag + execute_process( COMMAND "${GIT_EXECUTABLE}" rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY "${source_dir}" + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE rc + OUTPUT_VARIABLE output + ERROR_VARIABLE error ) + + set(${return_branch} ${output} PARENT_SCOPE) + +endfunction() + diff --git a/shacl_FetchContent/relative_git_url.cmake b/shacl_FetchContent/relative_git_url.cmake new file mode 100644 index 0000000..fa438cf --- /dev/null +++ b/shacl_FetchContent/relative_git_url.cmake @@ -0,0 +1,45 @@ +include_guard(GLOBAL) + +# Gets the URL of the git remote with name origin +function(get_git_remote_url return_url) + execute_process( COMMAND "${GIT_EXECUTABLE}" config --get remote.origin.url + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE rc + OUTPUT_VARIABLE output + ERROR_VARIABLE error ) + + if( rc ) + string(CONCAT error_output + "FetchContent GIT_REPOSITORY listed with relative URL.\n" + "Error encountered while obtaining parent repository for ${PROJECT_NAME} URL for remote named origin \n" + "${output}" + "${error}" + ) + message(FATAL_ERROR "${error_output}") + endif() + + set(${return_url} ${output} PARENT_SCOPE) + +endfunction() + +# If the dependency contains relative paths (i.e. ../../proj/repo) then update +# the url relative to the current project's url +function(get_dependency_url input_url return_url) + + if(${input_url} MATCHES "^[.][.][/]") + get_git_remote_url(remote_url) + set(remote_url_prefix "${remote_url}") + while(${input_url} MATCHES "^[.][.][/]") + string(FIND "${remote_url_prefix}" "/" truncate_point REVERSE) + string(SUBSTRING "${remote_url_prefix}" 0 ${truncate_point} remote_url_prefix) + string(SUBSTRING "${input_url}" 3 -1 input_url) + endwhile() + set(retval "${remote_url_prefix}/${input_url}") + else() + set(retval "${input_url}") + endif() + + set(${return_url} ${retval} PARENT_SCOPE) + +endfunction() diff --git a/tests/Backports/CMakeLists.txt b/tests/Backports/CMakeLists.txt new file mode 100644 index 0000000..5005e8b --- /dev/null +++ b/tests/Backports/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(X11) diff --git a/tests/Backports/X11/CMakeLists.txt b/tests/Backports/X11/CMakeLists.txt new file mode 100644 index 0000000..33e06de --- /dev/null +++ b/tests/Backports/X11/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.12) + +project(test_find_package_x11 LANGUAGES CXX) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../..") +include(Backports/X11) + +find_package(X11) + +if(NOT X11_FOUND) + message(WARNING "X11 not found!") +endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..fc739ac --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.8.0) +project(shacl_cmake LANGUAGES C CXX Fortran VERSION 1.0.0) + +include(CheckLanguage) +check_language(CUDA) +if (CMAKE_CUDA_COMPILER) + enable_language(CUDA) +endif() + +include(CTest) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/..) + +include(CMakeDependentCacheVar) +include(Selection) +include(CMakeDependentSelection) + +CMAKE_DEPENDENT_CACHE_VAR(test_dependent_var STRING + "a variable used to test CMAKE_DEPEPENDENT_CACHE_VAR" + "hello" "NOT use_fallback" "world") + +selection(trafficLight DOCSTRING "color of light" DEFAULT red OPTIONS red yellow green) +selection(activity DOCSTRING "programmer activity" OPTIONS hotrocks sleep reddit) + +CMAKE_DEPENDENT_SELECTION(test_selection + "a variable used to test CMAKE_DEPENDENT_SELECTION" + DEFAULT red OPTIONS red yellow green + CONDITION "NOT selection_fallback" green) + +#add_subdirectory(Backports) +add_subdirectory(Fortran) +add_subdirectory(FortranPreProcess) +add_subdirectory(Intel) +add_subdirectory(LinkOptions) +add_subdirectory(GeneratedSources) +add_subdirectory(Sanitizers) +# add_subdirectory(Git/Submodule/Packages) +add_subdirectory(shacl_FetchContent) +add_subdirectory(DependencyInjection) +add_subdirectory(Warnings) +add_subdirectory(DelegatingCacheVariable) +add_subdirectory(DelegatingOption) +add_subdirectory(DelegatingSelection) +add_subdirectory(DependentDelegatingCacheVariable) +add_subdirectory(DependentDelegatingOption) +add_subdirectory(DependentDelegatingSelection) + +# KEEP THIS AT THE BOTTOM +add_subdirectory(FunctionExtension) diff --git a/tests/DelegatingCacheVariable/CMakeLists.txt b/tests/DelegatingCacheVariable/CMakeLists.txt new file mode 100644 index 0000000..4cef44b --- /dev/null +++ b/tests/DelegatingCacheVariable/CMakeLists.txt @@ -0,0 +1,47 @@ +include(DelegatingCacheVariable) + +set(dcv_foo "1") +delegating_cache_variable(dcv_bar + DEFAULT dcv_foo + TYPE STRING + DOCSTRING "delegation test case") + +set(dcv_fob "OFF") +delegating_cache_variable(dcv_fib + DEFAULT dcv_fob + TYPE BOOL + DOCSTRING "delegation test case") + +set(dcv_baz "1" CACHE STRING "" FORCE) +set(dcv_bax "0") +delegating_cache_variable(dcv_baz + DEFAULT dcv_bax + TYPE STRING + DOCSTRING "non-delegation test case") + +set(dcv_gob "0" CACHE STRING "" FORCE) +set(dcv_gof "1") +delegating_cache_variable(dcv_gob + DEFAULT dcv_gof + TYPE STRING + DOCSTRING "non-delegation test case") + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test.cpp +" +#include +#include + + int main(){ + assert(${dcv_bar}); + assert(std::string(\"${dcv_fib}\") == \"OFF\"); + assert(${dcv_baz}); + assert(${dcv_gob} == 0); + } +") + +add_executable(DelegatingCacheVariable.test + "${CMAKE_CURRENT_BINARY_DIR}/test.cpp") + +add_test( + NAME shacl.cmake.DelegatingCacheVariable.test + COMMAND DelegatingCacheVariable.test) diff --git a/tests/DelegatingOption/CMakeLists.txt b/tests/DelegatingOption/CMakeLists.txt new file mode 100644 index 0000000..557db6b --- /dev/null +++ b/tests/DelegatingOption/CMakeLists.txt @@ -0,0 +1,31 @@ +include(DelegatingOption) + +set(do_foo "1") + +delegating_option(do_bar + DEFAULT do_foo + DOCSTRING "delegation test case") + +set(do_baz "ON" CACHE STRING "" FORCE) +set(do_bax "0") +delegating_option(do_baz + DEFAULT do_bax + DOCSTRING "non-delegation test case") + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test.cpp +" +#include +#include + +int main(){ + assert(std::string(\"${do_bar}\") == \"ON\"); + assert(std::string(\"${do_baz}\") == \"ON\"); +} +") + +add_executable(DelegatingOption.test + "${CMAKE_CURRENT_BINARY_DIR}/test.cpp") + +add_test( + NAME shacl.cmake.DelegatingOption.test + COMMAND DelegatingOption.test) diff --git a/tests/DelegatingSelection/CMakeLists.txt b/tests/DelegatingSelection/CMakeLists.txt new file mode 100644 index 0000000..61b9cae --- /dev/null +++ b/tests/DelegatingSelection/CMakeLists.txt @@ -0,0 +1,33 @@ +include(DelegatingSelection) + +set(ds_foo "oog") + +delegating_selection(ds_bar + DEFAULT ds_foo + DOCSTRING "delegation test case" + OPTIONS oog boo zap) + +set(ds_baz "fop" CACHE STRING "" FORCE) +set(ds_bax "0") +delegating_selection(ds_baz + DEFAULT ds_bax + DOCSTRING "non-delegation test case" + OPTIONS fop mag buz) + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test.cpp +" +#include +#include + +int main(){ + assert(std::string(\"${ds_bar}\") == \"oog\"); + assert(std::string(\"${ds_baz}\") == \"fop\"); +} +") + +add_executable(DelegatingSelection.test + "${CMAKE_CURRENT_BINARY_DIR}/test.cpp") + +add_test( + NAME shacl.cmake.DelegatingSelection.test + COMMAND DelegatingSelection.test) diff --git a/tests/DependencyInjection/CMakeLists.txt b/tests/DependencyInjection/CMakeLists.txt new file mode 100644 index 0000000..f6616f1 --- /dev/null +++ b/tests/DependencyInjection/CMakeLists.txt @@ -0,0 +1,17 @@ +include(DependencyInjection) + +set(diexe.injections ${CMAKE_CURRENT_LIST_DIR}/exe_injected.cmake) +add_executable(diexe "") + +set(dilib.injections ${CMAKE_CURRENT_LIST_DIR}/lib_injected.cmake) +add_library(dilib STATIC "") + +target_link_libraries(diexe PRIVATE dilib) + +add_test( + NAME shacl.cmake.di_test + COMMAND diexe +) +set_tests_properties(shacl.cmake.di_test PROPERTIES + PASS_REGULAR_EXPRESSION "Hello World!" +) diff --git a/tests/DependencyInjection/exe_injected.cmake b/tests/DependencyInjection/exe_injected.cmake new file mode 100644 index 0000000..961f539 --- /dev/null +++ b/tests/DependencyInjection/exe_injected.cmake @@ -0,0 +1,3 @@ +target_sources(diexe PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/exe_main.cpp +) diff --git a/tests/DependencyInjection/exe_main.cpp b/tests/DependencyInjection/exe_main.cpp new file mode 100644 index 0000000..c9108ea --- /dev/null +++ b/tests/DependencyInjection/exe_main.cpp @@ -0,0 +1,5 @@ +void lib_func(); + +int main() { + lib_func(); +} diff --git a/tests/DependencyInjection/lib.cpp b/tests/DependencyInjection/lib.cpp new file mode 100644 index 0000000..53fd8a9 --- /dev/null +++ b/tests/DependencyInjection/lib.cpp @@ -0,0 +1,4 @@ +#include +void lib_func() { + std::cout << "Hello World!" << "\n"; +} diff --git a/tests/DependencyInjection/lib_injected.cmake b/tests/DependencyInjection/lib_injected.cmake new file mode 100644 index 0000000..d905295 --- /dev/null +++ b/tests/DependencyInjection/lib_injected.cmake @@ -0,0 +1,3 @@ +target_sources(dilib PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/lib.cpp +) diff --git a/tests/DependentDelegatingCacheVariable/CMakeLists.txt b/tests/DependentDelegatingCacheVariable/CMakeLists.txt new file mode 100644 index 0000000..f9fd8f2 --- /dev/null +++ b/tests/DependentDelegatingCacheVariable/CMakeLists.txt @@ -0,0 +1,54 @@ +include(DependentDelegatingCacheVariable) + +set(condition ON) +set(ddcv_foo "1") + +dependent_delegating_cache_variable(ddcv_bar + DEFAULT ddcv_foo + TYPE STRING + DOCSTRING "dependent delegation test case" + CONDITION condition + FALLBACK "2") + +dependent_delegating_cache_variable(ddcv_baz + DEFAULT ddcv_foo + TYPE STRING + DOCSTRING "dependent delegation test case" + CONDITION "NOT condition" + FALLBACK "2") + +set(ddcv_fob "5" CACHE STRING "" FORCE) +dependent_delegating_cache_variable(ddcv_fob + DEFAULT ddcv_foo + TYPE STRING + DOCSTRING "dependent delegation test case" + CONDITION condition + FALLBACK "2") + +set(ddcv_fib "6" CACHE STRING "" FORCE) +dependent_delegating_cache_variable(ddcv_fib + DEFAULT ddcv_foo + TYPE STRING + DOCSTRING "dependent delegation test case" + CONDITION "NOT condition" + FALLBACK "8") + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test.cpp +" +#include +#include + + int main(){ + assert(${ddcv_bar} == 1); + assert(${ddcv_baz} == 2); + assert(${ddcv_fob} == 5); + assert(${ddcv_fib} == 8); + } +") + +add_executable(DependentDelegatingCacheVariable.test + "${CMAKE_CURRENT_BINARY_DIR}/test.cpp") + +add_test( + NAME shacl.cmake.DependentDelegatingCacheVariable.test + COMMAND DependentDelegatingCacheVariable.test) diff --git a/tests/DependentDelegatingOption/CMakeLists.txt b/tests/DependentDelegatingOption/CMakeLists.txt new file mode 100644 index 0000000..cea9bb7 --- /dev/null +++ b/tests/DependentDelegatingOption/CMakeLists.txt @@ -0,0 +1,50 @@ +include(DependentDelegatingOption) + +set(condition ON) +set(ddo_foo "1") + +dependent_delegating_option(ddo_bar + DEFAULT ddo_foo + DOCSTRING "dependent delegation test case" + CONDITION condition + FALLBACK "2") + +dependent_delegating_option(ddo_baz + DEFAULT ddo_foo + DOCSTRING "dependent delegation test case" + CONDITION "NOT condition" + FALLBACK "OFF") + +set(ddo_fob "ON" CACHE STRING "" FORCE) +dependent_delegating_option(ddo_fob + DEFAULT ddo_foo + DOCSTRING "dependent delegation test case" + CONDITION condition + FALLBACK "OFF") + +set(ddo_fib "ON" CACHE STRING "" FORCE) +dependent_delegating_option(ddo_fib + DEFAULT ddo_foo + DOCSTRING "dependent delegation test case" + CONDITION "NOT condition" + FALLBACK "OFF") + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test.cpp +" +#include +#include + + int main(){ + assert(std::string(\"${ddo_bar}\") == \"ON\"); + assert(std::string(\"${ddo_baz}\") == \"OFF\"); + assert(std::string(\"${ddo_fob}\") == \"ON\"); + assert(std::string(\"${ddo_fib}\") == \"OFF\"); + } +") + +add_executable(DependentDelegatingOption.test + "${CMAKE_CURRENT_BINARY_DIR}/test.cpp") + +add_test( + NAME shacl.cmake.DependentDelegatingOption.test + COMMAND DependentDelegatingOption.test) diff --git a/tests/DependentDelegatingSelection/CMakeLists.txt b/tests/DependentDelegatingSelection/CMakeLists.txt new file mode 100644 index 0000000..e798b6b --- /dev/null +++ b/tests/DependentDelegatingSelection/CMakeLists.txt @@ -0,0 +1,54 @@ +include(DependentDelegatingSelection) + +set(condition ON) +set(dds_foo "oog") + +dependent_delegating_selection(dds_bar + DEFAULT dds_foo + OPTIONS "oog" "osh" "poy" "mop" "lor" "lop" "nom" + DOCSTRING "dependent delegation test case" + CONDITION condition + FALLBACK "osh") + +dependent_delegating_selection(dds_baz + DEFAULT dds_foo + OPTIONS "oog" "osh" "poy" "mop" "lor" "lop" "nom" + DOCSTRING "dependent delegation test case" + CONDITION "NOT condition" + FALLBACK "poy") + +set(dds_fob "mop" CACHE STRING "" FORCE) +dependent_delegating_selection(dds_fob + DEFAULT dds_foo + OPTIONS "oog" "osh" "poy" "mop" "lor" "lop" "nom" + DOCSTRING "dependent delegation test case" + CONDITION condition + FALLBACK "lor") + +set(dds_fib "lop" CACHE STRING "" FORCE) +dependent_delegating_selection(dds_fib + DEFAULT dds_foo + OPTIONS "oog" "osh" "poy" "mop" "lor" "lop" "nom" + DOCSTRING "dependent delegation test case" + CONDITION "NOT condition" + FALLBACK "nom") + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test.cpp +" +#include +#include + + int main(){ + assert(std::string(\"${dds_bar}\") == \"oog\"); + assert(std::string(\"${dds_baz}\") == \"poy\"); + assert(std::string(\"${dds_fob}\") == \"mop\"); + assert(std::string(\"${dds_fib}\") == \"nom\"); + } +") + +add_executable(DependentDelegatingSelection.test + "${CMAKE_CURRENT_BINARY_DIR}/test.cpp") + +add_test( + NAME shacl.cmake.DependentDelegatingSelection.test + COMMAND DependentDelegatingSelection.test) diff --git a/tests/Fortran/BackslashEscape/CMakeLists.txt b/tests/Fortran/BackslashEscape/CMakeLists.txt new file mode 100644 index 0000000..0350ea5 --- /dev/null +++ b/tests/Fortran/BackslashEscape/CMakeLists.txt @@ -0,0 +1,55 @@ +include(Fortran) + +file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/use_backslash_escape.F90" + INPUT "${CMAKE_CURRENT_LIST_DIR}/use_backslash_escape.F90.in") + +add_executable(use_backslash_escape ${CMAKE_CURRENT_BINARY_DIR}/use_backslash_escape.F90) +set_target_properties(use_backslash_escape PROPERTIES Fortran_BACKSLASH_ESCAPE ON) +target_link_libraries(use_backslash_escape PRIVATE shacl::cmake::Fortran::BackslashEscape) + +set(expected "") + +if("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "PGI") + set(expected "-Mbackslash") +elseif("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "GNU") + set(expected "-fbackslash") +elseif("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Intel") + if(WIN32) + set(expected "/assume:bscc") + else() + set(expected "SHELL:-assume bscc") + endif() +endif() + +add_test( + NAME shacl.cmake.backslash_escape + COMMAND use_backslash_escape) + +set_tests_properties(shacl.cmake.backslash_escape PROPERTIES PASS_REGULAR_EXPRESSION "^${expected}\n$") + +file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/use_no_backslash_escape.F90" + INPUT "${CMAKE_CURRENT_LIST_DIR}/use_no_backslash_escape.F90.in") + +add_executable(use_no_backslash_escape ${CMAKE_CURRENT_BINARY_DIR}/use_no_backslash_escape.F90) +set_target_properties(use_no_backslash_escape PROPERTIES Fortran_BACKSLASH_ESCAPE OFF) +target_link_libraries(use_no_backslash_escape PRIVATE shacl::cmake::Fortran::BackslashEscape) + +set(expected "") + +if("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "PGI") + set(expected "-Mnobackslash\n") +elseif("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "GNU") + set(expected "") +elseif("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Intel") + if(WIN32) + set(expected "/assume:nobscc\n") + else() + set(expected "SHELL:-assume nobscc\n") + endif() +endif() + +add_test( + NAME shacl.cmake.no_backslash_escape + COMMAND use_no_backslash_escape) + +set_tests_properties(shacl.cmake.no_backslash_escape PROPERTIES PASS_REGULAR_EXPRESSION "^${expected}$") diff --git a/tests/Fortran/BackslashEscape/use_backslash_escape.F90.in b/tests/Fortran/BackslashEscape/use_backslash_escape.F90.in new file mode 100644 index 0000000..e8ee466 --- /dev/null +++ b/tests/Fortran/BackslashEscape/use_backslash_escape.F90.in @@ -0,0 +1,4 @@ +program use_standard_semantics + use, intrinsic :: iso_fortran_env + write(output_unit,'(a)',advance='no') "$" +end program diff --git a/tests/Fortran/BackslashEscape/use_no_backslash_escape.F90.in b/tests/Fortran/BackslashEscape/use_no_backslash_escape.F90.in new file mode 100644 index 0000000..bfce3d0 --- /dev/null +++ b/tests/Fortran/BackslashEscape/use_no_backslash_escape.F90.in @@ -0,0 +1,4 @@ +program use_standard_semantics + use, intrinsic :: iso_fortran_env + write(output_unit,'(a)',advance='no') "$" +end program diff --git a/tests/Fortran/Backtrace/CMakeLists.txt b/tests/Fortran/Backtrace/CMakeLists.txt new file mode 100644 index 0000000..08c0697 --- /dev/null +++ b/tests/Fortran/Backtrace/CMakeLists.txt @@ -0,0 +1,45 @@ +include(Fortran/Backtrace) + +set(Intel.Windows.ON "/traceback") +set(Intel.Windows.OFF "/notraceback") +set(Intel.Darwin.ON "-traceback") +set(Intel.Darwin.OFF "-notraceback") +set(Intel.Linux.ON "-traceback") +set(Intel.Linux.OFF "-notraceback") +set(PGI.Windows.ON "-traceback") +set(PGI.Windows.OFF "-notraceback") +set(PGI.Darwin.ON "-traceback") +set(PGI.Darwin.OFF "-notraceback") +set(PGI.Linux.ON "-traceback") +set(PGI.Linux.OFF "-notraceback") +set(GNU.CYGWIN.ON "-fbacktrace") +set(GNU.CYGWIN.OFF "-fno-backtrace") +set(GNU.Windows.ON "-fbacktrace") +set(GNU.Windows.OFF "-fno-backtrace") +set(GNU.Darwin.ON "-fbacktrace") +set(GNU.Darwin.OFF "-fno-backtrace") +set(GNU.Linux.ON "-fbacktrace") +set(GNU.Linux.OFF "-fno-backtrace") + +foreach(toggle ON OFF) + add_executable(backtrace.${toggle} "") + set_target_properties(backtrace.${toggle} + PROPERTIES Fortran_BACKTRACE ${toggle}) + target_link_libraries(backtrace.${toggle} PRIVATE shacl::cmake::Fortran::Backtrace) + set(target backtrace.${toggle}) + + configure_file( + ${CMAKE_CURRENT_LIST_DIR}/backtrace.f90.in + ${CMAKE_CURRENT_BINARY_DIR}/backtrace.${toggle}.f90.in + @ONLY) + + file(GENERATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/backtrace.${toggle}.f90 + INPUT ${CMAKE_CURRENT_BINARY_DIR}/backtrace.${toggle}.f90.in) + + target_sources(backtrace.${toggle} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/backtrace.${toggle}.f90) + add_test(NAME shacl.cmake.Fortran.Backtrace.${toggle} COMMAND backtrace.${toggle}) + set_tests_properties(shacl.cmake.Fortran.Backtrace.${toggle} PROPERTIES + PASS_REGULAR_EXPRESSION + "^${${CMAKE_Fortran_COMPILER_ID}.${CMAKE_HOST_SYSTEM_NAME}.${toggle}}\n$") +endforeach() diff --git a/tests/Fortran/Backtrace/backtrace.f90.in b/tests/Fortran/Backtrace/backtrace.f90.in new file mode 100644 index 0000000..639a9ce --- /dev/null +++ b/tests/Fortran/Backtrace/backtrace.f90.in @@ -0,0 +1,3 @@ +program main + write(*,'(a)') "$" +end program diff --git a/tests/Fortran/CMakeLists.txt b/tests/Fortran/CMakeLists.txt new file mode 100644 index 0000000..13458d1 --- /dev/null +++ b/tests/Fortran/CMakeLists.txt @@ -0,0 +1,10 @@ +add_subdirectory(BackslashEscape) +add_subdirectory(Backtrace) +add_subdirectory(Exceptions) +add_subdirectory(Integer) +add_subdirectory(ModuleDirectory) +add_subdirectory(Real) +add_subdirectory(StackArraySizeLimit) +add_subdirectory(Standard) +add_subdirectory(StandardCompliance) +add_subdirectory(LongLines) diff --git a/tests/Fortran/Exceptions/CMakeLists.txt b/tests/Fortran/Exceptions/CMakeLists.txt new file mode 100644 index 0000000..4bfb9b1 --- /dev/null +++ b/tests/Fortran/Exceptions/CMakeLists.txt @@ -0,0 +1,12 @@ +add_executable(shacl.cmake.Fortran.Exceptions a.f90) +set_target_properties(shacl.cmake.Fortran.Exceptions PROPERTIES + LINKER_LANGUAGE Fortran) +add_library(shacl.cmake.Fortran.Exceptions.lib STATIC b.cpp) + +target_link_libraries(shacl.cmake.Fortran.Exceptions PRIVATE + shacl.cmake.Fortran.Exceptions.lib + shacl::cmake::Fortran::Exceptions) + +add_test( + NAME shacl.cmake.Fortran.Exceptions + COMMAND shacl.cmake.Fortran.Exceptions) diff --git a/tests/Fortran/Exceptions/a.f90 b/tests/Fortran/Exceptions/a.f90 new file mode 100644 index 0000000..f2087ac --- /dev/null +++ b/tests/Fortran/Exceptions/a.f90 @@ -0,0 +1,11 @@ +program main +use iso_c_binding +implicit none + +interface +subroutine b() bind(C, name="b") +end subroutine +end interface + +call b() +end program main diff --git a/tests/Fortran/Exceptions/b.cpp b/tests/Fortran/Exceptions/b.cpp new file mode 100644 index 0000000..c46391c --- /dev/null +++ b/tests/Fortran/Exceptions/b.cpp @@ -0,0 +1,10 @@ +#include + +extern "C" { +void b (){ + try{ + throw std::runtime_error("ya dun f'd up"); + } catch (std::runtime_error&) { + } +} +} diff --git a/tests/Fortran/Integer/CMakeLists.txt b/tests/Fortran/Integer/CMakeLists.txt new file mode 100644 index 0000000..b85749e --- /dev/null +++ b/tests/Fortran/Integer/CMakeLists.txt @@ -0,0 +1,23 @@ +include(Fortran) + +foreach(size 4 8) + add_executable(Fortran.Integer${size}.C.test test.c) + set_target_properties(Fortran.Integer${size}.C.test PROPERTIES Fortran_INTEGER_SIZE_BYTES "${size}") + target_link_libraries(Fortran.Integer${size}.C.test PUBLIC shacl::cmake::Fortran::Integer_C) + target_compile_definitions(Fortran.Integer${size}.C.test PRIVATE EXPECTED=${size}) + add_test(NAME shacl.cmake.Fortran.Integer${size}.C.test COMMAND Fortran.Integer${size}.C.test) + + add_executable(Fortran.Integer${size}.CXX.test test.cpp) + set_target_properties(Fortran.Integer${size}.CXX.test PROPERTIES Fortran_INTEGER_SIZE_BYTES "${size}") + target_link_libraries(Fortran.Integer${size}.CXX.test PUBLIC shacl::cmake::Fortran::Integer_CXX) + target_compile_definitions(Fortran.Integer${size}.CXX.test PRIVATE EXPECTED=${size}) + add_test(NAME shacl.cmake.Fortran.Integer${size}.CXX.test COMMAND Fortran.Integer${size}.CXX.test) + + add_executable(Fortran.Integer${size}.Fortran.test test.F90) + set_target_properties(Fortran.Integer${size}.Fortran.test PROPERTIES Fortran_STANDARD 2008) + set_target_properties(Fortran.Integer${size}.Fortran.test PROPERTIES Fortran_INTEGER_SIZE_BYTES "${size}") + target_link_libraries(Fortran.Integer${size}.Fortran.test PUBLIC shacl::cmake::Fortran::Integer_Fortran) + add_test(NAME shacl.cmake.Fortran.Integer${size}.Fortran.test COMMAND Fortran.Integer${size}.Fortran.test) +endforeach() + + diff --git a/tests/Fortran/Integer/test.F90 b/tests/Fortran/Integer/test.F90 new file mode 100644 index 0000000..4217ca8 --- /dev/null +++ b/tests/Fortran/Integer/test.F90 @@ -0,0 +1,19 @@ +program main + use iso_c_binding + implicit none + + integer :: dummy + +#ifdef F90_INT_4BYTE + integer, parameter :: expected = 4 +#endif + +#ifdef F90_INT_8BYTE + integer, parameter :: expected = 8 +#endif + + if (c_sizeof(dummy) /= expected) then + write(*,*) "size: ", c_sizeof(dummy), ", expected: ", expected + stop 1 + endif +end program main diff --git a/tests/Fortran/Integer/test.c b/tests/Fortran/Integer/test.c new file mode 100644 index 0000000..441a898 --- /dev/null +++ b/tests/Fortran/Integer/test.c @@ -0,0 +1,12 @@ +int main(){ + +#ifdef F90_INT_4BYTE + int value = 4; +#endif + +#ifdef F90_INT_8BYTE + int value = 8; +#endif + + return EXPECTED == value ? 0 : 1; +} diff --git a/tests/Fortran/Integer/test.cpp b/tests/Fortran/Integer/test.cpp new file mode 100644 index 0000000..441a898 --- /dev/null +++ b/tests/Fortran/Integer/test.cpp @@ -0,0 +1,12 @@ +int main(){ + +#ifdef F90_INT_4BYTE + int value = 4; +#endif + +#ifdef F90_INT_8BYTE + int value = 8; +#endif + + return EXPECTED == value ? 0 : 1; +} diff --git a/tests/Fortran/LongLines/CMakeLists.txt b/tests/Fortran/LongLines/CMakeLists.txt new file mode 100644 index 0000000..3cd1a1e --- /dev/null +++ b/tests/Fortran/LongLines/CMakeLists.txt @@ -0,0 +1,19 @@ +include(Fortran/LongLines) + +set(GNU.CYGWIN "-ffree-line-length-none") +set(GNU.Windows "-ffree-line-length-none") +set(GNU.Darwin "-ffree-line-length-none") +set(GNU.Linux "-ffree-line-length-none") + +add_executable(longlines) +target_link_libraries(longlines PRIVATE shacl::cmake::Fortran::LongLines) + +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/longlines.f90" + INPUT "${CMAKE_CURRENT_LIST_DIR}/longlines.f90.in") + +target_sources(longlines PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/longlines.f90") +add_test(NAME shacl.cmake.Fortran.LongLines COMMAND longlines) +set_tests_properties(shacl.cmake.Fortran.LongLines PROPERTIES + PASS_REGULAR_EXPRESSION + "^${${CMAKE_Fortran_COMPILER_ID}.${CMAKE_HOST_SYSTEM_NAME}}\n$") diff --git a/tests/Fortran/LongLines/longlines.f90.in b/tests/Fortran/LongLines/longlines.f90.in new file mode 100644 index 0000000..170d434 --- /dev/null +++ b/tests/Fortran/LongLines/longlines.f90.in @@ -0,0 +1,3 @@ +program main + write(*,'(a)') "$" +end program diff --git a/tests/Fortran/ModuleDirectory/CMakeLists.txt b/tests/Fortran/ModuleDirectory/CMakeLists.txt new file mode 100644 index 0000000..5fd70be --- /dev/null +++ b/tests/Fortran/ModuleDirectory/CMakeLists.txt @@ -0,0 +1,21 @@ +include(Fortran) + +set(module_dir "${CMAKE_CURRENT_BINARY_DIR}/fortran_modules") + +add_library(testlib STATIC "test_mod.F90") +target_Fortran_module_directory(testlib PRIVATE + BUILD_INTERFACE "${module_dir}") + +set(test_module_dir "${module_dir}") + +set(test_module_dir_suffix "") +if( CMAKE_CONFIGURATION_TYPES ) + set(test_module_dir_suffix "/$") +endif() + +add_test( + NAME shacl.cmake.Fortran.ModuleDirectory + COMMAND + ${CMAKE_COMMAND} + -D module_file=${test_module_dir}${test_module_dir_suffix}/test_mod.mod + -P "${CMAKE_CURRENT_LIST_DIR}/check_exists.cmake") diff --git a/tests/Fortran/ModuleDirectory/check_exists.cmake b/tests/Fortran/ModuleDirectory/check_exists.cmake new file mode 100644 index 0000000..9dfd48b --- /dev/null +++ b/tests/Fortran/ModuleDirectory/check_exists.cmake @@ -0,0 +1,3 @@ +if(NOT EXISTS ${module_file}) + message(FATAL_ERROR "${module_file} does not exist") +endif() diff --git a/tests/Fortran/ModuleDirectory/test_mod.F90 b/tests/Fortran/ModuleDirectory/test_mod.F90 new file mode 100644 index 0000000..2ef291f --- /dev/null +++ b/tests/Fortran/ModuleDirectory/test_mod.F90 @@ -0,0 +1,13 @@ +module test_mod + implicit none + +contains + + function foo() + implicit none + integer :: foo + + foo = 0 + return + end function foo +end module diff --git a/tests/Fortran/Real/CMakeLists.txt b/tests/Fortran/Real/CMakeLists.txt new file mode 100644 index 0000000..6c26036 --- /dev/null +++ b/tests/Fortran/Real/CMakeLists.txt @@ -0,0 +1,23 @@ +include(Fortran) + +foreach( size 4 8 ) + add_executable(Fortran.Real${size}.C.test test.c) + set_target_properties(Fortran.Real${size}.C.test PROPERTIES Fortran_REAL_SIZE_BYTES "${size}") + target_link_libraries(Fortran.Real${size}.C.test PUBLIC shacl::cmake::Fortran::Real_C) + target_compile_definitions(Fortran.Real${size}.C.test PRIVATE EXPECTED=${size}) + add_test(NAME shacl.cmake.Fortran.Real${size}.C.test COMMAND Fortran.Real${size}.C.test) + + add_executable(Fortran.Real${size}.CXX.test test.cpp) + set_target_properties(Fortran.Real${size}.CXX.test PROPERTIES Fortran_REAL_SIZE_BYTES "${size}") + target_link_libraries(Fortran.Real${size}.CXX.test PUBLIC shacl::cmake::Fortran::Real_CXX) + target_compile_definitions(Fortran.Real${size}.CXX.test PRIVATE EXPECTED=${size}) + add_test(NAME shacl.cmake.Fortran.Real${size}.CXX.test COMMAND Fortran.Real${size}.CXX.test) + + add_executable(Fortran.Real${size}.Fortran.test test.F90) + set_target_properties(Fortran.Real${size}.Fortran.test PROPERTIES Fortran_REAL_SIZE_BYTES "${size}") + set_target_properties(Fortran.Real${size}.Fortran.test PROPERTIES Fortran_STANDARD 2008) + target_link_libraries(Fortran.Real${size}.Fortran.test PUBLIC shacl::cmake::Fortran::Real_Fortran) + add_test(NAME shacl.cmake.Fortran.Real${size}.Fortran.test COMMAND Fortran.Real${size}.Fortran.test) +endforeach() + + diff --git a/tests/Fortran/Real/test.F90 b/tests/Fortran/Real/test.F90 new file mode 100644 index 0000000..624a780 --- /dev/null +++ b/tests/Fortran/Real/test.F90 @@ -0,0 +1,19 @@ +program main + use iso_c_binding + implicit none + + real :: dummy + +#ifdef F90_REAL_4BYTE + integer, parameter :: expected = 4 +#endif + +#ifdef F90_REAL_8BYTE + integer, parameter :: expected = 8 +#endif + + if (c_sizeof(dummy) /= expected) then + write(*,*) "size: ", c_sizeof(dummy), ", expected: ", expected + stop 1 + endif +end program main diff --git a/tests/Fortran/Real/test.c b/tests/Fortran/Real/test.c new file mode 100644 index 0000000..0430003 --- /dev/null +++ b/tests/Fortran/Real/test.c @@ -0,0 +1,12 @@ +int main(){ + +#ifdef F90_REAL_4BYTE + int value = 4; +#endif + +#ifdef F90_REAL_8BYTE + int value = 8; +#endif + + return EXPECTED == value ? 0 : 1; +} diff --git a/tests/Fortran/Real/test.cpp b/tests/Fortran/Real/test.cpp new file mode 100644 index 0000000..0430003 --- /dev/null +++ b/tests/Fortran/Real/test.cpp @@ -0,0 +1,12 @@ +int main(){ + +#ifdef F90_REAL_4BYTE + int value = 4; +#endif + +#ifdef F90_REAL_8BYTE + int value = 8; +#endif + + return EXPECTED == value ? 0 : 1; +} diff --git a/tests/Fortran/StackArraySizeLimit/CMakeLists.txt b/tests/Fortran/StackArraySizeLimit/CMakeLists.txt new file mode 100644 index 0000000..1a6612a --- /dev/null +++ b/tests/Fortran/StackArraySizeLimit/CMakeLists.txt @@ -0,0 +1,23 @@ +include(Fortran) + +file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/use_temp_arrays.F90" + INPUT "${CMAKE_CURRENT_LIST_DIR}/use_temp_arrays.F90.in") + +add_executable(use_temp_arrays "${CMAKE_CURRENT_BINARY_DIR}/use_temp_arrays.F90") +set_target_properties(use_temp_arrays PROPERTIES Fortran_STACK_ARRAY_SIZE_LIMIT 1024) +target_link_libraries(use_temp_arrays PRIVATE shacl::cmake::Fortran::StackArraySizeLimit) + +set(expected_GNU "-fmax-stack-var-size=1024000") +if( WIN32 ) + set(expected_Intel "/heap-arrays:1024") +else() + set(expected_Intel "-heap-arrays 1024") +endif() +set(expected_PGI "-Mnostack_arrays") + +add_test( + NAME shacl.cmake.Fortran.StackArraySizeLimit + COMMAND use_temp_arrays) + +set_tests_properties(shacl.cmake.Fortran.StackArraySizeLimit PROPERTIES + PASS_REGULAR_EXPRESSION "^${expected_${CMAKE_Fortran_COMPILER_ID}}\n$") diff --git a/tests/Fortran/StackArraySizeLimit/use_temp_arrays.F90.in b/tests/Fortran/StackArraySizeLimit/use_temp_arrays.F90.in new file mode 100644 index 0000000..986d0d8 --- /dev/null +++ b/tests/Fortran/StackArraySizeLimit/use_temp_arrays.F90.in @@ -0,0 +1,5 @@ +program use_standard_semantics + use, intrinsic :: iso_fortran_env + write(output_unit,'(a)',advance='no') "$," + write(output_unit,'(a)',advance='no') " >" +end program diff --git a/tests/Fortran/Standard/CMakeLists.txt b/tests/Fortran/Standard/CMakeLists.txt new file mode 100644 index 0000000..c042f8a --- /dev/null +++ b/tests/Fortran/Standard/CMakeLists.txt @@ -0,0 +1,48 @@ +include(Fortran) + +set(expected_GNU_95 "-std=f95;") +set(expected_GNU_2003 "-std=f2003;") +set(expected_GNU_2008 "-std=f2008;") +if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "8") + set(expected_GNU_2018 "-std=f2008ts;") +else() + set(expected_GNU_2018 "-std=f2018;") +endif() + +if(WIN32) + set(prefix "/stand:") +else() + set(prefix "-stand=") +endif() + +set(expected_Intel_95 "${prefix}f95;") +set(expected_Intel_2003 "${prefix}f03;") +set(expected_Intel_2008 "${prefix}f08;") +if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "19") + set(expected_Intel_2018 "${prefix}f15;") +else() + set(expected_Intel_2018 "${prefix}f18;") +endif() + +foreach(standard 95 2003 2008 2018) + file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/f${standard}.f90" + CONTENT " +program f${standard} + write(*,'(a)') \"$\" +end program +") + + add_executable(Fortran.Standard.${standard} + "${CMAKE_CURRENT_BINARY_DIR}/f${standard}.f90") + set_target_properties(Fortran.Standard.${standard} PROPERTIES Fortran_STANDARD ${standard}) + target_link_libraries(Fortran.Standard.${standard} PRIVATE shacl::cmake::Fortran::Standard) + + add_test( + NAME shacl.cmake.Fortran.Standard.${standard} + COMMAND Fortran.Standard.${standard}) + + set_tests_properties(shacl.cmake.Fortran.Standard.${standard} + PROPERTIES + PASS_REGULAR_EXPRESSION "^${expected_${CMAKE_Fortran_COMPILER_ID}_${standard}}\n$") +endforeach() diff --git a/tests/Fortran/Standard/use_standard.f90.in b/tests/Fortran/Standard/use_standard.f90.in new file mode 100644 index 0000000..ed159ec --- /dev/null +++ b/tests/Fortran/Standard/use_standard.f90.in @@ -0,0 +1,3 @@ +program use_standard_semantics + write(*,'(a)') "$" +end program diff --git a/tests/Fortran/StandardCompliance/CMakeLists.txt b/tests/Fortran/StandardCompliance/CMakeLists.txt new file mode 100644 index 0000000..fd1dd5f --- /dev/null +++ b/tests/Fortran/StandardCompliance/CMakeLists.txt @@ -0,0 +1,23 @@ +include(Fortran) + +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/use_fortran_standard_adherence.f90" + INPUT "${CMAKE_CURRENT_LIST_DIR}/use_fortran_standard_adherence.F90.in") + +add_executable(fortran_standard_adherence "${CMAKE_CURRENT_BINARY_DIR}/use_fortran_standard_adherence.f90") +target_link_libraries(fortran_standard_adherence PUBLIC shacl::cmake::Fortran::StandardCompliance) + +set(expected_PGI "-Mstandard -Mnobackslash") +if( WIN32 ) + set(expected_Intel "/standard-semantics /assume:nostd_mod_proc_name /assume:nobscc") +else() + set(expected_Intel "-standard-semantics SHELL:-assume nostd_mod_proc_name SHELL:-assume nobscc") +endif() +set(expected_GNU "-pedantic-errors") +set(expected "${expected_${CMAKE_Fortran_COMPILER_ID}}\n") + +add_test(NAME shacl.cmake.Fortran.StandardAdherence + COMMAND fortran_standard_adherence) + +set_tests_properties(shacl.cmake.Fortran.StandardAdherence PROPERTIES + PASS_REGULAR_EXPRESSION "^${expected}$") diff --git a/tests/Fortran/StandardCompliance/use_fortran_standard_adherence.F90.in b/tests/Fortran/StandardCompliance/use_fortran_standard_adherence.F90.in new file mode 100644 index 0000000..b03c60d --- /dev/null +++ b/tests/Fortran/StandardCompliance/use_fortran_standard_adherence.F90.in @@ -0,0 +1,5 @@ +program main + use, intrinsic :: iso_fortran_env, only: output_unit + write(output_unit,'(a)',advance='no') "$," + write(output_unit,'(a)',advance='no') " >" +end program diff --git a/tests/FortranPreProcess/CMakeLists.txt b/tests/FortranPreProcess/CMakeLists.txt new file mode 100644 index 0000000..66beed1 --- /dev/null +++ b/tests/FortranPreProcess/CMakeLists.txt @@ -0,0 +1,19 @@ +include(FortranPreProcess) + +add_executable(fprepro_defines "") +target_compile_definitions(fprepro_defines PRIVATE DO_F_PRE_PRO) + +target_sources(fprepro_defines PREPROCESS + PRIVATE "${CMAKE_CURRENT_LIST_DIR}/fprepro_defines.F90") + +add_test(NAME shacl.cmake.FortranPreProcess.Defines + COMMAND fprepro_defines) + +add_executable(fprepro_includes "") +target_include_directories(fprepro_includes PRIVATE ${CMAKE_CURRENT_LIST_DIR}) +target_compile_definitions(fprepro_includes PRIVATE DO_F_PRE_PRO) +target_sources(fprepro_includes PREPROCESS PRIVATE + "${CMAKE_CURRENT_LIST_DIR}/fprepro_includes.F90") + +add_test(NAME shacl.cmake.FortranPreProcess.Includes + COMMAND fprepro_includes) diff --git a/tests/FortranPreProcess/fprepro_defines.F90 b/tests/FortranPreProcess/fprepro_defines.F90 new file mode 100644 index 0000000..0ccbb57 --- /dev/null +++ b/tests/FortranPreProcess/fprepro_defines.F90 @@ -0,0 +1,5 @@ +program fprepro +#ifndef DO_F_PRE_PRO + error stop 1 +#endif +end program diff --git a/tests/FortranPreProcess/fprepro_includes.F90 b/tests/FortranPreProcess/fprepro_includes.F90 new file mode 100644 index 0000000..2bb6996 --- /dev/null +++ b/tests/FortranPreProcess/fprepro_includes.F90 @@ -0,0 +1,8 @@ +#include "fprepro_includes.inc" + +program fprepro + implicit none + external :: quit_program + + call quit_program +end program diff --git a/tests/FortranPreProcess/fprepro_includes.inc b/tests/FortranPreProcess/fprepro_includes.inc new file mode 100644 index 0000000..342b469 --- /dev/null +++ b/tests/FortranPreProcess/fprepro_includes.inc @@ -0,0 +1,8 @@ +subroutine quit_program + implicit none +#ifndef DO_F_PRE_PRO + error stop 1 +#else + stop +#endif +end subroutine diff --git a/tests/FunctionExtension/CMakeLists.txt b/tests/FunctionExtension/CMakeLists.txt new file mode 100644 index 0000000..9ec40a1 --- /dev/null +++ b/tests/FunctionExtension/CMakeLists.txt @@ -0,0 +1,7 @@ +include(FunctionExtension) + +add_subdirectory(call) +add_subdirectory(integrated_features) +add_subdirectory(push_pop) +add_subdirectory(set_property) +add_subdirectory(set_target_properties) diff --git a/tests/FunctionExtension/call/CMakeLists.txt b/tests/FunctionExtension/call/CMakeLists.txt new file mode 100644 index 0000000..028fcb3 --- /dev/null +++ b/tests/FunctionExtension/call/CMakeLists.txt @@ -0,0 +1,33 @@ +macro(foo arg) + set(foo_output "${arg}") +endmacro() + +macro(bar arg) + set(bar_output "${arg}") +endmacro() + +set(function_name foo) + +# We can't do this ${function_name}(hello). +# call provides a workaround for the above limitation +call(${function_name} hello) +if(NOT foo_output STREQUAL "hello") + message(FATAL_ERROR "foo_output should equal hello") +endif() + +set(function_name bar) + +call(${function_name} world) +if(NOT bar_output STREQUAL "world") + message(FATAL_ERROR "bar_output should equal world") +endif() + +function(variadic) + set(testVar "${ARGN}" PARENT_SCOPE) +endfunction() + +call(variadic a b c) +if( NOT testVar STREQUAL "a;b;c" ) + message(STATUS "testVar: ${testVar}" ) + message(FATAL_ERROR "testVar should equal a;b;c" ) +endif() diff --git a/tests/FunctionExtension/integrated_features/CMakeLists.txt b/tests/FunctionExtension/integrated_features/CMakeLists.txt new file mode 100644 index 0000000..35356ee --- /dev/null +++ b/tests/FunctionExtension/integrated_features/CMakeLists.txt @@ -0,0 +1,10 @@ +include(FunctionExtension) + +backup(add_library) +function(add_library) + previous_add_library("${ARGN}") +endfunction() + +call(add_library integrated_features.test_library STATIC) +target_sources(integrated_features.test_library PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/test_source.cpp") diff --git a/tests/FunctionExtension/integrated_features/test_source.cpp b/tests/FunctionExtension/integrated_features/test_source.cpp new file mode 100644 index 0000000..d78a068 --- /dev/null +++ b/tests/FunctionExtension/integrated_features/test_source.cpp @@ -0,0 +1 @@ +void foo(){} diff --git a/tests/FunctionExtension/push_pop/CMakeLists.txt b/tests/FunctionExtension/push_pop/CMakeLists.txt new file mode 100644 index 0000000..05643db --- /dev/null +++ b/tests/FunctionExtension/push_pop/CMakeLists.txt @@ -0,0 +1,140 @@ +include(FunctionExtension) + +# - - - - - - - - - - - - - +# setting testVar +# - - - - - - - - - - - - - +set(testVar "original") + +if(NOT testVar STREQUAL "original") + message(FATAL_ERROR "testVar should be equal to original") +endif() + +if(DEFINED _testVar) + message(FATAL_ERROR "_testVar should not be defined") +endif() + +if(DEFINED __testVar) + message(FATAL_ERROR "__testVar should not be defined") +endif() + +# - - - - - - - - - - - - - +# calling push +# - - - - - - - - - - - - - +push(testVar) + +if(NOT testVar STREQUAL "original") + message(FATAL_ERROR "testVar should be equal to original") +endif() + +if(NOT _testVar STREQUAL "original") + message(FATAL_ERROR "_testVar should be equal to original") +endif() + +if(DEFINED __testVar) + message(FATAL_ERROR "__testVar should not be defined") +endif() + +# - - - - - - - - - - - - - +# updating testVar +# - - - - - - - - - - - - - +set(testVar "revised") + +if(NOT testVar STREQUAL "revised") + message(FATAL_ERROR "testVar should be equal to original") +endif() + +if(NOT _testVar STREQUAL "original") + message(FATAL_ERROR "_testVar should be equal to original") +endif() + +if(DEFINED __testVar) + message(FATAL_ERROR "__testVar should not be defined") +endif() + +# - - - - - - - - - - - - - +# calling push again +# - - - - - - - - - - - - - +push(testVar) + +if(NOT testVar STREQUAL "revised") + message(FATAL_ERROR "testVar should be equal to original") +endif() + +if(NOT _testVar STREQUAL "revised") + message(FATAL_ERROR "_testVar should be equal to revised") +endif() + +if(NOT __testVar STREQUAL "original") + message(FATAL_ERROR "__testVar should be equal to original") +endif() + +# - - - - - - - - - - - - - +# updating testVar again +# - - - - - - - - - - - - - +set(testVar "revised2") + +if(NOT testVar STREQUAL "revised2") + message(FATAL_ERROR "testVar should be equal to original") +endif() + +if(NOT _testVar STREQUAL "revised") + message(FATAL_ERROR "_testVar should be equal to revised") +endif() + +if(NOT __testVar STREQUAL "original") + message(FATAL_ERROR "__testVar should be equal to original") +endif() + +# - - - - - - - - - - - - - +# first call to pop +# - - - - - - - - - - - - - +pop(testVar) + +if(NOT testVar STREQUAL "revised") + message(FATAL_ERROR "testVar should be equal to original") +endif() + +if(NOT _testVar STREQUAL "original") + message(FATAL_ERROR "_testVar should be equal to revised") +endif() + +if(DEFINED __testVar) + message(FATAL_ERROR "__testVar should not be defined") +endif() + +# - - - - - - - - - - - - - +# next call to pop +# - - - - - - - - - - - - - +pop(testVar) + +if(NOT testVar STREQUAL "original") + message(FATAL_ERROR "testVar should be equal to original") +endif() + +if(DEFINED _testVar) + message(FATAL_ERROR "_testVar should not be defined") +endif() + +if(DEFINED __testVar) + message(FATAL_ERROR "__testVar should not be defined") +endif() + +# - - - - - - - - - - - - - +# final call to pop +# - - - - - - - - - - - - - +pop(testVar) + +if(DEFINED testVar) + message(FATAL_ERROR "testVar should not be defined") +endif() + +if(DEFINED _testVar) + message(FATAL_ERROR "_testVar should not be defined") +endif() + +if(DEFINED __testVar) + message(FATAL_ERROR "__testVar should not be defined") +endif() + + + diff --git a/tests/FunctionExtension/set_property/CMakeLists.txt b/tests/FunctionExtension/set_property/CMakeLists.txt new file mode 100644 index 0000000..4f128c3 --- /dev/null +++ b/tests/FunctionExtension/set_property/CMakeLists.txt @@ -0,0 +1,20 @@ +backup(set_property) + +function(set_property) + previous_set_property(${ARGN}) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sink1" "${ARGN}") +endfunction() + +backup(set_property) + +function(set_property) + previous_set_property(${ARGN}) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sink2" "${ARGN}") +endfunction() + +add_library(FunctionExtension.set_property INTERFACE) +set_property(TARGET FunctionExtension.set_property PROPERTY INTERFACE_bar hello) +add_test(NAME shacl.cmake.set_property_extension + COMMAND "${CMAKE_COMMAND}" -E compare_files + "${CMAKE_CURRENT_BINARY_DIR}/sink1" + "${CMAKE_CURRENT_BINARY_DIR}/sink2") diff --git a/tests/FunctionExtension/set_target_properties/CMakeLists.txt b/tests/FunctionExtension/set_target_properties/CMakeLists.txt new file mode 100644 index 0000000..6e509bc --- /dev/null +++ b/tests/FunctionExtension/set_target_properties/CMakeLists.txt @@ -0,0 +1,23 @@ +backup(set_target_properties) + +function(set_target_properties) + previous_set_target_properties(${ARGN}) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sink1" "${ARGN}") +endfunction() + +backup(set_target_properties) + +function(set_target_properties) + previous_set_target_properties(${ARGN}) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sink2" "${ARGN}") +endfunction() + +add_library(FunctionExtension.set_target_properties INTERFACE) + +set_target_properties(FunctionExtension.set_target_properties + PROPERTIES INTERFACE_bar hello) + +add_test(NAME shacl.cmake.set_target_properties_extension + COMMAND "${CMAKE_COMMAND}" -E compare_files + "${CMAKE_CURRENT_BINARY_DIR}/sink1" + "${CMAKE_CURRENT_BINARY_DIR}/sink2") diff --git a/tests/GeneratedSources/CMakeLists.txt b/tests/GeneratedSources/CMakeLists.txt new file mode 100644 index 0000000..509e2a5 --- /dev/null +++ b/tests/GeneratedSources/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(target_sources) diff --git a/tests/GeneratedSources/target_sources/CMakeLists.txt b/tests/GeneratedSources/target_sources/CMakeLists.txt new file mode 100644 index 0000000..11285d8 --- /dev/null +++ b/tests/GeneratedSources/target_sources/CMakeLists.txt @@ -0,0 +1,29 @@ +include(GeneratedSources) + +add_library(GeneratedSources.library STATIC) + +add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/bar.c" + COMMAND "${CMAKE_COMMAND}" -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/bar.c.in" + "${CMAKE_CURRENT_BINARY_DIR}/bar.c") + +add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/foo.c" + COMMAND "${CMAKE_COMMAND}" -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/foo.c.in" + "${CMAKE_CURRENT_BINARY_DIR}/foo.c" + + ) + +target_sources(GeneratedSources.library GENERATED + PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/foo.c" + PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/bar.c") + +add_subdirectory(subdirectory) + +add_test( + NAME + shacl.cmake.target_sources1 + COMMAND + "${CMAKE_COMMAND}" -E compare_files + "${CMAKE_CURRENT_SOURCE_DIR}/bar.c.in" + "${CMAKE_CURRENT_BINARY_DIR}/bar.c") diff --git a/tests/GeneratedSources/target_sources/bar.c.in b/tests/GeneratedSources/target_sources/bar.c.in new file mode 100644 index 0000000..4940fe1 --- /dev/null +++ b/tests/GeneratedSources/target_sources/bar.c.in @@ -0,0 +1 @@ +void bar(){} diff --git a/tests/GeneratedSources/target_sources/foo.c.in b/tests/GeneratedSources/target_sources/foo.c.in new file mode 100644 index 0000000..d78a068 --- /dev/null +++ b/tests/GeneratedSources/target_sources/foo.c.in @@ -0,0 +1 @@ +void foo(){} diff --git a/tests/GeneratedSources/target_sources/subdirectory/CMakeLists.txt b/tests/GeneratedSources/target_sources/subdirectory/CMakeLists.txt new file mode 100644 index 0000000..fa7b86a --- /dev/null +++ b/tests/GeneratedSources/target_sources/subdirectory/CMakeLists.txt @@ -0,0 +1,7 @@ +add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/foo.c" + COMMAND "${CMAKE_COMMAND}" -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/foo.c.in" + "${CMAKE_CURRENT_BINARY_DIR}/foo.c") + +target_sources(GeneratedSources.library GENERATED + PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/foo.c") diff --git a/tests/GeneratedSources/target_sources/subdirectory/foo.c.in b/tests/GeneratedSources/target_sources/subdirectory/foo.c.in new file mode 100644 index 0000000..01ebbe2 --- /dev/null +++ b/tests/GeneratedSources/target_sources/subdirectory/foo.c.in @@ -0,0 +1 @@ +void cool_foo(){} diff --git a/tests/GeneratedSources/target_sources/test1 b/tests/GeneratedSources/target_sources/test1 new file mode 100644 index 0000000..39daae8 --- /dev/null +++ b/tests/GeneratedSources/target_sources/test1 @@ -0,0 +1 @@ +library.ec54854.bar_c \ No newline at end of file diff --git a/tests/GeneratedSources/target_sources/test2 b/tests/GeneratedSources/target_sources/test2 new file mode 100644 index 0000000..25f11ba --- /dev/null +++ b/tests/GeneratedSources/target_sources/test2 @@ -0,0 +1 @@ +library.47b2370.baz_f90 \ No newline at end of file diff --git a/tests/Git/Submodule/Packages/CMakeLists.txt b/tests/Git/Submodule/Packages/CMakeLists.txt new file mode 100644 index 0000000..1ffb94c --- /dev/null +++ b/tests/Git/Submodule/Packages/CMakeLists.txt @@ -0,0 +1,24 @@ +include(CTest) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../..) + +include(Git/Submodule/Packages) + +set(JSON_BuildTests OFF CACHE INTERNAL "") +find_package(json 3.0.2 REQUIRED) +git_submodule_package(Catch2) + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bar.cpp +"#include + + int main(){ + assert(\"${git.submodule.package.json.hash}\" == \"7bfc406ded0434c438dd22139a8baa97f2ffa90e\" ); + assert(\"${json_FOUND}\" == \"TRUE\" ); + assert(\"${git.submodule.package.Catch2.branch}\" == \"master\" ); + } +") + +add_executable(Git.Submodule.Packages.test ${CMAKE_CURRENT_BINARY_DIR}/bar.cpp) + +add_test( + NAME shacl.cmake.Git.Submodule.Packages.test + COMMAND Git.Submodule.Packages.test) diff --git a/tests/Intel/CMakeLists.txt b/tests/Intel/CMakeLists.txt new file mode 100644 index 0000000..ce4341d --- /dev/null +++ b/tests/Intel/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(FortranAssumptions) +add_subdirectory(FPModel) +#add_subdirectory(FPSpeculation) diff --git a/tests/Intel/FPModel/CMakeLists.txt b/tests/Intel/FPModel/CMakeLists.txt new file mode 100644 index 0000000..f54aabd --- /dev/null +++ b/tests/Intel/FPModel/CMakeLists.txt @@ -0,0 +1,64 @@ +include(Intel) + +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_model.c + INPUT ${CMAKE_CURRENT_LIST_DIR}/use_intel_fp_model.c.in) + +add_executable(use_intel_fp_model_C ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_model.c) +set_target_properties(use_intel_fp_model_C PROPERTIES Intel_FLOATING_POINT_MODEL "consistent") +target_link_libraries(use_intel_fp_model_C PRIVATE shacl::cmake::Intel::FloatingPoint::Model_C) + +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_model.cpp + INPUT ${CMAKE_CURRENT_LIST_DIR}/use_intel_fp_model.cpp.in +) + +add_executable(use_intel_fp_model_CXX ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_model.cpp) +set_target_properties(use_intel_fp_model_CXX PROPERTIES Intel_FLOATING_POINT_MODEL "consistent") +target_link_libraries(use_intel_fp_model_CXX PRIVATE shacl::cmake::Intel::FloatingPoint::Model_CXX) + +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_model.F90 + INPUT ${CMAKE_CURRENT_LIST_DIR}/use_intel_fp_model.F90.in +) + +add_executable(use_intel_fp_model_Fortran ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_model.F90) +set_target_properties(use_intel_fp_model_Fortran PROPERTIES Intel_FLOATING_POINT_MODEL "consistent") +target_link_libraries(use_intel_fp_model_Fortran PRIVATE shacl::cmake::Intel::FloatingPoint::Model_Fortran) + +set(expected_C "") +set(expected_CXX "") +set(expected_Fortran "") + +if( "${CMAKE_C_COMPILER_ID}" STREQUAL "Intel" ) + set(expected_C "-fp-model=consistent\n") + if( WIN32 ) + set(expected_C "/fp:consistent\n") + endif() +endif() + +if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" ) + set(expected_CXX "-fp-model=consistent\n") + if( WIN32 ) + set(expected_CXX "/fp:consistent\n") + endif() +endif() + +if( "${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Intel" ) + set(expected_Fortran "-fp-model=consistent\n") + if( WIN32 ) + set(expected_Fortran "/fp:consistent\n") + endif() +endif() + +add_test( + NAME shacl.cmake.intel_fp_model_C + COMMAND use_intel_fp_model_C) +set_tests_properties(shacl.cmake.intel_fp_model_C PROPERTIES PASS_REGULAR_EXPRESSION "^${expected_C}$") + +add_test( + NAME shacl.cmake.intel_fp_model_CXX + COMMAND use_intel_fp_model_CXX) +set_tests_properties(shacl.cmake.intel_fp_model_CXX PROPERTIES PASS_REGULAR_EXPRESSION "^${expected_CXX}$") + +add_test( + NAME shacl.cmake.intel_fp_model_Fortran + COMMAND use_intel_fp_model_Fortran) +set_tests_properties(shacl.cmake.intel_fp_model_Fortran PROPERTIES PASS_REGULAR_EXPRESSION "^${expected_Fortran}$") diff --git a/tests/Intel/FPModel/use_intel_fp_model.F90.in b/tests/Intel/FPModel/use_intel_fp_model.F90.in new file mode 100644 index 0000000..6d6834c --- /dev/null +++ b/tests/Intel/FPModel/use_intel_fp_model.F90.in @@ -0,0 +1,4 @@ +program use_standard_semantics + use, intrinsic :: iso_fortran_env + write(output_unit,'(a)',advance='no') "$" +end program diff --git a/tests/Intel/FPModel/use_intel_fp_model.c.in b/tests/Intel/FPModel/use_intel_fp_model.c.in new file mode 100644 index 0000000..15f4fd7 --- /dev/null +++ b/tests/Intel/FPModel/use_intel_fp_model.c.in @@ -0,0 +1,7 @@ +#include + +int main() { + printf("%s","$"); + + return 0; +} diff --git a/tests/Intel/FPModel/use_intel_fp_model.cpp.in b/tests/Intel/FPModel/use_intel_fp_model.cpp.in new file mode 100644 index 0000000..79392c6 --- /dev/null +++ b/tests/Intel/FPModel/use_intel_fp_model.cpp.in @@ -0,0 +1,7 @@ +#include + +int main() { + std::cout << "$"; + + return 0; +} diff --git a/tests/Intel/FPSpeculation/CMakeLists.txt b/tests/Intel/FPSpeculation/CMakeLists.txt new file mode 100644 index 0000000..4cd5463 --- /dev/null +++ b/tests/Intel/FPSpeculation/CMakeLists.txt @@ -0,0 +1,65 @@ +include(Intel) + +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_speculation.c + INPUT ${CMAKE_CURRENT_LIST_DIR}/use_intel_fp_speculation.c.in) + +add_executable(use_intel_fp_speculation_C ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_speculation.c) +set_target_properties(use_intel_fp_speculation_C PROPERTIES Intel_FLOATING_POINT_SPECULATION "safe") +target_link_libraries(use_intel_fp_speculation_C PRIVATE shacl::cmake::Intel::FloatingPoint::Speculation_C) + +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_speculation.cpp + INPUT ${CMAKE_CURRENT_LIST_DIR}/use_intel_fp_speculation.cpp.in) + +add_executable(use_intel_fp_speculation_CXX ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_speculation.cpp) +set_target_properties(use_intel_fp_speculation_CXX PROPERTIES Intel_FLOATING_POINT_SPECULATION "safe") +target_link_libraries(use_intel_fp_speculation_CXX PRIVATE shacl::cmake::Intel::FloatingPoint::Speculation_CXX) + +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_speculation.F90 + INPUT ${CMAKE_CURRENT_LIST_DIR}/use_intel_fp_speculation.F90.in) + +add_executable(use_intel_fp_speculation_Fortran ${CMAKE_CURRENT_BINARY_DIR}/use_intel_fp_speculation.F90) +set_target_properties(use_intel_fp_speculation_Fortran PROPERTIES Intel_FLOATING_POINT_SPECULATION "safe") +target_link_libraries(use_intel_fp_speculation_Fortran PRIVATE shacl::cmake::Intel::FloatingPoint::Speculation_Fortran) + +set(expected_C "") +set(expected_CXX "") +set(expected_Fortran "") + +if( "${CMAKE_C_COMPILER_ID}" STREQUAL "Intel" ) + set(expected_C "-fp-speculation=safe\n") + if( WIN32 ) + set(expected_C "/Qfp-speculation:safe\n") + endif() +endif() + +if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" ) + set(expected_CXX "-fp-speculation=safe\n") + if( WIN32 ) + set(expected_CXX "/Qfp-speculation:safe\n") + endif() +endif() + +if( "${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Intel" ) + set(expected_Fortran "-fp-speculation=safe\n") + if( WIN32 ) + set(expected_Fortran "/Qfp-speculation:safe\n") + endif() +endif() + +add_test( + NAME shacl.cmake.intel_fp_speculation_C + COMMAND use_intel_fp_speculation_C +) +set_tests_properties(shacl.cmake.intel_fp_speculation_C PROPERTIES PASS_REGULAR_EXPRESSION "^${expected_C}$") + +add_test( + NAME shacl.cmake.intel_fp_speculation_CXX + COMMAND use_intel_fp_speculation_CXX +) +set_tests_properties(shacl.cmake.intel_fp_speculation_CXX PROPERTIES PASS_REGULAR_EXPRESSION "^${expected_CXX}$") + +add_test( + NAME shacl.cmake.intel_fp_speculation_Fortran + COMMAND use_intel_fp_speculation_Fortran +) +set_tests_properties(shacl.cmake.intel_fp_speculation_Fortran PROPERTIES PASS_REGULAR_EXPRESSION "^${expected_Fortran}$") diff --git a/tests/Intel/FPSpeculation/use_intel_fp_speculation.F90.in b/tests/Intel/FPSpeculation/use_intel_fp_speculation.F90.in new file mode 100644 index 0000000..6282730 --- /dev/null +++ b/tests/Intel/FPSpeculation/use_intel_fp_speculation.F90.in @@ -0,0 +1,4 @@ +program use_standard_semantics + use, intrinsic :: iso_fortran_env + write(output_unit,'(a)',advance='no') "$" +end program diff --git a/tests/Intel/FPSpeculation/use_intel_fp_speculation.c.in b/tests/Intel/FPSpeculation/use_intel_fp_speculation.c.in new file mode 100644 index 0000000..3a28c27 --- /dev/null +++ b/tests/Intel/FPSpeculation/use_intel_fp_speculation.c.in @@ -0,0 +1,7 @@ +#include + +int main() { + printf("%s","$"); + + return 0; +} diff --git a/tests/Intel/FPSpeculation/use_intel_fp_speculation.cpp.in b/tests/Intel/FPSpeculation/use_intel_fp_speculation.cpp.in new file mode 100644 index 0000000..0260a49 --- /dev/null +++ b/tests/Intel/FPSpeculation/use_intel_fp_speculation.cpp.in @@ -0,0 +1,7 @@ +#include + +int main() { + std::cout << "$"; + + return 0; +} diff --git a/tests/Intel/FortranAssumptions/CMakeLists.txt b/tests/Intel/FortranAssumptions/CMakeLists.txt new file mode 100644 index 0000000..d4bee51 --- /dev/null +++ b/tests/Intel/FortranAssumptions/CMakeLists.txt @@ -0,0 +1,28 @@ +include(Intel/Fortran/Assumptions) + +add_executable(assumptions.test "") +set_target_properties(assumptions.test PROPERTIES + Intel_Fortran_ENABLED_ASSUMPTIONS "old_xor;std_intent_in" + Intel_Fortran_DISABLED_ASSUMPTIONS "protect_parens;realloc_lhs") +target_link_libraries(assumptions.test PUBLIC shacl::cmake::Intel::Fortran::Assumptions) + +file(GENERATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/assumptions.f90 + INPUT ${CMAKE_CURRENT_LIST_DIR}/assumptions.f90.in) + +target_sources(assumptions.test PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/assumptions.f90) + +add_test(NAME shacl.cmake.Intel.FortranAssumptions COMMAND assumptions.test) + +if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") + if(WIN32) + set(regex "/assume:") + else() + set(regex "-assume;") + endif() + set(regex "${regex}old_xor,std_intent_in,noprotect_parens,norealloc_lhs") +endif() + +set_tests_properties(shacl.cmake.Intel.FortranAssumptions + PROPERTIES PASS_REGULAR_EXPRESSION "${regex}") diff --git a/tests/Intel/FortranAssumptions/assumptions.f90.in b/tests/Intel/FortranAssumptions/assumptions.f90.in new file mode 100644 index 0000000..a6bc894 --- /dev/null +++ b/tests/Intel/FortranAssumptions/assumptions.f90.in @@ -0,0 +1,3 @@ +program warnings + write(*,'(a)') "$" +end program diff --git a/tests/Intel/FortranStandardAdherence/CMakeLists.txt b/tests/Intel/FortranStandardAdherence/CMakeLists.txt new file mode 100644 index 0000000..507b006 --- /dev/null +++ b/tests/Intel/FortranStandardAdherence/CMakeLists.txt @@ -0,0 +1,26 @@ +include(Intel) + +file(GENERATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/adherence.f90 + INPUT ${CMAKE_CURRENT_LIST_DIR}/adherence.f90.in) + +add_executable(intel_standard_adherence + ${CMAKE_CURRENT_BINARY_DIR}/adherence.f90) + +target_link_libraries(intel_standard_adherence + PRIVATE Intel::FortranStandardAdherence) + +add_test(NAME shacl.cmake.Intel.FortranStandardAdherence + COMMAND intel_standard_adherence) + +if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") + if(WIN32) + set(regex "/standard-semantics;/assume:") + else() + set(regex "-standard-semantics;-assume;") + endif() + set(regex "${regex}nostd_mod_proc_name") +endif() + +set_tests_properties(shacl.cmake.Intel.FortranStandardAdherence + PROPERTIES PASS_REGULAR_EXPRESSION "${regex}") diff --git a/tests/Intel/FortranStandardAdherence/adherence.f90.in b/tests/Intel/FortranStandardAdherence/adherence.f90.in new file mode 100644 index 0000000..242bcf6 --- /dev/null +++ b/tests/Intel/FortranStandardAdherence/adherence.f90.in @@ -0,0 +1,3 @@ +program use_standard_semantics + write(*,'(a)') "$" +end program diff --git a/tests/LinkOptions/CMakeLists.txt b/tests/LinkOptions/CMakeLists.txt new file mode 100644 index 0000000..001b10b --- /dev/null +++ b/tests/LinkOptions/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(StackSize) diff --git a/tests/LinkOptions/StackSize/CMakeLists.txt b/tests/LinkOptions/StackSize/CMakeLists.txt new file mode 100644 index 0000000..44e70e9 --- /dev/null +++ b/tests/LinkOptions/StackSize/CMakeLists.txt @@ -0,0 +1,25 @@ +include(LinkOptions/StackSize) + +add_executable(use_stack_size_f90 ${CMAKE_CURRENT_LIST_DIR}/use_stack_size.f90) +set_target_properties(use_stack_size_f90 PROPERTIES LINK_STACK_SIZE 1024000) +target_link_libraries(use_stack_size_f90 PRIVATE shacl::cmake::LinkOptions::StackSize) + +add_executable(use_stack_size_c ${CMAKE_CURRENT_LIST_DIR}/use_stack_size.c) +set_target_properties(use_stack_size_c PROPERTIES LINK_STACK_SIZE 1024000) +target_link_libraries(use_stack_size_c PRIVATE shacl::cmake::LinkOptions::StackSize) + +add_executable(use_stack_size_cpp ${CMAKE_CURRENT_LIST_DIR}/use_stack_size.cpp) +set_target_properties(use_stack_size_cpp PROPERTIES LINK_STACK_SIZE 1024000) +target_link_libraries(use_stack_size_cpp PRIVATE shacl::cmake::LinkOptions::StackSize) + +add_custom_target(run_use_stack_size_f90 ALL + COMMAND use_stack_size_f90 + DEPENDS use_stack_size_f90) + +add_custom_target(run_use_stack_size_c ALL + COMMAND use_stack_size_c + DEPENDS use_stack_size_c) + +add_custom_target(run_use_stack_size_cpp ALL + COMMAND use_stack_size_cpp + DEPENDS use_stack_size_cpp) diff --git a/tests/LinkOptions/StackSize/use_stack_size.c b/tests/LinkOptions/StackSize/use_stack_size.c new file mode 100644 index 0000000..76e8197 --- /dev/null +++ b/tests/LinkOptions/StackSize/use_stack_size.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/LinkOptions/StackSize/use_stack_size.cpp b/tests/LinkOptions/StackSize/use_stack_size.cpp new file mode 100644 index 0000000..237c8ce --- /dev/null +++ b/tests/LinkOptions/StackSize/use_stack_size.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/tests/LinkOptions/StackSize/use_stack_size.f90 b/tests/LinkOptions/StackSize/use_stack_size.f90 new file mode 100644 index 0000000..ab8d586 --- /dev/null +++ b/tests/LinkOptions/StackSize/use_stack_size.f90 @@ -0,0 +1,6 @@ +program use_stack_size + implicit none + open(unit=42,file="terminal_output",status="unknown") + write(42,"(a)") "" + close(42) +end program diff --git a/tests/Sanitizers/CMakeLists.txt b/tests/Sanitizers/CMakeLists.txt new file mode 100644 index 0000000..935bc3f --- /dev/null +++ b/tests/Sanitizers/CMakeLists.txt @@ -0,0 +1,20 @@ +include(Sanitizers) + +set(asan_supported Linux_GNU Linux_Clang Darwin_AppleClang) +set(msan_supported Linux_Clang) +set(tsan_supported Linux_GNU Linux_Clang Darwin_AppleClang) +set(ubsan_supported Linux_GNU Linux_Clang Darwin_AppleClang) + +option(Sanitizer.tests "enable sanitizer tests" OFF) + +if(Sanitizer.tests) + foreach(san asan msan tsan ubsan) + if(${CMAKE_SYSTEM_NAME}_${CMAKE_CXX_COMPILER_ID} IN_LIST ${san}_supported) + add_executable(trigger_${san} trigger_${san}.cpp) + target_link_libraries(trigger_${san} PUBLIC shacl::cmake::Sanitizers_CXX) + target_compile_features(trigger_${san} PUBLIC cxx_std_14) + set_target_properties(trigger_${san} PROPERTIES ${san} ON) + add_test(NAME shacl.cmake.trigger_${san} COMMAND trigger_${san}) + endif() + endforeach() +endif() diff --git a/tests/Sanitizers/trigger_asan.cpp b/tests/Sanitizers/trigger_asan.cpp new file mode 100644 index 0000000..c4d8bc2 --- /dev/null +++ b/tests/Sanitizers/trigger_asan.cpp @@ -0,0 +1,17 @@ +// address sanitizer is only on unix-like platforms +#include +#include +#include + +int main(int argc, char **argv) { + auto child_pid = fork(); + + if (child_pid == 0){ + int *array = new int[100]; + delete [] array; + return array[argc]; // BOOM + } + int exit_status; + wait(&exit_status); + return (not exit_status); +} diff --git a/tests/Sanitizers/trigger_msan.cpp b/tests/Sanitizers/trigger_msan.cpp new file mode 100644 index 0000000..32c792d --- /dev/null +++ b/tests/Sanitizers/trigger_msan.cpp @@ -0,0 +1,20 @@ +// thread sanitizer is only on unix-like platforms +#include +#include +#include + +int main(int argc, char** argv) { + auto child_pid = fork(); + if (child_pid == 0){ + int* a = new int[10]; + a[5] = 0; + if (a[argc]){ // BOOM + printf("xx\n"); + } + return 0; + } + + int exit_status; + wait(&exit_status); + return 0; +} diff --git a/tests/Sanitizers/trigger_tsan.cpp b/tests/Sanitizers/trigger_tsan.cpp new file mode 100644 index 0000000..091e602 --- /dev/null +++ b/tests/Sanitizers/trigger_tsan.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include + +// thread sanitizer is only on unix-like platforms +#include +#include +#include + +using map_t = std::map; + +void threadfunc(map_t& m) { + m["foo"] = "bar" + std::to_string(1); +} + +int main() { + auto child_pid = fork(); + if (child_pid == 0){ + map_t m; + m["foo"] = "baz"; + std::thread t(threadfunc, std::ref(m)); + std::cout << "foo=" << m["foo"]; //BOOM + t.join(); + return 0; + } + + int exit_status; + wait(&exit_status); + + return (not exit_status); +} diff --git a/tests/Sanitizers/trigger_ubsan.cpp b/tests/Sanitizers/trigger_ubsan.cpp new file mode 100644 index 0000000..3b93aa3 --- /dev/null +++ b/tests/Sanitizers/trigger_ubsan.cpp @@ -0,0 +1,19 @@ +// thread sanitizer is only on unix-like platforms +#include +#include +#include + +int main(int argc, char **argv) { + auto child_pid = fork(); + + if (child_pid == 0){ + int k = 0x7fffffff; + k += argc; // BOOM + return 0; + } + + int exit_status; + wait(&exit_status); + + return (not exit_status); +} diff --git a/tests/Warnings/CMakeLists.txt b/tests/Warnings/CMakeLists.txt new file mode 100644 index 0000000..b5fbfed --- /dev/null +++ b/tests/Warnings/CMakeLists.txt @@ -0,0 +1,222 @@ +include(Warnings) + +set(C_GNU -Werror -Wall -Wextra -Wpedantic) +if(CMAKE_C_COMPILER_VERSION VERSION_GREATER "7.0") + list(APPEND C_GNU -Wduplicated-branches) +endif() +if(CMAKE_C_COMPILER_VERSION VERSION_GREATER "6.0") + list(APPEND C_GNU -Wduplicated-cond) +endif() +list(APPEND C_GNU -Wstrict-overflow -Wnonnull) +list(APPEND C_GNU -Wno-null-dereference -Wno-implicit) + +string(REPLACE ";" "\;" C_GNU "${C_GNU}") +set(C_Clang -Werror -Wall -Wextra -Wpedantic -Wassign-enum + -Wbad-function-cast -Wkeyword-macro + -Wnonportable-system-include-path + -Wsometimes-uninitialized + -Wabstract-vbase-init + -Warray-bounds-pointer-arithmetic + -Wno-asm-operand-widths + -Wno-assign-enum) +string(REPLACE ";" "\;" C_Clang "${C_Clang}") + +set(C_AppleClang "${C_Clang}") + +if(WIN32) + set(C_Intel "/WX" "/W3" "/Qdiag-enable:117,230" "/Qdiag-disable:450") +else() + set(C_Intel "-Werror" "-w2" "-diag-enable=117,230" "-diag-disable=450") +endif() + +set(C_MSVC "/WX" "/W4" "/w14806" "/w14807" "/wd14810" "/wd14811") + +add_executable(warnings.c.test "") +set_target_properties(warnings.c.test PROPERTIES + WARN_ALL ON + WARN_ERROR ON + GNU_ENABLED_WARNINGS "strict-overflow;nonnull" + GNU_DISABLED_WARNINGS "null-dereference;implicit" + LLVM_ENABLED_WARNINGS "abstract-vbase-init;array-bounds-pointer-arithmetic" + LLVM_DISABLED_WARNINGS "asm-operand-widths;assign-enum" + Intel_ENABLED_WARNINGS "117;230" + Intel_DISABLED_WARNINGS "450" + MSVC_ENABLED_WARNINGS "4806;4807" + MSVC_DISABLED_WARNINGS "4810;4811") +target_link_libraries(warnings.c.test PUBLIC shacl::cmake::Warnings_C) + +file(GENERATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/warnings.c + INPUT ${CMAKE_CURRENT_LIST_DIR}/warnings.c.in) + +target_sources(warnings.c.test PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/warnings.c) + +add_test(NAME shacl.cmake.warnings.c.test COMMAND warnings.c.test) + +set_tests_properties(shacl.cmake.warnings.c.test PROPERTIES + PASS_REGULAR_EXPRESSION "^${C_${CMAKE_C_COMPILER_ID}};*\n$") + +set(CXX_GNU + -Werror -Wall -Wextra -Wpedantic -Wsuggest-override) +if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "7.0") + list(APPEND CXX_GNU -Wduplicated-branches) +endif() +if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "6.0") + list(APPEND CXX_GNU -Wduplicated-cond) +endif() +list(APPEND CXX_GNU -Wstrict-overflow -Wnonnull) +list(APPEND CXX_GNU -Wno-null-dereference) + +string(REPLACE ";" "\;" CXX_GNU "${CXX_GNU}") +set(CXX_Clang + -Werror + -Wall + -Wextra + -Wpedantic + -Wassign-enum + -Wbad-function-cast + -Wkeyword-macro + -Wnonportable-system-include-path + -Wsometimes-uninitialized + -Wnon-virtual-dtor + -Wrange-loop-analysis + -Wabstract-vbase-init + -Warray-bounds-pointer-arithmetic + -Wno-asm-operand-widths + -Wno-assign-enum) +string(REPLACE ";" "\;" CXX_Clang "${CXX_Clang}") + +set(CXX_AppleClang "${CXX_Clang}") + +if(WIN32) + set(CXX_Intel "/WX" "/W3" "/Qdiag-enable:117,230" "/Qdiag-disable:450") +else() + set(CXX_Intel "-Werror" "-w3" "-diag-enable=117,230" "-diag-disable=450") +endif() + +set(CXX_MSVC "/WX" "/W4" "/w14806" "/w14807" "/wd14810" "/wd14811") + +add_executable(warnings.cxx.test "") +set_target_properties(warnings.cxx.test PROPERTIES + WARN_ALL ON + WARN_ERROR ON + GNU_ENABLED_WARNINGS "strict-overflow;nonnull" + GNU_DISABLED_WARNINGS "null-dereference" + LLVM_ENABLED_WARNINGS "abstract-vbase-init;array-bounds-pointer-arithmetic" + LLVM_DISABLED_WARNINGS "asm-operand-widths;assign-enum" + Intel_ENABLED_WARNINGS "117;230" + Intel_DISABLED_WARNINGS "450" + MSVC_ENABLED_WARNINGS "4806;4807" + MSVC_DISABLED_WARNINGS "4810;4811") +target_link_libraries(warnings.cxx.test PUBLIC shacl::cmake::Warnings_CXX) + +file(GENERATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/warnings.cpp + INPUT ${CMAKE_CURRENT_LIST_DIR}/warnings.cpp.in) + +target_sources(warnings.cxx.test PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/warnings.cpp) + +add_test(NAME shacl.cmake.warnings.cxx.test COMMAND warnings.cxx.test) + +set_tests_properties(shacl.cmake.warnings.cxx.test PROPERTIES + PASS_REGULAR_EXPRESSION "^${CXX_${CMAKE_CXX_COMPILER_ID}};*\n$") + +if (CMAKE_CUDA_COMPILER) + + set(CUDA_NVIDIA_GNU ${CXX_GNU}) + set(CUDA_NVIDIA_Clang ${CXX_Clang}) + + add_executable(warnings.cu.test "") + set_target_properties(warnings.cu.test PROPERTIES + WARN_ALL ON + WARN_ERROR ON + GNU_ENABLED_WARNINGS "strict-overflow;nonnull" + GNU_DISABLED_WARNINGS "null-dereference" + LLVM_ENABLED_WARNINGS "abstract-vbase-init;array-bounds-pointer-arithmetic" + LLVM_DISABLED_WARNINGS "asm-operand-widths;assign-enum" + Intel_ENABLED_WARNINGS "117;230" + Intel_DISABLED_WARNINGS "450" + MSVC_ENABLED_WARNINGS "4806;4807" + MSVC_DISABLED_WARNINGS "4810;4811") + + target_link_libraries(warnings.cu.test PUBLIC shacl::cmake::Warnings_CUDA) + + file(GENERATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/warnings.cu + INPUT ${CMAKE_CURRENT_LIST_DIR}/warnings.cu.in) + + target_sources(warnings.cu.test PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/warnings.cu) + + add_test(NAME shacl.cmake.warnings.cu.test COMMAND warnings.cu.test) + + if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") + if (NOT DEFINED CUDA_HOST_COMPILER) + set(CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER_ID}) + endif() + else() + if (NOT DEFINED CUDA_HOST_COMPILER) + set(CUDA_HOST_COMPILER "NA") + endif() + endif() + + set_tests_properties(shacl.cmake.warnings.cu.test PROPERTIES + PASS_REGULAR_EXPRESSION "^${CUDA_${CMAKE_CUDA_COMPILER_ID}_${CUDA_HOST_COMPILER}}\n$") + +endif() + +set(Fortran_GNU +"-Werror +-Wall +-Wextra +-Wpedantic +-Wcharacter-truncation +-Wrealloc-lhs" +) + +if( ${CMAKE_Fortran_COMPILER_VERSION} VERSION_LESS 7.3 ) + set(Fortran_GNU +"${Fortran_GNU} +-Wno-surprising") +endif() + +set(Fortran_GNU +"${Fortran_GNU} +-Wuse-without-only +-Wconversion +-Wline-truncation +-Wno-array-temporaries +-Wno-c-binding-type") + +if(WIN32) + set(Fortran_Intel +"/warn:error,stderror,all +/Qdiag-enable:8689,8685 +/Qdiag-disable:8694,8695") +else() + set(Fortran_Intel +"-warn +error,stderror,all +-diag-enable=8689,8685 +-diag-disable=8694,8695") +endif() + +add_executable(warnings.fortran.test "") +set_target_properties(warnings.fortran.test PROPERTIES + WARN_ALL ON + WARN_ERROR ON + GNU_ENABLED_WARNINGS "conversion;line-truncation" + GNU_DISABLED_WARNINGS "array-temporaries;c-binding-type" + Intel_ENABLED_WARNINGS "8689;8685" + Intel_DISABLED_WARNINGS "8694;8695") +target_link_libraries(warnings.fortran.test PUBLIC shacl::cmake::Warnings_Fortran) + +file(GENERATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/warnings.f90 + INPUT ${CMAKE_CURRENT_LIST_DIR}/warnings.f90.in) + +target_sources(warnings.fortran.test PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/warnings.f90) + +add_test(NAME shacl.cmake.warnings.fortran.test COMMAND warnings.fortran.test) +set_tests_properties(shacl.cmake.warnings.fortran.test PROPERTIES + PASS_REGULAR_EXPRESSION "^${Fortran_${CMAKE_Fortran_COMPILER_ID}};*\n*$") diff --git a/tests/Warnings/warnings.c.in b/tests/Warnings/warnings.c.in new file mode 100644 index 0000000..9f77eda --- /dev/null +++ b/tests/Warnings/warnings.c.in @@ -0,0 +1,6 @@ +#include + +int main(){ + puts("$"); + return 0; +} diff --git a/tests/Warnings/warnings.cpp.in b/tests/Warnings/warnings.cpp.in new file mode 100644 index 0000000..a1c7178 --- /dev/null +++ b/tests/Warnings/warnings.cpp.in @@ -0,0 +1,5 @@ +#include + +int main(){ + std::cout << "$" << std::endl; +} diff --git a/tests/Warnings/warnings.cu.in b/tests/Warnings/warnings.cu.in new file mode 100644 index 0000000..24ad462 --- /dev/null +++ b/tests/Warnings/warnings.cu.in @@ -0,0 +1,5 @@ +#include + +int main(){ + std::cout << "$" << std::endl; +} diff --git a/tests/Warnings/warnings.f90.in b/tests/Warnings/warnings.f90.in new file mode 100644 index 0000000..7ba6b41 --- /dev/null +++ b/tests/Warnings/warnings.f90.in @@ -0,0 +1,4 @@ +program warnings + write(*,'(a)') "$," + write(*,'(a)') ">" +end program diff --git a/tests/shacl_FetchContent/CMakeLists.txt b/tests/shacl_FetchContent/CMakeLists.txt new file mode 100644 index 0000000..b535c3f --- /dev/null +++ b/tests/shacl_FetchContent/CMakeLists.txt @@ -0,0 +1,29 @@ +include(CTest) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../..) + +include(shacl_FetchContent) + +include(dependencies.cmake) + +# calls to find_package will use the libraries found in dependencies.cmake via FETCHCONTENT +find_package(Catch2 2.0 REQUIRED) +find_package(shacl-trait REQUIRED) + +# Second inclusion does nothing and should not print anything extra +include(dependencies.cmake) + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bar.cpp +"#include + +// Test that find_package set the ${name}_FOUND variables to TRUE + int main(){ + assert(\"${Catch2_FOUND}\" == \"1\" ); + assert(\"${shacl-trait_FOUND}\" == \"1\" ); + } +") + +add_executable(Git.FetchContent.test ${CMAKE_CURRENT_BINARY_DIR}/bar.cpp) + +add_test( + NAME shacl.cmake.Git.FetchContent.test + COMMAND Git.FetchContent.test) diff --git a/tests/shacl_FetchContent/dependencies.cmake b/tests/shacl_FetchContent/dependencies.cmake new file mode 100644 index 0000000..9c2802b --- /dev/null +++ b/tests/shacl_FetchContent/dependencies.cmake @@ -0,0 +1,24 @@ + +# Test with relative path provided with FIND_PACKAGE_ARGS +shacl_FetchContent_Declare( Catch2 + GIT_REPOSITORY ../../catchorg/catch2 + GIT_TAG master + FIND_PACKAGE_ARGS 2.0 +) + +# First-in wins - these values are ignored +shacl_FetchContent_Declare( Catch2 + GIT_REPOSITORY nonsense + GIT_TAG morenonsense +) + +# Test with relative path +# shacl-trait also depends on Catch2 +shacl_FetchContent_Declare( shacl-trait + GIT_REPOSITORY ../trait + GIT_TAG master + GIT_SUBMODULES ".gitmodules" + GIT_SHALLOW TRUE +) + +shacl_FetchContent_MakeAvailable(shacl-trait Catch2) From 55bfeaa7ad66e6952a0626fd1cacb5a6637ff434 Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Tue, 28 Feb 2023 17:34:26 -0700 Subject: [PATCH 3/6] Adds shacl_FetchContent in place of FetchContent --- CMakeLists.txt | 2 +- cmake/develop_dependencies.cmake | 17 +++++++++-------- cmake/release_dependencies.cmake | 17 +++++++++-------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dfdf220..54f1630 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ if(DEFINED PROJECT_NAME) set(subproject ON) endif() -cmake_minimum_required( VERSION 3.14 ) +cmake_minimum_required( VERSION 3.24 ) project( Log LANGUAGES CXX ) diff --git a/cmake/develop_dependencies.cmake b/cmake/develop_dependencies.cmake index 8d856aa..d67bdbb 100644 --- a/cmake/develop_dependencies.cmake +++ b/cmake/develop_dependencies.cmake @@ -1,18 +1,19 @@ -cmake_minimum_required( VERSION 3.14 ) -include( FetchContent ) +cmake_minimum_required( VERSION 3.24 ) +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/.cmake) +include( shacl_FetchContent ) ####################################################################### # Declare project dependencies ####################################################################### -FetchContent_Declare( catch-adapter - GIT_REPOSITORY https://github.com/njoy/catch-adapter +shacl_FetchContent_Declare( catch-adapter + GIT_REPOSITORY ../../njoy/catch-adapter GIT_TAG origin/master GIT_SHALLOW TRUE ) -FetchContent_Declare( spdlog - GIT_REPOSITORY https://github.com/gabime/spdlog +shacl_FetchContent_Declare( spdlog + GIT_REPOSITORY ../../gabime/spdlog GIT_TAG a51b4856377a71f81b6d74b9af459305c4c644f8 ) set( SPDLOG_BUILD_TESTING CACHE BOOL OFF ) @@ -21,11 +22,11 @@ set( SPDLOG_BUILD_TESTING CACHE BOOL OFF ) # Load dependencies ####################################################################### -FetchContent_MakeAvailable( +shacl_FetchContent_MakeAvailable( spdlog ) if (${Log_unit_tests}) - FetchContent_MakeAvailable(catch-adapter) + shacl_FetchContent_MakeAvailable(catch-adapter) endif() diff --git a/cmake/release_dependencies.cmake b/cmake/release_dependencies.cmake index 6586750..84444e7 100644 --- a/cmake/release_dependencies.cmake +++ b/cmake/release_dependencies.cmake @@ -1,18 +1,19 @@ -cmake_minimum_required( VERSION 3.14 ) -include( FetchContent ) +cmake_minimum_required( VERSION 3.24 ) +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/.cmake) +include( shacl_FetchContent ) ####################################################################### # Declare project dependencies ####################################################################### -FetchContent_Declare( spdlog - GIT_REPOSITORY https://github.com/gabime/spdlog +shacl_FetchContent_Declare( spdlog + GIT_REPOSITORY ../../gabime/spdlog GIT_TAG a51b4856377a71f81b6d74b9af459305c4c644f8 ) set( SPDLOG_BUILD_TESTING CACHE BOOL OFF ) -FetchContent_Declare( catch-adapter - GIT_REPOSITORY https://github.com/njoy/catch-adapter +shacl_FetchContent_Declare( catch-adapter + GIT_REPOSITORY ../../njoy/catch-adapter GIT_TAG fb84b82ebf7a4789aa43cea560680cf745c6ee4f ) @@ -20,10 +21,10 @@ FetchContent_Declare( catch-adapter # Load dependencies ####################################################################### -FetchContent_MakeAvailable( +shacl_FetchContent_MakeAvailable( spdlog ) if (${Log_unit_tests}) - FetchContent_MakeAvailable(catch-adapter) + shacl_FetchContent_MakeAvailable(catch-adapter) endif() From 0799e0de81eba66c920110b7669f7e7714888c12 Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Wed, 1 Mar 2023 17:51:57 -0700 Subject: [PATCH 4/6] Adds njoy:: namespacing to CMake targets --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 54f1630..9bfa598 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,8 @@ string( CONCAT prefix add_library( Log INTERFACE ) +add_library( njoy::Log ALIAS Log ) + target_include_directories( Log INTERFACE ${prefix} ) # treat spdlog specially due to mixed namespace usage @@ -112,6 +114,7 @@ if(Log_installation) install(EXPORT Log-targets FILE "Log-targets.cmake" + NAMESPACE njoy:: DESTINATION share/cmake/Log ) From 9f70f9428219dc245b72042a284dac18e33bc946 Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Thu, 2 Mar 2023 11:56:31 -0700 Subject: [PATCH 5/6] Updates for lowercase-config filename --- CMakeLists.txt | 6 +++--- cmake/{Log-config.cmake.in => log-config.cmake.in} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename cmake/{Log-config.cmake.in => log-config.cmake.in} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bfa598..6e5e50a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,8 +119,8 @@ if(Log_installation) ) configure_package_config_file( - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Log-config.cmake.in - ${CMAKE_BINARY_DIR}/Log-config.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/log-config.cmake.in + ${CMAKE_BINARY_DIR}/log-config.cmake INSTALL_DESTINATION share/cmake/Log ) @@ -131,7 +131,7 @@ if(Log_installation) ) install(FILES - "${PROJECT_BINARY_DIR}/Log-config.cmake" + "${PROJECT_BINARY_DIR}/log-config.cmake" DESTINATION share/cmake/Log ) diff --git a/cmake/Log-config.cmake.in b/cmake/log-config.cmake.in similarity index 100% rename from cmake/Log-config.cmake.in rename to cmake/log-config.cmake.in From 5cabcda67183914ffea9afeef3dd0125e93bec67 Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Wed, 22 Mar 2023 10:39:14 -0600 Subject: [PATCH 6/6] Fixes bug in installation --- CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e5e50a..fc2eee4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,9 +118,11 @@ if(Log_installation) DESTINATION share/cmake/Log ) + string(TOLOWER Log lowercasePackageName) + configure_package_config_file( - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/log-config.cmake.in - ${CMAKE_BINARY_DIR}/log-config.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${lowercasePackageName}-config.cmake.in + ${PROJECT_BINARY_DIR}/${lowercasePackageName}-config.cmake INSTALL_DESTINATION share/cmake/Log ) @@ -131,7 +133,7 @@ if(Log_installation) ) install(FILES - "${PROJECT_BINARY_DIR}/log-config.cmake" + "${PROJECT_BINARY_DIR}/${lowercasePackageName}-config.cmake" DESTINATION share/cmake/Log )