Giter VIP home page Giter VIP logo

thelartians / moderncppstarter Goto Github PK

View Code? Open in Web Editor NEW
4.0K 66.0 355.0 341 KB

🚀 Kick-start your C++! A template for modern C++ projects using CMake, CI, code coverage, clang-format, reproducible dependency management and much more.

Home Page: https://thelartians.github.io/ModernCppStarter

License: The Unlicense

CMake 71.97% C++ 28.03%
cpp cmake template dependency-manager continuous-integration ci c modern-cmake-template modern-cmake starter

moderncppstarter's Introduction

Actions Status Actions Status Actions Status Actions Status Actions Status codecov

ModernCppStarter

Setting up a new C++ project usually requires a significant amount of preparation and boilerplate code, even more so for modern C++ projects with tests, executables and continuous integration. This template is the result of learnings from many previous projects and should help reduce the work required to setup up a modern C++ project.

Features

Usage

Adjust the template to your needs

  • Use this repo as a template.
  • Replace all occurrences of "Greeter" in the relevant CMakeLists.txt with the name of your project
    • Capitalization matters here: Greeter means the name of the project, while greeter is used in file names.
    • Remember to rename the include/greeter directory to use your project's lowercase name and update all relevant #includes accordingly.
  • Replace the source files with your own
  • For header-only libraries: see the comments in CMakeLists.txt
  • Add your project's codecov token to your project's github secrets under CODECOV_TOKEN
  • Happy coding!

Eventually, you can remove any unused files, such as the standalone directory or irrelevant github workflows for your project. Feel free to replace the License with one suited for your project.

To cleanly separate the library and subproject code, the outer CMakeList.txt only defines the library itself while the tests and other subprojects are self-contained in their own directories. During development it is usually convenient to build all subprojects at once.

Build and run the standalone target

Use the following command to build and run the executable target.

cmake -S standalone -B build/standalone
cmake --build build/standalone
./build/standalone/Greeter --help

Build and run test suite

Use the following commands from the project's root directory to run the test suite.

cmake -S test -B build/test
cmake --build build/test
CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/test --target test

# or simply call the executable: 
./build/test/GreeterTests

To collect code coverage information, run CMake with the -DENABLE_TEST_COVERAGE=1 option.

Run clang-format

Use the following commands from the project's root directory to check and fix C++ and CMake source style. This requires clang-format, cmake-format and pyyaml to be installed on the current system.

cmake -S test -B build/test

# view changes
cmake --build build/test --target format

# apply changes
cmake --build build/test --target fix-format

See Format.cmake for details. These dependencies can be easily installed using pip.

pip install clang-format==14.0.6 cmake_format==0.6.11 pyyaml

Build the documentation

The documentation is automatically built and published whenever a GitHub Release is created. To manually build documentation, call the following command.

cmake -S documentation -B build/doc
cmake --build build/doc --target GenerateDocs
# view the docs
open build/doc/doxygen/html/index.html

To build the documentation locally, you will need Doxygen, jinja2 and Pygments installed on your system.

Build everything at once

The project also includes an all directory that allows building all targets at the same time. This is useful during development, as it exposes all subprojects to your IDE and avoids redundant builds of the library.

cmake -S all -B build
cmake --build build

# run tests
./build/test/GreeterTests
# format code
cmake --build build --target fix-format
# run standalone
./build/standalone/Greeter --help
# build docs
cmake --build build --target GenerateDocs

Additional tools

The test and standalone subprojects include the tools.cmake file which is used to import additional tools on-demand through CMake configuration arguments. The following are currently supported.

Sanitizers

Sanitizers can be enabled by configuring CMake with -DUSE_SANITIZER=<Address | Memory | MemoryWithOrigins | Undefined | Thread | Leak | 'Address;Undefined'>.

Static Analyzers

Static Analyzers can be enabled by setting -DUSE_STATIC_ANALYZER=<clang-tidy | iwyu | cppcheck>, or a combination of those in quotation marks, separated by semicolons. By default, analyzers will automatically find configuration files such as .clang-format. Additional arguments can be passed to the analyzers by setting the CLANG_TIDY_ARGS, IWYU_ARGS or CPPCHECK_ARGS variables.

Ccache

Ccache can be enabled by configuring with -DUSE_CCACHE=<ON | OFF>.

FAQ

Can I use this for header-only libraries?

Yes, however you will need to change the library type to an INTERFACE library as documented in the CMakeLists.txt. See here for an example header-only library based on the template.

I don't need a standalone target / documentation. How can I get rid of it?

Simply remove the standalone / documentation directory and according github workflow file.

Can I build the standalone and tests at the same time? / How can I tell my IDE about all subprojects?

To keep the template modular, all subprojects derived from the library have been separated into their own CMake modules. This approach makes it trivial for third-party projects to re-use the projects library code. To allow IDEs to see the full scope of the project, the template includes the all directory that will create a single build for all subprojects. Use this as the main directory for best IDE support.

I see you are using GLOB to add source files in CMakeLists.txt. Isn't that evil?

Glob is considered bad because any changes to the source file structure might not be automatically caught by CMake's builders and you will need to manually invoke CMake on changes. I personally prefer the GLOB solution for its simplicity, but feel free to change it to explicitly listing sources.

I want create additional targets that depend on my library. Should I modify the main CMakeLists to include them?

Avoid including derived projects from the libraries CMakeLists (even though it is a common sight in the C++ world), as this effectively inverts the dependency tree and makes the build system hard to reason about. Instead, create a new directory or project with a CMakeLists that adds the library as a dependency (e.g. like the standalone directory). Depending type it might make sense move these components into a separate repositories and reference a specific commit or version of the library. This has the advantage that individual libraries and components can be improved and updated independently.

You recommend to add external dependencies using CPM.cmake. Will this force users of my library to use CPM.cmake as well?

CPM.cmake should be invisible to library users as it's a self-contained CMake Script. If problems do arise, users can always opt-out by defining the CMake or env variable CPM_USE_LOCAL_PACKAGES, which will override all calls to CPMAddPackage with the according find_package call. This should also enable users to use the project with their favorite external C++ dependency manager, such as vcpkg or Conan.

Can I configure and build my project offline?

No internet connection is required for building the project, however when using CPM missing dependencies are downloaded at configure time. To avoid redundant downloads, it's highly recommended to set a CPM.cmake cache directory, e.g.: export CPM_SOURCE_CACHE=$HOME/.cache/CPM. This will enable shallow clones and allow offline configurations dependencies are already available in the cache.

Can I use CPack to create a package installer for my project?

As there are a lot of possible options and configurations, this is not (yet) in the scope of this template. See the CPack documentation for more information on setting up CPack installers.

This is too much, I just want to play with C++ code and test some libraries.

Perhaps the MiniCppStarter is something for you!

Related projects and alternatives

Star History

Star History Chart

moderncppstarter's People

Contributors

bongani-m avatar chaitan94 avatar clausklein avatar cvelth avatar dominicd avatar friendlyanon avatar gerodote avatar giacomo-b avatar hazelnusse avatar jeremylwright avatar kparmar09 avatar ldeng-ustc avatar mscofield0 avatar nerrons avatar robertindie avatar schtobia avatar sisakat avatar thelartians avatar vsoch avatar zen-is avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

moderncppstarter's Issues

Use `code-coverage.cmake` from `cmake-scripts`

Currently, the template just applies -fprofile-arcs -ftest-coverage to the Greeter target from test. As far as I could tell, it doesn't really generate the code coverage data locally, and I think it'd be useful to be able to do that.

The code-coverage.cmake script exposes targets that we can run if we want to generate the data locally too. It also does checks that the current ModernCppStarter solution doesn't.

Running doxygen command on windows

I was trying to compile Doxygen on my windows machine and I have installed Doxygen, jinja2 and Pygments . The following is the error message I received after running the command below. Any suggestions on how to resolve the issue?

Command : cmake --build build/doc --target GenerateDocs

AzureAD+GS@DESKTOP-JMINGW64 ~/Documents/GIT/ModernCppStarter (feature/architecture_drawing)
$ cmake --build build/doc --target GenerateDocs
Microsoft (R) Build Engine version 16.8.2+25e4d540b for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

Checking File Globs
CUSTOMBUILD : warning : libgs not found [C:\Users\GS\Documents\GIT\ModernCppStarter\build\doc\GenerateDocs.vcxproj]
Traceback (most recent call last):
File "C:\Users\GS\Documents\GIT\ModernCppStarter\build\doc_deps\mcss-src\documentation\doxygen.py", line 3857, in
subprocess.run(["doxygen", doxyfile], cwd=os.path.dirname(doxyfile), check=True)
File "C:\Python38\lib\subprocess.py", line 489, in run
with Popen(*popenargs, **kwargs) as process:
File "C:\Python38\lib\subprocess.py", line 854, in init
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\Python38\lib\subprocess.py", line 1307, in _execute_child
hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
FileNotFoundError: [WinError 2] The system cannot find the file specified
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(238,5): error MSB8066: Custom build for 'C:\Users\GS\Documents\GIT\ModernCppStarter\build\doc\CMakeFiles\5d6b58ea6af2e68a3fc47579611072b8\GenerateDocs.rule' exited with code 1. [C:\Users\GS\Documents\GIT\ModernCppStarter\build\doc\GenerateDocs.vcxproj]

`

Standalone doc is not correct for CLion

The build directory in CLion is 'cmake-build-debug', not 'build'.

Or you can right-click Standalone's CMakeLists.txt file and select 'Load CMake Project'. Then Standalone becomes available to Run or Debug.

`cmake --build build/test --target format` not working

I've installed all that the documentation said is required:

$ pip list
Package      Version
------------ -------
cmake-format 0.6.13
cmakelang    0.6.13
pip          21.0.1
PyYAML       5.4.1
setuptools   49.2.1
six          1.15.0
$ clang-format.exe --version
clang-format version 11.0.1

However, cmake --build build/standalone --target format works.

CMake Error: install(EXPORT "GreeterTargets" ...) includes target "Greeter" which requires target "fmt-header-only" that is not in any export set.

after adding a new build dependency I get this error:

Claus-iMac:ModernCppStarter clausklein$ !rm
rm -rf build/
Claus-iMac:ModernCppStarter clausklein$ cmake -G Ninja -B build -S standalone/
-- The CXX compiler identification is AppleClang 12.0.0.12000032
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Downloading CPM.cmake to /Users/clausklein/Workspace/cpp/ModernCppStarter/build/cmake/CPM_0.28.2.cmake
-- CPM: adding package [email protected] (v1.2.2)
-- Using ccache: /usr/local/bin/ccache
-- CPM: adding package [email protected] (v2.2.0)
-- cxxopts version 2.2.0
-- The C compiler identification is AppleClang 12.0.0.12000032
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- CPM: adding package Greeter@ (/Users/clausklein/Workspace/cpp/ModernCppStarter/standalone/..)
-- CPM: Greeter: adding package [email protected] (v1.4)
-- CPM: Greeter: adding package [email protected] (7.1.3)
-- Version: 7.1.3
-- Build type: 
-- CXX_STANDARD: 17
-- Performing Test has_std_17_flag
-- Performing Test has_std_17_flag - Success
-- Performing Test has_std_1z_flag
-- Performing Test has_std_1z_flag - Success
-- Performing Test SUPPORTS_USER_DEFINED_LITERALS
-- Performing Test SUPPORTS_USER_DEFINED_LITERALS - Success
-- Performing Test FMT_HAS_VARIANT
-- Performing Test FMT_HAS_VARIANT - Success
-- Required features: cxx_variadic_templates
-- Performing Test HAS_NULLPTR_WARNING
-- Performing Test HAS_NULLPTR_WARNING - Success
-- Looking for strtod_l
-- Looking for strtod_l - found
-- Configuring done
CMake Error: install(EXPORT "GreeterTargets" ...) includes target "Greeter" which requires target "fmt-header-only" that is not in any export set.
-- Generating done
CMake Generate step failed.  Build files cannot be regenerated correctly.
Claus-iMac:ModernCppStarter clausklein$ 

Adding 3rd party libs to target_include_directories

How to properly add other local third-party libraries inside the main package? the main package is not a single header libarary.

issue_project
├── include
│   ├── main_lib1
│   │   └── mainlib.h
│   ├── main_lib2
│   │   └── mainlib2.h
│   └── main_project.h
└── thirdparty
    ├── lib1
    │   └── lib1.h
    └── lib2
        └── lib2.h

I tried this

target_include_directories(
  Greeter PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include;${THIRD_PARTY_LIBRARY}">
                 $<INSTALL_INTERFACE:include/${PROJECT_NAME}-${PROJECT_VERSION}>
)

But with an error that the header file not found. However, if I tried to put "include_directories(${THIRD_PARTY_LIBRARY})" it will build the main Cmake but the test's Cmake will fail due to the following error:

#include <xx/x.h> No such file or directory

If I was not clear enough, I will create a simplified project to reproduce the issue.

Thanks,

Unable to open source file "doctest/doctest.h" and "cxxopts.hpp"

I clone the repo and opened it using CLION and visual studio code. I expected that both the doctest.hpp and cxxopts.hpp will be added automatically (since both packages are available in the CMakeLists.txt. But this is not the case as I get the following errors:

cannot open source file "doctest/doctest.h"     
cannot open source file "cxxopts/cxxopts.h"

CI/Github Actions for Ubuntu and MacOS

If I am not mistaken, unix and mac (default) build systems are not multi configuration. Thus, your github actions for ubuntu and mac (while still working) might not do what you actually expect them to do. So I think

# ubuntu.yaml
    - name: configure
      run: cmake -Htest -Bbuild -DENABLE_TEST_COVERAGE=1

    - name: build
      run: cmake --build build --config Debug -j4

should rather be

    - name: configure
      run: cmake -Htest -Bbuild -D ENABLE_TEST_COVERAGE=1 -D CMAKE_BUILD_TYPE=Debug

    - name: build
      run: cmake --build build -j4

Any comments?

Starter with CLion

I would like to use this starter with Clion (from jetbrains).

I can't find out how to setup all. In FAQ you said that is possible to make folder for example 'All' with single build (standalone/tests). Can you make a little sample?

add a package for a interface(or not executable) library

I noticed the CMakeList.txt file at the top level of your project, the line 55

# Link dependencies
target_link_libraries(Greeter PRIVATE fmt::fmt)

Use target_link_libraries to link an external library which add by

CPMAddPackage(
  NAME fmt
  GIT_TAG 7.1.3
  GITHUB_REPOSITORY fmtlib/fmt
  OPTIONS "FMT_INSTALL YES" # create an installable target
)

I am puzzled why this can be done, as far as I know, this will remind me of an error on my IDE (CLion).

Cannot specify link libraries for target "PROJECT_NAME" which is not built by this project.

This is the structure of my project:

cmake
|--- CPM.cmake

exec
|--- main.cpp
|--- CMakeList.txt

include
|--- *.hpp

src
|--- *.cpp

CMakeList.txt

The content of CMakeList.txt in top level:

cmake_minimum_required(VERSION 2.8.12...3.17)
project(
		foo
		VERSION 0.0.1
		LANGUAGES CXX
)

include(cmake/CPM.cmake)
CPMAddPackage("gh:TheLartians/PackageProject.cmake#master")

file(GLOB_RECURSE fooHeader CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
file(GLOB_RECURSE fooSource CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")

add_library(
		${PROJECT_NAME}
		${fooHeader}
		${fooSource}
)

set_target_properties(
		${PROJECT_NAME} PROPERTIES
		LINKER_LANGUAGE CXX
		CXX_STANDARD 17
)

# being a cross-platform target, we enforce standards conformance on MSVC
target_compile_options(${PROJECT_NAME} PUBLIC "$<$<BOOL:${MSVC}>:/permissive->")

# MARK1
# CPMAddPackage("gh:jarro2783/cxxopts#master")
# set(CXXOPTS_BUILD_EXAMPLES off)
# set(CXXOPTS_BUILD_TESTS off)
# target_link_libraries(${PROJECT_NAME} cxxopts)

target_include_directories(
		${PROJECT_NAME}
		PUBLIC
		$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
		$<INSTALL_INTERFACE:include/${PROJECT_NAME}-${PROJECT_VERSION}>
)

string(TOLOWER ${PROJECT_NAME}/version.h VERSION_HEADER_LOCATION)

packageProject(
		NAME ${PROJECT_NAME}
		VERSION ${PROJECT_VERSION}
		NAMESPACE ${PROJECT_NAME}
		BINARY_DIR ${PROJECT_BINARY_DIR}
		INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include
		INCLUDE_DESTINATION include/${PROJECT_NAME}-${PROJECT_VERSION}
		VERSION_HEADER "${VERSION_HEADER_LOCATION}"
		DEPENDENCIES "foo"
)

The content of CMakeList.txt in exec:

cmake_minimum_required(VERSION 2.8.12...3.17)

project(
		fooExec
		LANGUAGES CXX
)

include(../cmake/CPM.cmake)

CPMAddPackage(
		NAME foo
		SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..
)

add_executable(
		${PROJECT_NAME}
		main.cpp
)

set_target_properties(
		${PROJECT_NAME}
		PROPERTIES CXX_STANDARD 17
		OUTPUT_NAME "fooExec"
)

# MARK2
CPMAddPackage("gh:jarro2783/cxxopts#master")
set(CXXOPTS_BUILD_EXAMPLES off)
set(CXXOPTS_BUILD_TESTS off)
target_link_libraries(
		${PROJECT_NAME}
		PRIVATE
		foo::foo
)

You may have noticed that I have a mark in each of the two files.

At the beginning, I wrote the code that needs cxxopts in the exec folder (the same directory as main.cpp) and the exec folder's structure is similar to the top level (also has include and src folders), I use

target_link_libraries(
		${PROJECT_NAME}
		PRIVATE
		foo::foo
		cxxopts
)

everything work well

// and if I write
#include <cxx

// It immediately reminds me whether to write
#include <cxxopts.hpp>

// Yes, IDE knows that there is a file called cxxopts.hpp

But soon I discovered that there are some problems with the design of this structure. I need to move the code that uses cxxopts to the include and src folders at the top level. So I tried to delete the cxxopts at MARK2 to

target_link_libraries(
		${PROJECT_NAME}
		PRIVATE
		foo::foo
)

And added the code at MARK1 (they didn't exist at the beginning).

CPMAddPackage("gh:jarro2783/cxxopts#master")
set(CXXOPTS_BUILD_EXAMPLES off)
set(CXXOPTS_BUILD_TESTS off)

# the code below is also not exist now
# target_link_libraries(${PROJECT_NAME} cxxopts)

then

```c++
// and if I write
#include <cxx

// It reminds me nothing
#include <cxxopts.hpp>

// Yes, IDE does not knows that there is a file called cxxopts.hpp and it tells me file not found

After this, I came back here, I use target_link_libraries like you

CPMAddPackage("gh:jarro2783/cxxopts#master")
set(CXXOPTS_BUILD_EXAMPLES off)
set(CXXOPTS_BUILD_TESTS off)
target_link_libraries(${PROJECT_NAME} cxxopts)

What I didn’t expect was that the error this time was not

Cannot specify link libraries for target "PROJECT_NAME" which is not built by this project.

It output

CMake Error: install(EXPORT "fooTargets" ...) includes target "foo" which requires target "cxxopts" that is not in any export set.

What I didn't expect again is

// and if I write
#include <cxx

// It immediately reminds me whether to write
#include <cxxopts.hpp>

// Yes, IDE knows that there is a file called cxxopts.hpp again!!!

I don't know what to do.

Add sanitizer support

Hi, at first thanks for the template project.

Have you considered to add Sanitizer support as well other utilities like Valgrind?
If you would like to add these, i have already created a few projects for personal usage.
I think it might be also useful for you if you want to extend your template:
https://github.com/reapler/Sanitize-Coredump-Coverage
https://github.com/reapler/Memory-Sanitizer-Instrumentation

However i believe there are a few edge cases on my projects (for e.g. shared libraries) where the compilation might fail and a few more cmake modules would look better.
But otherwise it could help to get a better overview of these tools.

Use ${PROJECT_NAME} instead of writing projectname multiple times

Is there a reason ${PROJECT_NAME} is not used?
I thought this is the recommended way to go about it?
Also it makes it easier to do the initial setup with your template.

Example:
Instead of:

project(
  Greeter
  VERSION 1.0
  LANGUAGES CXX
)

add_library(Greeter ${headers} ${sources})

set_target_properties(Greeter PROPERTIES CXX_STANDARD 17)

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

target_link_libraries(Greeter PRIVATE fmt::fmt)

use :

project(
  Greeter
  VERSION 1.0
  LANGUAGES CXX
)

add_library(${PROJECT_NAME}${headers} ${sources})

set_target_properties(${PROJECT_NAME}PROPERTIES CXX_STANDARD 17)

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

target_link_libraries(${PROJECT_NAME}PRIVATE fmt::fmt)

Include errors

I tried to add multiple libraries to this template project, but all my library includes seem to be failing (eg: #include <SDL.h>
). I am not sure if I did something wrong. Could you take a look for me? The other problem I had when I tried to use spdlog with the

"SPDLOG_FMT_EXTERNAL YES"

option, the spdlog was not able to find fmt which was downloaded by CPMAddPackage already.
Here is my CMakeList.txt:

cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

# ---- Project ----

# Note: update this to your new project's name and version
project(
  ArcaneLords
  VERSION 0.1
  LANGUAGES CXX
)


set(OpenGL_GL_PREFERENCE "GLVND")


# ---- Include guards ----

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."
  )
endif()

# ---- Add dependencies via CPM ----
# see https://github.com/TheLartians/CPM.cmake for more info

include(cmake/CPM.cmake)

# PackageProject.cmake will be used to make our target installable
CPMAddPackage("gh:TheLartians/[email protected]")

CPMAddPackage(
  NAME fmt
  GIT_TAG 7.1.3
  GITHUB_REPOSITORY fmtlib/fmt
  OPTIONS "FMT_INSTALL YES" # create an installable target
)
CPMAddPackage(
  NAME SDL2
  VERSION 2.0.12
  URL https://libsdl.org/release/SDL2-2.0.16.zip
)
CPMAddPackage(
  NAME glm
  GITHUB_REPOSITORY g-truc/glm
  OPTIONS "GLM_STATIC_LIBRARY_ENABLE"
  GIT_TAG 0.9.9.8
)

CPMAddPackage(
  NAME spdlog
  GITHUB_REPOSITORY gabime/spdlog
  OPTIONS "SPDLOG_INSTALL YES"
  GIT_TAG v1.9.2
)

# GLFW
CPMAddPackage(
  NAME glfw
  GITHUB_REPOSITORY glfw/glfw
  GIT_TAG 3.3.2
  OPTIONS
	"GLFW_BUILD_TESTS Off"
	"GLFW_BUILD_EXAMPLES Off"
	"GLFW_BUILD_DOCS Off"
    "GLFW_INSTALL Off"
    "GLFW_USE_HYBRID_HPG On"
)

# ---- 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/*.h")
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")

# ---- Create library ----

# Note: for header-only libraries change all PUBLIC flags to INTERFACE and create an interface
# target: add_library(ArcaneLords INTERFACE)
add_library(ArcaneLords ${headers} ${sources})

set_target_properties(ArcaneLords PROPERTIES CXX_STANDARD 17)

# being a cross-platform target, we enforce standards conformance on MSVC
target_compile_options(ArcaneLords PUBLIC "$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/permissive->")

# Link dependencies
target_link_libraries(ArcaneLords PRIVATE ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} fmt::fmt OpenGL32 spdlog::spdlog)

target_include_directories(
    ArcaneLords PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
                 $<INSTALL_INTERFACE:include/${PROJECT_NAME}-${PROJECT_VERSION}>
)

# ---- Create an installable target ----
# this allows users to install and find the library via `find_package()`.

# the location where the project's version header will be placed should match the project's regular
# header paths
string(TOLOWER ${PROJECT_NAME}}/version.h VERSION_HEADER_LOCATION)

packageProject(
  NAME ${PROJECT_NAME}
  VERSION ${PROJECT_VERSION}
  NAMESPACE ${PROJECT_NAME}
  BINARY_DIR ${PROJECT_BINARY_DIR}
  INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include
  INCLUDE_DESTINATION include/${PROJECT_NAME}-${PROJECT_VERSION}
  VERSION_HEADER "${PROJECT_NAME}version.h"
  EXPORT_HEADER "${PROJECT_NAME}/source/export.h"
  COMPATIBILITY SameMajorVersion
  DEPENDENCIES "fmt 7.1.3"; "SDL2"; "glm"; "spdlog"
)

Compile options and warnings for standalone?

Similar to how it's done in this other starter attempt, I feel like those options and warnings could be beneficial.

I would like to get some input on how the IPO (LTO) optimization should be done before making a PR.
In that other project it seems to be a global option whether LTO is on or off. Is that right?

Distinguish "Greeter" as the name of the CMake project and as the name of files/directories/classes

Hi TheLartians

First of all thanks for this great project; it really simplifies things quite a bit.

One thing might be confusing for beginners though: the name "Greeter" is used both as the name of the CMake project and as the name of several files/directories/classes. Although you can technically distinguish these two by the capitalization of the first letter it still opens possibilities for mistakes.

One side effect in renaming the project name is also missing from the README: one needs to change #include <greeter/version.h> to #include <NewProjName/version.h> in .cpp files as well.

Do you think changing the project name to something like "YourProject" is better? I can make the PR.

the format target does not work?

Claus-iMac:ModernCppStarter clausklein$ cmake -B build -S test -G Ninja
-- CPM: adding package [email protected] (v1.2.2)
-- Using ccache: /usr/local/bin/ccache
-- CPM: adding package Greeter@ (/Users/clausklein/Workspace/cpp/ModernCppStarter/test/..)
-- CPM: Greeter: adding package [email protected] (v1.4)
-- CPM: adding package [email protected] (v1.6)
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/clausklein/Workspace/cpp/ModernCppStarter/build
Claus-iMac:ModernCppStarter clausklein$ ninja -C build 
ninja: Entering directory `build'
[0/2] Re-checking globbed directories...
ninja: no work to do.
Claus-iMac:ModernCppStarter clausklein$ 

Claus-iMac:ModernCppStarter clausklein$ ninja -C build format
ninja: Entering directory `build'
[0/2] Re-checking globbed directories...
[1/2] cd /Users/clausklein/Workspace/cpp/ModernCppStarter/test && /usr/local/Frameworks/Pyt...binary=/usr/local/opt/llvm/bin/clang-format --diff 4b825dc642cb6eb9a060e54bf8d69288fbee490
clang-format did not modify any files
[2/2] cd /Users/clausklein/Workspace/cpp/ModernCppStarter/test && /usr/local/Cellar/cmake/3...s/clausklein/Workspace/cpp/ModernCppStarter/build/_deps/format.cmake-src/cmake-format.cmak
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 633, in main
    return inner_main()
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 616, in inner_main
    onefile_main(infile_path, args, argparse_dict)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 508, in onefile_main
    config_dict = get_config(infile_path, args.config_files)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 359, in get_config
    return get_configdict(configfile_paths)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 312, in get_configdict
    increment_dict = get_one_config_dict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 303, in get_one_config_dict
    return try_get_configdict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 256, in try_get_configdict
    raise RuntimeError("Failed to parse {} as any of yaml, json, or python"
RuntimeError: Failed to parse /Users/clausklein/Workspace/cpp/ModernCppStarter/.cmake-format as any of yaml, json, or python
error: Could not access '/Users/clausklein/Workspace/cpp/ModernCppStarter/build/_deps/format.cmake-build/formatted.cmake'
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 633, in main
    return inner_main()
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 616, in inner_main
    onefile_main(infile_path, args, argparse_dict)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 508, in onefile_main
    config_dict = get_config(infile_path, args.config_files)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 359, in get_config
    return get_configdict(configfile_paths)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 312, in get_configdict
    increment_dict = get_one_config_dict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 303, in get_one_config_dict
    return try_get_configdict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 256, in try_get_configdict
    raise RuntimeError("Failed to parse {} as any of yaml, json, or python"
RuntimeError: Failed to parse /Users/clausklein/Workspace/cpp/ModernCppStarter/.cmake-format as any of yaml, json, or python
error: Could not access '/Users/clausklein/Workspace/cpp/ModernCppStarter/build/_deps/format.cmake-build/formatted.cmake'
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 633, in main
    return inner_main()
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 616, in inner_main
    onefile_main(infile_path, args, argparse_dict)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 508, in onefile_main
    config_dict = get_config(infile_path, args.config_files)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 359, in get_config
    return get_configdict(configfile_paths)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 312, in get_configdict
    increment_dict = get_one_config_dict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 303, in get_one_config_dict
    return try_get_configdict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 256, in try_get_configdict
    raise RuntimeError("Failed to parse {} as any of yaml, json, or python"
RuntimeError: Failed to parse /Users/clausklein/Workspace/cpp/ModernCppStarter/.cmake-format as any of yaml, json, or python
error: Could not access '/Users/clausklein/Workspace/cpp/ModernCppStarter/build/_deps/format.cmake-build/formatted.cmake'
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 633, in main
    return inner_main()
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 616, in inner_main
    onefile_main(infile_path, args, argparse_dict)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 508, in onefile_main
    config_dict = get_config(infile_path, args.config_files)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 359, in get_config
    return get_configdict(configfile_paths)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 312, in get_configdict
    increment_dict = get_one_config_dict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 303, in get_one_config_dict
    return try_get_configdict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 256, in try_get_configdict
    raise RuntimeError("Failed to parse {} as any of yaml, json, or python"
RuntimeError: Failed to parse /Users/clausklein/Workspace/cpp/ModernCppStarter/.cmake-format as any of yaml, json, or python
error: Could not access '/Users/clausklein/Workspace/cpp/ModernCppStarter/build/_deps/format.cmake-build/formatted.cmake'
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 633, in main
    return inner_main()
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 616, in inner_main
    onefile_main(infile_path, args, argparse_dict)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 508, in onefile_main
    config_dict = get_config(infile_path, args.config_files)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 359, in get_config
    return get_configdict(configfile_paths)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 312, in get_configdict
    increment_dict = get_one_config_dict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 303, in get_one_config_dict
    return try_get_configdict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 256, in try_get_configdict
    raise RuntimeError("Failed to parse {} as any of yaml, json, or python"
RuntimeError: Failed to parse /Users/clausklein/Workspace/cpp/ModernCppStarter/.cmake-format as any of yaml, json, or python
error: Could not access '/Users/clausklein/Workspace/cpp/ModernCppStarter/build/_deps/format.cmake-build/formatted.cmake'
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 633, in main
    return inner_main()
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 616, in inner_main
    onefile_main(infile_path, args, argparse_dict)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 508, in onefile_main
    config_dict = get_config(infile_path, args.config_files)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 359, in get_config
    return get_configdict(configfile_paths)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 312, in get_configdict
    increment_dict = get_one_config_dict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 303, in get_one_config_dict
    return try_get_configdict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 256, in try_get_configdict
    raise RuntimeError("Failed to parse {} as any of yaml, json, or python"
RuntimeError: Failed to parse /Users/clausklein/Workspace/cpp/ModernCppStarter/.cmake-format as any of yaml, json, or python
error: Could not access '/Users/clausklein/Workspace/cpp/ModernCppStarter/build/_deps/format.cmake-build/formatted.cmake'
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 633, in main
    return inner_main()
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 616, in inner_main
    onefile_main(infile_path, args, argparse_dict)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 508, in onefile_main
    config_dict = get_config(infile_path, args.config_files)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 359, in get_config
    return get_configdict(configfile_paths)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 312, in get_configdict
    increment_dict = get_one_config_dict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 303, in get_one_config_dict
    return try_get_configdict(configfile_path)
  File "/usr/local/lib/python3.9/site-packages/cmakelang/format/__main__.py", line 256, in try_get_configdict
    raise RuntimeError("Failed to parse {} as any of yaml, json, or python"
RuntimeError: Failed to parse /Users/clausklein/Workspace/cpp/ModernCppStarter/.cmake-format as any of yaml, json, or python
error: Could not access '/Users/clausklein/Workspace/cpp/ModernCppStarter/build/_deps/format.cmake-build/formatted.cmake'
Claus-iMac:ModernCppStarter clausklein$ 

Static analyzis

Have you considered triggering static analysis on build? Gcc and clang supports that now I believe?

Just saw another reddit add cppcheck to his template project and thought it could be interesting.

prevent clang-tidy warnings for extern libraries used

i.e. the example use cxxopts which was fetched with CPM.cmake:

builddriver executing: 'run-clang-tidy.py -p build/standalone -checks=-*,modernize-*,misc-*,hicpp-*,cert-*,readability-*,portability-*,performance-*,google-* standalone'
Compilation SUCCEED in 8.628576 seconds
Number of warnings: 238
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='51', severity='warning', message="declaration uses identifier 'CXXOPTS__VERSION_MAJOR', which is a reserved identifier [cert-dcl37-c,cert-dcl51-cpp]", column='9')
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='52', severity='warning', message="declaration uses identifier 'CXXOPTS__VERSION_MINOR', which is a reserved identifier [cert-dcl37-c,cert-dcl51-cpp]", column='9')
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='53', severity='warning', message="declaration uses identifier 'CXXOPTS__VERSION_PATCH', which is a reserved identifier [cert-dcl37-c,cert-dcl51-cpp]", column='9')
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='212', severity='warning', message="use 'using' instead of 'typedef' [modernize-use-using]", column='3')
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='216', severity='warning', message='use a trailing return type for this function [modernize-use-trailing-return-type]', column='3')
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='223', severity='warning', message='use a trailing return type for this function [modernize-use-trailing-return-type]', column='3')
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='230', severity='warning', message='use a trailing return type for this function [modernize-use-trailing-return-type]', column='3')
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='230', severity='warning', message="non-const reference parameter 's', make it const or use a pointer [google-runtime-references]", column='23')
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='230', severity='warning', message="the parameter 'a' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]", column='33')
WarningErrorEntry(path='/Users/clausklein/.cache/CPM/cxxopts/d5c328043c71a6a5670c290d8646b093756db962/include/cxxopts.hpp', lineno='232', severity='warning', message='passing result of std::move() as a const reference argument; no move will actually happen [hicpp-move-const-arg,performance-move-const-arg]', column='21')
# . . .

code template for standalone versioning

When releasing a binary, it might be of interest to specify the software version through a cmake variable:
-DSTANDALONE_VERSION=1.32.1

I'm not aware what the best practice is for c++ and cmake, but I am aware this can easily be achieved through templates:

# CMakeLists.txt
if(NOT STANDALONE_VERSION)
  set(STANDALONE_VERSION "0.0.0")
endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.template.h" "${CMAKE_CURRENT_SOURCE_DIR}/src/version.h")
// version.template.h
#pragma once

// clang-format off
const auto version{"@STANDALONE_VERSION@"};
// clang-format on

The version.h can then be included in the main.cpp file, allowing the standalone version to be printed out when needed. eg. myapp --version.

configure test only does not work if CPM_USE_LOCAL_PACKAGES is TRUE

Claus-iMac:ModernCppStarter clausklein$ cmake -S test -B ./cmake-build-ModernCppStarter-x86_64-Debug/test -G Ninja -D CMAKE_CXX_COMPILER_LAUNCHER=/usr/local/bin/ccache -D CMAKE_EXPORT_COMPILE_COMMANDS=1 -D CMAKE_BUILD_TYPE=Debug -D CMAKE_PREFIX_PATH=/Users/clausklein/Workspace/cpp/stagedir -D BUILD_TESTING=1 -D CMAKE_CXX_STANDARD=20 -DBUILD_SHARED_LIBS=NO -Wdev -Wdeprecated
-- The CXX compiler identification is AppleClang 14.0.0.14000029
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Downloading CPM.cmake to /Users/clausklein/Workspace/cpp/ModernCppStarter/cmake-build-ModernCppStarter-x86_64-Debug/test/cmake/CPM_0.37.0.cmake
-- CPM: Using local package [email protected]
-- CPM: Adding package [email protected] (v1.7.3)
-- Found Python: /usr/local/Frameworks/Python.framework/Versions/3.11/bin/python3.11 (found version "3.11.1") found components: Interpreter 
-- Format.cmake: clang-format and/or python not found, adding dummy targets
-- CPM: Using local package [email protected]
CMake Error at CMakeLists.txt:37 (target_compile_options):
  Cannot specify compile options for target "Greeter" which is not built by
  this project.


CMake Error at CMakeLists.txt:52 (include):
  include could not find requested file:

    /scripts/cmake/doctest.cmake


CMake Error at CMakeLists.txt:53 (doctest_discover_tests):
  Unknown CMake command "doctest_discover_tests".


-- Configuring incomplete, errors occurred!
See also "/Users/clausklein/Workspace/cpp/ModernCppStarter/cmake-build-ModernCppStarter-x86_64-Debug/test/CMakeFiles/CMakeOutput.log".
See also "/Users/clausklein/Workspace/cpp/ModernCppStarter/cmake-build-ModernCppStarter-x86_64-Debug/test/CMakeFiles/CMakeError.log".
Claus-iMac:ModernCppStarter clausklein$ git log -2
commit 84ed75ca7db28672a29d865382389ad3e0f03f8a (HEAD -> master, origin/master, origin/HEAD)
Author: Lars Melchior <[email protected]>
Date:   Fri Feb 3 18:38:14 2023 +0100

    Update CPM.cmake (#164)

commit ab5c08abed71ac2d43723a91cebc1588e68df250
Author: Lars Melchior <[email protected]>
Date:   Fri Feb 3 18:31:28 2023 +0100

    Update fmt and doctest (#163)
    
    * update dependencies
    
    * update cache version used
    
    * update checkout version used
Claus-iMac:ModernCppStarter clausklein$ git status -s -b
## master...remotes/origin/master
?? cmake-build-ModernCppStarter-x86_64-Debug/
Claus-iMac:ModernCppStarter clausklein$

USE_<TOOL> defines cause a warning

Steps to reproduce:

  • Make a new project
  • cmake -Hall -Bbuild -DUSE_CCACHE=ON

Expected output:

No warnings.

Actual output:

CMake Warning:
  Manually-specified variables were not used by the project:

    USE_CCACHE

Suggestion to define main project name in a separate file

The main project name (Greeter) is currently used across multiple files. So it requires modifications in all these files to use this template, which can be time-consuming and error-prone.

I suggest defining the main project name in a separate file. This way, any changes to the name would only need to be made in one place, reducing potential errors and increasing efficiency.

for example, we can create a new file info.cmake:

# Note: update this to your new project's name and version
set(MAIN_PROJECT_NAME Greeter)

And then, include this file in other files:

# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.14...3.22)

# ---- Project ----
include(info.cmake)
project(
  ${MAIN_PROJECT_NAME}
  VERSION 1.0
  LANGUAGES CXX
)

Then, one can start its own projects with changing only one Greeter.

I write a demo in this branch, but I haven’t updated the documentation. If this suggestion is accepted, I can submit a PR.

Docs

I noticed you dont support doc generation from code. Is this something you will add?

`cmake --build build/docs --target GenerateDocs` not working

Happens on both Ubuntu WSL and Windows:

cmake --build build/docs --target GenerateDocs
[0/2] Re-checking globbed directories...
[1/1] cd /mnt/c/Users/u26i76/Projects/ModernCppStarterOrig...26i76/Projects/ModernCppStarterOriginal/build/docs/doxygen
FAILED: CMakeFiles/GenerateDocs
cd .../build/docs && /usr/bin/cmake -E make_directory .../build/docs/doxygen && .../.cache/CPM/m.css/ce3daea984872362c3a8ed1c3d8956adbc400a88/documentation/doxygen.py .../build/docs/conf.py && echo Docs\ written\ to:\ .../build/docs/doxygen
Warning: libgs not found
Traceback (most recent call last):
  File ".../.cache/CPM/m.css/ce3daea984872362c3a8ed1c3d8956adbc400a88/documentation/doxygen.py", line 3857, in <module>
    subprocess.run(["doxygen", doxyfile], cwd=os.path.dirname(doxyfile), check=True)
  File "/usr/lib/python3.8/subprocess.py", line 489, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/lib/python3.8/subprocess.py", line 854, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/lib/python3.8/subprocess.py", line 1702, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'doxygen'
ninja: build stopped: subcommand failed.

`cmake --build build/test` fails

after running

cmake -S test -B build/test
cmake --build build/test

cmake --build build/test fails with:

[ 37%] Built target fmt
[ 62%] Built target Greeter
[ 75%] Building CXX object CMakeFiles/GreeterTests.dir/source/main.cpp.o
In file included from /home/ivan/Desktop/test-cmake/test/source/main.cpp:3:
/home/ivan/Desktop/test-cmake/build/test/_deps/doctest-src/doctest/doctest.h:4299:47: error: size of array ‘altStackMem’ is not an integral constant-expression
 4299 |         static char             altStackMem[4 * SIGSTKSZ];
      |                                               ^
gmake[2]: *** [CMakeFiles/GreeterTests.dir/build.make:95: CMakeFiles/GreeterTests.dir/source/main.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:201: CMakeFiles/GreeterTests.dir/all] Error 2
gmake: *** [Makefile:160: all] Error 2

I have Ubuntu 21.10 OS.

CMake Error at ../CMakeLists.txt:47 (add_library):

After rename Greeter in global and test CMakeList.txt I cant build it anymore.

CMake Error at ../CMakeLists.txt:47 (add_library):

Produced in test/CmakeList.txt

if(TEST_INSTALLED_VERSION)
...
else()
..
CPMAddPackage(NAME Greeter SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
..
endif()

Having a issue when adding asio to my project using this template

Hello

I thought I would give this template a chance but I'm unfortunally having issue when the project needs asio

I'm pulling in asio with CPM as I always do with the extra configuration that is listed in the CPM example, but unfortunally since asio don't distribute as a cmake project then I'm facing this issue when trying to add it

CMake Error: install(EXPORT "tanja84dk_httplibTargets" ...) includes target "tanja84dk_httplib" which requires target "asio" that is not in any export set.

I'm using this way to include it except updated up to the newest version https://github.com/cpm-cmake/CPM.cmake/blob/master/examples/asio-standalone/CMakeLists.txt

Is there a way I'm able to work around it?

How to Debug configuration with GreeterStandalone in CLion

As I opened starter with CLion, I can't find binary in configuration.
CLion Settings:
CMake: CMake options: -Hall -Bbuild
Build directory: build.

Only Greeter and fmt shows in Debug configuration, How to configure to debug the binary module?

github workflow does not support c++2a

Just noticed that the latest ubuntu build, for example, uses gcc 7.5 which I don't believe support c++20 features. Eg. here the bit implementation is missing: https://github.com/andersfylling/sorting-nine-inputs-requires-twenty-five-comparisons/runs/605230180?check_suite_focus=true

ubuntu-latest refers to the lts version 18.04, and sadly ubuntu-18.10 is not a valid version. It seems that either the gcc must be updated somehow or just add a quick note in the README.

Documentation build failure due to empty MCSS_SOURCE_DIR

On 4212173 when I follow the directions for building the documentation, I get the following:

[I] luke@t480s ~/r/ModernCppStarter (master)> cmake -Hdocumentation -Bbuild/doc
-- The C compiler identification is GNU 10.2.0
-- The CXX compiler identification is GNU 10.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Downloading CPM.cmake to /home/luke/repos/ModernCppStarter/build/doc/cmake/CPM_0.31.1.cmake
-- CPM: adding package m.css@0 (42d4a9a48f31f5df6e246c948403b54b50574a2a)
-- CPM: adding package Greeter@ (/home/luke/repos/ModernCppStarter/documentation/..)
-- CPM: Greeter: adding package [email protected] (v1.4.1)
-- CPM: Greeter: adding package [email protected] (7.1.3)
-- Version: 7.1.3
-- Build type: 
-- CXX_STANDARD: 11
-- Performing Test has_std_11_flag
-- Performing Test has_std_11_flag - Success
-- Performing Test has_std_0x_flag
-- Performing Test has_std_0x_flag - Success
-- Performing Test SUPPORTS_USER_DEFINED_LITERALS
-- Performing Test SUPPORTS_USER_DEFINED_LITERALS - Success
-- Performing Test FMT_HAS_VARIANT
-- Performing Test FMT_HAS_VARIANT - Success
-- Required features: cxx_variadic_templates
-- Looking for strtod_l
-- Looking for strtod_l - not found
-- Configuring done
-- Generating done
-- Build files have been written to: /home/luke/repos/ModernCppStarter/build/doc

[I] luke@t480s ~/r/ModernCppStarter (master)> cmake --build build/doc --target GenerateDocs
[0/2] Re-checking globbed directories...
[1/1] cd /home/luke/repos/ModernCppStarter/build/doc && /usr/bin/cmake -E make_directory /home/luke/repos/Moder...ernCppStarter/build/doc/conf.py && echo Docs\ written\ to:\ /home/luke/repos/ModernCppStarter/build/doc/doxygen
FAILED: CMakeFiles/GenerateDocs 
cd /home/luke/repos/ModernCppStarter/build/doc && /usr/bin/cmake -E make_directory /home/luke/repos/ModernCppStarter/build/doc/doxygen && /documentation/doxygen.py /home/luke/repos/ModernCppStarter/build/doc/conf.py && echo Docs\ written\ to:\ /home/luke/repos/ModernCppStarter/build/doc/doxygen
/bin/sh: line 1: /documentation/doxygen.py: No such file or directory
ninja: build stopped: subcommand failed.

I have Doxygen, jinja2, and pygments installed:

[I] luke@t480s ~/r/ModernCppStarter (master)> doxygen --version
1.9.1
                                                                                                                                                                                                      [ 0s008 | Mar 20 09:45AM ]
[I] luke@t480s ~/r/ModernCppStarter (master)> python -c "import jinja2; print(jinja2.__version__)"
2.11.3
                                                                                                                                                                                                      [ 0s073 | Mar 20 09:45AM ]
[I] luke@t480s ~/r/ModernCppStarter (master)> python -c "import pygments; print(pygments.__version__)"                                                                                                                           
2.8.1                                                                                                                                                                                                                            
                                                                                                                                                                                                      [ 0s023 | Mar 20 09:45AM ] 
[I] luke@t480s ~/r/ModernCppStarter (master)> python --version                                                                                                                                                                   
Python 3.9.2                                    

For some reason, the MCSS_SOURCE_DIR is empty and is causing the command of the GenerateDocs custom command to be just /documentation/doxygen.py.

cmake test for c++2a concepts

How about an optional cmake script that can test for concepts support?

Maybe something like :

include(CheckCXXSourceCompiles)

macro(SUPPORT_CONCEPTS VAR)
    check_cxx_source_compiles("
#include <iostream>

template <typename T, typename = void>
struct is_something : std::false_type {};

template <typename T>
concept SpecialType = is_something<T>::value;


int main() {
  return 0;
}
" ${VAR})
endmacro()

Then just include it and check if the var is true.

Add documentation generation through Breathe / Sphinx

The current generated Doxygen docs work great, however the generated site doesn't have a particularly modern style and the customisation options are limited. Afaik we can use Doxygen together with Breathe / Sphinx to get much better looking docs. If it doesn't require too much boilerplate code I'd love to include that here.

gitignore proposition

Proposition for the .gitignore:

# Build
/build*

# Project files
/.vscode

# CPM modules
/cpm_modules

# Log files
*.log

# Generated by MacOS
.DS_Store

# Generated by Windows
Thumbs.db

# Applications
*.app
*.exe
*.war

# Large media files
*.xlsx
*.docx
*.pdf
*.mp4
*.tiff
*.avi
*.flv
*.mov
*.wmv

Bests,

The GitHub workflow actions needs an update

Problem

Run actions/cache@v2
8
Warning: The save-state command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
9
Cache not found for input keys: Windows-cpm-modules-8d17b6a5807bef3fb2c80fa8008f8eb7583d7ae9df0c462d2a34e90edc700324

Solution

upgrade to v3:
actions/cache@v3

do:
perl -p -i.bak -e's/v2/v3/;' *.yml

cmake -S test -B build-test -DTEST_INSTALLED_VERSION=1 fails

I'm not sure whether this is expected or not, but I figured I would report here just to clarify.

[I] luke@t480s ~/r/ModernCppStarter (master)> git rev-parse HEAD
742110856c29224bfd576603d9d490ccd4f6b4d0
                                                                                                                                                                        [ 0s006 | Mar 30 07:18PM ]
[I] luke@t480s ~/r/ModernCppStarter (master)> git status
On branch master
Your branch is up to date with 'upstream/master'.

nothing to commit, working tree clean
                                                                                                                                                                        [ 0s008 | Mar 30 07:18PM ]
[I] luke@t480s ~/r/ModernCppStarter (master)> cmake -S test -B build-test -DTEST_INSTALLED_VERSION=1
-- The CXX compiler identification is GNU 10.2.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- CPM: adding package [email protected] (2.4.5 at /home/luke/.cache/cpm/packages/doctest/5a9c0f357efafb61890e91b445aa0f5d4c2bca1b)
-- Found Python: /usr/bin/python3.9 (found version "3.9.2") found components: Interpreter 
-- CPM: adding package [email protected] (v1.7.0 at /home/luke/.cache/cpm/packages/format.cmake/e25a26778e5810b3fa49523bf8cadf5f71bacc26)
CMake Error at CMakeLists.txt:22 (find_package):
  By not providing "FindGreeter.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "Greeter", but
  CMake did not find one.

  Could not find a package configuration file provided by "Greeter" with any
  of the following names:

    GreeterConfig.cmake
    greeter-config.cmake

  Add the installation prefix of "Greeter" to CMAKE_PREFIX_PATH or set
  "Greeter_DIR" to a directory containing one of the above files.  If
  "Greeter" provides a separate development package or SDK, be sure it has
  been installed.


-- Configuring incomplete, errors occurred!
See also "/home/luke/repos/ModernCppStarter/build-test/CMakeFiles/CMakeOutput.log".
                                                                                                                                                                        [ 0s316 | Mar 30 07:18PM ]
[I] luke@t480s ~/r/ModernCppStarter (master) [1]> 

In contrast, the following does work as expected (I think):

[I] luke@t480s ~/r/ModernCppStarter (master)> cmake -S all -B build-all -DTEST_INSTALLED_VERSION=1
-- The CXX compiler identification is GNU 10.2.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- cxxopts version 2.2.0
-- CPM: adding package [email protected] (v2.2.1 at /home/luke/.cache/cpm/packages/cxxopts/e6a190480e8d9ef81c1874707d528a2c07f21fa3)
-- CPM: adding package Greeter@ (/home/luke/repos/ModernCppStarter/standalone/..)
-- CPM: Greeter: adding package [email protected] (v1.6.0 at /home/luke/.cache/cpm/packages/packageproject.cmake/d10abef59d67d4a5c303763ad9a3331bf4c1ee01)
-- Version: 7.1.3
-- Build type: 
-- CXX_STANDARD: 11
-- Performing Test has_std_11_flag
-- Performing Test has_std_11_flag - Success
-- Performing Test has_std_0x_flag
-- Performing Test has_std_0x_flag - Success
-- Performing Test SUPPORTS_USER_DEFINED_LITERALS
-- Performing Test SUPPORTS_USER_DEFINED_LITERALS - Success
-- Performing Test FMT_HAS_VARIANT
-- Performing Test FMT_HAS_VARIANT - Success
-- Required features: cxx_variadic_templates
-- Looking for strtod_l
-- Looking for strtod_l - found
-- CPM: Greeter: adding package [email protected] (7.1.3 at /home/luke/.cache/cpm/packages/fmt/9dd47b889fbf7c876d24be56ca097a884004b789)
-- CPM: adding package [email protected] (2.4.5 at /home/luke/.cache/cpm/packages/doctest/5a9c0f357efafb61890e91b445aa0f5d4c2bca1b)
-- Found Python: /usr/bin/python3.9 (found version "3.9.2") found components: Interpreter 
-- CPM: adding package [email protected] (v1.7.0 at /home/luke/.cache/cpm/packages/format.cmake/e25a26778e5810b3fa49523bf8cadf5f71bacc26)
-- The C compiler identification is GNU 10.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- CPM: adding package m.css@0 (42d4a9a48f31f5df6e246c948403b54b50574a2a at /home/luke/.cache/cpm/packages/m.css/ce3daea984872362c3a8ed1c3d8956adbc400a88)
-- Configuring done
-- Generating done
-- Build files have been written to: /home/luke/repos/ModernCppStarter/build-all

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.