diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 070ee77c..4097e9ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,17 +31,14 @@ jobs: vcvarsall: true - os: "windows-2022" compiler: "msvc" - cmake: 3.18.0 cmake_generator: "Ninja" vcvarsall: true - os: "windows-2022" compiler: "msvc" - cmake: 3.18.0 cmake_generator: "Ninja" vcvarsall: false - os: "windows-2022" compiler: "msvc" - cmake: 3.18.0 vcvarsall: false steps: - uses: actions/checkout@v2 diff --git a/README.md b/README.md index 988aa012..12c8ba22 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,29 @@ # project_options -A general-purpose CMake library that provides functions that improve the CMake experience. - -It provides different functions such as `project_options`, `package_project`, `dynamic_project_options`, `run_vcpkg`, `target_link_system_libraries`, etc. +A general-purpose CMake library that provides functions that improve the CMake experience following the best practices. + +## Features + +- `project_options`: + - compiler warnings, + - compiler optimizations (intraprocedural, native), + - caching (ccache, sccache), + - sanitizers, + - static code analyzers (clang-tidy, cppcheck, visual studio, include-what-you-use), + - document generation (doxygen), + - test coverage analysis, + - precompiled headers, + - build time measurement, + - unity builds + - using custom linkers (e.g. lld) +- `package_project`: automatic packaging/installation of the project for seamless usage via find_package/target_link through CMake's FetchContent, vcpkg, etc. +- `run_vcpkg`: automatic installation of vcpkg and the project dependencies +- `ENABLE_CONAN` in `project_options`: automatic installation of Conan and the project dependencies +- `dynamic_project_options`: a wrapper around `project_options` to change the options on the fly dynamically +- `target_link_system_libraries` and `target_include_system_directories`: linking/including external dependencies/headers without warnings +- `target_link_cuda`: linking Cuda to a target + +[![ci](https://github.com/aminya/project_options/actions/workflows/ci.yml/badge.svg)](https://github.com/aminya/project_options/actions/workflows/ci.yml) ## Usage @@ -11,17 +32,17 @@ See `project_options()` in action in [this template repository](https://github.c Here is a full example: ```cmake -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.20) # set a default CXX standard for the tools and targets that do not specify them. # If commented, the latest supported standard for your compiler is automatically set. # set(CMAKE_CXX_STANDARD 20) -# Add project_options v0.22.4 +# Add project_options v0.26.1 # https://github.com/aminya/project_options # Change the version in the following URL to update the package (watch the releases of the repository for future updates) include(FetchContent) -FetchContent_Declare(_project_options URL https://github.com/aminya/project_options/archive/refs/tags/v0.22.4.zip) +FetchContent_Declare(_project_options URL https://github.com/aminya/project_options/archive/refs/tags/v0.26.1.zip) FetchContent_MakeAvailable(_project_options) include(${_project_options_SOURCE_DIR}/Index.cmake) @@ -221,6 +242,7 @@ It accepts the following named flags: It gets the following named parameters that can have different values in front of them: +- `PREFIX`: the optional prefix that is used to define `${PREFIX}_project_options` and `${PREFIX}_project_warnings` targets when the function is used in a multi-project fashion. - `DOXYGEN_THEME`: the name of the Doxygen theme to use. Supported themes: - `awesome-sidebar` (default) - `awesome` @@ -232,15 +254,32 @@ It gets the following named parameters that can have different values in front o - `CLANG_WARNINGS`: Override the defaults for the CLANG warnings - `GCC_WARNINGS`: Override the defaults for the GCC warnings - `CUDA_WARNINGS`: Override the defaults for the CUDA warnings -- `CPPCHECK_WARNINGS`: Override the defaults for the options passed to cppcheck +- `CPPCHECK_OPTIONS`: Override the defaults for the options passed to cppcheck - `VS_ANALYSIS_RULESET`: Override the defaults for the code analysis rule set in Visual Studio. - `CONAN_OPTIONS`: Extra Conan options ## `run_vcpkg` function +```cmake +run_vcpkg() +``` + +Or by specifying the options + +```cmake +run_vcpkg( + VCPKG_URL "https://github.com/microsoft/vcpkg.git" + VCPKG_REV "33c8f025390f8682811629b6830d2d66ecedcaa5" + ENABLE_VCPKG_UPDATE +) +``` + Named Option: -- `ENABLE_VCPKG_UPDATE`: (Disabled by default). If enabled, the vcpkg registry is updated before building (using `git pull`). As a result, if some of your vcpkg dependencies have been updated in the registry, they will be rebuilt. +- `ENABLE_VCPKG_UPDATE`: (Disabled by default). If enabled, the vcpkg registry is updated before building (using `git pull`). + + If `VCPKG_REV` is set to a specific commit sha, no rebuilds are triggered. + If `VCPKG_REV` is not specified or is a branch, enabling `ENABLE_VCPKG_UPDATE` will rebuild your updated vcpkg dependencies. Named String: @@ -249,6 +288,9 @@ Named String: - `VCPKG_URL`: (Defaults to `https://github.com/microsoft/vcpkg.git`). This option allows setting the URL of the vcpkg repository. By default, the official vcpkg repository is used. +- `VCPKG_REV`: This option allows checking out a specific branch name or a commit sha. +If `VCPKG_REV` is set to a specific commit sha, the builds will become reproducible because that exact commit is always used for the builds. To make sure that this commit sha is pulled, enable `ENABLE_VCPKG_UPDATE` + ## `target_link_system_libraries` function A function that accepts the same arguments as `target_link_libraries`. It has the following features: @@ -303,6 +345,20 @@ Other arguments that are automatically found and manually specifying them is not - `CONFIG_INSTALL_DESTINATION`: the destination for installation of the configuration files. Defaults to `${CMAKE_INSTALL_DATADIR}/${NAME}` +## Disabling static analysis for external targets + +This function disables static analysis for the given target: + +```cmake +target_disable_static_analysis(some_external_target) +``` + +There is also individual functions to disable a specific analysis for the target: + +- `target_disable_cpp_check(target)` +- `target_disable_vs_analysis(target)` +- `target_disable_clang_tidy(target)` + ## Changing the project_options dynamically During the test and development, it can be useful to change options on the fly. For example, to enable sanitizers when running tests. You can include `DynamicOptions.cmake`, which imports the `dynamic_project_options` function. @@ -329,17 +385,17 @@ See `dynamic_project_options()` in action in [this template repository](https:// 👉 Click to show the example: ```cmake -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.20) # set a default CXX standard for the tools and targets that do not specify them. # If commented, the latest supported standard for your compiler is automatically set. # set(CMAKE_CXX_STANDARD 20) -# Add project_options v0.22.4 +# Add project_options v0.26.1 # https://github.com/aminya/project_options # Change the version in the following URL to update the package (watch the releases of the repository for future updates) include(FetchContent) -FetchContent_Declare(_project_options URL https://github.com/aminya/project_options/archive/refs/tags/v0.22.4.zip) +FetchContent_Declare(_project_options URL https://github.com/aminya/project_options/archive/refs/tags/v0.26.1.zip) FetchContent_MakeAvailable(_project_options) include(${_project_options_SOURCE_DIR}/Index.cmake) diff --git a/cspell.config.yaml b/cspell.config.yaml index 0aa60cb0..d3fe0b48 100644 --- a/cspell.config.yaml +++ b/cspell.config.yaml @@ -22,12 +22,14 @@ words: - ccmake - choco - cmake + - CMAKE - cmakelint - cmds - cond - CPATH - Cppcheck - cppcoreguidelines + - cppdbg - CPPFLAGS - cpprc - ctest @@ -45,6 +47,7 @@ words: - gcovr - Graphviz - hwrap + - iwwu - kcov - LDFLAGS - libc @@ -62,6 +65,7 @@ words: - myprogram - myproj - myproject + - mythirdpartylib - nothrow - nvcc - Opencppcoverage @@ -104,10 +108,3 @@ words: - Wuseless - xcrun - Yahyaabadi - - "ARGN" - - "CMAKE" - - "fargs" - - "shlib" - - "vcpkg" - - cppdbg - - mythirdpartylib diff --git a/src/Common.cmake b/src/Common.cmake index 499992fb..3deb3c9d 100644 --- a/src/Common.cmake +++ b/src/Common.cmake @@ -1,7 +1,17 @@ include_guard() +# This function sets ProjectOptions_SRC_DIR using the current lists path +macro(set_project_options_src_dir) + get_directory_property(LISTFILE_STACK LISTFILE_STACK) + list(POP_BACK LISTFILE_STACK _LIST_FILE) + cmake_path(GET _LIST_FILE PARENT_PATH ProjectOptions_SRC_DIR) +endmacro() + # Common project settings run by default for all the projects that call `project_options()` macro(common_project_options) + set_project_options_src_dir() + message(DEBUG "${ProjectOptions_SRC_DIR}") + include("${ProjectOptions_SRC_DIR}/PreventInSourceBuilds.cmake") assure_out_of_source_builds() diff --git a/src/CompilerWarnings.cmake b/src/CompilerWarnings.cmake index b4fb252a..db895867 100644 --- a/src/CompilerWarnings.cmake +++ b/src/CompilerWarnings.cmake @@ -44,6 +44,7 @@ function( set(CLANG_WARNINGS -Wall -Wextra # reasonable and standard + -Wextra-semi # Warn about semicolon after in-class function definition. -Wshadow # warn the user if a variable declaration shadows one from a parent context -Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps # catch hard to track down memory errors diff --git a/src/Conan.cmake b/src/Conan.cmake index 9067a3eb..b27200b0 100644 --- a/src/Conan.cmake +++ b/src/Conan.cmake @@ -56,7 +56,7 @@ macro(run_conan) if(NOT ${_is_verbose}) set(OUTPUT_QUIET "OUTPUT_QUIET") else() - set(OUTPUT_QUIET OFF) + set(OUTPUT_QUIET) endif() foreach(TYPE ${LIST_OF_BUILD_TYPES}) @@ -69,7 +69,11 @@ macro(run_conan) set(CONAN_ENV ENV "CC=${CMAKE_C_COMPILER}" "CXX=${CMAKE_CXX_COMPILER}") else() # Derive all conan settings from a conan profile - set(CONAN_SETTINGS PROFILE ${ProjectOptions_CONAN_PROFILE}) + set(CONAN_SETTINGS + PROFILE + ${ProjectOptions_CONAN_PROFILE} + SETTINGS + "build_type=${TYPE}") # CONAN_ENV should be redundant, since the profile can set CC & CXX endif() diff --git a/src/Index.cmake b/src/Index.cmake index 23fb5ba3..71c8f588 100644 --- a/src/Index.cmake +++ b/src/Index.cmake @@ -1,46 +1,39 @@ -if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.18.0") - cmake_minimum_required(VERSION 3.18) -else() - cmake_minimum_required(VERSION 3.16) - message( - WARNING - "Consider upgrading CMake to the latest version. CMake ${CMAKE_VERSION} might fail in the linking stage because of missing references." - ) -endif() +cmake_minimum_required(VERSION 3.20) +# 3.20 is required by the windows toolchain and cmake_path. It also has a more reliable building functionality. +# 3.18 required by package_project and interprocedural optimization. It also has a more reliable building functionality (no errors during the linking stage). include_guard() -set(ProjectOptions_SRC_DIR - ${CMAKE_CURRENT_LIST_DIR} - CACHE FILEPATH "") +# only useable here +set(ProjectOptions_SRC_DIR ${CMAKE_CURRENT_LIST_DIR}) # include the files to allow calling individual functions (including the files does not run any code.) -include("${ProjectOptions_SRC_DIR}/Common.cmake") -include("${ProjectOptions_SRC_DIR}/Utilities.cmake") -include("${ProjectOptions_SRC_DIR}/Vcpkg.cmake") -include("${ProjectOptions_SRC_DIR}/SystemLink.cmake") -include("${ProjectOptions_SRC_DIR}/Cuda.cmake") -include("${ProjectOptions_SRC_DIR}/PackageProject.cmake") -include("${ProjectOptions_SRC_DIR}/Optimization.cmake") -include("${ProjectOptions_SRC_DIR}/Cache.cmake") -include("${ProjectOptions_SRC_DIR}/Linker.cmake") -include("${ProjectOptions_SRC_DIR}/CompilerWarnings.cmake") -include("${ProjectOptions_SRC_DIR}/Tests.cmake") -include("${ProjectOptions_SRC_DIR}/Sanitizers.cmake") -include("${ProjectOptions_SRC_DIR}/Doxygen.cmake") -include("${ProjectOptions_SRC_DIR}/StaticAnalyzers.cmake") -include("${ProjectOptions_SRC_DIR}/VCEnvironment.cmake") -include("${ProjectOptions_SRC_DIR}/MinGW.cmake") -include("${ProjectOptions_SRC_DIR}/DetectCompiler.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Common.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Utilities.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/SystemLink.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Cuda.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/PackageProject.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Optimization.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Cache.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Linker.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/CompilerWarnings.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Tests.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Sanitizers.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Doxygen.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/StaticAnalyzers.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/VCEnvironment.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/MinGW.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/DetectCompiler.cmake") # Include msvc toolchain on windows if the generator is not visual studio. Should be called before run_vcpkg and run_conan to be effective msvc_toolchain() -include("${ProjectOptions_SRC_DIR}/Conan.cmake") -include("${ProjectOptions_SRC_DIR}/Vcpkg.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Conan.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Vcpkg.cmake") # # Params: +# - PREFIX: the optional prefix to be prepended to the `project_options` and `project_warnings` targets when the function is used in a multi-project fashion. # - WARNINGS_AS_ERRORS: Treat compiler warnings as errors # - ENABLE_CPPCHECK: Enable static analysis with cppcheck # - ENABLE_CLANG_TIDY: Enable static analysis with clang-tidy @@ -94,7 +87,11 @@ macro(project_options) ENABLE_SANITIZER_UNDEFINED_BEHAVIOR ENABLE_SANITIZER_THREAD ENABLE_SANITIZER_MEMORY) - set(oneValueArgs LINKER VS_ANALYSIS_RULESET CONAN_PROFILE) + set(oneValueArgs + PREFIX + LINKER + VS_ANALYSIS_RULESET + CONAN_PROFILE) set(multiValueArgs DOXYGEN_THEME MSVC_WARNINGS @@ -121,8 +118,26 @@ macro(project_options) common_project_options() - # Link this 'library' to set the c++ standard / compile-time options requested - add_library(project_options INTERFACE) + # Add an interface library for the options + set(_options_target project_options) + set(_warnings_target project_warnings) + if(NOT + "${ProjectOptions_PREFIX}" + STREQUAL + "") + set(_options_target "${ProjectOptions_PREFIX}_project_options") + set(_warnings_target "${ProjectOptions_PREFIX}_project_warnings") + else() + if(TARGET project_options) + message( + FATAL + "Multiple calls to `project_options` in the same `project` detected, but the argument `PREFIX` that is prepended to `project_options` and `project_warnings` is not set." + ) + endif() + endif() + + add_library(${_options_target} INTERFACE) + add_library(${_warnings_target} INTERFACE) # fix mingw mingw_unicode() @@ -135,33 +150,30 @@ macro(project_options) set(ProjectOptions_ENABLE_INTERPROCEDURAL_OPTIMIZATION ${ProjectOptions_ENABLE_IPO}) endif() if(${ProjectOptions_ENABLE_INTERPROCEDURAL_OPTIMIZATION}) - enable_interprocedural_optimization(project_options) + enable_interprocedural_optimization(${_options_target}) endif() if(${ProjectOptions_ENABLE_NATIVE_OPTIMIZATION}) - enable_native_optimization(project_options) + enable_native_optimization(${_options_target}) endif() if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") if(ProjectOptions_ENABLE_BUILD_WITH_TIME_TRACE) - target_compile_options(project_options INTERFACE -ftime-trace) + target_compile_options(${_options_target} INTERFACE -ftime-trace) endif() endif() - # Link this 'library' to use the warnings specified in CompilerWarnings.cmake - add_library(project_warnings INTERFACE) - if(${ProjectOptions_ENABLE_CACHE}) # enable cache system enable_cache() endif() # use the linker - configure_linker(project_options "${ProjectOptions_LINKER}") + configure_linker(${_options_target} "${ProjectOptions_LINKER}") # standard compiler warnings set_project_warnings( - project_warnings + ${_warnings_target} "${WARNINGS_AS_ERRORS}" "${ProjectOptions_MSVC_WARNINGS}" "${ProjectOptions_CLANG_WARNINGS}" @@ -169,12 +181,12 @@ macro(project_options) "${ProjectOptions_CUDA_WARNINGS}") if(${ProjectOptions_ENABLE_COVERAGE}) - enable_coverage(project_options) + enable_coverage(${_options_target}) endif() # sanitizer options if supported by compiler enable_sanitizers( - project_options + ${_options_target} ${ProjectOptions_ENABLE_SANITIZER_ADDRESS} ${ProjectOptions_ENABLE_SANITIZER_LEAK} ${ProjectOptions_ENABLE_SANITIZER_UNDEFINED_BEHAVIOR} @@ -211,7 +223,7 @@ macro(project_options) ) endif() - target_precompile_headers(project_options INTERFACE ${ProjectOptions_PCH_HEADERS}) + target_precompile_headers(${_options_target} INTERFACE ${ProjectOptions_PCH_HEADERS}) endif() if(${ProjectOptions_ENABLE_VCPKG}) @@ -224,7 +236,7 @@ macro(project_options) if(${ProjectOptions_ENABLE_UNITY}) # Add for any project you want to apply unity builds for - set_target_properties(project_options PROPERTIES UNITY_BUILD ON) + set_target_properties(${_options_target} PROPERTIES UNITY_BUILD ON) endif() endmacro() diff --git a/src/MinGW.cmake b/src/MinGW.cmake index 09b0e6cf..11b06a62 100644 --- a/src/MinGW.cmake +++ b/src/MinGW.cmake @@ -18,7 +18,7 @@ function(is_mingw value) return() endif() - # if the copmiler is unknown by CMake + # if the compiler is unknown by CMake if(NOT CMAKE_CXX_COMPILER AND NOT CMAKE_C_COMPILER AND NOT CMAKE_CXX_COMPILER_ID diff --git a/src/Optimization.cmake b/src/Optimization.cmake index eac85a62..7b3991cf 100644 --- a/src/Optimization.cmake +++ b/src/Optimization.cmake @@ -1,29 +1,22 @@ include_guard() macro(enable_interprocedural_optimization project_name) - if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.18.0") - if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") - include(CheckIPOSupported) - check_ipo_supported(RESULT result OUTPUT output) - is_mingw(_is_mingw) - if(result AND NOT ${_is_mingw}) - # If a static library of this project is used in another project that does not have `CMAKE_INTERPROCEDURAL_OPTIMIZATION` enabled, a linker error might happen. - # TODO set this option in `package_project` function. - message( - STATUS - "Interprocedural optimization is enabled. In other projects, linking with the compiled libraries of this project might require `set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)`" - ) - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) - set_target_properties(${project_name} PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON) - else() - message(WARNING "Interprocedural Optimization is not supported. Not using it. Here is the error log: ${output}") - endif() + if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + include(CheckIPOSupported) + check_ipo_supported(RESULT result OUTPUT output) + is_mingw(_is_mingw) + if(result AND NOT ${_is_mingw}) + # If a static library of this project is used in another project that does not have `CMAKE_INTERPROCEDURAL_OPTIMIZATION` enabled, a linker error might happen. + # TODO set this option in `package_project` function. + message( + STATUS + "Interprocedural optimization is enabled. In other projects, linking with the compiled libraries of this project might require `set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)`" + ) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) + set_target_properties(${project_name} PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON) + else() + message(WARNING "Interprocedural Optimization is not supported. Not using it. Here is the error log: ${output}") endif() - else() - message( - WARNING - "Consider upgrading CMake to the latest version. CMake ${CMAKE_VERSION} does not support ENABLE_INTERPROCEDURAL_OPTIMIZATION." - ) endif() endmacro() diff --git a/src/PackageProject.cmake b/src/PackageProject.cmake index f272175c..f06c9c93 100644 --- a/src/PackageProject.cmake +++ b/src/PackageProject.cmake @@ -5,18 +5,8 @@ include_guard() # A function that packages the project for external usage (e.g. from vcpkg, Conan, etc). # See the [README.md] for more details function(package_project) - if(${CMAKE_VERSION} VERSION_LESS "3.18.0") - message( - WARNING - "Consider upgrading CMake to the latest version. CMake ${CMAKE_VERSION} does not support checking for policy CMP0103." - ) - else() - cmake_minimum_required(VERSION 3.18) - cmake_policy(SET CMP0103 NEW) # disallow multiple calls with the same NAME - endif() - - set(_options ARCH_INDEPENDENT # default to false - ) + # default to false + set(_options ARCH_INDEPENDENT) set(_oneValueArgs # default to the project_name: NAME @@ -148,18 +138,27 @@ function(package_project) # Installation of package (compatible with vcpkg, etc) set(_targets_list ${_PackageProject_TARGETS}) unset(_PackageProject_TARGETS) # to avoid ycm conflict + + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.23.0") + # required in CMake 3.23 and more + set(FILE_SET_ARGS "FILE_SET" "HEADERS") + endif() + install( TARGETS ${_targets_list} EXPORT ${_PackageProject_EXPORT} LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin - PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${_PackageProject_NAME}" COMPONENT dev) + PUBLIC_HEADER + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${_PackageProject_NAME}" + COMPONENT dev + ${FILE_SET_ARGS}) # download ForwardArguments FetchContent_Declare( _fargs - URL https://github.com/polysquare/cmake-forward-arguments/archive/8c50d1f956172edb34e95efa52a2d5cb1f686ed2.zip) + URL https://github.com/polysquare/cmake-forward-arguments/archive/refs/tags/v1.0.0.zip) FetchContent_GetProperties(_fargs) if(NOT _fargs_POPULATED) FetchContent_Populate(_fargs) diff --git a/src/StaticAnalyzers.cmake b/src/StaticAnalyzers.cmake index 1f9f8103..b302f027 100644 --- a/src/StaticAnalyzers.cmake +++ b/src/StaticAnalyzers.cmake @@ -159,7 +159,6 @@ macro(enable_include_what_you_use) endif() endmacro() - # Disable clang-tidy for target macro(target_disable_clang_tidy TARGET) find_program(CLANGTIDY clang-tidy) @@ -183,17 +182,18 @@ macro(target_disable_vs_analysis TARGET) if(CMAKE_GENERATOR MATCHES "Visual Studio") set_target_properties( ${TARGET} - PROPERTIES - VS_GLOBAL_EnableMicrosoftCodeAnalysis false - VS_GLOBAL_CodeAnalysisRuleSet "" - VS_GLOBAL_EnableClangTidyCodeAnalysis "" - ) + PROPERTIES VS_GLOBAL_EnableMicrosoftCodeAnalysis false + VS_GLOBAL_CodeAnalysisRuleSet "" + VS_GLOBAL_EnableClangTidyCodeAnalysis "") endif() endmacro() # Disable static analysis for target macro(target_disable_static_analysis TARGET) - if(NOT CMAKE_GENERATOR MATCHES "Visual Studio") + if(NOT + CMAKE_GENERATOR + MATCHES + "Visual Studio") target_disable_clang_tidy(${TARGET}) target_disable_cpp_check(${TARGET}) endif() diff --git a/src/SystemLink.cmake b/src/SystemLink.cmake index 73610f88..62227f0d 100644 --- a/src/SystemLink.cmake +++ b/src/SystemLink.cmake @@ -12,10 +12,9 @@ function(target_include_system_directories target) foreach(scope IN ITEMS INTERFACE PUBLIC PRIVATE) foreach(lib_include_dirs IN LISTS ARG_${scope}) - if(NOT MSVC) - # system includes do not work in MSVC - # awaiting https://gitlab.kitware.com/cmake/cmake/-/issues/18272# - # awaiting https://gitlab.kitware.com/cmake/cmake/-/issues/17904 + if(NOT MSVC OR (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL + "19.29.30036.3")) + # system includes do not work prior to CMake 3.24.0 and MSVC 19.29.30036.3 set(_SYSTEM SYSTEM) endif() if(${scope} STREQUAL "INTERFACE" OR ${scope} STREQUAL "PUBLIC") diff --git a/src/Utilities.cmake b/src/Utilities.cmake index 7b3ef253..392d49ec 100644 --- a/src/Utilities.cmake +++ b/src/Utilities.cmake @@ -131,9 +131,9 @@ endmacro() # Is CMake verbose? function(is_verbose var) - if("CMAKE_MESSAGE_LOG_LEVEL" STREQUAL "VERBOSE" - OR "CMAKE_MESSAGE_LOG_LEVEL" STREQUAL "DEBUG" - OR "CMAKE_MESSAGE_LOG_LEVEL" STREQUAL "TRACE") + if("${CMAKE_MESSAGE_LOG_LEVEL}" STREQUAL "VERBOSE" + OR "${CMAKE_MESSAGE_LOG_LEVEL}" STREQUAL "DEBUG" + OR "${CMAKE_MESSAGE_LOG_LEVEL}" STREQUAL "TRACE") set(${var} ON PARENT_SCOPE) diff --git a/src/VCEnvironment.cmake b/src/VCEnvironment.cmake index aea0b7d4..fb6928bf 100644 --- a/src/VCEnvironment.cmake +++ b/src/VCEnvironment.cmake @@ -1,6 +1,6 @@ include_guard() -include("${ProjectOptions_SRC_DIR}/Utilities.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Utilities.cmake") # detect if the compiler is msvc function(is_msvc value) @@ -64,10 +64,10 @@ macro(msvc_toolchain) is_msvc(_is_msvc) if(${_is_msvc}) # if msvc - message(STATUS "Using Windows MSVC toolchain") + message(STATUS "Using Windows Windows toolchain") include(FetchContent) FetchContent_Declare( - _msvc_toolchain URL "https://github.com/aminya/Toolchain/archive/95891a1e28a406ffb22e572f3ef24a7a8ad27ec0.zip") + _msvc_toolchain URL "https://github.com/MarkSchofield/WindowsToolchain/archive/refs/tags/v0.5.1.zip") FetchContent_MakeAvailable(_msvc_toolchain) include("${_msvc_toolchain_SOURCE_DIR}/Windows.MSVC.toolchain.cmake") message(STATUS "Setting CXX/C compiler to ${CMAKE_CXX_COMPILER}") @@ -96,7 +96,7 @@ macro(run_vcvarsall) # if msvc_found is set by msvc_toolchain # or if MSVC but VSCMD_VER is not set, which means vcvarsall has not run - if(MSVC_FOUND OR (MSVC AND "$ENV{VSCMD_VER}" STREQUAL "")) + if((MSVC_FOUND OR MSVC) AND "$ENV{VSCMD_VER}" STREQUAL "") # find vcvarsall.bat get_filename_component(MSVC_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) @@ -113,19 +113,38 @@ macro(run_vcvarsall) if(EXISTS ${VCVARSALL_FILE}) # run vcvarsall and print the environment variables message(STATUS "Running `${VCVARSALL_FILE} ${VCVARSALL_ARCH}` to set up the MSVC environment") + + # make vcvarsall quiet + set(VSCMD_DEBUG "$ENV{VSCMD_DEBUG}") + set($ENV{VSCMD_DEBUG} 0) + execute_process( COMMAND - "cmd" "/c" ${VCVARSALL_FILE} ${VCVARSALL_ARCH} # - "&&" "call" "echo" "VCVARSALL_ENV_START" # - "&" "set" # + "cmd" "/c" "${VCVARSALL_FILE}" "${VCVARSALL_ARCH}" "1>NUL" # + "&&" "call" "echo" "VCVARSALL_ENV_START" # a starting point + "&" "set" # print the environment variables OUTPUT_VARIABLE VCVARSALL_OUTPUT - OUTPUT_STRIP_TRAILING_WHITESPACE) + ERROR_VARIABLE VCVARSALL_ERROR + OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE) + + # recover VSCMD_DEBUG variable + set($ENV{VSCMD_DEBUG} "${VSCMD_DEBUG}") + + if("${VCVARSALL_ERROR}" STREQUAL "" + AND NOT + "${VCVARSALL_OUTPUT}" + STREQUAL + "") + # parse the output and get the environment variables string + find_substring_by_prefix(VCVARSALL_ENV "VCVARSALL_ENV_START" "${VCVARSALL_OUTPUT}") + + # set the environment variables + set_env_from_string("${VCVARSALL_ENV}") + else() + message(WARNING "Failed to parse the vcvarsall output. ${VCVARSALL_ERROR}.\nIgnoring this error") - # parse the output and get the environment variables string - find_substring_by_prefix(VCVARSALL_ENV "VCVARSALL_ENV_START" "${VCVARSALL_OUTPUT}") + endif() - # set the environment variables - set_env_from_string("${VCVARSALL_ENV}") else() message( WARNING diff --git a/src/Vcpkg.cmake b/src/Vcpkg.cmake index a83ab8b4..4f689c29 100644 --- a/src/Vcpkg.cmake +++ b/src/Vcpkg.cmake @@ -4,10 +4,10 @@ include(FetchContent) # Install vcpkg and vcpkg dependencies: - should be called before defining project() macro(run_vcpkg) - # named boolean ENABLE_VCPKG_UPDATE argument + # named boolean ENABLE_VCPKG_UPDATE arguments set(options ENABLE_VCPKG_UPDATE) - # optional named VCPKG_DIR and VCPKG_URL argument - set(oneValueArgs VCPKG_DIR VCPKG_URL) + # optional named VCPKG_DIR, VCPKG_URL, and VCPKG_REV arguments + set(oneValueArgs VCPKG_DIR VCPKG_URL VCPKG_REV) cmake_parse_arguments( _vcpkg_args "${options}" @@ -15,20 +15,22 @@ macro(run_vcpkg) "" ${ARGN}) + find_program(GIT_EXECUTABLE "git" REQUIRED) + if(NOT "${_vcpkg_args_VCPKG_DIR}" STREQUAL "") # the installation directory is specified - get_filename_component(VCPKG_PARENT_DIR ${_vcpkg_args_VCPKG_DIR} DIRECTORY) + get_filename_component(VCPKG_PARENT_DIR "${_vcpkg_args_VCPKG_DIR}" DIRECTORY) else() # Default vcpkg installation directory if(WIN32) set(VCPKG_PARENT_DIR $ENV{userprofile}) - set(_vcpkg_args_VCPKG_DIR ${VCPKG_PARENT_DIR}/vcpkg) + set(_vcpkg_args_VCPKG_DIR "${VCPKG_PARENT_DIR}/vcpkg") else() set(VCPKG_PARENT_DIR $ENV{HOME}) - set(_vcpkg_args_VCPKG_DIR ${VCPKG_PARENT_DIR}/vcpkg) + set(_vcpkg_args_VCPKG_DIR "${VCPKG_PARENT_DIR}/vcpkg") endif() endif() @@ -39,19 +41,48 @@ macro(run_vcpkg) if(EXISTS "${_vcpkg_args_VCPKG_DIR}" AND EXISTS "${_vcpkg_args_VCPKG_DIR}/vcpkg${CMAKE_EXECUTABLE_SUFFIX}") message(STATUS "vcpkg is already installed at ${_vcpkg_args_VCPKG_DIR}.") if(${_vcpkg_args_ENABLE_VCPKG_UPDATE}) + + if(NOT + "${_vcpkg_args_VCPKG_REV}" + STREQUAL + "") + # detect if the head is detached, if so, switch back before calling git pull on a detached head + set(_vcpkg_git_status "") + execute_process( + COMMAND "${GIT_EXECUTABLE}" "rev-parse" "--abbrev-ref" "--symbolic-full-name" "HEAD" + OUTPUT_VARIABLE _vcpkg_git_status + WORKING_DIRECTORY "${_vcpkg_args_VCPKG_DIR}" + OUTPUT_STRIP_TRAILING_WHITESPACE) + if("${_vcpkg_git_status}" STREQUAL "HEAD") + message(STATUS "Switching back before updating") + execute_process(COMMAND "${GIT_EXECUTABLE}" "switch" "-" WORKING_DIRECTORY "${_vcpkg_args_VCPKG_DIR}") + endif() + endif() + message(STATUS "Updating the repository...") - execute_process(COMMAND "git" "pull" WORKING_DIRECTORY ${_vcpkg_args_VCPKG_DIR}) + execute_process(COMMAND "${GIT_EXECUTABLE}" "pull" WORKING_DIRECTORY "${_vcpkg_args_VCPKG_DIR}") endif() else() message(STATUS "Installing vcpkg at ${_vcpkg_args_VCPKG_DIR}") # clone vcpkg from Github + if("${_vcpkg_args_VCPKG_URL}" STREQUAL "") + set(_vcpkg_args_VCPKG_URL "https://github.com/microsoft/vcpkg.git") + endif() if(NOT EXISTS "${_vcpkg_args_VCPKG_DIR}") - if("${_vcpkg_args_VCPKG_URL}" STREQUAL "") - set(_vcpkg_args_VCPKG_URL "https://github.com/microsoft/vcpkg.git") - endif() - find_program(GIT_EXECUTABLE "git" REQUIRED) execute_process(COMMAND "${GIT_EXECUTABLE}" "clone" "${_vcpkg_args_VCPKG_URL}" - WORKING_DIRECTORY ${VCPKG_PARENT_DIR} COMMAND_ERROR_IS_FATAL LAST) + WORKING_DIRECTORY "${VCPKG_PARENT_DIR}" COMMAND_ERROR_IS_FATAL LAST) + else() + # ensure that the given vcpkg remote is the current remote + execute_process( + COMMAND "${GIT_EXECUTABLE}" "remote" "-v" + WORKING_DIRECTORY "${VCPKG_PARENT_DIR}" COMMAND_ERROR_IS_FATAL LAST + OUTPUT_VARIABLE _vcpkg_git_remote_info) + string(FIND "${_vcpkg_git_remote_info}" "${_vcpkg_args_VCPKG_URL}" _vcpkg_has_remote) + if(NOT ${_vcpkg_has_remote}) + message( + FATAL + "The current vcpkg remote at ${_vcpkg_args_VCPKG_DIR} does not match the given URL ${_vcpkg_args_VCPKG_URL}") + endif() endif() # Run vcpkg bootstrap if(WIN32) @@ -63,6 +94,14 @@ macro(run_vcpkg) endif() endif() + if(NOT + "${_vcpkg_args_VCPKG_REV}" + STREQUAL + "") + execute_process(COMMAND "${GIT_EXECUTABLE}" "checkout" "${_vcpkg_args_VCPKG_REV}" + WORKING_DIRECTORY "${VCPKG_PARENT_DIR}/vcpkg" COMMAND_ERROR_IS_FATAL LAST) + endif() + configure_mingw_vcpkg() # Setting up vcpkg toolchain diff --git a/src/detect_compiler/CMakeLists.txt b/src/detect_compiler/CMakeLists.txt index 693a767e..86853bdc 100644 --- a/src/detect_compiler/CMakeLists.txt +++ b/src/detect_compiler/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.20) enable_language(CXX) enable_language(C) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c43767dc..5c9f9820 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -117,10 +117,7 @@ target_link_system_libraries( PRIVATE fmt::fmt Eigen3::Eigen) -target_link_system_libraries( - lib2 - PRIVATE - mythirdpartylib) +target_link_system_libraries(lib2 PRIVATE mythirdpartylib) # package everything automatically package_project( diff --git a/test/include/mylib/lib.hpp b/test/include/mylib/lib.hpp index e808b290..6ecad59b 100644 --- a/test/include/mylib/lib.hpp +++ b/test/include/mylib/lib.hpp @@ -18,13 +18,13 @@ #include int some_fun() { - fmt::print("Hello from fmt{}", "!"); + fmt::print("Hello from fmt{}", "!"); - // populate an Eigen vector with the values - auto eigen_vec = Eigen::VectorXd::LinSpaced(10, 0, 1); + // populate an Eigen vector with the values + auto eigen_vec = Eigen::VectorXd::LinSpaced(10, 0, 1); - // print the vector - fmt::print("{}", eigen_vec); + // print the vector + fmt::print("{}", eigen_vec); - return 0; + return 0; } diff --git a/test/libs/mythirdpartylib/CMakeLists.txt b/test/libs/mythirdpartylib/CMakeLists.txt index ddc7e17b..d035dda3 100644 --- a/test/libs/mythirdpartylib/CMakeLists.txt +++ b/test/libs/mythirdpartylib/CMakeLists.txt @@ -1,11 +1,6 @@ - add_library(mythirdpartylib STATIC src/Foo.cpp) generate_export_header(mythirdpartylib) -target_include_directories(mythirdpartylib - PUBLIC $ - $ -) -target_include_directories(mythirdpartylib - PUBLIC $ -) \ No newline at end of file +target_include_directories(mythirdpartylib PUBLIC $ + $) +target_include_directories(mythirdpartylib PUBLIC $) diff --git a/test/libs/mythirdpartylib/include/Foo.hpp b/test/libs/mythirdpartylib/include/Foo.hpp index 24621a36..26aa7e0e 100644 --- a/test/libs/mythirdpartylib/include/Foo.hpp +++ b/test/libs/mythirdpartylib/include/Foo.hpp @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include "mythirdpartylib_export.h" @@ -9,17 +9,17 @@ namespace mythirdpartylib { class MYTHIRDPARTYLIB_EXPORT Foo { public: - Foo() = default; + Foo() = default; - /*implicit*/ Foo(int a) : m_a(a) {} + /*implicit*/ Foo(int a) : m_a(a) {} - int a() const { return m_a; } + int a() const { return m_a; } - void update(bool b, bool c, bool d); - void bad(std::vector& v); + void update(bool b, bool c, bool d); + void bad(std::vector &v); private: - int m_a; + int m_a; }; -} \ No newline at end of file +} // namespace mythirdpartylib \ No newline at end of file diff --git a/test/libs/mythirdpartylib/src/Foo.cpp b/test/libs/mythirdpartylib/src/Foo.cpp index f83ced37..9e777af4 100644 --- a/test/libs/mythirdpartylib/src/Foo.cpp +++ b/test/libs/mythirdpartylib/src/Foo.cpp @@ -3,22 +3,22 @@ namespace mythirdpartylib { void Foo::update(bool b, bool c, bool d) { - int e = b + d; - m_a = e; + int e = b + d; + m_a = e; } -void Foo::bad(std::vector& v) { - std::string val = "hello"; - int index = -1; // bad, plus should use gsl::index - for (int i = 0; i < v.size(); ++i) { - if (v[i] == val) { - index = i; - break; - } +void Foo::bad(std::vector &v) { + std::string val = "hello"; + int index = -1; // bad, plus should use gsl::index + for (int i = 0; i < v.size(); ++i) { + if (v[i] == val) { + index = i; + break; } + } } -static Foo foo (5); +static Foo foo(5); static Foo bar = 42; -} \ No newline at end of file +} // namespace mythirdpartylib \ No newline at end of file diff --git a/test/src/main/main.cpp b/test/src/main/main.cpp index 8493180a..3dc72141 100644 --- a/test/src/main/main.cpp +++ b/test/src/main/main.cpp @@ -16,20 +16,20 @@ #include int main() { - fmt::print("Hello from fmt{}", "!"); + fmt::print("Hello from fmt{}", "!"); - Eigen::VectorXd eigen_vec = Eigen::Vector3d(1, 2, 3); - fmt::print("{}", eigen_vec); + Eigen::VectorXd eigen_vec = Eigen::Vector3d(1, 2, 3); + fmt::print("{}", eigen_vec); -#if !defined(__MINGW32__) && !defined(__MSYS__)// TODO fails - Eigen::VectorXd eigen_vec2 = Eigen::VectorXd::LinSpaced(10, 0, 1); - fmt::print("{}", eigen_vec2); +#if !defined(__MINGW32__) && !defined(__MSYS__) // TODO fails + Eigen::VectorXd eigen_vec2 = Eigen::VectorXd::LinSpaced(10, 0, 1); + fmt::print("{}", eigen_vec2); #endif - // trigger address sanitizer - // int *p = nullptr; - // *p = 1; + // trigger address sanitizer + // int *p = nullptr; + // *p = 1; - // trigger compiler warnings, clang-tidy, and cppcheck - int a; + // trigger compiler warnings, clang-tidy, and cppcheck + int a; } diff --git a/test/src/mylib2/lib.cpp b/test/src/mylib2/lib.cpp index 41e4b510..38458dce 100644 --- a/test/src/mylib2/lib.cpp +++ b/test/src/mylib2/lib.cpp @@ -16,15 +16,15 @@ #include int some_fun2() { - fmt::print("Hello from fmt{}", "!"); + fmt::print("Hello from fmt{}", "!"); - Eigen::VectorXd eigen_vec = Eigen::Vector3d(1, 2, 3); - fmt::print("{}", eigen_vec); + Eigen::VectorXd eigen_vec = Eigen::Vector3d(1, 2, 3); + fmt::print("{}", eigen_vec); -#if !defined(__MINGW32__) && !defined(__MSYS__)// TODO fails - Eigen::VectorXd eigen_vec2 = Eigen::VectorXd::LinSpaced(10, 0, 1); - fmt::print("{}", eigen_vec2); +#if !defined(__MINGW32__) && !defined(__MSYS__) // TODO fails + Eigen::VectorXd eigen_vec2 = Eigen::VectorXd::LinSpaced(10, 0, 1); + fmt::print("{}", eigen_vec2); #endif - return 0; + return 0; } diff --git a/test_install/src/another_main.cpp b/test_install/src/another_main.cpp index 4b80c7b0..f14a6747 100644 --- a/test_install/src/another_main.cpp +++ b/test_install/src/another_main.cpp @@ -2,6 +2,6 @@ #include int main() { - some_fun2(); - return some_fun2(); + some_fun2(); + return some_fun2(); } \ No newline at end of file