From c0c014487f599ecf484079a38de187ba73a4979a Mon Sep 17 00:00:00 2001 From: S David <2100425+s-daveb@users.noreply.github.com> Date: Thu, 16 May 2024 18:56:21 -0400 Subject: [PATCH] Initial commit; standardizing these scripts from various projects --- BuildOptions.cmake | 52 +++++++++++++++++++++ BuildProperties.cmake | 102 ++++++++++++++++++++++++++++++++++++++++++ CPM.cmake | 24 ++++++++++ LICENSE | 25 +++++++++++ README.md | 59 ++++++++++++++++++++++++ Util.cmake | 37 +++++++++++++++ 6 files changed, 299 insertions(+) create mode 100644 BuildOptions.cmake create mode 100644 BuildProperties.cmake create mode 100644 CPM.cmake create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Util.cmake diff --git a/BuildOptions.cmake b/BuildOptions.cmake new file mode 100644 index 0000000..59f3362 --- /dev/null +++ b/BuildOptions.cmake @@ -0,0 +1,52 @@ + +function(use_ccache) + option(USE_CCACHE + "Use ccache compiler cache to speed up builds.\nEnabled by default if ccache is found" + ON + ) + if (USE_CCACHE) + message(CHECK_START "Detecting cacche") + + find_program(CCACHE_PATH ccache) + if(CCACHE_PATH) + message(CHECK_PASS("found")) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PATH}) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_PATH}) + endif() + + list(APPEND CMAKE_MESSAGE_INDENT " ") + message(STATUS "(set -DUSE_CCACHE=Off to disable)") + list(POP_BACK CMAKE_MESSAGE_INDENT) + endif() + +endfunction() + +function(check_and_set_linker) + option(USE_MOLD "Use the mold/sold parallel linker for faster builds" ON) + if(USE_MOLD) + # Determine if the compiler is GCC or Clang + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + message(STATUS "Detected GCC/Clang, checking for mold/sold linker...") + + # Check for mold linker on general systems and ld64.mold on macOS + if(APPLE) + find_program(MOLD_LINKER ld64.mold) + set(CMAKE_LINKER_TYPE SOLD) + else() + find_program(MOLD_LINKER mold) + set(CMAKE_LINKER_TYPE MOLD) + endif() + + if(MOLD_LINKER) + message(STATUS "LINKER_TYPE set to ${CMAKE_LINKER_TYPE} for faster builds") + list(APPEND CMAKE_MESSAGE_INDENT " ") + message(STATUS "(set -DUSE_MOLD=OFF to disable)") + list(POP_BACK CMAKE_MESSAGE_INDENT) + else() + message(STATUS " -- No suitable mold linker found. Using default linker.") + endif() + else() + message(STATUS "Compiler is neither GCC nor Clang. Skipping mold linker check.") + endif() + endif() +endfunction() diff --git a/BuildProperties.cmake b/BuildProperties.cmake new file mode 100644 index 0000000..73c7ab4 --- /dev/null +++ b/BuildProperties.cmake @@ -0,0 +1,102 @@ +# BuildPreferences.cmake +# Copyright (c) 2024 Saul D Beniquez +# License: MIT +# +# This module defines a function prevent_in_source_build() that prevents in-source builds +# and sets a policy for CMake version 3.24.0 and above. + +function(prevent_in_source_build) + # Prevent in-source builds + if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR) + message(FATAL_ERROR "Source and build directories cannot be the same.") + endif() +endfunction() + +function(disable_deprecated_features) + # Use new timestamp behavior when extracting files archives + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") + cmake_policy(SET CMP0135 NEW) + endif() +endfunction() + + + +function(set_artifact_dir path) + # Set local variable, not necessary to be parent scope since it's not used outside this function + set(ARTIFACT_DIR "${path}") + + # Set project-specific artifact directory in parent scope + set(${PROJECT_NAME}_ARTIFACT_DIR "${path}" PARENT_SCOPE) + set(${PROJECT_NAME}_INCLUDE_OUTPUT_DIR "${path}/include" PARENT_SCOPE) + + # Set output directories in parent scope using the provided path directly + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${path}/lib" PARENT_SCOPE) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${path}/lib" PARENT_SCOPE) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${path}/bin" PARENT_SCOPE) +endfunction() + +function(package_library_headers LibraryTarget) + + if (NOT DEFINED ${PROJECT_NAME}_INCLUDE_OUTPUT_DIR) + message(FATAL_ERROR "Before calling package_library_headers, set the artifact directory using set_artifact_dir()") + endif() + + # Create the custom target name + set(target_name "${LibraryTarget}_copy_include_directory") + set(output_dir "${${PROJECT_NAME}_INCLUDE_OUTPUT_DIR}") + + # Create a list to hold custom commands + set(custom_commands + COMMAND ${CMAKE_COMMAND} -E make_directory ${output_dir}/${LibraryTarget} ) + + set(is_glob false) + # Iterate over each argument to copy them + foreach(item IN LISTS ARGN) + if (IS_DIRECTORY ${item}) + get_filename_component(item_name ${item} NAME) + list(APPEND custom_commands + COMMAND ${CMAKE_COMMAND} -E copy_directory ${item} ${output_dir}/${LibraryTarget}/${item_name} + ) + else() + if (${is_glob}) + file(GLOB glob_files ${item}) + list(APPEND expanded_items ${glob_files}) + message(STATUS "glob_files" ${glob_files}) + set(is_glob false) + foreach(expanded IN LISTS expanded_items) + get_filename_component(item_name ${expanded} NAME) + list(APPEND custom_commands + COMMAND ${CMAKE_COMMAND} -E copy ${expanded} ${output_dir}/${LibraryTarget}/${item_name} + ) + endforeach() + elseif (item STREQUAL "GLOB") + set(is_glob true) + else() + get_filename_component(item_name ${item} NAME) + list(APPEND custom_commands + COMMAND ${CMAKE_COMMAND} -E copy ${item} ${output_dir}/${LibraryTarget}/${item_name} + ) + endif() + endif() + endforeach() + + # Create the target to copy directories and files + add_custom_target(${target_name} ALL + ${custom_commands} + COMMENT "Copying files and directories to ${output_dir}/include/${LibraryTarget}/" + ) + + # Add the custom target as a dependency of the library target + add_dependencies(${LibraryTarget} ${target_name}) +endfunction() + +function(disable_tests_if_subproject) + option(BUILD_TESTING "Build unit tests" ON) + + if (DEFINED PROJECT_NAME) + set(BUILD_TESTING OFF PARENT_SCOPE) + endif() +endfunction() + + +# vim: ts=4 sts=4 sw=4 noet foldmethod=indent : diff --git a/CPM.cmake b/CPM.cmake new file mode 100644 index 0000000..cc25ec2 --- /dev/null +++ b/CPM.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +# +# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors + +set(CPM_DOWNLOAD_VERSION 0.38.7) +set(CPM_HASH_SUM "83e5eb71b2bbb8b1f2ad38f1950287a057624e385c238f6087f94cdfc44af9c5") + +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +endif() + +# Expand relative path. This is important if the provided path contains a tilde (~) +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) + +file(DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} +) + +include(${CPM_DOWNLOAD_LOCATION}) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..dbae3ec --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +The .cmake files in this directory are intended to be included in other CMake build scripts. +They are free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/README.md b/README.md new file mode 100644 index 0000000..56210e4 --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# CmakeTools + +[![License](https://img.shields.io/badge/License-Unlicense-lightgrey.svg)](https://unlicense.org/) +[![CMake](https://img.shields.io/badge/CMake-3.26.0-blue.svg)](https://cmake.org/) + +## Overview + +This repository contains CMake scripts I use in my projects to +manage build options, preferences, properties, and utilities for a CMake-based project. + +The main scripts included are: + +- `BuildOptions.cmake` +- `BuildPreferences.cmake` +- `Util.cmake` + +Additional third-party scripts included are: +- [![GitHub](https://img.shields.io/badge/GitHub-CPM.cmake-yellow.svg)](https://github.com/cpm-cmake/CPM.cmake) ![MIT](https://img.shields.io/badge/License-MIT-red.svg) +## Getting Started + +### Prerequisites + +- CMake 3.26.0 or above. Might work with lesser verisons, but not tested. + +### Setup + +1. Create a project repository and a directory to contain these scripts. (e.g `CMake`) +2. ```sh + $ git submodule add ${REPO_URL} CMake # You can use any directory name you wish + ``` + +### Usage + +1. Create your `CMakeLists.txt` +2. Add this at the top: + + ```cmake + # CMakeLists.txt + cmake_minimum_required(VERSION 3.26) + + include(CMake/Util) + git_setup_submodules() + + include(CMake/BuildPreferences) + iunclude(Cmake/BuildOptions) + + prevent_in_source_build() + disable_deprecated_features() + + ## or + # include(CMake/DefaultConfig) + + project(MyProject) + ``` + +### License +The .cmake scripts in this repository are disstributed under the Unlicense - see the [LICENSE](LICENSE) file for details. + +The included CPM.cmake module is © Lars Melchior and contributors, and is distributed under the MIT License - see the [LICENSE](https://github.com/cpm-cmake/CPM.cmake/blob/33bdbae902df5365ad545a7d082949883bd8d99d/LICENSE) file for details. diff --git a/Util.cmake b/Util.cmake new file mode 100644 index 0000000..3518045 --- /dev/null +++ b/Util.cmake @@ -0,0 +1,37 @@ +macro(ASSERT condition message) + if(NOT ${condition}) + message(FATAL_ERROR ${message}) + endif() +endmacro() + +macro(git_setup_submodules) + find_package(Git QUIET) + if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git") + option(GIT_SUBMODULE "Check submodules during build" ON) + if(GIT_SUBMODULE) + message(STATUS "Git submodule update") + execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE GIT_SUBMOD_RESULT) + if(NOT GIT_SUBMOD_RESULT EQUAL "0") + message(FATAL_ERROR "git submodule update --init --recursive failed with ${GIT_SUBMOD_RESULT}, please checkout submodules") + endif() + endif() + else() + message(FATAL_ERROR "Git not found or .git directory not found") + endif() +endmacro() + +macro(prevent_in_source_build) + # Prevent in-source builds + if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR) + message(FATAL_ERROR "Source and build directories cannot be the same.") + endif() +endmacro() + +macro(disable_deprecated_features) + # Use new timestamp behavior when extracting files archives + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") + cmake_policy(SET CMP0135 NEW) + endif() +endmacro()