|
| 1 | +[](https://github.com/TheLartians/ModernCppStarter/actions) |
| 2 | +[](https://github.com/TheLartians/ModernCppStarter/actions) |
| 3 | +[](https://github.com/TheLartians/ModernCppStarter/actions) |
| 4 | +[](https://github.com/TheLartians/ModernCppStarter/actions) |
| 5 | +[](https://github.com/TheLartians/ModernCppStarter/actions) |
| 6 | +[](https://codecov.io/gh/TheLartians/ModernCppStarter) |
| 7 | + |
| 8 | +<p align="center"> |
| 9 | + <img src="https://repository-images.githubusercontent.com/254842585/4dfa7580-7ffb-11ea-99d0-46b8fe2f4170" height="175" width="auto" /> |
| 10 | +</p> |
| 11 | +[英文版](README.md) |
| 12 | +# ModernCppStarter |
| 13 | + |
| 14 | +创建一个新的C++项目通常需要大量的准备工作和模板代码,尤其是对于有测试、可执行文件和持续集成的现代C++项目而言。 |
| 15 | +这个模板是从多个以前的项目中获得的经验总结,应该有助于减少设置一个现代C++项目所需的工作量。 |
| 16 | + |
| 17 | +## Features |
| 18 | + |
| 19 | +- [现代 CMake 实践](https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/) |
| 20 | +- 适用于任何规模项目,无论单头文件库还是大型项目 |
| 21 | +- 库和可执行代码的干净分离 |
| 22 | +- 集成测试套件 |
| 23 | +- 通过[GitHub Actions](https://help.github.com/en/actions/)实现持续集成CI:使用GitHub的自动化工具,每次代码更改时都会触发一系列的测试、构建和部署任务 |
| 24 | +- 通过[codecov](https://codecov.io)进行代码覆盖率分析:分析测试套件覆盖了多少代码,帮助开发者找出未被测试覆盖的代码部分 |
| 25 | +- 通过 [Format.cmake](https://github.com/TheLartians/Format.cmake)强制使用[clang-format](https://clang.llvm.org/docs/ClangFormat.html)和 [cmake-format](https://github.com/cheshirekow/cmake_format)规范代码格式 |
| 26 | +- 通过 [CPM.cmake](https://github.com/TheLartians/CPM.cmake)实现可重复的依赖管理:管理项目的依赖,确保在不同环境或不同时间构建项目时,依赖的版本都是一致的 |
| 27 | + |
| 28 | +- 通过[PackageProject.cmake](https://github.com/TheLartians/PackageProject.cmake)生成可安装的目标,并自动包含版本信息和头文件 |
| 29 | +- 使用 [Doxygen](https://www.doxygen.nl) 和 [GitHub Pages](https://pages.github.com) 自动实现[documentation](https://thelartians.github.io/ModernCppStarter)和部署:Doxygen是一个用于从源代码中生成文档的工具,而GitHub Pages则是一个用于托管静态网页的平台。结合两者,可以自动地从代码生成文档,并部署到网页上供人查阅 |
| 30 | +- 支持 [sanitizer tools等](#additional-tools):sanitizer工具通常用于内存错误检测,如地址越界、内存泄漏等。这个功能意味着该工具或框架集成了对这类工具的支持,以帮助开发者更好地检测代码中的潜在问题 |
| 31 | + |
| 32 | +## Usage |
| 33 | + |
| 34 | +### Adjust the template to your needs |
| 35 | + |
| 36 | +- Use this repo [as a template](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template). |
| 37 | +- Replace all occurrences of "Greeter" in the relevant CMakeLists.txt with the name of your project |
| 38 | + - Capitalization matters here: `Greeter` means the name of the project, while `greeter` is used in file names. |
| 39 | + - Remember to rename the `include/greeter` directory to use your project's lowercase name and update all relevant `#include`s accordingly. |
| 40 | +- Replace the source files with your own |
| 41 | +- For header-only libraries: see the comments in [CMakeLists.txt](CMakeLists.txt) |
| 42 | +- Add [your project's codecov token](https://docs.codecov.io/docs/quick-start) to your project's github secrets under `CODECOV_TOKEN` |
| 43 | +- Happy coding! |
| 44 | + |
| 45 | +Eventually, you can remove any unused files, such as the standalone directory or irrelevant github workflows for your project. |
| 46 | +Feel free to replace the License with one suited for your project. |
| 47 | + |
| 48 | +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. |
| 49 | +During development it is usually convenient to [build all subprojects at once](#build-everything-at-once). |
| 50 | + |
| 51 | +### Build and run the standalone target |
| 52 | + |
| 53 | +Use the following command to build and run the executable target. |
| 54 | + |
| 55 | +```bash |
| 56 | +cmake -S standalone -B build/standalone |
| 57 | +cmake --build build/standalone |
| 58 | +./build/standalone/Greeter --help |
| 59 | +``` |
| 60 | + |
| 61 | +### Build and run test suite |
| 62 | + |
| 63 | +Use the following commands from the project's root directory to run the test suite. |
| 64 | + |
| 65 | +```bash |
| 66 | +cmake -S test -B build/test |
| 67 | +cmake --build build/test |
| 68 | +CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/test --target test |
| 69 | + |
| 70 | +# or simply call the executable: |
| 71 | +./build/test/GreeterTests |
| 72 | +``` |
| 73 | + |
| 74 | +To collect code coverage information, run CMake with the `-DENABLE_TEST_COVERAGE=1` option. |
| 75 | + |
| 76 | +### Run clang-format |
| 77 | + |
| 78 | +Use the following commands from the project's root directory to check and fix C++ and CMake source style. |
| 79 | +This requires _clang-format_, _cmake-format_ and _pyyaml_ to be installed on the current system. |
| 80 | + |
| 81 | +```bash |
| 82 | +cmake -S test -B build/test |
| 83 | + |
| 84 | +# view changes |
| 85 | +cmake --build build/test --target format |
| 86 | + |
| 87 | +# apply changes |
| 88 | +cmake --build build/test --target fix-format |
| 89 | +``` |
| 90 | + |
| 91 | +See [Format.cmake](https://github.com/TheLartians/Format.cmake) for details. |
| 92 | +These dependencies can be easily installed using pip. |
| 93 | + |
| 94 | +```bash |
| 95 | +pip install clang-format==14.0.6 cmake_format==0.6.11 pyyaml |
| 96 | +``` |
| 97 | + |
| 98 | +### Build the documentation |
| 99 | + |
| 100 | +The documentation is automatically built and [published](https://thelartians.github.io/ModernCppStarter) whenever a [GitHub Release](https://help.github.com/en/github/administering-a-repository/managing-releases-in-a-repository) is created. |
| 101 | +To manually build documentation, call the following command. |
| 102 | + |
| 103 | +```bash |
| 104 | +cmake -S documentation -B build/doc |
| 105 | +cmake --build build/doc --target GenerateDocs |
| 106 | +# view the docs |
| 107 | +open build/doc/doxygen/html/index.html |
| 108 | +``` |
| 109 | + |
| 110 | +To build the documentation locally, you will need Doxygen, jinja2 and Pygments installed on your system. |
| 111 | + |
| 112 | +### Build everything at once |
| 113 | + |
| 114 | +The project also includes an `all` directory that allows building all targets at the same time. |
| 115 | +This is useful during development, as it exposes all subprojects to your IDE and avoids redundant builds of the library. |
| 116 | + |
| 117 | +```bash |
| 118 | +cmake -S all -B build |
| 119 | +cmake --build build |
| 120 | + |
| 121 | +# run tests |
| 122 | +./build/test/GreeterTests |
| 123 | +# format code |
| 124 | +cmake --build build --target fix-format |
| 125 | +# run standalone |
| 126 | +./build/standalone/Greeter --help |
| 127 | +# build docs |
| 128 | +cmake --build build --target GenerateDocs |
| 129 | +``` |
| 130 | + |
| 131 | +### Additional tools |
| 132 | + |
| 133 | +The test and standalone subprojects include the [tools.cmake](cmake/tools.cmake) file which is used to import additional tools on-demand through CMake configuration arguments. |
| 134 | +The following are currently supported. |
| 135 | + |
| 136 | +#### Sanitizers |
| 137 | + |
| 138 | +Sanitizers can be enabled by configuring CMake with `-DUSE_SANITIZER=<Address | Memory | MemoryWithOrigins | Undefined | Thread | Leak | 'Address;Undefined'>`. |
| 139 | + |
| 140 | +#### Static Analyzers |
| 141 | + |
| 142 | +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. |
| 143 | +By default, analyzers will automatically find configuration files such as `.clang-format`. |
| 144 | +Additional arguments can be passed to the analyzers by setting the `CLANG_TIDY_ARGS`, `IWYU_ARGS` or `CPPCHECK_ARGS` variables. |
| 145 | + |
| 146 | +#### Ccache |
| 147 | + |
| 148 | +Ccache can be enabled by configuring with `-DUSE_CCACHE=<ON | OFF>`. |
| 149 | + |
| 150 | +## FAQ |
| 151 | + |
| 152 | +> Can I use this for header-only libraries? |
| 153 | +
|
| 154 | +Yes, however you will need to change the library type to an `INTERFACE` library as documented in the [CMakeLists.txt](CMakeLists.txt). |
| 155 | +See [here](https://github.com/TheLartians/StaticTypeInfo) for an example header-only library based on the template. |
| 156 | + |
| 157 | +> I don't need a standalone target / documentation. How can I get rid of it? |
| 158 | +
|
| 159 | +Simply remove the standalone / documentation directory and according github workflow file. |
| 160 | + |
| 161 | +> Can I build the standalone and tests at the same time? / How can I tell my IDE about all subprojects? |
| 162 | +
|
| 163 | +To keep the template modular, all subprojects derived from the library have been separated into their own CMake modules. |
| 164 | +This approach makes it trivial for third-party projects to re-use the projects library code. |
| 165 | +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. |
| 166 | +Use this as the main directory for best IDE support. |
| 167 | + |
| 168 | +> I see you are using `GLOB` to add source files in CMakeLists.txt. Isn't that evil? |
| 169 | +
|
| 170 | +Glob is considered bad because any changes to the source file structure [might not be automatically caught](https://cmake.org/cmake/help/latest/command/file.html#filesystem) by CMake's builders and you will need to manually invoke CMake on changes. |
| 171 | + I personally prefer the `GLOB` solution for its simplicity, but feel free to change it to explicitly listing sources. |
| 172 | + |
| 173 | +> I want create additional targets that depend on my library. Should I modify the main CMakeLists to include them? |
| 174 | +
|
| 175 | +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. |
| 176 | +Instead, create a new directory or project with a CMakeLists that adds the library as a dependency (e.g. like the [standalone](standalone/CMakeLists.txt) directory). |
| 177 | +Depending type it might make sense move these components into a separate repositories and reference a specific commit or version of the library. |
| 178 | +This has the advantage that individual libraries and components can be improved and updated independently. |
| 179 | + |
| 180 | +> You recommend to add external dependencies using CPM.cmake. Will this force users of my library to use CPM.cmake as well? |
| 181 | +
|
| 182 | +[CPM.cmake](https://github.com/TheLartians/CPM.cmake) should be invisible to library users as it's a self-contained CMake Script. |
| 183 | +If problems do arise, users can always opt-out by defining the CMake or env variable [`CPM_USE_LOCAL_PACKAGES`](https://github.com/cpm-cmake/CPM.cmake#options), which will override all calls to `CPMAddPackage` with the according `find_package` call. |
| 184 | +This should also enable users to use the project with their favorite external C++ dependency manager, such as vcpkg or Conan. |
| 185 | + |
| 186 | +> Can I configure and build my project offline? |
| 187 | +
|
| 188 | +No internet connection is required for building the project, however when using CPM missing dependencies are downloaded at configure time. |
| 189 | +To avoid redundant downloads, it's highly recommended to set a CPM.cmake cache directory, e.g.: `export CPM_SOURCE_CACHE=$HOME/.cache/CPM`. |
| 190 | +This will enable shallow clones and allow offline configurations dependencies are already available in the cache. |
| 191 | + |
| 192 | +> Can I use CPack to create a package installer for my project? |
| 193 | +
|
| 194 | +As there are a lot of possible options and configurations, this is not (yet) in the scope of this template. See the [CPack documentation](https://cmake.org/cmake/help/latest/module/CPack.html) for more information on setting up CPack installers. |
| 195 | + |
| 196 | +> This is too much, I just want to play with C++ code and test some libraries. |
| 197 | +
|
| 198 | +Perhaps the [MiniCppStarter](https://github.com/TheLartians/MiniCppStarter) is something for you! |
| 199 | + |
| 200 | +## Related projects and alternatives |
| 201 | + |
| 202 | +- [**ModernCppStarter & PVS-Studio Static Code Analyzer**](https://github.com/viva64/pvs-studio-cmake-examples/tree/master/modern-cpp-starter): Official instructions on how to use the ModernCppStarter with the PVS-Studio Static Code Analyzer. |
| 203 | +- [**cpp-best-practices/gui_starter_template**](https://github.com/cpp-best-practices/gui_starter_template/): A popular C++ starter project, created in 2017. |
| 204 | +- [**filipdutescu/modern-cpp-template**](https://github.com/filipdutescu/modern-cpp-template): A recent starter using a more traditional approach for CMake structure and dependency management. |
| 205 | +- [**vector-of-bool/pitchfork**](https://github.com/vector-of-bool/pitchfork/): Pitchfork is a Set of C++ Project Conventions. |
| 206 | + |
| 207 | +## Star History |
| 208 | + |
| 209 | +[](https://star-history.com/#TheLartians/ModernCppStarter&cpp-best-practices/gui_starter_template&filipdutescu/modern-cpp-template&Date) |
0 commit comments