Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,9 @@ compile_commands.json

# Check files
cppcheck.txt

# macOS system files
.DS_Store

# macOS folder settings
__MACOSX/
256 changes: 137 additions & 119 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
cmake_minimum_required(VERSION 3.22)

# ######################################################################################################################
# Include guards: Prevent building in the source directory
# ######################################################################################################################
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.\n")
endif()

# Make sure that custom modules are found
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)

# ######################################################################################################################
cmake_minimum_required(VERSION 3.24...3.31)
# ##############################################################################
# Define the Project Name and Description
# ######################################################################################################################
# ##############################################################################
project(
modern_cpp_project
VERSION 1.0.0
LANGUAGES CXX
DESCRIPTION "ModernCppProject is a project template for Modern C++"
)

# ##############################################################################
# Include guards: Prevent building in the source directory
# ##############################################################################
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(FATAL_ERROR
"In-source builds not allowed. "
"Please make a new directory (called a build directory) and "
"run CMake from there.\n"
)
endif()
message(STATUS "Started CMake for ${PROJECT_NAME} v${PROJECT_VERSION}...\n")

include(CMakeDependentOption)
include(CheckCXXCompilerFlag)
include(CheckTypeSize)
include(CMakePrintHelpers)

option(${PROJECT_NAME}_USE_ALT_NAMES "Use alternative names for the project, such as naming the include directory all lowercase." ON)
option(${PROJECT_NAME}_USE_ALT_NAMES
"Use alternative names for the project, such as naming the include directory all lowercase."
ON
)

if(${PROJECT_NAME}_USE_ALT_NAMES)
string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWERCASE)
string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERCASE)
Expand All @@ -34,54 +39,58 @@ else()
set(PROJECT_NAME_UPPERCASE ${PROJECT_NAME})
endif()

# ######################################################################################################################
# ##############################################################################
# Setup project
# ######################################################################################################################
# ##############################################################################
include(cmake/StandardSettings.cmake)
include(cmake/Utils.cmake)
include(cmake/CompilerWarnings.cmake)
include(cmake/CompilerWarnings.cmake)

##############################################################################
# Global Project Settings
# only activate for top level project
##############################################################################
##############################################################################
# Global Project Settings
# only activate for top level project
##############################################################################
if(PROJECT_IS_TOP_LEVEL)
# Put the libraries and binaries that get built into directories at the top of
# the build tree rather than in hard-to-find leaf directories. This simplifies
# manual testing and the use of the build tre.
# Put the libraries and binaries that get built into directories at the
# top of the build tree rather than in hard-to-find leaf directories.
# This simplifies manual testing and the use of the build tre.
set(MAINFOLDER ${PROJECT_SOURCE_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
# Windows DLLs are "runtime" for CMake.
# Windows DLLs are "runtime" for CMake.
# Output them to "bin" like the Visual Studio projects do.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# Let's nicely support folders in IDE's
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json")
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json
execute_process(COMMAND ${CMAKE_COMMAND} -E
copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json
${CMAKE_CURRENT_SOURCE_DIR}/compile_commands.json
)
endif()
endif()
include(cmake/StaticAnalyzers.cmake)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
endif()

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()

message(STATUS "Started CMake for ${PROJECT_NAME} v${PROJECT_VERSION}...\n")

# ######################################################################################################################
##############################################################################
# Add dependencies
# ######################################################################################################################
##############################################################################

# ---- Add dependencies via CPM ----
# see https://github.com/TheLartians/CPM.cmake for more info
include(cmake/CPM.cmake)
CPMAddPackage("gh:TheLartians/Format.cmake@1.8.1")

CPMAddPackage("gh:TheLartians/Format.cmake@1.8.1")
# PackageProject.cmake will be used to make our target installable
CPMAddPackage("gh:TheLartians/PackageProject.cmake@1.12.0")
include(cmake/PackageProject.cmake)

# Collect the built libraries and include directories
# A semicolon separated list of the project's dependencies
Expand All @@ -99,114 +108,123 @@ CPMAddPackage(
NAME spdlog
GITHUB_REPOSITORY gabime/spdlog
VERSION 1.15.0
OPTIONS "SPDLOG_INSTALL YES" "SPDLOG_FMT_EXTERNAL YES" # create an installable target and force uses a external fmt
OPTIONS "SPDLOG_INSTALL YES" "SPDLOG_FMT_EXTERNAL YES"
)

list(APPEND ${PROJECT_NAME}_DEPENDENCIES "spdlog 1.12.0")

# ######################################################################################################################
# Source tree
# ######################################################################################################################
#add_subdirectory(extern)
add_subdirectory(src)
set(CMAKE_VERIFY_INTERFACE_HEADER_SETS ${PROJECT_IS_TOP_LEVEL})

# ######################################################################################################################
# Add version header: the location where the project's version header will be placed should match the project's
# regular header paths
# ######################################################################################################################
set(VERSION_HEADER_LOCATION "${PROJECT_NAME_LOWERCASE}/version.hpp")
configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/version.hpp.in include/${VERSION_HEADER_LOCATION} @ONLY)

# ---- Add source files ----
# Note: globbing sources is considered bad practice as CMake's generators may
# not detect new files automatically. Keep that in mind when changing files,
# or explicitly mention them here.
file(
GLOB_RECURSE headers
CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp"
)
file(
GLOB_RECURSE sources
CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
)
# IDEs should put the headers in a nice place
source_group(
TREE "${CMAKE_CURRENT_SOURCE_DIR}/include"
PREFIX "Header Files"
FILES ${HEADER_LIST}
)

##############################################################################
# ---- Create library ----
##############################################################################
if(${PROJECT_NAME_UPPERCASE}_BUILD_HEADERS_ONLY)
add_library(${PORJECT_NAME_LOWERCASE} INTERFACE)
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_23)
else()
add_library(${PROJECT_NAME_LOWERCASE} ${headers} ${sources})
target_compile_features(${PROJECT_NAME_LOWERCASE} PUBLIC cxx_std_23)
verbose_message("Added all header and implementation files.\n")
endif()

# #############################################################################
# Add version header: the location where the project's version header will be
# placed should match the project's regular header paths
# #############################################################################
set(VERSION_HEADER_LOCATION "${PROJECT_NAME_LOWERCASE}/version.hpp")
configure_file(
${CMAKE_CURRENT_LIST_DIR}/cmake/version.hpp.in
${VERSION_HEADER_LOCATION}
@ONLY
)
string(TOLOWER ${PROJECT_NAME}/version.hpp VERSION_HEADER_LOCATION)

# ######################################################################################################################
# Create an installable target
# ######################################################################################################################

target_sources(
${PROJECT_NAME_LOWERCASE}
PRIVATE ${sources}
PUBLIC FILE_SET public_headers
TYPE HEADERS BASE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}
FILES
${headers}
${CMAKE_CURRENT_BINARY_DIR}/${VERSION_HEADER_LOCATION}
)

target_compile_options(
${PROJECT_NAME_LOWERCASE}
PUBLIC "$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/permissive->"
)

# Link dependencies
find_package(Threads)
# Identify and link with the specific "packages" the project uses
target_link_libraries(
${PROJECT_NAME_LOWERCASE}
PRIVATE
Threads::Threads fmt::fmt spdlog::spdlog
)

if(CMAKE_SKIP_INSTALL_RULES)
add_library(
${PROJECT_NAME_LOWERCASE}::${PROJECT_NAME_LOWERCASE}
ALIAS ${PROJECT_NAME_LOWERCASE}
)
return()
endif()


##############################################################################
# Add uninstall target
##############################################################################
include(cmake/AddUninstallTarget.cmake)

packageProject(
# the name of the target to export
NAME ${PROJECT_NAME}
# the version of the target to export
VERSION ${PROJECT_VERSION}
# (optional) install your library with a namespace (Note: do NOT add extra '::')
NAMESPACE ${PROJECT_NAME}
# a temporary directory to create the config files
BINARY_DIR ${PROJECT_BINARY_DIR}
# location of the target's public headers
# A.K.A Install the `include` directory
INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include
# Install the `include` directory.
# NOTE: should match the target's INSTALL_INTERFACE include directory
INCLUDE_DESTINATION include/${PROJECT_NAME}-${PROJECT_VERSION}
# (optional) create a header containing the version info
# Note: that the path to headers should be lowercase
VERSION_HEADER "${VERSION_HEADER_LOCATION}"

# (optional) create a export header using GenerateExportHeader module
#EXPORT_HEADER "${PROJECT_NAME}/export.hpp"

# (optional) define the project's version compatibility, defaults to `AnyNewerVersion`
# supported values: `AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion`
# (optional) define the project's version compatibility,
# defaults to `AnyNewerVersion` supported values:
# `AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion`
COMPATIBILITY SameMajorVersion
RUNTIME_DESTINATION /
# semicolon separated list of the project's dependencies
DEPENDENCIES "${${PROJECT_NAME}_DEPENDENCIES}"
# (optional) option to disable the versioning of install destinations
DISABLE_VERSION_SUFFIX YES
# (optional) option to ignore target architecture for package resolution
# defaults to YES for header only (i.e. INTERFACE) libraries
ARCH_INDEPENDENT YES
)


# ######################################################################################################################
# Add uninstall target
# ######################################################################################################################
CONFIGURE_FILE(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake"
IMMEDIATE @ONLY)

ADD_CUSTOM_TARGET(${PROJECT_NAME_LOWERCASE}_uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake"
HEADER_SETS public_headers
)


# ######################################################################################################################
# Unit testing setup: Testing only available if this is the main app
# ######################################################################################################################

if (PROJECT_IS_TOP_LEVEL AND ${PROJECT_NAME_UPPERCASE}_ENABLE_TESTING)
message(STATUS "Build unit tests for the project. Tests should always be found in the test folder\n")
enable_testing()
add_subdirectory(test)
endif()

if (PROJECT_IS_TOP_LEVEL AND ${PROJECT_NAME_UPPERCASE}_ENABLE_STANDALONE)
add_subdirectory(standalone)
endif()

# ######################################################################################################################
# ############################################################################
# INFO
# ######################################################################################################################
# ############################################################################
if(PROJECT_IS_TOP_LEVEL)
message(STATUS "CMake ${CMAKE_VERSION} successfully configured ${PROJECT_NAME} using ${CMAKE_GENERATOR} generator")
message(STATUS "${PROJECT_NAME} package version: ${CMAKE_PROJECT_VERSION}")
message(STATUS "${PROJECT_NAME} package dependencies: ${${PROJECT_NAME}_DEPENDENCIES}")
message(STATUS "${PROJECT_NAME} shared libraries: ${${PROJECT_NAME_UPPERCASE}_BUILD_SHARED_LIBS}")
if(${BUILD_SHARED_LIBS})
message(STATUS "Building dynamic libraries")
else()
message(STATUS "Building static libraries")
endif()
message(STATUS "[cmake] Installation target path: ${CMAKE_INSTALL_PREFIX}")
if(CMAKE_TOOLCHAIN_FILE)
message(STATUS "[cmake] Use toolchain file: ${CMAKE_TOOLCHAIN_FILE}")
endif()
string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
message(STATUS "[cmake] Build for OS type: ${CMAKE_SYSTEM_NAME}")
message(STATUS "[cmake] Build for OS version: ${CMAKE_SYSTEM_VERSION}")
message(STATUS "[cmake] Build for CPU type: ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS "[cmake] Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "[cmake] Build with cxx flags: ${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}")
message(STATUS "[cmake] Build with c flags: ${CMAKE_C_FLAGS_${BUILD_TYPE}} ${CMAKE_C_FLAGS}")
message(STATUS "[cmake] Source Directory: ${CMAKE_SOURCE_DIR}")
print_project_configuration()
endif()
13 changes: 13 additions & 0 deletions all/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# this script adds all subprojects to a single build to allow IDEs understand the full project
# structure.
cmake_minimum_required(VERSION 3.24...3.31)

project(BuildAll LANGUAGES CXX)

include(../cmake/Utils.cmake)

# needed to generate test target
enable_testing()

add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../standalone ${CMAKE_BINARY_DIR}/standalone)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../test ${CMAKE_BINARY_DIR}/test)
Loading
Loading