Compare commits

...

416 Commits

Author SHA1 Message Date
Duncan Ogilvie 25f015bc83 Bump to 0.2.46 2026-02-01 16:39:51 +01:00
Duncan Ogilvie fc674b4c6b Merge pull request #195 from build-cpp/conditional-languages
Add support for conditional [project].languages
2026-02-01 16:39:16 +01:00
Duncan Ogilvie 433dbb0500 Add test for conditional Objective-C support
Closes #183
2026-02-01 16:37:23 +01:00
Duncan Ogilvie 4772a2b683 Add support for conditional [project].languages
Closes #184
2026-02-01 16:14:17 +01:00
Duncan Ogilvie fb4931df1f Merge pull request #193 from build-cpp/toml11-upgrade
Support TOML 1.1.0
2026-02-01 15:36:15 +01:00
Duncan Ogilvie e96cd30217 Merge pull request #194 from build-cpp/add-dependencies
Add support for [target].dependencies
2026-02-01 15:36:04 +01:00
Duncan Ogilvie 2db8d1ee1d Add support for [target].dependencies
Closes #177
2026-02-01 15:33:09 +01:00
Duncan Ogilvie 645737afd4 Merge pull request #191 from de-ep/fix-tilde-expansion
fix #186
2025-12-21 14:33:09 +01:00
deep 98c2e962c0 fix tilde expansion: add windows support 2025-12-21 14:44:32 +05:30
Duncan Ogilvie 438feccf0f Add support for toml 1.1.0 2025-12-20 15:11:36 +01:00
Duncan Ogilvie 80cc29b8e1 Upgrade toml11 to 3.8.1 2025-12-20 14:29:26 +01:00
Duncan Ogilvie 1a62034a8a Fix formatting 2025-12-20 13:49:34 +01:00
Duncan Ogilvie c12472cd8f Merge pull request #180 from d06i/fix
fix #172
2025-12-17 18:35:20 +01:00
deep 228553d43a fix #186 2025-12-10 19:23:24 +05:30
Duncan Ogilvie 8f4b376e42 Bump to 0.2.45 2025-08-26 17:16:10 +02:00
Duncan Ogilvie fcbf937c49 Merge pull request #189 from iamtimmy/main
template add-function arguments
2025-08-26 17:00:55 +02:00
iamtimmy e609c8a48f template add-function arguments
add arguments support to add-function functionality in templates
2025-08-26 16:46:32 +02:00
Duncan Ogilvie 735898dbac Update basics.md 2025-08-11 03:37:01 +02:00
Duncan Ogilvie f7126b0158 Update basics.md 2025-08-11 03:35:53 +02:00
Duncan Ogilvie b6702714eb Fix info 2025-08-11 03:31:57 +02:00
Duncan Ogilvie efa4f716c2 Add CMake phases to basics 2025-08-11 03:30:28 +02:00
Duncan Ogilvie 76b7b8e778 Clarify basics documentation page 2025-08-11 03:05:37 +02:00
Duncan Ogilvie 501b26ced5 Update fetch-content documentation 2025-06-25 01:50:29 +02:00
Duncan Ogilvie 5bc36275ad Merge pull request #185 from build-cpp/gh-actions-bump
Bump github actions
2025-05-30 01:16:56 +02:00
Duncan Ogilvie 35c837a181 Bump github actions 2025-05-30 00:24:22 +02:00
Duncan Ogilvie 710dfa4963 Merge pull request #182 from evanwporter/patch-1
bumped up upload version
2025-05-30 00:15:38 +02:00
Duncan Ogilvie c49ee6bafe Update README.md 2025-05-29 23:21:04 +02:00
Evan 368273bab2 bumped up upload version 2025-04-19 15:49:15 -07:00
d06i ffe08ae60c fix #172 2025-04-18 00:19:51 +03:00
Duncan Ogilvie b1249af365 Bump to 0.2.44 2025-01-19 15:12:34 +01:00
Duncan Ogilvie ea2ff31b5a Merge pull request #173 from build-cpp/fix-empty-properties
Make sure empty target properties are emitted correctly
2025-01-19 15:10:06 +01:00
Duncan Ogilvie a32eb66df4 Make sure empty target properties are emitted correctly 2025-01-19 14:53:50 +01:00
Duncan Ogilvie 9b85833240 Add link to example vcpkg repository 2024-12-06 18:19:35 +01:00
Duncan Ogilvie ccb3d0b9ef Bump to 0.2.43 2024-12-04 13:00:03 +01:00
Duncan Ogilvie 49cdab39bd Merge pull request #169 from build-cpp/namespace-targets
Support `::mylib` which that target that exists at configure-time
2024-12-04 12:55:57 +01:00
Duncan Ogilvie e318139314 Add documentation for ::mylib 2024-12-04 12:15:51 +01:00
Duncan Ogilvie 0f2a9a55fb Support link-libraries = ["::mylib"] which checks the if target exists
https://gitlab.kitware.com/cmake/cmake/-/issues/26497
2024-12-04 12:15:49 +01:00
Duncan Ogilvie 38cec2d5d1 Do not allow lambdas on a single line 2024-12-04 11:55:13 +01:00
Duncan Ogilvie 3caf593438 Bump to 0.2.42 2024-12-03 15:35:05 +01:00
Duncan Ogilvie c94dbd6416 Merge pull request #168 from build-cpp/target-directory-bug
Fix linking against a target that's also a directory
2024-12-03 13:41:16 +01:00
Duncan Ogilvie a1eaf601c6 Fix linking against a target that's also a directory
Closes #166
2024-12-03 13:39:32 +01:00
Duncan Ogilvie 10320c8e55 Bump to 0.2.41 2024-12-02 15:56:02 +01:00
Duncan Ogilvie 45e12c8d98 Merge pull request #165 from build-cpp/cmake-support
Fix vcpkg support for CMake 3.30
2024-12-02 15:55:43 +01:00
Duncan Ogilvie e12ebc060d Use FetchContent_MakeAvailable for vcpkg 2024-12-02 15:54:19 +01:00
Duncan Ogilvie c6e3fc159f Suppress deprecation warning for CMake <3.10 2024-12-02 15:50:22 +01:00
Duncan Ogilvie dc6f306d9c Bump to 0.2.40 2024-11-28 23:02:34 +01:00
Duncan Ogilvie e08bd5a311 Merge pull request #164 from build-cpp/vcpkg-overlay-bugfix
Use absolute paths for vcpkg overlays
2024-11-28 23:02:17 +01:00
Duncan Ogilvie 068977e2f5 Use absolute paths for vcpkg overlays 2024-11-28 23:01:14 +01:00
Duncan Ogilvie 73147747a4 Bump to 0.2.39 2024-11-28 21:26:27 +01:00
Duncan Ogilvie a64fa9cc34 Merge pull request #163 from build-cpp/vcpkg-fetch-folder
Move vcpkg download location directly in `${CMAKE_BINARY_DIR}/vcpkg`
2024-11-28 21:25:53 +01:00
Duncan Ogilvie eb6ccb39ee Move vcpkg download location directly in ${CMAKE_BINARY_DIR} 2024-11-28 21:24:03 +01:00
Duncan Ogilvie 91dd8ce51f Bump to 0.2.38 2024-11-28 14:40:22 +01:00
Duncan Ogilvie efbfca27bd Merge pull request #160 from build-cpp/vcpkg-triplets
Add support for `[vcpkg].overlay-triplets`
2024-11-28 14:38:46 +01:00
Duncan Ogilvie 78bcf2acf7 Add support for [vcpkg].overlay-triplets 2024-11-28 14:28:10 +01:00
Duncan Ogilvie 83559cc5d4 Improve target reference documentation 2024-11-28 14:28:08 +01:00
Duncan Ogilvie 5d85cc83e3 Ignore generated vcpkg.json 2024-11-28 13:44:11 +01:00
Duncan Ogilvie dea41d80b5 Bump to 0.2.37 2024-11-27 14:17:48 +01:00
Duncan Ogilvie b52cf5b241 Merge pull request #158 from build-cpp/vcpkg-default-features
Allow disabling default features with vcpkg
2024-11-27 14:16:25 +01:00
Duncan Ogilvie e9480a625f Allow disabling default features with vcpkg 2024-11-27 14:13:37 +01:00
Duncan Ogilvie 13a7a8788a Bump to 0.2.36 2024-11-26 13:36:24 +01:00
Duncan Ogilvie 45ca74099c Merge pull request #156 from build-cpp/vcpkg-overlay-ports
Add [vcpkg].overlay-ports feature
2024-11-26 13:35:32 +01:00
Duncan Ogilvie ae3d73896e Add [vcpkg].overlay-ports feature 2024-11-26 12:33:29 +01:00
Duncan Ogilvie 57042565d1 Merge pull request #154 from build-cpp/configure-depends
Use CMAKE_CONFIGURE_DEPENDS when supported
2024-11-03 11:44:02 +01:00
deep d02ee3ed24 Added check to make sure hash is valid hex (#153) 2024-11-03 10:49:33 +01:00
Duncan Ogilvie 4a15d2ba55 Use CMAKE_CONFIGURE_DEPENDS when supported 2024-11-03 10:33:32 +01:00
Duncan Ogilvie 87c0295f93 Fix CI 2024-10-14 13:02:20 +02:00
Duncan Ogilvie a608e6b778 Bump to 0.2.35 2024-10-13 16:16:36 +02:00
Duncan Ogilvie 523f5f4a8a Merge pull request #150 from build-cpp/msvc-runtime-root
Only emit `MSVC_RUNTIME_LIBRARY` in the root project
2024-09-06 14:39:47 +02:00
Duncan Ogilvie 510cf71af5 Only emit MSVC_RUNTIME_LIBRARY in the root project 2024-09-06 14:33:04 +02:00
Duncan Ogilvie 87d90138b4 Merge pull request #149 from build-cpp/relative-libs
Improve relative path functionality for link-libraries
2024-09-06 14:25:33 +02:00
Duncan Ogilvie 50615e0c27 Bump clang-format-lint-action
https://github.com/DoozyX/clang-format-lint-action/issues/73
2024-09-06 14:22:12 +02:00
Duncan Ogilvie 42ed3048b3 Improve relative path functionality for link-libraries 2024-09-06 13:50:43 +02:00
Duncan Ogilvie b0a1d79a42 Bump to 0.2.34 2024-08-05 15:28:58 +02:00
Duncan Ogilvie 5882bc082d Support integer properties
Closes #148
2024-08-05 15:28:38 +02:00
Duncan Ogilvie a90b3c6095 Add RC as a default language 2024-08-05 15:28:16 +02:00
Duncan Ogilvie 0a887c08f8 Bump to 0.2.33 2024-07-06 14:50:39 +02:00
Duncan Ogilvie 9f2cfe4083 Merge pull request #146 from build-cpp/improved-conditions
Improve error-prone condition handling
2024-07-06 14:49:32 +02:00
Duncan Ogilvie 15ad1dc6a7 Support nested condition syntax for named conditions 2024-07-06 14:43:32 +02:00
Duncan Ogilvie dabffeaed9 Add back the option name as a named condition 2024-07-06 14:43:32 +02:00
Duncan Ogilvie 59fe5c38b8 Consider PROJECT_OPTION to be a valid condition 2024-07-06 14:43:32 +02:00
Duncan Ogilvie dcdc7ac410 Add a few more default named conditions 2024-07-06 14:43:32 +02:00
Duncan Ogilvie 88377a8bfb Bump to 0.2.32 2024-07-06 14:03:55 +02:00
Duncan Ogilvie 3a9685be82 Merge pull request #145 from build-cpp/system-bug
Fix uninitialized 'system' field for fetch-content
2024-07-06 14:03:08 +02:00
Duncan Ogilvie 5576789c18 Fix uninitialized 'system' field for fetch-content 2024-07-06 14:02:33 +02:00
Duncan Ogilvie a362978f99 Bump to 0.2.31 2024-06-21 00:33:33 +02:00
Duncan Ogilvie a2f33297e4 Merge pull request #144 from build-cpp/msvc-runtime-subproject
Do not set CMAKE_MSVC_RUNTIME_LIBRARY if it's already set
2024-06-21 00:32:50 +02:00
Duncan Ogilvie 674c976647 Do not set CMAKE_MSVC_RUNTIME_LIBRARY if it's already set 2024-06-21 00:32:30 +02:00
Duncan Ogilvie 714a666e88 Merge pull request #143 from build-cpp/project-improvements
Project improvements
2024-06-01 01:25:26 +02:00
Duncan Ogilvie d613e433d5 Skip linting on pull requests for the same repository 2024-06-01 00:55:31 +02:00
Duncan Ogilvie 7c828d8740 Add custom targets for running cmkr/tests 2024-06-01 00:55:31 +02:00
Duncan Ogilvie 559f750c89 Fix undefined behavior with std::tolower/toupper 2024-06-01 00:55:29 +02:00
Duncan Ogilvie 4b6b72874e Remove nlohmann_json 2024-05-31 22:45:27 +02:00
Duncan Ogilvie 6bffa7cc71 Bump to 0.2.30 2024-05-31 22:36:39 +02:00
Duncan Ogilvie f415b432ed Also run linting on pull requests 2024-05-31 22:34:27 +02:00
Duncan Ogilvie 6c46664336 Merge pull request #142 from anthonyprintup/globbing-extension-fix
Fixed globbing when multiple extensions are present in the file name
2024-05-31 22:31:18 +02:00
Duncan Ogilvie f32aac63aa Review improvements 2024-05-31 22:24:01 +02:00
Anthony Printup 33d4cc4156 Fixed globbing when multiple extensions are present in the file name 2024-05-30 00:36:14 +02:00
Duncan Ogilvie 9288c8a87d Bump to 0.2.29 2024-04-15 03:08:33 +02:00
Duncan Ogilvie e36eee4420 Merge pull request #140 from build-cpp/improved-conditions
Allow arbitrary CMake expressions as conditions
2024-04-15 03:08:02 +02:00
Duncan Ogilvie 53820c9f65 Support $<condition> in unnamed conditions 2024-04-15 03:01:51 +02:00
Duncan Ogilvie ff7e4b8f23 Allow arbitrary CMake expressions as conditions 2024-04-15 02:12:02 +02:00
Duncan Ogilvie 1072cb44e2 Bump to 0.2.28 2024-04-14 00:08:11 +02:00
Duncan Ogilvie 926fc15fa2 Merge pull request #139 from build-cpp/vcpkg-bump
Bump to the latest vcpkg
2024-04-14 00:06:00 +02:00
Duncan Ogilvie e2c929adb0 Fix out-of-the-box vcpkg experience on macos 2024-04-13 23:57:30 +02:00
Duncan Ogilvie 0dec7ca4d5 Bump to the latest vcpkg 2024-04-13 23:21:25 +02:00
Duncan Ogilvie 45e346b4a3 Bump to 0.2.27 2024-03-28 11:38:01 +01:00
Duncan Ogilvie 7165986190 Merge pull request #138 from build-cpp/find-package-first
Generate find-package before fetch-content
2024-03-28 11:37:31 +01:00
Duncan Ogilvie be0ef6d615 Generate find-package before fetch-content 2024-03-28 11:36:15 +01:00
Duncan Ogilvie d607b9028c Bump to 0.2.26 2023-11-09 13:32:05 +01:00
Duncan Ogilvie 099b14552c Merge pull request #131 from build-cpp/fetch-subdir
Add [fetch-content].subdir
2023-11-09 13:31:48 +01:00
Duncan Ogilvie 771c80a41a Add [fetch-content].subdir
Closes #98
2023-11-09 13:28:29 +01:00
Duncan Ogilvie 58c7de1d60 Merge pull request #129 from build-cpp/gitignore-improvement
Improve the default .gitignore that's generated
2023-10-18 13:22:44 +02:00
Duncan Ogilvie a61e4bb999 Merge pull request #128 from build-cpp/language-documentation
Document the supported languages
2023-10-18 13:22:32 +02:00
Duncan Ogilvie 47aaeaf8ce Document the supported languages 2023-10-18 12:27:04 +02:00
Duncan Ogilvie 62609a0088 Improve the default .gitignore that's generated 2023-10-18 12:26:38 +02:00
Duncan Ogilvie e0d8a085db Merge pull request #121 from anthonyprintup/relative-paths
Added support for relative paths in `link-libraries`
2023-09-22 16:13:03 +02:00
Duncan Ogilvie 56da4144ae Merge pull request #125 from anthonyprintup/fix-124
fix(generator): Prevent calling `std::string::back` on an empty string
2023-09-22 16:12:20 +02:00
Duncan Ogilvie 9388b3f29d Merge pull request #123 from anthonyprintup/quotes-fix
Prevent wrapping test command arguments in quotes
2023-09-22 16:12:07 +02:00
Anthony Printup 079644cfeb fix(generator): Prevent calling std::string::back on an empty string
Fixes #124
2023-09-20 02:34:02 +02:00
Anthony Printup a7ca9f04c0 fix(relative-paths): Replaced has_parent_path with a simpler path check 2023-09-20 00:35:41 +02:00
Anthony Printup 339c2aac94 fix(generator): Prevent command arguments from being quoted when generating tests
Fixes #122
2023-09-18 18:36:58 +02:00
Anthony Printup c573c9a76d test(relative-paths): Add the test-library file to libs 2023-09-18 17:49:21 +02:00
Anthony Printup b24a0a2fdc test(relative-paths): Make link-libraries conditional to the Windows platform 2023-09-18 17:49:20 +02:00
Anthony Printup 854e8817c4 test(relative-paths): Remove inlined CMake from cmake.toml 2023-09-18 17:49:11 +02:00
Anthony Printup 1c2947b2fc fix(relative-paths): Prevent processing paths which may contain CMake macros, added a check to see if the library that's being linked exists on disk 2023-09-18 17:35:46 +02:00
Anthony Printup 19e61aa1aa test(relative-paths): Attempt to fix the tests workflow 2023-09-18 16:41:37 +02:00
Anthony Printup bfa1e1fe0d test(relative-paths): Added the latest relative-paths test to the tests workflow 2023-09-18 15:49:17 +02:00
Anthony Printup 56bd78f7ad feat(project-parser): Added support for relative paths in link-libraries
Fixes #116
2023-09-18 15:44:44 +02:00
Anthony Printup 4362b3547f test(relative-paths): Added tests for #116 2023-09-18 15:43:46 +02:00
Duncan Ogilvie 08204d9847 Bump to 0.2.25 2023-09-16 18:51:26 +02:00
Duncan Ogilvie 2202aa8173 Merge pull request #120 from anthonyprintup/new-lines-fix
Trim additional newline characters at the end of CMakeLists.txt
2023-09-16 18:49:45 +02:00
Anthony Printup d3829fb6cd Trim additional new lines at the end of the generated CMakeLists.txt 2023-09-16 18:49:30 +02:00
Duncan Ogilvie 3fb095210a Merge pull request #118 from ZehMatt/vcpkg-errors
Report better error messages for vcpkg projects and features
2023-08-25 22:21:52 +02:00
ζeh Matt 9f99365a25 Report better error messages for vcpkg projects and features 2023-08-25 15:58:24 +03:00
Duncan Ogilvie be387141b5 Add a 'Compiler flags' example to the documentation 2023-07-09 19:26:07 +02:00
Duncan Ogilvie 09ded38f70 Merge pull request #115 from build-cpp/clang-cl-condition
Add `clang-cl` and `clang-any` conditions
2023-07-09 18:01:06 +02:00
Duncan Ogilvie ad90b1ad3e Add 'clang-cl' and 'clang-any' conditions 2023-07-09 16:20:05 +02:00
Duncan Ogilvie 5bfa03d311 Bump to 0.2.24 2023-06-12 19:12:47 +02:00
Duncan Ogilvie bdd9d393d6 Merge pull request #113 from build-cpp/editorconfig
Add `.editorconfig` and linting
2023-06-12 18:28:12 +02:00
Duncan Ogilvie 1deaec2b41 Add .editorconfig and linting
Closes #112
2023-06-12 18:26:13 +02:00
Duncan Ogilvie cfee3bbc14 Merge pull request #111 from anthonyprintup/fetch-content-system
Fix #110
2023-06-12 17:48:54 +02:00
Anthony Printup bcaa60cabe feat: Added SYSTEM flag support to fetch-content 2023-06-12 15:41:20 +02:00
Duncan Ogilvie 7b1d33395e Bump to 0.2.23 2023-03-25 11:25:18 +00:00
Duncan Ogilvie 240fafc102 Merge pull request #101 from build-cpp/minor-cleanup
Cleanup
2023-03-25 11:24:44 +00:00
Duncan Ogilvie 7a7ddf2699 Speed up the pipeline by using Ninja 2023-03-25 11:19:48 +00:00
Duncan Ogilvie 605a04e72d Fix formatting of files 2023-03-24 11:07:02 +00:00
Duncan Ogilvie fd7f078127 Add workflow for checking clang-format 2023-03-24 11:04:58 +00:00
Duncan Ogilvie ee0e0d71d9 Remove a bunch of dead code 2023-03-24 11:03:45 +00:00
Duncan Ogilvie 9d6897b572 Suppress warnings related to DOWNLOAD_EXTRACT_TIMESTAMP 2023-03-24 11:03:40 +00:00
Duncan Ogilvie f8c34e5545 Error when [vcpkg] is used from a non-root project 2023-03-24 10:43:17 +00:00
Duncan Ogilvie e6d783ea20 Fix a few clang-tidy warnings 2023-03-24 10:41:59 +00:00
Duncan Ogilvie ee7fe38a7b Merge pull request #100 from build-cpp/include-subdir-bugfix
Fix a bug where includes in a subdir would not work
2023-03-24 10:13:30 +00:00
Duncan Ogilvie 66b2aad843 Fix a bug where includes in a subdir would not work 2023-03-24 10:04:32 +00:00
Duncan Ogilvie d2e376080a Bump to 0.2.22 2023-03-09 21:36:11 +01:00
Duncan Ogilvie 634908c651 Merge pull request #97 from build-cpp/cmkr-init-regression
Fix a regression where cmkr init wouldn't create any source files
2023-03-09 21:35:25 +01:00
Duncan Ogilvie 33911f3f1b Fix a regression where cmkr init wouldn't create any source files 2023-03-09 21:35:11 +01:00
Duncan Ogilvie e650073bef Bump to 0.2.21 2023-03-08 09:48:40 +01:00
Duncan Ogilvie 96e44f7771 Merge pull request #96 from build-cpp/check-sources
Improve error messages and check if specified sources exist
2023-03-08 09:47:43 +01:00
Duncan Ogilvie cb9ad5cdb3 Improve error messages and check if specified sources exist 2023-03-08 09:41:40 +01:00
Duncan Ogilvie c785b540d3 Document target templates 2023-03-08 09:01:39 +01:00
Duncan Ogilvie 275b73eefa Remove debug print 2023-03-02 08:43:45 +01:00
Duncan Ogilvie ea49a3acb7 Bump to 0.2.20 2023-02-28 21:31:18 +01:00
Duncan Ogilvie 257e14c869 Merge pull request #93 from build-cpp/gitattributes
Automatically generate .gitattributes and .gitignore with cmkr init
2023-02-28 21:30:34 +01:00
Duncan Ogilvie 7508816fe7 Merge pull request #94 from build-cpp/user-experience
Add a special "root" value for `[options]`
2023-02-28 21:27:11 +01:00
Duncan Ogilvie 45678bc5bc Automatically generate .gitattributes and .gitignore with cmkr init 2023-02-28 21:26:07 +01:00
Duncan Ogilvie b869e5646f Add a special "root" value for [options] 2023-02-28 19:34:31 +01:00
Duncan Ogilvie a499df84b1 Bump to 0.2.19 2023-02-28 17:11:55 +01:00
Duncan Ogilvie 49440f99e0 Merge pull request #92 from build-cpp/improved-options
Improve and document the `[options]` feature
2023-02-20 02:13:50 +01:00
Duncan Ogilvie 0c19c3da0c Improve the code related to [options] 2023-02-20 02:09:36 +01:00
Duncan Ogilvie 233cadadd0 Merge pull request #90 from mike1k/sanity
Error on unknown language & unacceptable source file.
2023-02-20 01:31:47 +01:00
Duncan Ogilvie 58a5a935e5 Add a bunch of missing languages and extensions and refactor 2023-02-20 01:18:48 +01:00
Duncan Ogilvie e69427bf94 Merge pull request #91 from build-cpp/clang-condition
Fix the `clang` condition and CI improvements
2023-02-19 22:30:15 +01:00
Duncan Ogilvie bc6359805d Change the clang condition to not detect clang-cl
References:
- https://github.com/cursey/safetyhook/issues/18
- https://discourse.cmake.org/t/clang-on-windows-detected-with-msvc-interface/3470
2023-02-19 22:23:34 +01:00
Duncan Ogilvie 8dcc11e349 Add helper function Project::cmake_minimum_version for version-dependent features 2023-02-19 22:19:12 +01:00
Duncan Ogilvie 51dc49e6f1 Improve CI performance for non-tagged builds 2023-02-19 20:06:58 +01:00
mike 7d27c28b59 Fixed failing tests due to implicit project languages (internal list empty) 2023-02-09 10:53:48 -06:00
Duncan Ogilvie ae6bea3b58 Improve reference documentation 2023-01-28 11:57:22 +01:00
Duncan Ogilvie 5a0eda7abc Automatically generate release notes 2023-01-15 13:34:36 +01:00
Duncan Ogilvie f17923c18b Bump to 0.2.18 2023-01-14 21:28:17 +01:00
Duncan Ogilvie ad17890e23 Merge pull request #85 from build-cpp/settings-rename
Rename `[settings]` to `[variables]`
2023-01-14 21:14:12 +01:00
Duncan Ogilvie c0b98b3ef4 Add documentation for the [variables] section 2023-01-14 18:12:57 +01:00
Duncan Ogilvie 2c6fc569af Preserve backwards compatibility 2023-01-14 16:17:06 +01:00
Duncan Ogilvie 12ee23a44c Improve error messages 2023-01-14 15:52:19 +01:00
Duncan Ogilvie 82342a6b6f Rename [settings] to [variables] 2023-01-14 15:51:57 +01:00
Duncan Ogilvie 1d95fab0ce Switch to giscus for documentation comments 2023-01-02 14:56:38 +01:00
Duncan Ogilvie 44a77329bf Merge pull request #83 from build-cpp/document-basics
Document basics
2023-01-02 12:43:24 +01:00
Duncan Ogilvie e68c5fccdc Add utteranc.es comments 2023-01-02 12:43:20 +01:00
Duncan Ogilvie e2722d2c09 Initial draft of new documentation 2023-01-02 12:02:24 +01:00
Duncan Ogilvie 2627864383 Merge pull request #78 from build-cpp/fix-tests
Successfully fail when running cmkr subcommands
2022-11-29 10:11:45 +01:00
Duncan Ogilvie 05e21f734a Fix the tests 2022-11-29 10:06:34 +01:00
Duncan Ogilvie 1fd18503cd Successfully fail when running cmkr subcommands 2022-11-24 00:32:31 +01:00
Duncan Ogilvie 8b19441d34 Bump to 0.2.17 2022-11-24 00:31:42 +01:00
Duncan Ogilvie 2437eb90fe Minor improvements
- Drastically improve quality of generated CMake
- Fix a regression with recursive globbing in the root
- Automatically include CSharpUtilities when using CSharp
2022-11-24 00:23:30 +01:00
Duncan Ogilvie 6e4006ec07 Fix typo in the docs 2022-10-25 00:59:58 +02:00
Duncan Ogilvie 697b638723 Fix warning on macos 2022-10-11 14:19:29 +02:00
Duncan Ogilvie 109c4bc99f Bump to 0.2.16 2022-10-08 10:48:16 +02:00
Duncan Ogilvie cad85f0bb1 Merge pull request #70 from build-cpp/fix-msvc-runtime
Actually generate the set(CMAKE_MSVC_RUNTIME_LIBRARY)
2022-10-08 10:47:56 +02:00
Duncan Ogilvie 53c88ceafa Actually generate the set(CMAKE_MSVC_RUNTIME_LIBRARY)
Closes #69 (nice)
2022-10-08 10:37:27 +02:00
Duncan Ogilvie d2aa15b1c7 Bump to 0.2.15 2022-10-07 22:21:07 +02:00
Duncan Ogilvie e6ded077cf Merge pull request #65 from gmh5225/feature-msvc-static
[feature] msvc-static
2022-10-07 22:20:36 +02:00
Duncan Ogilvie 3615ccab94 Document msvc-runtime feature 2022-10-07 22:15:32 +02:00
Duncan Ogilvie 73622aa5ba Remove the add_test hook to generate tests the same on all platforms 2022-10-07 22:09:54 +02:00
Duncan Ogilvie 69d844a152 Refactor msvc-static to msvc-runtime 2022-10-07 17:46:36 +02:00
gmh5225 af9a117f50 Fix merge 2022-10-07 06:50:26 +08:00
gmh5225 5fe8220728 Merge branch 'feature-msvc-static' of https://github.com/gmh5225/cmkr into feature-msvc-static 2022-10-07 06:41:43 +08:00
gmh5225 28f541cd3c [feature] add CMP0091 2022-10-07 06:41:11 +08:00
gmh5225 2f3fd7b95e Merge branch 'main' into feature-msvc-static 2022-10-07 05:35:11 +08:00
Duncan Ogilvie 07d99c582d Merge pull request #68 from build-cpp/headers-crash
Fix the way target.headers is merged into target.sources
2022-10-06 18:30:13 +02:00
Duncan Ogilvie 5af2385cc3 Fix the way target.headers is merged into target.sources
- It would crash if you did not specify target.sources
- Headers with condition would be merged incorrectly
2022-10-06 18:22:51 +02:00
gmh5225 981c48dbc5 [feature] msvc-static 2022-10-02 10:43:32 +08:00
Duncan Ogilvie 153bdbe591 Bump to 0.2.14 2022-07-19 14:17:47 +02:00
Duncan Ogilvie 97f1c5c1cc Fix a bug when there are regex characters in the path
Closes #61
2022-07-19 14:05:47 +02:00
Duncan Ogilvie 5b6d9c3826 Replace illegal characters in the project name with _ when doing cmkr init 2022-07-19 13:42:56 +02:00
Duncan Ogilvie a90988b81a Update the formatting to now allow functions on a single line
This makes it less annoying when the IDE is auto-formatting while you type
2022-07-19 13:41:43 +02:00
Duncan Ogilvie 3a1298f4e8 Merge pull request #60 from pmeerw/fix-warning
error: fix warning, signedness of comparison
2022-06-28 19:47:39 +02:00
Peter Meerwald-Stadler 534f955827 error: fix warning, signedness of comparison
cmkr/src/error.cpp:23:24: warning: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’ [-Wsign-compare]
   23 |     assert(i >= 0 && i < (sizeof(err_string) / sizeof(*(err_string))));
2022-06-28 18:21:15 +02:00
Duncan Ogilvie ef537ce084 Bump to 0.2.13 2022-06-01 19:27:03 +02:00
Duncan Ogilvie 9cdd0f7344 Escape lists when generating commands 2022-06-01 19:26:41 +02:00
Duncan Ogilvie e69cf4d2b9 Add install.optional flag 2022-06-01 19:06:53 +02:00
Duncan Ogilvie e98a906231 Document the install.component option 2022-06-01 16:59:54 +02:00
Duncan Ogilvie 9a82f8c796 Temporarily remove the crt-linkage and library-linkage options
These require a lot more work to integrate properly with vcpkg, reimplement triplet detection and set a custom triplet
2022-06-01 16:57:09 +02:00
Duncan Ogilvie 13255c68cf Use FetchContent_MakeAvailable for vcpkg in case they add CMakeLists.txt 2022-06-01 16:53:38 +02:00
Duncan Ogilvie 5768460827 Update credits 2022-04-08 18:16:38 +02:00
Duncan Ogilvie 50d4a905b6 Merge pull request #55 from ZehMatt/fix/#54
Fix #54: Fix settings not being properly quoted
2022-04-01 12:49:02 +02:00
ζeh Matt f957cec2dc Update CMakeLists.txt for tests 2022-04-01 03:37:04 +03:00
Duncan Ogilvie 232e49e087 Add support for vcpkg CRT and library linkage customization 2022-04-01 02:27:41 +02:00
ζeh Matt 7408d42160 Fix #54: Fix settings not being properly quoted 2022-04-01 03:15:32 +03:00
Duncan Ogilvie 1596a8143d Bump to 0.2.12 2022-03-06 06:07:55 +01:00
Duncan Ogilvie 9b0f18ee94 Fix a bug in fetch-content generation 2022-03-06 06:05:17 +01:00
Duncan Ogilvie 887086dc05 Credits 2022-02-23 21:32:58 +01:00
Duncan Ogilvie edc8e1e02e Bump to 0.2.11 2022-02-12 04:42:19 +01:00
Duncan Ogilvie 1f6e31e0ef Add optional CMKR_COMMIT_HASH for the paranoid 2022-02-12 04:39:34 +01:00
Duncan Ogilvie 4de1500bb3 Refactor cmake injection 2022-02-12 04:14:47 +01:00
Duncan Ogilvie 85370968f8 Improved fetch-content support
Closes #38
2022-02-12 04:05:51 +01:00
Duncan Ogilvie 06a4c04df6 Add support for 'shallow' in fetch-content 2022-02-12 03:10:25 +01:00
Duncan Ogilvie fef2a0215b Error when recursively globbing in the project root
Closes #48
2022-02-12 03:03:57 +01:00
Duncan Ogilvie fc74a5e802 Bump to 0.2.10 2022-02-12 02:45:10 +01:00
Duncan Ogilvie e48d402e21 Improve version bumping script 2022-02-12 02:44:45 +01:00
Duncan Ogilvie f6a245618e Merge pull request #53 from build-cpp/better-validation
Better TOML validation
2022-02-12 02:44:05 +01:00
Duncan Ogilvie c713606fd4 Error when using an unknown key in the root of the TOML
[error] Unknown key 'fetch-cntent'
 --> cmake.toml:2
   |
 2 | [fetch-cntent.blah]
   |  ~~~~~~~~~~~~
2022-02-12 02:19:37 +01:00
Duncan Ogilvie fe9b6587a9 Error when trying to parse an empty cmake.toml file 2022-02-12 02:07:30 +01:00
Duncan Ogilvie a2f8d9e5c9 Bump to 0.2.9 2022-02-11 02:51:18 +01:00
Duncan Ogilvie c7925e7110 Merge pull request #52 from build-cpp/fix-options
Do not omit non-optional documentation in option()
2022-02-11 02:49:21 +01:00
Duncan Ogilvie c778a5fe2b Do not omit non-optional documentation in option() 2022-02-11 02:42:20 +01:00
Duncan Ogilvie 16b2cbbb57 Add sitemap.xml and robots.txt 2022-02-10 01:20:54 +01:00
Duncan Ogilvie 2f5c7823be Redirect /getting-started to https://cmkr.build 2022-02-10 00:54:32 +01:00
Duncan Ogilvie a29b6a8aaa SEO-friendly permalink 2022-02-10 00:15:28 +01:00
Duncan Ogilvie 5ac8b15c9a Bump to 0.2.8 2022-02-02 17:25:10 +01:00
Duncan Ogilvie e7d9faa6bb Merge pull request #51 from cursey/improvement/install-component
Allow specifying install component name
2022-01-29 11:31:29 +01:00
cursey 6f8b07a801 Allow specifying install component name 2022-01-28 17:16:19 -08:00
Duncan Ogilvie e8c6ccb698 Minor improvements to bootstrapping code 2022-01-26 01:07:18 +01:00
Duncan Ogilvie 539ebc8f4b Host documentation on https://cmkr.build 2022-01-14 18:06:04 +01:00
Duncan Ogilvie 37ca385673 Show vcpkg version when configuring 2022-01-14 13:42:03 +01:00
Duncan Ogilvie 8ae029dab1 Bump to 0.2.7 2022-01-14 01:04:11 +01:00
Duncan Ogilvie fb16cc34b1 Fix a regression with invalid names being generated in vcpkg.json 2022-01-14 01:03:37 +01:00
Duncan Ogilvie 47703871e1 Bump to 0.2.6 2022-01-13 00:35:13 +01:00
Duncan Ogilvie a8d6b15dcb Merge pull request #47 from cursey/templates
Add support for target templates
2022-01-13 00:33:05 +01:00
Duncan Ogilvie 87b3c7ec6c Document template targets 2022-01-13 00:24:04 +01:00
Duncan Ogilvie d905be1d13 Final touches 2022-01-12 23:57:14 +01:00
Duncan Ogilvie 8d13ccbeaa Delete driver test to add later 2022-01-12 23:56:53 +01:00
cursey bcbc9d2b20 Remove use of std::make_unique for C++11 compliance 2022-01-11 00:12:02 -08:00
cursey 05324f593b Improve code reuse for target cmds 2022-01-11 00:04:01 -08:00
cursey 2b7ee72e86 Separate template parsing and generation
* Reuse type for specifying template to use
* Add support for template add-function
* Add support for template pass-sources-to-add-function
2022-01-10 23:29:26 -08:00
cursey 61d5e64d87 Fix parser expecting to always find templates 2022-01-10 18:59:34 -08:00
cursey eed1e38407 Add support for target templates 2022-01-10 18:59:33 -08:00
Duncan Ogilvie 61851d2bee Bump to 0.2.5 2022-01-07 19:45:08 +01:00
Duncan Ogilvie c0d665095e Add script to automatically bump the version
Closes #44
2022-01-07 19:44:33 +01:00
Duncan Ogilvie 6c1e388391 Add root, x64 and x32 conditions 2021-12-30 14:27:07 +01:00
Duncan Ogilvie 04905371b8 Bump to 0.2.4 2021-12-30 02:45:02 +01:00
Duncan Ogilvie 5a6ac44fcf Merge pull request #46 from build-cpp/expanded-conditions
Support conditions everywhere
2021-12-30 02:44:02 +01:00
Duncan Ogilvie 9db82dfd05 Update toml reference 2021-12-30 02:43:17 +01:00
Duncan Ogilvie 459ebb14b5 Support conditions everywhere
Closes #36
2021-12-30 02:35:59 +01:00
Duncan Ogilvie 490869b9a2 Bump to 0.2.3 2021-12-28 12:08:16 +01:00
Duncan Ogilvie 8ae2754994 Merge pull request #45 from cursey/bootstrap-vcpkg-early
Bootstrap Vcpkg prior to FetchContent
2021-12-28 07:01:05 +01:00
cursey 18419297f4 Bootstrap Vcpkg prior to FetchContent 2021-12-27 16:49:11 -08:00
Duncan Ogilvie bdaf5c94e6 Bump to 0.2.2 2021-12-27 11:49:22 +01:00
Duncan Ogilvie fa3b7a346c Emit options and settings before the project() 2021-12-27 11:45:23 +01:00
Duncan Ogilvie df1dbf7953 Bump to 0.2.1 2021-12-27 11:17:20 +01:00
Duncan Ogilvie 5951f6930e Update documentation for vcpkg features 2021-12-27 11:12:28 +01:00
Duncan Ogilvie a6d5f1c99b Merge pull request #41 from cursey/vcpkg-package-features
Add support for vcpkg package features
2021-12-27 11:01:04 +01:00
Duncan Ogilvie dc852b9a2f Run clang-format 2021-12-27 10:54:46 +01:00
cursey 66621a9818 Fix spacing 2021-12-27 01:50:25 -08:00
cursey 2cd8ad0f18 Add missing const 2021-12-27 01:13:16 -08:00
cursey 084cbd6159 Cleanup vcpkg.json generation a little 2021-12-27 01:08:56 -08:00
cursey b4b0f533a9 Validate vcpkg features 2021-12-27 01:02:05 -08:00
cursey 0acc9b4e5a Report the badly formed package name to the user 2021-12-27 00:57:48 -08:00
cursey 61dfb0eb60 Fix tabbing in vcpkg.json for packages that have features 2021-12-26 16:32:38 -08:00
cursey 3201fd052e Add support for vcpkg package features 2021-12-26 15:40:45 -08:00
Duncan Ogilvie 83087ff06e Release v0.2.0 (finally) 2021-12-23 20:13:12 +01:00
Duncan Ogilvie 88e9241e9f Improve onboarding experience
Thanks Matthaus :give:
2021-12-23 18:04:54 +01:00
Duncan Ogilvie eff967277d Update README with a migration guide 2021-12-23 13:32:46 +01:00
Duncan Ogilvie ea01497246 Bump CMKR_TAG 2021-12-23 04:01:18 +01:00
Duncan Ogilvie 04bf40a5a6 Generate resources/version.hpp with the project version 2021-12-23 03:53:07 +01:00
Duncan Ogilvie 4d14395994 Implement support a CMKR_CACHE environment variable
Closes #17
2021-12-23 03:52:20 +01:00
Duncan Ogilvie 3dd3368e4e Build in Debug with CMAKE_UNITY_BUILD
This gives the fastest bootstrapping times and cmkr isn't noticeably slower during generation.
2021-12-23 01:56:11 +01:00
Duncan Ogilvie bb7874a6df Improve compilation times
Compilation with make went from 13 -> 10 seconds.
CMAKE_UNITY_BUILD went even lower to 6 seconds.

Closes #11
2021-12-23 01:54:57 +01:00
Duncan Ogilvie 91dbf2986e Remove dependency on nlohmann json 2021-12-23 00:55:20 +01:00
Duncan Ogilvie 2bcf15c4ed Add support for object libraries
Closes #34
2021-12-23 00:01:18 +01:00
Duncan Ogilvie 6a825e15a0 Slightly improve cmkr init #24 2021-12-22 18:29:13 +01:00
Duncan Ogilvie cc2b984aa5 Update documentation for conditions 2021-12-22 18:28:38 +01:00
Duncan Ogilvie 56a88c41e2 Merge pull request #35 from build-cpp/toml-checker
Proper error messages for invalid keys/conditions
2021-12-22 17:14:05 +01:00
Duncan Ogilvie 6809e8da41 Refactor and add checking for conditions 2021-12-22 16:51:55 +01:00
Duncan Ogilvie 9f9934e9a5 Implemented checking of keys in conditions 2021-12-22 13:31:52 +01:00
Duncan Ogilvie 77f4bf7da0 Some minor fixes related to newlines and formatting 2021-12-22 13:30:59 +01:00
Duncan Ogilvie 09c9c28934 Initial implementation of TomlChecker
This is to error when the user specifies an invalid key.

Closes #31
2021-12-19 02:34:48 +01:00
Duncan Ogilvie f02ccc2309 Refactor fetch-content to vector<Content> 2021-12-12 20:11:20 +01:00
Duncan Ogilvie 37e9a1f1a0 Merge pull request #33 from pmeerw/fix-linux
Ceating a directory with no name apparently fails on Linux, but silen…
2021-12-10 18:59:23 +01:00
Duncan Ogilvie a28e63fddc Merge pull request #32 from pmeerw/cleanup
Some cleanup
2021-12-10 18:59:09 +01:00
Peter Meerwald-Stadler 156fc961ec Ceating a directory with no name apparently fails on Linux, but silently succeeds on Windows 2021-12-10 17:39:36 +01:00
Peter Meerwald-Stadler 31cc1c9481 Avoid explicit number of error strings in cmkr_error_status() 2021-12-10 17:10:06 +01:00
Peter Meerwald-Stadler 19101cd726 Reduce scope of err_string; add missing error codes 2021-12-10 17:10:06 +01:00
Peter Meerwald-Stadler 8ebf69da7e Use C++ includes 2021-12-10 17:10:06 +01:00
Duncan Ogilvie 1c23469c8c Bump CMKR_TAG 2021-12-08 14:40:41 +01:00
Duncan Ogilvie 52671dcf5b Improve documentation for conditions 2021-12-08 14:39:48 +01:00
Duncan Ogilvie 094bab1b81 Add clarification that the system compiler is used when building cmkr 2021-12-08 14:39:35 +01:00
Duncan Ogilvie 0f559bc803 Do not make Package.config default to true 2021-12-08 14:39:18 +01:00
Duncan Ogilvie 491486075d Error when running cmkr.cmake as a script 2021-11-28 22:18:14 +01:00
Duncan Ogilvie ed84fc0251 Merge pull request #29 from build-cpp/fix-actions-pr
Fix a bug in the logic to skip building pull requests from the same repo
2021-10-27 18:11:24 +02:00
Duncan Ogilvie 8b6780fe1a Fix a bug in the logic to skip building pull requests from the same repository 2021-10-27 18:03:17 +02:00
Duncan Ogilvie 9ebcb1fb06 Bump CMKR_TAG 2021-10-24 16:19:50 +02:00
Duncan Ogilvie 7c7144b183 Also generate CMakeLists.txt when calling cmkr init 2021-10-24 16:19:08 +02:00
Duncan Ogilvie 07797988b5 Fix a critical bug in generate_resources.cmake 2021-10-24 16:19:03 +02:00
Duncan Ogilvie 285614e4c2 Automatically generate cmkr.cmake when missing 2021-09-13 17:01:46 +02:00
Mohammed Alyousef e725b10a9f Just removing my name from the Readme 2021-09-01 22:55:51 +03:00
Duncan Ogilvie aafaf58c70 Reduce GitHub Actions OS matrix 2021-08-28 13:50:24 +02:00
Duncan Ogilvie 87db22f134 Add documentation for the cmake.toml format 2021-08-28 13:41:51 +02:00
Duncan Ogilvie 416a8365f9 Bump CMKR_TAG 2021-07-04 13:27:01 +02:00
Duncan Ogilvie a718dfd675 Inherit conditions from the parent project 2021-07-03 16:27:01 +02:00
Duncan Ogilvie 25da3171f0 Add default conditions for gcc/clang/msvc 2021-07-03 16:03:22 +02:00
Duncan Ogilvie 95907602b4 Do not allow in-tree builds per default 2021-07-03 15:56:51 +02:00
Duncan Ogilvie 4b300df8d5 Add some more tests for the documentation 2021-06-27 21:36:01 +02:00
Duncan Ogilvie 760b2a8511 Show a nice error when specifying an invalid vcpkg package name 2021-06-27 00:21:22 +02:00
Duncan Ogilvie fb9af0213b Bump CMKR_TAG 2021-06-26 17:16:25 +02:00
Duncan Ogilvie 264e4ace18 Fix bug checking the root path of subdirectories 2021-06-26 17:15:56 +02:00
Duncan Ogilvie b6ab584a1a Bump CMKR_TAG 2021-06-26 16:28:12 +02:00
Duncan Ogilvie 3cd84a9708 Add basic support for [subdir.mydir] 2021-06-26 16:22:26 +02:00
Duncan Ogilvie 9932e501ce Rename files to make the project easier to navigate 2021-06-25 12:38:48 +02:00
Duncan Ogilvie 1b37dd76a5 Rename things to try to make the code more readable 2021-06-25 12:25:58 +02:00
Duncan Ogilvie 82f2a11311 Bump CMKR_TAG 2021-06-23 22:36:29 +02:00
Duncan Ogilvie eaf03eb785 Add support for target condition 2021-06-15 02:15:06 +02:00
Duncan Ogilvie 8ea5b77ba5 Merge pull request #28 from build-cpp/conditional-properties
Implement conditional properties
2021-06-14 23:38:47 +02:00
Duncan Ogilvie a12b3ae021 Bump CMKR_TAG 2021-06-14 23:36:39 +02:00
Duncan Ogilvie 2450cfb2c9 Implement conditional properties
Closes #8
2021-06-14 23:29:51 +02:00
Duncan Ogilvie 8d024556e3 Fix CI 2021-06-14 04:34:44 +02:00
Duncan Ogilvie af3807ca2b Add support for private- target options 2021-06-14 04:01:02 +02:00
Duncan Ogilvie 17f085c66d Minor improvements to cmkr.cmake 2021-06-01 17:14:08 +02:00
Duncan Ogilvie 5ad6134e07 Merge pull request #27 from build-cpp/manifest
Add support for headers and vcpkg manifest mode
2021-05-31 15:30:34 +02:00
Duncan Ogilvie 7b20d8c54c Restore [vcpkg].version functionality and add a test + documentation 2021-05-31 14:02:13 +02:00
MoAlyousef ffdedbdace fixes 2021-05-29 17:40:44 +03:00
MoAlyousef bb7a0bc0ed signal failure to write a vcpkg.json file 2021-05-28 05:48:23 +03:00
MoAlyousef dd0003f8fe add nlohmann_json to cmake toml 2021-05-28 05:39:00 +03:00
MoAlyousef a32caca8f0 fix fetching vcpkg 2021-05-28 05:08:45 +03:00
MoAlyousef f565ad2af0 fix formatting, add check for project version in manifest mode 2021-05-28 05:03:00 +03:00
MoAlyousef dc4b59f05d prelim vcpkg manifest support 2021-05-28 04:54:04 +03:00
Duncan Ogilvie 4988f141e4 Bump version in cmkr.cmake bootstrapper 2021-05-18 13:14:43 +02:00
Duncan Ogilvie 64b58425e6 Add missing code generation for link-options 2021-05-18 13:13:48 +02:00
Duncan Ogilvie d4f0cdf152 Allow test working directories with a relative path 2021-05-16 23:07:22 +02:00
Duncan Ogilvie 306bb3d4fc Automatically generate documentation from tests 2021-05-16 22:55:55 +02:00
Duncan Ogilvie acd3688d16 Fix [fetch-content] 2021-05-16 22:51:42 +02:00
Duncan Ogilvie 23c5713c6b Fix pipeline typos 2021-05-13 21:48:21 +02:00
Duncan Ogilvie cebe73c8e5 Improved dark theme 2021-05-13 21:43:34 +02:00
Duncan Ogilvie 779d4ae96a Update README.md 2021-05-13 15:32:07 +02:00
Duncan Ogilvie 7eed60bc7d Use dark theme when the system uses dark theme in the documentation 2021-05-13 06:16:36 +02:00
Duncan Ogilvie aa468dcf9c Only upload artifacts for certain operating systems in the matrix 2021-05-13 05:53:46 +02:00
Duncan Ogilvie 1bd9d2228e Logic for prereleases in github actions 2021-05-13 05:47:37 +02:00
Duncan Ogilvie 5364b5ea72 Add credits for documentation favicon 2021-05-13 05:30:56 +02:00
Duncan Ogilvie 7a5d3b0491 Github actions artifacts and release binaries 2021-05-13 05:29:21 +02:00
Duncan Ogilvie 02f1a70628 Use relative paths in the install command to support --prefix 2021-05-13 04:37:28 +02:00
Duncan Ogilvie 7bd97e56e3 Update README.md 2021-05-13 04:19:08 +02:00
Duncan Ogilvie 6e0e3d8215 Update index.md 2021-05-13 04:18:55 +02:00
Duncan Ogilvie 00230ee11a Update index.md 2021-05-13 04:18:42 +02:00
Duncan Ogilvie e734886d9f Merge pull request #22 from darknessxk/feature/docs
Feature/docs
2021-05-13 04:14:59 +02:00
Duncan Ogilvie cf748514fb Use rewritten readme as a base for the documentation 2021-05-13 03:58:23 +02:00
Luiz "darknessxk" Felipe fbe968f817 Fixed search issue 2021-05-13 03:29:42 +02:00
Luiz "darknessxk" Felipe d1097c8303 Rolled back dark theme,e removed import from folder, more examples will be added with time 2021-05-13 03:29:41 +02:00
Luiz "darknessxk" Felipe 8697d87e50 Fixed wrong permalinks 2021-05-13 03:29:41 +02:00
Luiz "darknessxk" Felipe 7dfa905625 Changed the examples pattern to a better one with indexation, better ordered menus 2021-05-13 03:29:41 +02:00
Luiz "darknessxk" Felipe 9a008f0e40 Enabled search 2021-05-13 03:29:41 +02:00
Luiz "darknessxk" Felipe deb08bcf79 Changed page's title to h1 2021-05-13 03:29:41 +02:00
Luiz "darknessxk" Felipe 3ba07bfd17 Added Quickstart example 2021-05-13 03:29:41 +02:00
Luiz "darknessxk" Felipe 3f1dfe5be3 Added shell to markdown code blocks 2021-05-13 03:29:41 +02:00
Luiz "darknessxk" Felipe a002ddc606 Added Usage title to the page 2021-05-13 03:29:40 +02:00
Luiz "darknessxk" Felipe c686f1bec5 Added building page 2021-05-13 03:29:40 +02:00
Luiz "darknessxk" Felipe 812ef8e7a6 Added navigation order, split building block to its own page 2021-05-13 03:29:40 +02:00
Luiz "darknessxk" Felipe 862fce189c Removed about page 2021-05-13 03:29:40 +02:00
Luiz "darknessxk" Felipe cd98345125 Enabled dark theme 2021-05-13 03:29:40 +02:00
Luiz "darknessxk" Felipe 945e4b74c4 Added readme content to index page 2021-05-13 03:29:39 +02:00
Luiz "darknessxk" Felipe 2ad6acbce9 Used to run jekyll locally 2021-05-13 03:29:39 +02:00
Luiz "darknessxk" Felipe c893ddd8c5 Default assets 2021-05-13 03:29:39 +02:00
Luiz "darknessxk" Felipe 55fa8b937a Added default index (to be changed) 2021-05-13 03:29:39 +02:00
Luiz "darknessxk" Felipe 2648d8c6c8 Added About, Examples, Usage folders with a few content 2021-05-13 03:29:39 +02:00
Luiz "darknessxk" Felipe 3413105fec Default 404 page 2021-05-13 03:29:39 +02:00
Luiz "darknessxk" Felipe 85bef09710 docs ignored folder 2021-05-13 03:29:38 +02:00
Luiz "darknessxk" Felipe 964961eb64 Jekyll configuration and prep 2021-05-13 03:29:38 +02:00
Duncan Ogilvie b350ed2c55 Rewrite README 2021-05-13 03:22:38 +02:00
Duncan Ogilvie 7cf16eaf70 Merge pull request #20 from build-cpp/conditional-subdirs
Add support for conditional subdirs
2021-05-04 12:42:04 +02:00
Duncan Ogilvie 9622334bf1 Switch to using target_sources instead of passing sources directly to add_xxx 2021-05-03 19:39:22 +02:00
Duncan Ogilvie 6ad29ef624 Allow conditional subdirs 2021-05-03 19:37:39 +02:00
Duncan Ogilvie 718c2c7527 Get rid of redundant name field in cmkr init 2021-05-03 17:45:51 +02:00
Duncan Ogilvie 8ea0c7396c Merge pull request #19 from build-cpp/project-refactor
Project refactor
2021-05-03 17:42:08 +02:00
Duncan Ogilvie 34c12379c2 Add a check to see whether cmkr was run before pushing 2021-05-03 17:35:31 +02:00
Duncan Ogilvie 6395267e4b Merge cmkrlib into the cmkr target 2021-05-03 17:23:33 +02:00
Duncan Ogilvie 6d9b40bd15 Get rid of hack to hide a warning during bootstrapping on Windows 2021-05-03 17:08:23 +02:00
Duncan Ogilvie c4673d59e2 Simplify default conditions
It was JustMagic's idea to add 'lunix'
2021-05-03 17:05:19 +02:00
Duncan Ogilvie 220dec6bbb Merge pull request #18 from darknessxk/task/change-init-code
Task/change init code
2021-05-03 16:27:16 +02:00
darknessxk 4efa74f91f Changed project string from [[target]] to [target.%s] 2021-05-03 11:21:59 -03:00
darknessxk fbd07c47bc Added argument to target name 2021-05-03 11:21:26 -03:00
Duncan Ogilvie 17d4dc0555 Move all links to the new organization 2021-05-03 15:42:37 +02:00
Duncan Ogilvie a6dfb2272d Add docs placeholder for pages 2021-05-03 14:09:42 +02:00
Duncan Ogilvie 7fdafa4189 Delete CHANGELOG.md and move to GitHub releases 2021-05-03 11:45:28 +02:00
Duncan Ogilvie 7cdf36f317 Initial support for conditional arguments 2021-05-02 23:53:12 +02:00
Duncan Ogilvie bf14f069a7 Minor fixes (removed TODOs and rename checks) 2021-05-02 21:51:04 +02:00
Duncan Ogilvie 3b4bc919a1 Merge branch 'bootstrapper-upgrade' 2021-05-02 02:22:46 +02:00
Duncan Ogilvie c0bdbeb9d8 Merge branch 'array-properties' 2021-05-02 02:22:39 +02:00
Duncan Ogilvie 42725d0339 Update the README to be in sync with master 2021-05-02 02:12:24 +02:00
Duncan Ogilvie 8f393d967d Make cmkr bootstrapper more robust 2021-05-01 00:44:29 +02:00
133 changed files with 7351 additions and 2395 deletions
+4 -3
View File
@@ -10,16 +10,17 @@ AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: true
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortLambdasOnASingleLine: None
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
@@ -72,7 +73,7 @@ PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
+24
View File
@@ -0,0 +1,24 @@
root = true
[*]
end_of_line = lf
trim_trailing_whitespace = true
charset = utf-8
[*.{c,h,cpp,hpp,toml}]
indent_style = space
insert_final_newline = true
[{CMakeLists.txt, *.cmake}]
indent_style = tab
tab_width = 8
insert_final_newline = true
# Exclude the third_party folder
[/third_party/**]
charset = unset
end_of_line = unset
insert_final_newline = unset
trim_trailing_whitespace = unset
indent_style = unset
indent_size = unset
+1
View File
@@ -0,0 +1 @@
CMakeLists.txt linguist-generated
+1
View File
@@ -0,0 +1 @@
github: [mrexodia]
+55 -7
View File
@@ -1,24 +1,72 @@
name: CMake
name: build
on: [push, pull_request]
jobs:
build:
cmake:
# Skip building pull requests from the same repository
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-2016, windows-2019, macos-10.15, ubuntu-16.04, ubuntu-18.04, ubuntu-20.04]
os: [windows-2022, macos-latest, ubuntu-22.04]
env:
BUILD_TYPE: Release
BUILD_TYPE: 'Release'
CMAKE_GENERATOR: 'Ninja'
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Visual Studio Development Environment
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.1
- name: Tag cmkr.cmake
if: ${{ startsWith(github.ref, 'refs/tags/') }}
run: cmake -P "cmake/replace_tag.cmake"
- name: Build
run: |
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}
cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_UNITY_BUILD=ON
cmake --build build --config ${{ env.BUILD_TYPE }} --parallel
cmake --install build --prefix ./install --config ${{ env.BUILD_TYPE }}
- name: Check if cmkr was run
run: |
./install/bin/cmkr gen
git diff --exit-code -- . ":(exclude)cmake/cmkr.cmake"
- name: Test
run: |
cd build/tests
ctest -C ${{ env.BUILD_TYPE }}
ctest -C ${{ env.BUILD_TYPE }} --verbose
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ github.event.repository.name }}-${{ matrix.os }}
path: install/bin/*
- name: Get lowercase OS name
id: osname
uses: ASzc/change-string-case-action@ccb130a4e483d3e86287289183704dc9bf53e77e # master 2024-04-05
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
string: ${{ runner.os }}
- name: Compress artifacts
uses: vimtor/action-zip@1379ea20d4c5705669ba81fd626dd01b1c738f26 # v1.2
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
files: install/bin/
dest: ${{ github.event.repository.name }}-${{ steps.osname.outputs.lowercase }}.zip
- name: Release
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') || contains(github.ref, '-pre') }}
files: ${{ github.event.repository.name }}-${{ steps.osname.outputs.lowercase }}.zip
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+41
View File
@@ -0,0 +1,41 @@
name: lint
on: [push, pull_request]
jobs:
clang-format:
# Skip building pull requests from the same repository
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: clang-format
id: clang-format
uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2
with:
exclude: './third_party'
extensions: 'c,h,cpp,hpp'
clangFormatVersion: 15
style: file
- name: clang-format instructions
if: ${{ failure() && steps.clang-format.outcome == 'failure' }}
run: |
# Instructions for fixing the formatting errors
echo -e "\n\033[0;31mTo fix the formatting, run:\nclang-format -style=file -i \$(git ls-files \"*.c\" \"*.h\" \"*.cpp\" \"*.hpp\")\033[0m\n"
exit 1
editorconfig:
# Skip building pull requests from the same repository
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run editorconfig-checker
uses: editorconfig-checker/action-editorconfig-checker@27dd658c2b1282c7f1f4dc242cdf0f6d8af728ab # master 2025-05-30
+2
View File
@@ -9,3 +9,5 @@ build*/
.idea/
cmake-build*/
CMakeLists.txt.user
.vscode/
.DS_Store
-27
View File
@@ -1,27 +0,0 @@
# CHANGELOG
## 0.1.4 - 2021-04-11
- Use `GIT_SHALLOW ON` by default when getting git dependencies.
- Add cmake.description field.
- Change bin.defines to bin.definitions.
## 0.1.3 - 2020-11-27
- Support building with C++11.
- @mrexodia implemented CMake integration and bootstrapping.
- Add dependency on ghc_filesystem and mpark_variant which are fetched automatically using FetchContent.
## 0.1.2 - 2020-11-20
- Add support for target properties.
- Add installs.
- Require cmake >= 3.15.
- Support settings and caching settings.
- Support config when running cmkr build.
- Add prompt prior to CMakeLists.txt generation if already existent in the current dir.
## 0.1.1 - 2020-11-19
- Add support for globbing.
- Add support for find_package components.
- Add options.
- Support aliases.
- Support interface libs (header-only libs).
- Support testing.
+45 -56
View File
@@ -1,42 +1,36 @@
# This file was generated automatically by cmkr.
# This file is automatically generated from cmake.toml - DO NOT EDIT
# See https://github.com/build-cpp/cmkr for more information
cmake_minimum_required(VERSION 2.8...3.8)
cmake_minimum_required(VERSION 2.8...3.31)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build")
endif()
# Regenerate CMakeLists.txt automatically in the root project
set(CMKR_ROOT_PROJECT OFF)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(CMKR_ROOT_PROJECT ON)
# Bootstrap cmkr
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)
if(CMKR_INCLUDE_RESULT)
cmkr()
endif()
# Enable folder support
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
endif()
# Create a configure-time dependency on cmake.toml to improve IDE support
if(CMKR_ROOT_PROJECT)
# Create a configure-time dependency on cmake.toml to improve IDE support
configure_file(cmake.toml cmake.toml COPYONLY)
endif()
# Hack to hide a warning during cmkr bootstrapping on Windows
if(CMAKE_BUILD_TYPE)
endif()
project(cmkr
LANGUAGES
CXX
VERSION
0.1.3
0.2.46
DESCRIPTION
"CMakeLists generator from TOML"
)
# third_party
include("cmake/generate_documentation.cmake")
include("cmake/generate_resources.cmake")
# Subdirectory: third_party
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
if(CMAKE_FOLDER)
set(CMAKE_FOLDER "${CMAKE_FOLDER}/third_party")
@@ -46,7 +40,7 @@ endif()
add_subdirectory(third_party)
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
# tests
# Subdirectory: tests
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
if(CMAKE_FOLDER)
set(CMAKE_FOLDER "${CMAKE_FOLDER}/tests")
@@ -56,70 +50,65 @@ endif()
add_subdirectory(tests)
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
# Target: cmkr_generate_documentation
add_library(cmkr_generate_documentation INTERFACE)
# Target cmkrlib
set(cmkrlib_SOURCES
"src/cmkrlib/args.cpp"
"src/cmkrlib/build.cpp"
"src/cmkrlib/cmake.cpp"
"src/cmkrlib/error.cpp"
"src/cmkrlib/gen.cpp"
"src/cmkrlib/help.cpp"
"src/cmkrlib/cmake.hpp"
"src/cmkrlib/enum_helper.hpp"
"src/cmkrlib/fs.hpp"
"include/args.h"
"include/build.h"
"include/error.h"
"include/gen.h"
"include/help.h"
"include/literals.h"
set(CMKR_TARGET cmkr_generate_documentation)
generate_documentation()
# Target: cmkr
set(cmkr_SOURCES
cmake.toml
"cmake/cmkr.cmake"
"cmake/version.hpp.in"
"include/arguments.hpp"
"include/build.hpp"
"include/cmake_generator.hpp"
"include/fs.hpp"
"include/help.hpp"
"include/literals.hpp"
"include/project_parser.hpp"
"src/arguments.cpp"
"src/build.cpp"
"src/cmake_generator.cpp"
"src/help.cpp"
"src/main.cpp"
"src/project_parser.cpp"
)
add_library(cmkrlib STATIC ${cmkrlib_SOURCES})
add_executable(cmkr)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkrlib_SOURCES})
target_sources(cmkr PRIVATE ${cmkr_SOURCES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkr_SOURCES})
target_compile_features(cmkrlib PUBLIC
target_compile_features(cmkr PRIVATE
cxx_std_11
)
target_include_directories(cmkrlib PUBLIC
target_include_directories(cmkr PRIVATE
include
)
target_link_libraries(cmkrlib PUBLIC
target_link_libraries(cmkr PRIVATE
toml11
ghc_filesystem
mpark_variant
ordered_map
)
# Target cmkr
set(cmkr_SOURCES
"src/main.cpp"
cmake.toml
)
add_executable(cmkr ${cmkr_SOURCES})
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
if(NOT CMKR_VS_STARTUP_PROJECT)
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT cmkr)
endif()
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkr_SOURCES})
target_link_libraries(cmkr PRIVATE
cmkrlib
)
set(CMKR_TARGET cmkr)
include("cmake/custom_targets.cmake")
install(
TARGETS
cmkr
DESTINATION
"${CMAKE_INSTALL_PREFIX}/bin"
bin
COMPONENT
cmkr
)
+46 -129
View File
@@ -1,160 +1,77 @@
# cmkr
cmkr, pronounced "cmaker", is A CMakeLists.txt generator from TOML.
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/build-cpp/cmkr)
`cmkr`, pronounced "cmaker", is a modern build system based on [CMake](https://cmake.org/) and [TOML](https://toml.io).
## Building
cmkr requires a C++11 compiler, cmake >= 3.15.
```
git clone https://github.com/moalyousef/cmkr
cd cmkr
cmake -Bbin
cmake --build bin --parallel
```
`cmkr` parses `cmake.toml` files and generates a modern, idiomatic `CMakeLists.txt` for you. A minimal example:
## Usage
cmkr parses cmake.toml files (using toml11 by Toru Niina) at the project directory. A basic hello world format with the minimum required fields:
```toml
[cmake]
minimum = "3.15"
[project]
name = "app"
version = "0.1.0"
name = "cmkr_for_beginners"
[[target]]
name = "app"
[target.hello_world]
type = "executable"
sources = ["src/main.cpp"]
```
This project's cmake.toml:
```toml
[cmake]
minimum = "3.15"
`cmkr` can bootstrap itself and you only need CMake and a C++ compiler to use it.
[project]
name = "cmkr"
version = "0.1.4"
description = "CMakeLists generator from TOML"
## Getting started
[fetch-content]
toml11 = { git = "https://github.com/ToruNiina/toml11" }
filesystem = { git = "https://github.com/gulrak/filesystem" }
mpark_variant = { url = "https://github.com/mpark/variant/archive/v1.4.0.tar.gz" }
To get started, run the following commands from your project directory:
[[target]]
name = "cmkrlib"
type = "static"
sources = ["src/cmake.cpp", "src/gen.cpp", "src/help.cpp", "src/build.cpp", "src/error.cpp"]
include-directories = ["include"]
compile-features = ["cxx_std_11"]
link-libraries = ["toml11::toml11", "ghc_filesystem"]
[[target]]
name = "cmkr"
type = "executable"
sources = ["src/main.cpp", "src/args.cpp"]
link-libraries = ["cmkrlib"]
[[install]]
targets = ["cmkr"]
destination = "${CMAKE_INSTALL_PREFIX}/bin"
```sh
curl https://raw.githubusercontent.com/build-cpp/cmkr/main/cmake/cmkr.cmake -o cmkr.cmake
cmake -P cmkr.cmake
```
Currently supported fields:
```toml
[cmake] # required for top-level project
minimum = "3.15" # required
description = "" # optional
subdirs = [] # optional
build-dir = "build" # optional
cpp-flags = [] # optional
c-flags = [] # optional
link-flags = [] # optional
generator = "Ninja" # optional, only valid when run using: cmkr build
config = "Release" # optional, only valid when run using: cmkr build
arguments = ["CMAKE_TOOLCHAIN_FILE=/path/to/toolchain"] # optional, valid when run using: cmkr build
After the bootstrapping process finishes, customize [`cmake.toml`](https://build-cpp.github.io/cmkr/cmake-toml) for your project and run CMake:
[settings] # optional
CMAKE_BUILD_TYPE = "Release"
TOML_BUILD_TESTS = false # optional
TOML_BUILD_DOCS = { value = false, comment = "builds dependency docs", cache = true, force = true } # optional
OLD_VERSION = "0.1.1" # optional
[project] # required per project
name = "app" # required
version = "0.1.0" # required
[find-package] # optional, runs find_package, use "*" to ignore version
Boost = { version = "1.74.0", required = false, components = ["system"] } # optional
spdlog = "*"
[fetch-content] # optional, runs fetchContent
toml11 = { git = "https://github.com/ToruNiina/toml11", tag = "v3.5.0" } # optional
[options] # optional
APP_BUILD_STUFF = false # optional
APP_OTHER_STUFF = { comment = "does other stuff", value = false } # optional
[[target]] # required, can define several binaries
name = "app" # required
type = "executable" # required (executable || library || shared || static || interface)
sources = ["src/*.cpp"] # required, supports globbing
include-directories = ["include"] # optional
alias = "" # optional
compile-features = [] # optional
compile-definitions = [] # optional
link-libraries = [] # optional
properties = { PROPERTY1 = "property1", ... } # optional
[[test]] # optional, can define several
name = "test1" # required
command = "app" # required
arguments = ["arg1", "arg2"] # optional
[[install]] # optional, can define several
targets = ["app"] # optional
files = ["include/*.h"] # optional
dirs = [] # optional
configs = [] # optional (Release|Debug...etc)
destination = "${CMAKE_INSTALL_PREFIX}/bin" # required
```sh
cmake -B build
cmake --build build
```
The cmkr executable can be run from the command-line:
Once bootstrapped, `cmkr` does not introduce extra steps to your workflow. After modifying `cmake.toml` you simply build/configure your CMake project and `cmkr` will automatically regenerate `CMakeLists.txt` when necessary.
<sub>**Note**: The `cmake.toml` project file, generated `CMakeLists.txt` and `cmkr.cmake` bootstrapping script are all intended to be added to source control.</sub>
In CI environments the `cmkr` bootstrapping process is skipped, so there is no additional overhead in your pipelines.
## Template repositories
Another way to get started is to use the [cmkr_for_beginners](https://github.com/build-cpp/cmkr_for_beginners) template repository. Either open it in [Gitpod](https://gitpod.io/#https://github.com/build-cpp/cmkr_for_beginners), or clone the repository and run:
```sh
cmake -B build
cmake --build build
```
Check out the [cmkr topic](https://github.com/topics/cmkr), the [build-cpp organization](https://github.com/build-cpp) or the [tests](https://github.com/build-cpp/cmkr/tree/main/tests) for more examples and templates.
## Command line
Optionally you can put a [`cmkr` release](https://github.com/build-cpp/cmkr/releases) in your `PATH` and use it as a utility from the command line:
```
Usage: cmkr [arguments]
arguments:
init [executable|library|shared|static|interface] Starts a new project in the same directory.
init [executable|library|shared|static|interface] Create a project.
gen Generates CMakeLists.txt file.
build <extra cmake args> Run cmake and build.
install Run cmake --install. Needs admin privileges.
install Run cmake --install.
clean Clean the build directory.
help Show help.
version Current cmkr version.
```
The build command invokes cmake and the default build-system on your platform (unless a generator is specified), it also accepts extra cmake build arguments:
```
cmkr build --config Release
```
## Binary types
## Credits
### executable
Executable binary. Equivalent to [add_executable(name)](https://cmake.org/cmake/help/latest/command/add_executable.html).
### library
Library, can be static or shared depending on the BUILD_SHARED_LIBS variable. Equivalent to [add_library()](https://cmake.org/cmake/help/latest/command/add_library.html).
### static
Static library/archive. Equivalent to [add_library(name STATIC)](https://cmake.org/cmake/help/latest/command/add_library.html).
### shared
Shared/dynamic library. Equivalent to [add_library(name SHARED)](https://cmake.org/cmake/help/latest/command/add_library.html).
### interface
Header-only library. Equivalent to [add_library(name INTERFACE)](https://cmake.org/cmake/help/latest/command/add_library.html).
## Roadmap
- Support more cmake fields.
- Support conditional cmake args somehow!
- [gulrak/filesystem](https://github.com/gulrak/filesystem)
- [Tessil/ordered-map](https://github.com/Tessil/ordered-map)
- [ToruNiina/toml11](https://github.com/ToruNiina/toml11)
- [mpark/variant](https://github.com/mpark/variant)
- [SVG Repo Hammer](https://www.svgrepo.com/svg/192268/hammer)
- [can1357](https://github.com/can1357) for buying `cmkr.build` ❤️
- [JustasMasiulis](https://github.com/JustasMasiulis) for fixing the dark theme ❤️
+30 -16
View File
@@ -1,30 +1,44 @@
[cmake]
version = "2.8...3.8"
version = "2.8...3.31"
cmkr-include = false
[project]
cmake-before = """
# Hack to hide a warning during cmkr bootstrapping on Windows
if(CMAKE_BUILD_TYPE)
endif()
"""
name = "cmkr"
version = "0.1.4"
version = "0.2.46"
description = "CMakeLists generator from TOML"
languages = ["CXX"]
include-after = [
"cmake/generate_documentation.cmake",
"cmake/generate_resources.cmake"
]
subdirs = ["third_party", "tests"]
[target.cmkrlib]
type = "static"
sources = ["src/cmkrlib/*.cpp", "src/cmkrlib/*.hpp", "include/*.h"]
include-directories = ["include"]
compile-features = ["cxx_std_11"]
link-libraries = ["toml11", "ghc_filesystem", "mpark_variant", "ordered_map"]
[target.cmkr_generate_documentation]
type = "interface"
cmake-after = """
generate_documentation()
"""
[target.cmkr]
type = "executable"
sources = ["src/main.cpp"]
link-libraries = ["cmkrlib"]
sources = [
"src/*.cpp",
"include/*.hpp",
"cmake/cmkr.cmake",
"cmake/version.hpp.in",
]
include-directories = [
"include",
]
compile-features = ["cxx_std_11"]
link-libraries = [
"toml11",
"ghc_filesystem",
"mpark_variant",
"ordered_map",
]
include-after = ["cmake/custom_targets.cmake"]
[[install]]
targets = ["cmkr"]
destination = "${CMAKE_INSTALL_PREFIX}/bin"
destination = "bin"
-27
View File
@@ -1,27 +0,0 @@
# This file was generated automatically by cmkr.
# Regenerate CMakeLists.txt file when necessary
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)
if(CMKR_INCLUDE_RESULT)
cmkr()
endif()
cmake_minimum_required(VERSION 3.15)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(example_PROJECT_VERSION 0.1.0)
project(example VERSION ${example_PROJECT_VERSION})
set(EXAMPLE_SOURCES
src/example.cpp
cmake.toml
)
add_executable(example ${EXAMPLE_SOURCES})
source_group(TREE ${PROJECT_SOURCE_DIR} FILES ${EXAMPLE_SOURCES})
+78
View File
@@ -0,0 +1,78 @@
cmake_minimum_required(VERSION 3.20)
if(NOT CMAKE_SCRIPT_MODE_FILE)
message(FATAL_ERROR "Usage: cmake -P bump_version.cmake [1.2.3]")
endif()
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake.toml")
message(FATAL_ERROR "Cannot find cmake.toml")
endif()
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake/cmkr.cmake")
message(FATAL_ERROR "Cannot find cmkr.cmake")
endif()
# Validate branch
find_package(Git REQUIRED)
execute_process(COMMAND "${GIT_EXECUTABLE}" branch --show-current OUTPUT_VARIABLE GIT_BRANCH)
string(STRIP "${GIT_BRANCH}" GIT_BRANCH)
if(NOT GIT_BRANCH STREQUAL "main")
message(FATAL_ERROR "You need to be on the main branch, you are on: ${GIT_BRANCH}")
endif()
file(READ "${CMAKE_SOURCE_DIR}/cmake.toml" CMAKE_TOML)
string(FIND "${CMAKE_TOML}" "[project]" PROJECT_INDEX)
string(SUBSTRING "${CMAKE_TOML}" ${PROJECT_INDEX} -1 CMAKE_TOML_PROJECT)
set(SEMVER_REGEX "([0-9]+)\\.([0-9]+)\\.([0-9]+)")
set(VERSION_REGEX "version = \"${SEMVER_REGEX}\"")
if(CMAKE_TOML_PROJECT MATCHES "${VERSION_REGEX}")
set(MAJOR "${CMAKE_MATCH_1}")
set(MINOR "${CMAKE_MATCH_2}")
set(PATCH "${CMAKE_MATCH_3}")
set(OLDVERSION "${MAJOR}.${MINOR}.${PATCH}")
else()
message(FATAL_ERROR "Failed to match semantic version in cmake.toml")
endif()
if(CMAKE_ARGV3)
if(NOT CMAKE_ARGV3 MATCHES "${SEMVER_REGEX}")
message(FATAL_ERROR "Invalid semantic version number '${CMAKE_ARGV3}'")
endif()
set(NEWVERSION "${CMAKE_ARGV3}")
else()
math(EXPR NEWPATCH "${PATCH} + 1")
set(NEWVERSION "${MAJOR}.${MINOR}.${NEWPATCH}")
endif()
message(STATUS "Version ${OLDVERSION} -> ${NEWVERSION}")
find_program(CMKR_EXECUTABLE "cmkr" PATHS "${CMAKE_SOURCE_DIR}/build" PATH_SUFFIXES Debug Release RelWithDebInfo MinSizeRel NO_CACHE REQUIRED)
message(STATUS "Found cmkr: ${CMKR_EXECUTABLE}")
# Replace version in cmake.toml
string(REPLACE "version = \"${OLDVERSION}\"" "version = \"${NEWVERSION}\"" CMAKE_TOML "${CMAKE_TOML}")
file(CONFIGURE
OUTPUT "${CMAKE_SOURCE_DIR}/cmake.toml"
CONTENT "${CMAKE_TOML}"
@ONLY
NEWLINE_STYLE LF
)
# Run cmkr gen
execute_process(COMMAND "${CMKR_EXECUTABLE}" gen RESULT_VARIABLE CMKR_EXEC_RESULT)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "cmkr gen failed (exit code ${CMKR_EXEC_RESULT})")
endif()
# Replace version in cmkr.cmake
file(READ "${CMAKE_SOURCE_DIR}/cmake/cmkr.cmake" CMKR_CMAKE)
string(REGEX REPLACE "CMKR_TAG \"[^\"]+\"" "CMKR_TAG \"v${NEWVERSION}\"" CMKR_CMAKE "${CMKR_CMAKE}")
file(CONFIGURE
OUTPUT "${CMAKE_SOURCE_DIR}/cmake/cmkr.cmake"
CONTENT "${CMKR_CMAKE}"
@ONLY
NEWLINE_STYLE LF
)
# Print git commands
message(STATUS "Git commands to create new version:\ngit commit -a -m \"Bump to ${NEWVERSION}\"\ngit tag v${NEWVERSION}\ngit push origin main v${NEWVERSION}")
-13
View File
@@ -1,13 +0,0 @@
# This is a minimal example project used for testing the cmkr bootstrapping process
[cmake]
minimum = "3.15"
[project]
name = "example"
version = "0.1.0"
[[target]]
name = "example"
type = "executable"
sources = ["src/example.cpp"]
+260 -147
View File
@@ -1,147 +1,260 @@
include_guard()
# Change these defaults to point to your infrastructure if desired
set(CMKR_REPO "https://github.com/MoAlyousef/cmkr" CACHE STRING "cmkr git repository")
set(CMKR_TAG "archive_84f6b39f" CACHE STRING "cmkr git tag (this needs to be available forever)")
set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable")
set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation")
# Disable cmkr if generation is disabled
if(CMKR_SKIP_GENERATION)
message(STATUS "[cmkr] Skipping automatic cmkr generation")
macro(cmkr)
endmacro()
return()
endif()
# Disable cmkr if no cmake.toml file is found
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
macro(cmkr)
endmacro()
return()
endif()
# Convert a Windows native path to CMake path
if(CMKR_EXECUTABLE MATCHES "\\\\")
string(REPLACE "\\" "/" CMKR_EXECUTABLE_CMAKE "${CMKR_EXECUTABLE}")
set(CMKR_EXECUTABLE "${CMKR_EXECUTABLE_CMAKE}" CACHE FILEPATH "" FORCE)
unset(CMKR_EXECUTABLE_CMAKE)
endif()
# Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher)
function(cmkr_exec)
execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})")
endif()
endfunction()
# Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment)
if(WIN32)
set(CMKR_EXECUTABLE_NAME "cmkr.exe")
else()
set(CMKR_EXECUTABLE_NAME "cmkr")
endif()
# Use cached cmkr if found
set(CMKR_CACHED_EXECUTABLE "${CMAKE_CURRENT_BINARY_DIR}/_cmkr/bin/${CMKR_EXECUTABLE_NAME}")
if(CMKR_EXECUTABLE AND EXISTS "${CMKR_EXECUTABLE}")
message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'")
elseif(CMKR_EXECUTABLE AND NOT CMKR_EXECUTABLE STREQUAL CMKR_CACHED_EXECUTABLE)
message(FATAL_ERROR "[cmkr] '${CMKR_EXECUTABLE}' not found")
else()
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'")
message(STATUS "[cmkr] Fetching cmkr...")
set(CMKR_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_cmkr")
if(EXISTS "${CMKR_DIRECTORY}")
cmkr_exec("${CMAKE_COMMAND}" -E rm -rf "${CMKR_DIRECTORY}")
endif()
find_package(Git QUIET REQUIRED)
cmkr_exec("${GIT_EXECUTABLE}"
clone
--config advice.detachedHead=false
--branch ${CMKR_TAG}
--depth 1
${CMKR_REPO}
"${CMKR_DIRECTORY}"
)
message(STATUS "[cmkr] Building cmkr...")
cmkr_exec("${CMAKE_COMMAND}"
"${CMKR_DIRECTORY}"
"-B${CMKR_DIRECTORY}/build"
"-DCMAKE_BUILD_TYPE=Release"
"-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}"
)
cmkr_exec("${CMAKE_COMMAND}"
--build "${CMKR_DIRECTORY}/build"
--config Release
--parallel
)
cmkr_exec("${CMAKE_COMMAND}"
--install "${CMKR_DIRECTORY}/build"
--config Release
--prefix "${CMKR_DIRECTORY}"
--component cmkr
)
if(NOT EXISTS ${CMKR_EXECUTABLE})
message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'")
endif()
cmkr_exec("${CMKR_EXECUTABLE}" version)
message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}")
endif()
execute_process(COMMAND "${CMKR_EXECUTABLE}" version
RESULT_VARIABLE CMKR_EXEC_RESULT
)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding")
endif()
# This is the macro that contains black magic
macro(cmkr)
# When this macro is called from the generated file, fake some internal CMake variables
get_source_file_property(CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" CMKR_CURRENT_LIST_FILE)
if(CMKR_CURRENT_LIST_FILE)
set(CMAKE_CURRENT_LIST_FILE "${CMKR_CURRENT_LIST_FILE}")
get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
endif()
# File-based include guard (include_guard is not documented to work)
get_source_file_property(CMKR_INCLUDE_GUARD "${CMAKE_CURRENT_LIST_FILE}" CMKR_INCLUDE_GUARD)
if(NOT CMKR_INCLUDE_GUARD)
set_source_files_properties("${CMAKE_CURRENT_LIST_FILE}" PROPERTIES CMKR_INCLUDE_GUARD TRUE)
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_PRE)
# Generate CMakeLists.txt
cmkr_exec("${CMKR_EXECUTABLE}" gen
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST)
if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST)
# Copy the now-generated CMakeLists.txt to CMakerLists.txt
# This is done because you cannot include() a file you are currently in
set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt")
configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY)
# Add the macro required for the hack at the start of the cmkr macro
set_source_files_properties("${CMKR_TEMP_FILE}" PROPERTIES
CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}"
)
# 'Execute' the newly-generated CMakeLists.txt
include("${CMKR_TEMP_FILE}")
# Delete the generated file
file(REMOVE "${CMKR_TEMP_FILE}")
# Do not execute the rest of the original CMakeLists.txt
return()
endif()
# Resume executing the unmodified CMakeLists.txt
endif()
endmacro()
include_guard()
# Change these defaults to point to your infrastructure if desired
set(CMKR_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE)
set(CMKR_TAG "v0.2.46" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE)
# To bootstrap/generate a cmkr project: cmake -P cmkr.cmake
if(CMAKE_SCRIPT_MODE_FILE)
set(CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}/build")
set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}")
endif()
# Set these from the command line to customize for development/debugging purposes
set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable")
set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation")
set(CMKR_BUILD_TYPE "Debug" CACHE STRING "cmkr build configuration")
mark_as_advanced(CMKR_REPO CMKR_TAG CMKR_COMMIT_HASH CMKR_EXECUTABLE CMKR_SKIP_GENERATION CMKR_BUILD_TYPE)
# Disable cmkr if generation is disabled
if(DEFINED ENV{CI} OR CMKR_SKIP_GENERATION OR CMKR_BUILD_SKIP_GENERATION)
message(STATUS "[cmkr] Skipping automatic cmkr generation")
unset(CMKR_BUILD_SKIP_GENERATION CACHE)
macro(cmkr)
endmacro()
return()
endif()
# Disable cmkr if no cmake.toml file is found
if(NOT CMAKE_SCRIPT_MODE_FILE AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
macro(cmkr)
endmacro()
return()
endif()
# Convert a Windows native path to CMake path
if(CMKR_EXECUTABLE MATCHES "\\\\")
string(REPLACE "\\" "/" CMKR_EXECUTABLE_CMAKE "${CMKR_EXECUTABLE}")
set(CMKR_EXECUTABLE "${CMKR_EXECUTABLE_CMAKE}" CACHE FILEPATH "" FORCE)
unset(CMKR_EXECUTABLE_CMAKE)
endif()
# Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher)
function(cmkr_exec)
execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})")
endif()
endfunction()
# Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment)
if(WIN32)
set(CMKR_EXECUTABLE_NAME "cmkr.exe")
else()
set(CMKR_EXECUTABLE_NAME "cmkr")
endif()
# Use cached cmkr if found
if(DEFINED ENV{CMKR_CACHE})
set(CMKR_DIRECTORY_PREFIX "$ENV{CMKR_CACHE}")
string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
if(CMKR_DIRECTORY_PREFIX MATCHES "^~")
if(WIN32)
string(REGEX REPLACE "^~" "$ENV{USERPROFILE}" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
elseif(UNIX)
string(REGEX REPLACE "^~" "$ENV{HOME}" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
endif()
endif()
if(NOT CMKR_DIRECTORY_PREFIX MATCHES "\\/$")
set(CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}/")
endif()
# Build in release mode for the cache
set(CMKR_BUILD_TYPE "Release")
else()
set(CMKR_DIRECTORY_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/_cmkr_")
endif()
set(CMKR_DIRECTORY "${CMKR_DIRECTORY_PREFIX}${CMKR_TAG}")
set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}")
# Helper function to check if a string starts with a prefix
# Cannot use MATCHES, see: https://github.com/build-cpp/cmkr/issues/61
function(cmkr_startswith str prefix result)
string(LENGTH "${prefix}" prefix_length)
string(LENGTH "${str}" str_length)
if(prefix_length LESS_EQUAL str_length)
string(SUBSTRING "${str}" 0 ${prefix_length} str_prefix)
if(prefix STREQUAL str_prefix)
set("${result}" ON PARENT_SCOPE)
return()
endif()
endif()
set("${result}" OFF PARENT_SCOPE)
endfunction()
# Handle upgrading logic
if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE)
cmkr_startswith("${CMKR_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/_cmkr" CMKR_STARTSWITH_BUILD)
cmkr_startswith("${CMKR_EXECUTABLE}" "${CMKR_DIRECTORY_PREFIX}" CMKR_STARTSWITH_CACHE)
if(CMKR_STARTSWITH_BUILD)
if(DEFINED ENV{CMKR_CACHE})
message(AUTHOR_WARNING "[cmkr] Switching to cached cmkr: '${CMKR_CACHED_EXECUTABLE}'")
if(EXISTS "${CMKR_CACHED_EXECUTABLE}")
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
else()
unset(CMKR_EXECUTABLE CACHE)
endif()
else()
message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
unset(CMKR_EXECUTABLE CACHE)
endif()
elseif(DEFINED ENV{CMKR_CACHE} AND CMKR_STARTSWITH_CACHE)
message(AUTHOR_WARNING "[cmkr] Upgrading cached '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
unset(CMKR_EXECUTABLE CACHE)
endif()
endif()
if(CMKR_EXECUTABLE AND EXISTS "${CMKR_EXECUTABLE}")
message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'")
elseif(CMKR_EXECUTABLE AND NOT CMKR_EXECUTABLE STREQUAL CMKR_CACHED_EXECUTABLE)
message(FATAL_ERROR "[cmkr] '${CMKR_EXECUTABLE}' not found")
elseif(NOT CMKR_EXECUTABLE AND EXISTS "${CMKR_CACHED_EXECUTABLE}")
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
message(STATUS "[cmkr] Found cached cmkr: '${CMKR_EXECUTABLE}'")
else()
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'")
message(STATUS "[cmkr] Fetching cmkr...")
if(EXISTS "${CMKR_DIRECTORY}")
cmkr_exec("${CMAKE_COMMAND}" -E rm -rf "${CMKR_DIRECTORY}")
endif()
find_package(Git QUIET REQUIRED)
cmkr_exec("${GIT_EXECUTABLE}"
clone
--config advice.detachedHead=false
--branch ${CMKR_TAG}
--depth 1
${CMKR_REPO}
"${CMKR_DIRECTORY}"
)
if(CMKR_COMMIT_HASH)
execute_process(
COMMAND "${GIT_EXECUTABLE}" checkout -q "${CMKR_COMMIT_HASH}"
RESULT_VARIABLE CMKR_EXEC_RESULT
WORKING_DIRECTORY "${CMKR_DIRECTORY}"
)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "Tag '${CMKR_TAG}' hash is not '${CMKR_COMMIT_HASH}'")
endif()
endif()
message(STATUS "[cmkr] Building cmkr (using system compiler)...")
cmkr_exec("${CMAKE_COMMAND}"
--no-warn-unused-cli
"${CMKR_DIRECTORY}"
"-B${CMKR_DIRECTORY}/build"
"-DCMAKE_BUILD_TYPE=${CMKR_BUILD_TYPE}"
"-DCMAKE_UNITY_BUILD=ON"
"-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}"
"-DCMKR_GENERATE_DOCUMENTATION=OFF"
)
cmkr_exec("${CMAKE_COMMAND}"
--build "${CMKR_DIRECTORY}/build"
--config "${CMKR_BUILD_TYPE}"
--parallel
)
cmkr_exec("${CMAKE_COMMAND}"
--install "${CMKR_DIRECTORY}/build"
--config "${CMKR_BUILD_TYPE}"
--prefix "${CMKR_DIRECTORY}"
--component cmkr
)
if(NOT EXISTS ${CMKR_EXECUTABLE})
message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'")
endif()
cmkr_exec("${CMKR_EXECUTABLE}" version)
message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}")
endif()
execute_process(COMMAND "${CMKR_EXECUTABLE}" version
RESULT_VARIABLE CMKR_EXEC_RESULT
)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding")
endif()
# Use cmkr.cmake as a script
if(CMAKE_SCRIPT_MODE_FILE)
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake.toml")
execute_process(COMMAND "${CMKR_EXECUTABLE}" init
RESULT_VARIABLE CMKR_EXEC_RESULT
)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "[cmkr] Failed to bootstrap cmkr project. Please report an issue: https://github.com/build-cpp/cmkr/issues/new")
else()
message(STATUS "[cmkr] Modify cmake.toml and then configure using: cmake -B build")
endif()
else()
execute_process(COMMAND "${CMKR_EXECUTABLE}" gen
RESULT_VARIABLE CMKR_EXEC_RESULT
)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "[cmkr] Failed to generate project.")
else()
message(STATUS "[cmkr] Configure using: cmake -B build")
endif()
endif()
endif()
# This is the macro that contains black magic
macro(cmkr)
# When this macro is called from the generated file, fake some internal CMake variables
get_source_file_property(CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" CMKR_CURRENT_LIST_FILE)
if(CMKR_CURRENT_LIST_FILE)
set(CMAKE_CURRENT_LIST_FILE "${CMKR_CURRENT_LIST_FILE}")
get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
endif()
# File-based include guard (include_guard is not documented to work)
get_source_file_property(CMKR_INCLUDE_GUARD "${CMAKE_CURRENT_LIST_FILE}" CMKR_INCLUDE_GUARD)
if(NOT CMKR_INCLUDE_GUARD)
set_source_files_properties("${CMAKE_CURRENT_LIST_FILE}" PROPERTIES CMKR_INCLUDE_GUARD TRUE)
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_PRE)
# Generate CMakeLists.txt
cmkr_exec("${CMKR_EXECUTABLE}" gen
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST)
# Delete the temporary file if it was left for some reason
set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt")
if(EXISTS "${CMKR_TEMP_FILE}")
file(REMOVE "${CMKR_TEMP_FILE}")
endif()
if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST)
# Copy the now-generated CMakeLists.txt to CMakerLists.txt
# This is done because you cannot include() a file you are currently in
configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY)
# Add the macro required for the hack at the start of the cmkr macro
set_source_files_properties("${CMKR_TEMP_FILE}" PROPERTIES
CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}"
)
# 'Execute' the newly-generated CMakeLists.txt
include("${CMKR_TEMP_FILE}")
# Delete the generated file
file(REMOVE "${CMKR_TEMP_FILE}")
# Do not execute the rest of the original CMakeLists.txt
return()
endif()
# Resume executing the unmodified CMakeLists.txt
endif()
endmacro()
+18
View File
@@ -0,0 +1,18 @@
generate_resources(cmkr)
add_custom_target(regenerate-cmake
COMMAND "$<TARGET_FILE:cmkr>" gen
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
)
if(CMAKE_CONFIGURATION_TYPES)
add_custom_target(run-tests
COMMAND "${CMAKE_CTEST_COMMAND}" -C $<CONFIG>
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/tests"
)
else()
add_custom_target(run-tests
COMMAND "${CMAKE_CTEST_COMMAND}"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/tests"
)
endif()
+20
View File
@@ -0,0 +1,20 @@
---
# Automatically generated from tests/@EXAMPLE_PERMALINK@/cmake.toml - DO NOT EDIT
layout: default
title: @EXAMPLE_TITLE@
permalink: /examples/@EXAMPLE_PERMALINK@
parent: Examples
nav_order: @EXAMPLE_INDEX@
---
# @EXAMPLE_TITLE@
@EXAMPLE_HEADER@
```toml
@EXAMPLE_TOML@
```
@EXAMPLE_FOOTER@
<sup><sub>This page was automatically generated from [tests/@EXAMPLE_PERMALINK@/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/@EXAMPLE_PERMALINK@/cmake.toml).</sub></sup>
+76
View File
@@ -0,0 +1,76 @@
option(CMKR_GENERATE_DOCUMENTATION "Generate cmkr documentation" ${CMKR_ROOT_PROJECT})
function(generate_documentation)
if(CMKR_GENERATE_DOCUMENTATION)
message(STATUS "[cmkr] Generating documentation...")
# Extract the order of the tests
set(CMKR_TESTS "")
file(READ "${PROJECT_SOURCE_DIR}/tests/cmake.toml" tests_toml NO_HEX_CONVERSION)
string(REGEX MATCHALL "working-directory = \"([^\"]+)\"" tests_match "${tests_toml}")
foreach(match ${tests_match})
if(match MATCHES "working-directory = \"([^\"]+)\"")
list(APPEND CMKR_TESTS "${CMAKE_MATCH_1}")
else()
message(FATAL_ERROR "This should not happen (wrong regex?)")
endif()
endforeach()
# Delete previously generated examples
set(example_folder "${PROJECT_SOURCE_DIR}/docs/examples")
file(GLOB example_files "${example_folder}/*.md")
list(REMOVE_ITEM example_files "${example_folder}/index.md")
if(example_files)
file(REMOVE ${example_files})
endif()
message(DEBUG "[cmkr] Test directories: ${CMKR_TESTS}")
set(test_index 0)
foreach(test_dir ${CMKR_TESTS})
set(test_name "${test_dir}")
set(test_dir "${PROJECT_SOURCE_DIR}/tests/${test_dir}")
set(test_toml "${test_dir}/cmake.toml")
if(IS_DIRECTORY "${test_dir}" AND EXISTS "${test_toml}")
message(DEBUG "[cmkr] Generating documentation for: ${test_toml} (index: ${test_index})")
# Set template variables
set(EXAMPLE_PERMALINK "${test_name}")
set(EXAMPLE_INDEX ${test_index})
math(EXPR test_index "${test_index}+1")
# Read cmake.toml file
file(READ "${test_toml}" test_contents NO_HEX_CONVERSION)
string(LENGTH "${test_contents}" toml_length)
# Extract header text
string(REGEX MATCH "^(\n*(#[^\n]+\n)+\n*)" EXAMPLE_HEADER "${test_contents}")
string(LENGTH "${EXAMPLE_HEADER}" header_length)
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
string(REGEX REPLACE "\n# ?" "\n\n" EXAMPLE_HEADER "\n${EXAMPLE_HEADER}")
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
# Extract footer text
string(REGEX MATCH "(((#[^\n]+)(\n+|$))+)$" EXAMPLE_FOOTER "${test_contents}")
string(LENGTH "${EXAMPLE_FOOTER}" footer_length)
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
string(REGEX REPLACE "\n# ?" "\n\n" EXAMPLE_FOOTER "\n${EXAMPLE_FOOTER}")
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
# Extract toml body
math(EXPR toml_length "${toml_length}-${header_length}-${footer_length}")
string(SUBSTRING "${test_contents}" ${header_length} ${toml_length} EXAMPLE_TOML)
string(STRIP "${EXAMPLE_TOML}" EXAMPLE_TOML)
# Extract title from description
if("${EXAMPLE_TOML}" MATCHES "description *= *\"([^\"]+)\"")
set(EXAMPLE_TITLE "${CMAKE_MATCH_1}")
# Generate documentation markdown page
configure_file("${PROJECT_SOURCE_DIR}/cmake/example.md.in" "${example_folder}/${EXAMPLE_PERMALINK}.md" @ONLY NEWLINE_STYLE LF)
else()
message(DEBUG "[cmkr] Skipping documentation generation for ${test_name} because description is missing")
endif()
endif()
endforeach()
endif()
endfunction()
+24
View File
@@ -0,0 +1,24 @@
# Enumerates the target sources and automatically generates include/resources/${RESOURCE_NAME}.h from all .cmake files
function(generate_resources target)
get_property(TARGET_SOURCES
TARGET ${target}
PROPERTY SOURCES
)
foreach(SOURCE ${TARGET_SOURCES})
get_filename_component(RESOURCE_NAME "${SOURCE}" NAME_WE)
set(RESOURCE_HEADER "include/resources/${RESOURCE_NAME}.hpp")
if(SOURCE MATCHES ".cmake$")
# Add configure-time dependency on the source file
configure_file("${SOURCE}" "${RESOURCE_HEADER}" COPYONLY)
# Generate the actual resource into the header
file(READ "${SOURCE}" RESOURCE_CONTENTS)
configure_file("${PROJECT_SOURCE_DIR}/cmake/resource.hpp.in" "${RESOURCE_HEADER}" @ONLY)
message(STATUS "[cmkr] Generated ${RESOURCE_HEADER}")
elseif(SOURCE MATCHES ".in$")
configure_file("${SOURCE}" "${RESOURCE_HEADER}" @ONLY)
message(STATUS "[cmkr] Generated ${RESOURCE_HEADER}")
endif()
endforeach()
target_include_directories(${target} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/include")
endfunction()
+27
View File
@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.20)
find_package(Git REQUIRED)
execute_process(COMMAND
"${GIT_EXECUTABLE}" name-rev --tags --name-only HEAD
OUTPUT_VARIABLE GIT_TAG
)
string(FIND "${GIT_TAG}" "\n" NEWLINE_POS)
string(SUBSTRING "${GIT_TAG}" 0 ${NEWLINE_POS} GIT_TAG)
string(STRIP "${GIT_TAG}" GIT_TAG)
if("${GIT_TAG}" STREQUAL "")
message(FATAL_ERROR "Failed to retrieve git tag!")
endif()
message(STATUS "CMKR_TAG: '${GIT_TAG}'")
file(READ "cmake/cmkr.cmake" CMKR_CMAKE)
string(REGEX REPLACE "CMKR_TAG \"[^\"]+\"" "CMKR_TAG \"${GIT_TAG}\"" CMKR_CMAKE "${CMKR_CMAKE}")
file(CONFIGURE
OUTPUT "cmake/cmkr.cmake"
CONTENT "${CMKR_CMAKE}"
@ONLY
NEWLINE_STYLE LF
)
+7
View File
@@ -0,0 +1,7 @@
namespace cmkr {
namespace resources {
static const char* @RESOURCE_NAME@ = R"RESOURCE(@RESOURCE_CONTENTS@)RESOURCE";
}
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#define CMKR_VERSION "@PROJECT_VERSION@"
+3
View File
@@ -0,0 +1,3 @@
_site/
.jekyll-metadata
assets/
+25
View File
@@ -0,0 +1,25 @@
---
permalink: /404.html
layout: default
---
<style type="text/css" media="screen">
.container {
margin: 10px auto;
max-width: 600px;
text-align: center;
}
h1 {
margin: 30px 0;
font-size: 4em;
line-height: 1;
letter-spacing: -1px;
}
</style>
<div class="container">
<h1>404</h1>
<p><strong>Page not found :(</strong></p>
<p>The requested page could not be found.</p>
</div>
+1
View File
@@ -0,0 +1 @@
cmkr.build
+16
View File
@@ -0,0 +1,16 @@
source "https://rubygems.org"
gem "minima", "~> 2.5"
gem "github-pages", group: :jekyll_plugins
gem "jekyll-remote-theme"
gem "jekyll-sitemap", "~> 1.4.0"
platforms :mingw, :x64_mingw, :mswin, :jruby do
gem "tzinfo", "~> 1.2"
gem "tzinfo-data"
end
gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
gem "just-the-docs"
gem "webrick", "~> 1.7"
+283
View File
@@ -0,0 +1,283 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (6.0.3.6)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.11.1)
colorator (1.1.0)
commonmarker (0.17.13)
ruby-enum (~> 0.5)
concurrent-ruby (1.1.8)
dnsruby (1.61.5)
simpleidn (~> 0.1)
em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
ethon (0.14.0)
ffi (>= 1.15.0)
eventmachine (1.2.7)
execjs (2.7.0)
faraday (1.4.1)
faraday-excon (~> 1.1)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.1)
multipart-post (>= 1.2, < 3)
ruby2_keywords (>= 0.0.4)
faraday-excon (1.1.0)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.1.0)
ffi (1.15.0)
forwardable-extended (2.6.0)
gemoji (3.0.1)
github-pages (214)
github-pages-health-check (= 1.17.0)
jekyll (= 3.9.0)
jekyll-avatar (= 0.7.0)
jekyll-coffeescript (= 1.1.1)
jekyll-commonmark-ghpages (= 0.1.6)
jekyll-default-layout (= 0.1.4)
jekyll-feed (= 0.15.1)
jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.13.0)
jekyll-mentions (= 1.6.0)
jekyll-optional-front-matter (= 0.3.2)
jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.3.0)
jekyll-redirect-from (= 0.16.0)
jekyll-relative-links (= 0.6.1)
jekyll-remote-theme (= 0.4.3)
jekyll-sass-converter (= 1.5.2)
jekyll-seo-tag (= 2.7.1)
jekyll-sitemap (= 1.4.0)
jekyll-swiss (= 1.0.0)
jekyll-theme-architect (= 0.1.1)
jekyll-theme-cayman (= 0.1.1)
jekyll-theme-dinky (= 0.1.1)
jekyll-theme-hacker (= 0.1.2)
jekyll-theme-leap-day (= 0.1.1)
jekyll-theme-merlot (= 0.1.1)
jekyll-theme-midnight (= 0.1.1)
jekyll-theme-minimal (= 0.1.1)
jekyll-theme-modernist (= 0.1.1)
jekyll-theme-primer (= 0.5.4)
jekyll-theme-slate (= 0.1.1)
jekyll-theme-tactile (= 0.1.1)
jekyll-theme-time-machine (= 0.1.1)
jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.12.0)
kramdown (= 2.3.1)
kramdown-parser-gfm (= 1.1.0)
liquid (= 4.0.3)
mercenary (~> 0.3)
minima (= 2.5.1)
nokogiri (>= 1.10.4, < 2.0)
rouge (= 3.26.0)
terminal-table (~> 1.4)
github-pages-health-check (1.17.0)
addressable (~> 2.3)
dnsruby (~> 1.60)
octokit (~> 4.0)
public_suffix (>= 2.0.2, < 5.0)
typhoeus (~> 1.3)
html-pipeline (2.14.0)
activesupport (>= 2)
nokogiri (>= 1.4)
http_parser.rb (0.6.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
jekyll (3.9.0)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
i18n (~> 0.7)
jekyll-sass-converter (~> 1.0)
jekyll-watch (~> 2.0)
kramdown (>= 1.17, < 3)
liquid (~> 4.0)
mercenary (~> 0.3.3)
pathutil (~> 0.9)
rouge (>= 1.7, < 4)
safe_yaml (~> 1.0)
jekyll-avatar (0.7.0)
jekyll (>= 3.0, < 5.0)
jekyll-coffeescript (1.1.1)
coffee-script (~> 2.2)
coffee-script-source (~> 1.11.1)
jekyll-commonmark (1.3.1)
commonmarker (~> 0.14)
jekyll (>= 3.7, < 5.0)
jekyll-commonmark-ghpages (0.1.6)
commonmarker (~> 0.17.6)
jekyll-commonmark (~> 1.2)
rouge (>= 2.0, < 4.0)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
jekyll-feed (0.15.1)
jekyll (>= 3.7, < 5.0)
jekyll-gist (1.5.0)
octokit (~> 4.2)
jekyll-github-metadata (2.13.0)
jekyll (>= 3.4, < 5.0)
octokit (~> 4.0, != 4.4.0)
jekyll-mentions (1.6.0)
html-pipeline (~> 2.3)
jekyll (>= 3.7, < 5.0)
jekyll-optional-front-matter (0.3.2)
jekyll (>= 3.0, < 5.0)
jekyll-paginate (1.1.0)
jekyll-readme-index (0.3.0)
jekyll (>= 3.0, < 5.0)
jekyll-redirect-from (0.16.0)
jekyll (>= 3.3, < 5.0)
jekyll-relative-links (0.6.1)
jekyll (>= 3.3, < 5.0)
jekyll-remote-theme (0.4.3)
addressable (~> 2.0)
jekyll (>= 3.5, < 5.0)
jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
jekyll-seo-tag (2.7.1)
jekyll (>= 3.8, < 5.0)
jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0)
jekyll-swiss (1.0.0)
jekyll-theme-architect (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-cayman (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-dinky (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.1.2)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-merlot (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-midnight (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-minimal (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-modernist (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-primer (0.5.4)
jekyll (> 3.5, < 5.0)
jekyll-github-metadata (~> 2.9)
jekyll-seo-tag (~> 2.0)
jekyll-theme-slate (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-tactile (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-time-machine (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-titles-from-headings (0.5.3)
jekyll (>= 3.3, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
jemoji (0.12.0)
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (>= 3.0, < 5.0)
just-the-docs (0.3.3)
jekyll (>= 3.8.5)
jekyll-seo-tag (~> 2.0)
rake (>= 12.3.1, < 13.1.0)
kramdown (2.3.1)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.5.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mini_portile2 (2.5.1)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.14.4)
multipart-post (2.1.1)
nokogiri (1.11.3)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
octokit (4.21.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (4.0.6)
racc (1.5.2)
rake (13.0.3)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.5)
rouge (3.26.0)
ruby-enum (0.9.0)
i18n
ruby2_keywords (0.0.4)
rubyzip (2.3.0)
safe_yaml (1.0.5)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sawyer (0.8.2)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
simpleidn (0.2.1)
unf (~> 0.1.4)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (1.2.9)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
webrick (1.7.0)
zeitwerk (2.4.2)
PLATFORMS
ruby
DEPENDENCIES
github-pages
jekyll-remote-theme
jekyll-sitemap (~> 1.4.0)
just-the-docs
minima (~> 2.5)
tzinfo (~> 1.2)
tzinfo-data
wdm (~> 0.1.1)
webrick (~> 1.7)
BUNDLED WITH
2.2.26
+42
View File
@@ -0,0 +1,42 @@
title: cmkr
plugins:
- jekyll-remote-theme
- jekyll-sitemap
# Automatically deduce dark theme preference https://github.com/pmarsceill/just-the-docs/pull/464
remote_theme: build-cpp/just-the-docs@light-switch
search_enabled: true
color_scheme: light-or-dark
heading_anchors: true
aux_links:
"GitHub":
- "https://github.com/build-cpp/cmkr"
aux_links_new_tab: true
gh_edit_link: true
gh_edit_link_text: "Edit this page on GitHub."
gh_edit_repository: "https://github.com/build-cpp/cmkr"
gh_edit_branch: "main"
gh_edit_view_mode: "edit"
gh_edit_source: docs
ga_tracking: G-DY172KY7Z9
production_url : https://cmkr.build
footer_content: |
<script src="https://giscus.app/client.js"
data-repo="build-cpp/cmkr"
data-repo-id="MDEwOlJlcG9zaXRvcnkyOTQwMDc3MzY="
data-category="Documentation"
data-category-id="DIC_kwDOEYYzuM4CTXeA"
data-mapping="pathname"
data-strict="1"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="top"
data-theme="preferred_color_scheme"
data-lang="en"
crossorigin="anonymous"
async>
</script>
+143
View File
@@ -0,0 +1,143 @@
---
layout: page
title: Basics
nav_order: 1
---
# Basics
To effectively use cmkr it helps to understand the basic concepts of CMake. This page serves as an introduction to CMake for beginners. Links to the CMake documentation are included for reference.
## Projects
A CMake **project** is a collection of targets. In the context of libraries the project usually corresponds to the **package** that other projects can depend on.
<sub>Visual Studio: a CMake **project** corresponds to a _solution_.</sub>
## Targets
The basic unit of CMake is called a **target**. A target (also referred to as [binary target](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#binary-targets) in the CMake documentation) corresponds to an executable or static/dynamic library you can build.
<sub>Visual Studio: a **target** corresponds to a _project_.</sub>
Most important target types:
|Type|Purpose|
|-|-|
|Executable|Program you run on your computer (`.exe`)|
|Static library|Library code _compiled into_ the final executable (`.lib`, `.a`)|
|Dynamic library|Library code loaded at runtime (`.dll`, `.so`, `.dylib`)|
|Interface|Used for organizational purposes (common flags/includes/libraries)|
There are also other [pseudo targets](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#pseudo-targets), but they are not important for now.
## Target Properties
Targets have a collection of **properties** that describe how the compiler builds them.
The most commonly-used properties:
- [_Sources_](https://cmake.org/cmake/help/latest/command/target_sources.html): the `*.cpp` files used to build the target.
- [_Include directories_](https://cmake.org/cmake/help/latest/command/target_include_directories.html): Paths to directories the compiler will search when doing `#include`.
- [_Compile definitions_](https://cmake.org/cmake/help/latest/command/target_compile_definitions.html): Preprocessor macro definitions used for compilation (`-DMYOPTION`).
- [_Compile options_](https://cmake.org/cmake/help/latest/command/target_compile_options.html): Command line flags for the compiler (platform/compiler specific).
- [_Compile features_](https://cmake.org/cmake/help/latest/command/target_compile_features.html): C/C++ standard version to build with.
- [_Link libraries_](https://cmake.org/cmake/help/latest/command/target_link_libraries.html): The **dependencies** required to build this target.
- [_Link options_](https://cmake.org/cmake/help/latest/command/target_link_options.html): Command line flags for the linker (platform/linker specific).
<sub>See the [CMake documentation](https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#properties-on-targets) for an exhaustive list of target properties.</sub>
**Important**: The term **link** has a slightly different meaning in CMake than you might expect. In addition to adding a library to the command line, CMake also (transitively) propagates properties of the target you link to based on their _visibility_.
You should think of **linking** in CMake as _depending on_.
{:.info}
The propagation of properties depends on their **visibility**:
- **Private**: properties that are only used when building the target itself.
- **Interface**: properties that are used when depending on this target.
- **Public**: combination of private and interface.
In practice you default to **private**, unless consumers of your library _require_ the property to build their target. In that case you use **public**.
## Example
The most intuitive example is with _include directories_. Imagine there are two targets:
1. `StringUtils`: A library with string utilities.
- _Sources_: `StringUtils/src/stringutils.cpp`
- _Include directories_: `StringUtils/include`
2. `DataProcessor`: An executable that uses functionality from `StringUtils` to process some data.
- _Sources_: `DataProcessor/src/main.cpp`
- _Link libraries_: `StringUtils`
The _include directories_ property of `StringUtils` has to be **public**. If it was **private**, the `DataProcessor` target would fail to `#include <stringutils.hpp>` since the _include directories_ property is not propagated.
The `cmake.toml` for this example would look something like this:
```toml
[project]
name = "DataProcessor"
[target.StringUtils]
type = "static"
sources = ["StringUtils/src/stringutils.cpp"]
headers = ["StringUtils/include/stringutils.hpp"]
include-directories = ["StringUtils/include"] # public (default for libraries)
[target.DataProcessor]
type = "executable"
sources = ["DataProcessor/src/main.cpp"]
link-libraries = ["StringUtils"] # private (default for executables)
```
The generated `CMakeLists.txt` (simplified) looks like this:
```cmake
project(DataProcessor)
# Target: StringUtils
add_library(StringUtils STATIC
"StringUtils/include/stringutils.hpp"
"StringUtils/src/stringutils.cpp"
)
target_include_directories(StringUtils PUBLIC
"StringUtils/include"
)
# Target: DataProcessor
add_executable(DataProcessor
"DataProcessor/src/main.cpp"
)
target_link_libraries(DataProcessor PRIVATE
StringUtils
)
```
## CMake Phases
CMake works in three phases:
1. **Configure**: Execute `CMakeLists.txt` (find dependencies, create targets, OS/compiler-specific conditions, etc).
2. **Generate**: Generate build files (propagates target properties and handles [_generator expressions_](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html)).
3. **Build**: Execute the compiler to produce executables/libraries.
CMake keeps generated files separate from your source in a **build directory**. You specify a [**generator**](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) (Visual Studio/Ninja) and [**build type**](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations) (Debug/Release) during configuration.
```bash
# Configure project and generate build files in build directory
cmake -B build -DCMAKE_BUILD_TYPE=Release
# Build the project
cmake --build build --config Release
```
We specify both `CMAKE_BUILD_TYPE` and `--config` to be compatible with generators that support multiple configurations at once ((like Visual Studio/Xcode/Ninja Multi-Config).
{:.info}
**Build Types**:
- `Debug`: No optimization, debug symbols
- `Release`: Full optimization, no debug symbols
- `RelWithDebInfo`: Medium optimizations, debug symbols
- `MinSizeRel`: Optimize for size, no debug symbols
**Generators**: CMake auto-detects (Makefiles on Linux/macOS, Visual Studio on Windows), but you can specify explicitly with `-G` during the _configure_ step.
+345
View File
@@ -0,0 +1,345 @@
---
layout: page
title: Reference
permalink: /cmake-toml/
nav_order: 3
---
# Reference
This page is a reference for the options in the `cmake.toml` file. If you think anything is missing or unclear, please [edit this page](https://github.com/build-cpp/cmkr/edit/main/docs/cmake-toml.md) or open an [issue](https://github.com/build-cpp/cmkr/issues).
This is a reference page. Check out the [examples](/examples) and the [cmkr topic](https://github.com/topics/cmkr) as well.
{:.info}
## CMake configuration
```toml
[cmake]
version = "3.15"
cmkr-include = "cmkr.cmake"
```
## Project configuration
```toml
[project]
name = "myproject"
version = "1.0.0"
description = "Description of the project"
languages = ["C", "CXX"]
msvc-runtime = "" # dynamic (implicit default), static
cmake-before = """
message(STATUS "CMake injected before the project() call")
"""
cmake-after = """
message(STATUS "CMake injected after the project() call")
"""
include-before = ["cmake/before-project.cmake"]
include-after = ["cmake/after-project.cmake"]
```
### Languages
Supported languages are (see [`enable_language`](https://cmake.org/cmake/help/latest/command/enable_language.html) for more information):
- `C`
- `CXX` → C++
- `CSharp` → C#
- `CUDA`
- `OBJC` → Objective-C
- `OBJCXX` → Objective-C++
- `Fortran`
- `HIP`
- `ISPC`
- `Swift`
- `ASM`
- `ASM_MASM` → [Microsoft Macro Assembler (MASM)](https://learn.microsoft.com/en-US/cpp/assembler/masm/masm-for-x64-ml64-exe)
- `ASM_NASM` → [Netwide Assembler (NASM)](https://www.nasm.us)
- `ASM_MARMASM` [Microsoft ARM Assembler](https://learn.microsoft.com/en-us/cpp/assembler/arm/arm-assembler-command-line-reference)
- `ASM-ATT`
- `Java` (undocumented)
- `RC` (undocumented)
After a language is enabled, adding sources files with the corresponding extension to your target will automatically use the appropriate compiler/assembler for it.
_Note_: It is generally discouraged to disable the `C` language, unless you are absolutely sure it is not used. Sometimes projects added with `fetch-content` implicitly require it and the error messages can be extremely confusing.
## Conditions
You can specify your own named conditions and use them in any `condition` field:
```toml
[conditions]
ptr64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
ptr32 = "CMAKE_SIZEOF_VOID_P EQUAL 4"
```
This will make the `ptr64` and `ptr32` conditions available with their respective CMake expressions.
**Note**: condition names can only contain lower-case alphanumeric characters (`[0-9a-z]`) and dashes (`-`).
You can also prefix most keys with `condition.` to represent a conditional:
```toml
[target]
type = "executable"
sources = ["src/main.cpp"]
ptr64.sources = ["src/ptr64_only.cpp"]
```
Instead of a named condition you can also specify a [CMake expression](https://cmake.org/cmake/help/latest/command/if.html#condition-syntax) in quotes. Instances of `$<name>` are replaced with the corresponding condition. For example: `"CONDITIONS_BUILD_TESTS AND $<linux>"` becomes `CONDITIONS_BUILD_TESTS AND (CMAKE_SYSTEM_NAME MATCHES "Linux")` in the final `CMakeLists.txt` file.
### Predefined conditions
The following conditions are predefined (you can override them if you desire):
```toml
[conditions]
windows = "WIN32"
macos = "CMAKE_SYSTEM_NAME MATCHES \"Darwin\""
unix = "UNIX"
bsd = "CMAKE_SYSTEM_NAME MATCHES \"BSD\""
linux = "CMAKE_SYSTEM_NAME MATCHES \"Linux\""
gcc = "CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" OR CMAKE_C_COMPILER_ID STREQUAL \"GNU\""
msvc = "MSVC"
clang = "(CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" AND NOT CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\") OR (CMAKE_C_COMPILER_ID MATCHES \"Clang\" AND NOT CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\")"
clang-cl = "(CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\") OR (CMAKE_C_COMPILER_ID MATCHES \"Clang\" AND CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\")"
clang-any = "CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" OR CMAKE_C_COMPILER_ID MATCHES \"Clang\""
root = "CMKR_ROOT_PROJECT"
x64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
x32 = "CMAKE_SIZEOF_VOID_P EQUAL 4"
android = "ANDROID"
apple = "APPLE"
bsd = "BSD"
cygwin = "CYGWIN"
ios = "IOS"
xcode = "XCODE"
wince = "WINCE"
```
## Subdirectories
```toml
[subdir.mysubdir]
condition = "mycondition"
cmake-before = """
message(STATUS "CMake injected before the add_subdirectory() call"
"""
cmake-after = """
message(STATUS "CMake injected after the add_subdirectory() call")
"""
include-before = ["cmake/before-subdir.cmake"]
include-after = ["cmake/after-subdir.cmake"]
```
## Options
```toml
[options]
MYPROJECT_BUILD_TESTS = false
MYPROJECT_SPECIAL_OPTION = { value = true, help = "Docstring for this option." }
MYPROJECT_BUILD_EXAMPLES = "root"
```
Options correspond to [CMake cache variables](https://cmake.org/cmake/help/book/mastering-cmake/chapter/CMake%20Cache.html) that can be used to customize your project at configure-time. You can configure with `cmake -DMYPROJECT_BUILD_TESTS=ON` to enable the option. Every option automatically gets a corresponding [condition](#conditions). Additionally, a normalized condition is created based on the `[project].name` (i.e. `MYPROJECT_BUILD_TESTS` becomes `build-tests`).
The special value `root` can be used to set the option to `true` if the project is compiled as the root project (it will be `false` if someone is including your project via `[fetch-content]` or `[subdir]`).
## Variables
```toml
[variables]
MYBOOL = true
MYSTRING = "hello"
```
Variables emit a [`set`](https://cmake.org/cmake/help/latest/command/set.html) and can be used to configure subprojects and packages.
## Vcpkg
```toml
[vcpkg]
version = "2024.11.16"
url = "https://github.com/microsoft/vcpkg/archive/refs/tags/2024.11.16.tar.gz"
packages = ["fmt", "zlib"]
overlay-ports = ["my-ports"]
overlay-triplets = ["my-triplets"]
```
The vcpkg `version` will automatically generate the `url` from the [official repository](https://github.com/microsoft/vcpkg/releases). For a custom registry you can specify your own `url` (and omit the `version`). You can browse available packages on [vcpkg.io](https://vcpkg.io/en/packages.html) or [vcpkg.link](https://vcpkg.link).
To specify package features you can use the following syntax: `imgui[docking-experimental,freetype,sdl2-binding,opengl3-binding]`. To disable the [default features](https://learn.microsoft.com/en-us/vcpkg/concepts/default-features) you can do: `cpp-httplib[core,openssl]`
The `overlay-ports` feature allows you to embed vcpkg ports inside your project, without having to fork the main vcpkg registry or creating a custom registry. You can find more information in the relevant [documentation](https://learn.microsoft.com/en-us/vcpkg/concepts/overlay-ports). The `overlay-triplets` feature allows you to customize triplets and change the default behavior (for example always preferring static libraries on Windows). To specify both in one go you can do `[vcpkg].overlay = "vcpkg-overlay"`.
For a concrete example of all the features, take a look at the [vcpkg_template](https://github.com/build-cpp/vcpkg_template) repository.
## Packages
```toml
[find-package.mypackage]
condition = "mycondition"
version = "1.0"
required = true
config = true
components = ["mycomponent"]
```
## FetchContent
**Note**: The `[fetch-content]` feature is unpolished and will likely change in a future release.
```toml
# Include CMake project from git
[fetch-content.gitcontent]
condition = "mycondition"
git = "https://github.com/myuser/gitcontent"
tag = "v0.1"
shallow = false # shallow clone (--depth 1)
system = false
subdir = "" # folder containing CMakeLists.txt
# Include a CMake project from a URL
[fetch-content.urlcontent]
condition = "mycondition"
url = "https://content-host.com/urlcontent.zip"
# Other supported algorithms:
# md5, sha1, sha224, sha256, sha384, sha512, sha3_224, sha3_256, sha3_384, sha3_512
hash = "SHA1 502a4e25b8b209889c99c7fa0732102682c2e4ff"
sha1 = "502a4e25b8b209889c99c7fa0732102682c2e4ff"
[fetch-content.svncontent]
condition = "mycondition"
svn = "https://svn-host.com/url"
rev = "svn_rev"
```
Table keys that match CMake variable names (`[A-Z_]+`) will be passed to the [`FetchContent_Declare`](https://cmake.org/cmake/help/latest/module/FetchContent.html#command:fetchcontent_declare) command.
## Targets
```toml
[target.mytarget]
condition = "mycondition"
alias = "mytarget::mytarget"
type = "static" # executable, library, shared (DLL), static, interface, object, custom
headers = ["src/mytarget.h"]
sources = ["src/mytarget.cpp"]
msvc-runtime = "" # dynamic (implicit default), static
# The keys below match the target_xxx CMake commands
# Keys prefixed with private- will get PRIVATE visibility
compile-definitions = [""] # preprocessor define (-DFOO)
private-compile-definitions = [""]
compile-features = [""] # C++ standard version (cxx_std_20)
private-compile-features = [""]
compile-options = [""] # compiler flags
private-compile-options = [""]
include-directories = [""] # include paths/directories
private-include-directories = [""]
link-directories = [""] # library directories
private-link-directories = [""]
link-libraries = [""] # dependencies
private-link-libraries = [""]
link-options = [""] # linker flags
private-link-options = [""]
precompile-headers = [""] # precompiled headers
private-precompile-headers = [""]
cmake-before = """
message(STATUS "CMake injected before the target")
"""
cmake-after = """
message(STATUS "CMake injected after the target")
"""
include-before = "cmake/target-before.cmake"
include-after = "cmake/target-after.cmake"
# See https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#properties-on-targets for a list of target properties
[target.mytarget.properties]
CXX_STANDARD = 17
CXX_STANDARD_REQUIRED = true
FOLDER = "MyFolder"
```
A table mapping the cmkr features to the relevant CMake construct and the relevant documentation pages:
| cmkr | CMake construct | Description |
| ---- | ----- | ----------- |
| `alias` | [Alias Libraries](https://cmake.org/cmake/help/latest/command/add_library.html#alias-libraries) | Create an [alias target](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#alias-targets), used for namespacing or clarity. |
| `sources` | [`target_sources`](https://cmake.org/cmake/help/latest/command/target_sources.html) | Source files (`PRIVATE` except `interface` targets). |
| `headers` | [`target_sources`](https://cmake.org/cmake/help/latest/command/target_sources.html) | For readability (and future packaging). |
| `msvc-runtime` | [`MSVC_RUNTIME_LIBRARY`](https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html) | The [CMP0091](https://cmake.org/cmake/help/latest/policy/CMP0091.html) policy is set automatically. |
| `compile-definitions` | [`target_compile_definitions`](https://cmake.org/cmake/help/latest/command/target_compile_definitions.html) | Adds a macro definition (define, `-DMYMACRO=XXX`). |
| `compile-features` | [`target_compile_features`](https://cmake.org/cmake/help/latest/command/target_compile_features.html) | Specifies the C++ standard version (`cxx_std_20`). |
| `compile-options` | [`target_compile_options`](https://cmake.org/cmake/help/latest/command/target_compile_options.html) | Adds compiler flags. |
| `include-directories` | [`target_include_directories`](https://cmake.org/cmake/help/latest/command/target_include_directories.html) | Adds include directories. |
| `link-directories` | [`target_link_directories`](https://cmake.org/cmake/help/latest/command/target_link_directories.html) | Adds library directories. |
| `link-libraries` | [`target_link_libraries`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) | Adds library dependencies. Use `::mylib` to make sure a target exists. |
| `link-options` | [`target_link_options`](https://cmake.org/cmake/help/latest/command/target_link_options.html) | Adds linker flags. |
| `precompile-headers` | [`target_precompile_headers`](https://cmake.org/cmake/help/latest/command/target_precompile_headers.html) | Specifies precompiled headers. |
| `properties` | [`set_target_properties`](https://cmake.org/cmake/help/latest/command/set_target_properties.html) | See [properties on targets](https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#properties-on-targets) for more information. |
The default [visibility](/basics) is as follows:
| Type | Visibility |
| ------------ | ----------- |
| `executable` | `PRIVATE` |
| `library` | `PUBLIC` |
| `shared` | `PUBLIC` |
| `static` | `PUBLIC` |
| `object` | `PUBLIC` |
| `interface` | `INTERFACE` |
## Templates
To avoid repeating yourself you can create your own target type and use it in your targets:
```toml
[template.example]
condition = "MYPROJECT_BUILD_EXAMPLES"
type = "executable"
link-libraries = ["myproject::mylib"]
add-function = ""
add-arguments = ["myoption"]
pass-sources = false
# Properties from the template are merged with the ones here
[target.myexample]
type = "example"
sources = ["src/myexample.cpp"]
```
The properties declared on a `template` are the same as the ones you use for targets. The only exceptions are:
- `add-function`: Specifies a custom add function. Projects like [pybind11](https://pybind11.readthedocs.io/en/stable/cmake/index.html#new-findpython-mode) have their own `add_xxx` function, which you can specify here.
- `add-arguments`: Arguments to pass to the `add-function` before the list of sources. See [cmake_parse_arguments](https://cmake.org/cmake/help/latest/command/cmake_parse_arguments.html) for more details.
- `pass-sources`: Pass sources directly to the add function instead of using `target_sources`.
## Tests and installation (unfinished)
**Note**: The `[[test]]` and `[[install]]` are unfinished features and will likely change in a future release.
```toml
# You can declare as many as you want like this, but the name has to be unique
[[test]]
condition = "mycondition"
name = "mytest"
command = "$<TARGET_FILE:mytest>"
arguments = ["arg1", "arg2"]
configurations = ["Debug", "Release", "RelWithDebInfo", "MinSizeRelease"]
working-directory = "mytest-dir"
```
```toml
[[install]]
condition = "mycondition"
targets = ["mytarget", "mytest"]
destination = ["bin"]
component = "mycomponent"
files = ["content/my.png"]
dirs = ["include"]
configs = ["Release", "Debug"]
optional = false
```
+26
View File
@@ -0,0 +1,26 @@
---
# Automatically generated from tests/basic/cmake.toml - DO NOT EDIT
layout: default
title: Minimal example
permalink: /examples/basic
parent: Examples
nav_order: 0
---
# Minimal example
A minimal `cmake.toml` project:
```toml
[project]
name = "basic"
description = "Minimal example"
[target.basic]
type = "executable"
sources = ["src/basic.cpp"]
```
Declares an executable target called `basic` with `src/basic.cpp` as a source file. Equivalent to CMake's [add_executable](https://cmake.org/cmake/help/latest/command/add_executable.html)`(basic src/basic.cpp)`.
<sup><sub>This page was automatically generated from [tests/basic/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/basic/cmake.toml).</sub></sup>
+34
View File
@@ -0,0 +1,34 @@
---
# Automatically generated from tests/compile-options/cmake.toml - DO NOT EDIT
layout: default
title: Compiler flags
permalink: /examples/compile-options
parent: Examples
nav_order: 9
---
# Compiler flags
Example project that sets compiler flags and preprocessor defines for various platforms.
```toml
[project]
name = "compile-options"
description = "Compiler flags"
[target.hello]
type = "executable"
sources = ["src/main.cpp"]
msvc.compile-options = ["/W2"]
msvc.compile-definitions = ["PLATFORM=\"msvc\""]
gcc.compile-options = ["-Wall"]
gcc.compile-definitions = ["PLATFORM=\"gcc\""]
clang.compile-options = ["-Wall"]
clang.compile-definitions = ["PLATFORM=\"clang\""]
```
The `hello` target uses [conditions](/cmake-toml#conditions) to set different compiler flags and definitions depending on the platform. See the [targets](/cmake-toml/#targets) documentation for other things you can set.
_Note_: In general you only want to specify flags _required_ to compile your code without errors.
<sup><sub>This page was automatically generated from [tests/compile-options/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/compile-options/cmake.toml).</sub></sup>
+27
View File
@@ -0,0 +1,27 @@
---
# Automatically generated from tests/cxx-standard/cmake.toml - DO NOT EDIT
layout: default
title: Changing C++ standard
permalink: /examples/cxx-standard
parent: Examples
nav_order: 5
---
# Changing C++ standard
Require a C++11 compiler for the target `example`.
```toml
[project]
name = "cxx-standard"
description = "Changing C++ standard"
[target.example]
type = "executable"
sources = ["src/main.cpp"]
compile-features = ["cxx_std_11"]
```
This is equivalent to CMake's [target_compile_features](https://cmake.org/cmake/help/latest/command/target_compile_features.html)`(example PRIVATE cxx_std_11)`. For more information on available C/C++ standards and features see [cmake-compile-features(7)](https://cmake.org/cmake/help/latest/manual/cmake-compile-features.7.html).
<sup><sub>This page was automatically generated from [tests/cxx-standard/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/cxx-standard/cmake.toml).</sub></sup>
+31
View File
@@ -0,0 +1,31 @@
---
# Automatically generated from tests/fetch-content/cmake.toml - DO NOT EDIT
layout: default
title: Fetching from git
permalink: /examples/fetch-content
parent: Examples
nav_order: 2
---
# Fetching from git
Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) from [GitHub](https://github.com) and links an `example` target to it:
```toml
[project]
name = "fetch-content"
description = "Fetching from git"
[fetch-content.fmt]
git = "https://github.com/fmtlib/fmt"
tag = "7.1.3"
[target.example]
type = "executable"
sources = ["src/main.cpp"]
link-libraries = ["fmt::fmt"]
```
This is equivalent to calling CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html).
<sup><sub>This page was automatically generated from [tests/fetch-content/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/fetch-content/cmake.toml).</sub></sup>
+35
View File
@@ -0,0 +1,35 @@
---
# Automatically generated from tests/globbing/cmake.toml - DO NOT EDIT
layout: default
title: Globbing sources
permalink: /examples/globbing
parent: Examples
nav_order: 6
---
# Globbing sources
```toml
[project]
name = "globbing"
description = "Globbing sources"
# Recursively glob in the mylib/ folder
[target.mylib]
type = "static"
alias = "mylib::mylib"
sources = ["mylib/**.hpp", "mylib/**.cpp"]
include-directories = ["mylib/include"]
# Single-folder glob in example/src/
[target.example]
type = "executable"
sources = ["example/src/*.cpp"]
link-libraries = ["mylib::mylib"]
```
As you can see in the example above you can use `**.ext` to glob recursively and `*.ext` to glob non-recursively. This **does not** generate `file(GLOB ...)` commands, but instead globs when cmkr is run. Files are sorted to give deterministic results regardless of the platform used.
<sup><sub>This page was automatically generated from [tests/globbing/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/globbing/cmake.toml).</sub></sup>
+11
View File
@@ -0,0 +1,11 @@
---
layout: default
title: Examples
permalink: /examples/
nav_order: 100
has_children: true
---
# Examples
The examples in this section are automatically generated from the [tests](https://github.com/build-cpp/cmkr/blob/main/tests/cmake.toml).
+32
View File
@@ -0,0 +1,32 @@
---
# Automatically generated from tests/interface/cmake.toml - DO NOT EDIT
layout: default
title: Header-only library
permalink: /examples/interface
parent: Examples
nav_order: 1
---
# Header-only library
```toml
[project]
name = "interface"
description = "Header-only library"
[target.mylib]
type = "interface"
include-directories = ["include"]
compile-features = ["cxx_std_11"]
[target.example]
type = "executable"
sources = ["src/main.cpp"]
link-libraries = ["mylib"]
```
<sup><sub>This page was automatically generated from [tests/interface/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/interface/cmake.toml).</sub></sup>
+34
View File
@@ -0,0 +1,34 @@
---
# Automatically generated from tests/msvc-runtime/cmake.toml - DO NOT EDIT
layout: default
title: Static MSVC runtime
permalink: /examples/msvc-runtime
parent: Examples
nav_order: 8
---
# Static MSVC runtime
```toml
[project]
name = "msvc-runtime"
description = "Static MSVC runtime"
msvc-runtime = "static"
# This target will compile with a static runtime
[target.static-runtime]
type = "executable"
sources = ["src/main.cpp"]
# This target overrides the [project].msvc-runtime
[target.dynamic-runtime]
type = "executable"
sources = ["src/main.cpp"]
msvc-runtime = "dynamic"
```
<sup><sub>This page was automatically generated from [tests/msvc-runtime/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/msvc-runtime/cmake.toml).</sub></sup>
+30
View File
@@ -0,0 +1,30 @@
---
# Automatically generated from tests/objective-c/cmake.toml - DO NOT EDIT
layout: default
title: Objective-C
permalink: /examples/objective-c
parent: Examples
nav_order: 11
---
# Objective-C
Add Objective-C sources on Apple platforms:
```toml
[project]
name = "objective-c"
description = "Objective-C"
languages = ["C"]
apple.languages = ["OBJC"]
[target.hello]
type = "executable"
sources = ["src/main.c"]
apple.sources = ["src/apple.m"]
apple.link-libraries = ["$<LINK_LIBRARY:FRAMEWORK,Foundation>"]
```
<sup><sub>This page was automatically generated from [tests/objective-c/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/objective-c/cmake.toml).</sub></sup>
+40
View File
@@ -0,0 +1,40 @@
---
# Automatically generated from tests/templates/cmake.toml - DO NOT EDIT
layout: default
title: Target templates
permalink: /examples/templates
parent: Examples
nav_order: 7
---
# Target templates
To avoid repeating yourself in targets you can create your own target type (template). All properties of the template are inherited when used as a target type.
```toml
[project]
name = "templates"
description = "Target templates"
[template.app]
type = "executable"
sources = ["src/templates.cpp"]
compile-definitions = ["IS_APP"]
# Unlike interface targets you can also inherit properties
properties = {
CXX_STANDARD = "11",
CXX_STANDARD_REQUIRED = true,
}
[target.app-a]
type = "app"
compile-definitions = ["APP_A"]
[target.app-b]
type = "app"
compile-definitions = ["APP_B"]
```
**Note**: In most cases you probably want to use an [interface](/examples/interface) target instead.
<sup><sub>This page was automatically generated from [tests/templates/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/templates/cmake.toml).</sub></sup>
+37
View File
@@ -0,0 +1,37 @@
---
# Automatically generated from tests/vcpkg/cmake.toml - DO NOT EDIT
layout: default
title: Dependencies from vcpkg
permalink: /examples/vcpkg
parent: Examples
nav_order: 4
---
# Dependencies from vcpkg
Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) using [vcpkg](https://github.com/microsoft/vcpkg) and links an `example` target to it:
```toml
[project]
name = "vcpkg"
description = "Dependencies from vcpkg"
# See https://github.com/microsoft/vcpkg/releases for vcpkg versions
# See https://vcpkg.io/en/packages or https://vcpkg.link for available packages
[vcpkg]
version = "2024.11.16"
packages = ["fmt"]
[find-package.fmt]
[target.example]
type = "executable"
sources = ["src/main.cpp"]
link-libraries = ["fmt::fmt"]
```
The bootstrapping of vcpkg is fully automated and no user interaction is necessary. You can disable vcpkg by setting `CMKR_DISABLE_VCPKG=ON`.
To specify package features you can use the following syntax: `imgui[docking-experimental,freetype,sdl2-binding,opengl3-binding]`.
<sup><sub>This page was automatically generated from [tests/vcpkg/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/vcpkg/cmake.toml).</sub></sup>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

+10
View File
@@ -0,0 +1,10 @@
---
layout: null
permalink: /getting-started/
---
<html>
<head>
<meta http-equiv="refresh" content="0;url=https://cmkr.build">
</head>
</html>
+1
View File
@@ -0,0 +1 @@
google-site-verification: google13f7c659b54c069f.html
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+46
View File
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 508 508" style="enable-background:new 0 0 508 508;" xml:space="preserve">
<circle style="fill:#90DFAA;" cx="254" cy="254" r="254"/>
<rect x="185.183" y="201.014" transform="matrix(-0.6939 -0.7201 0.7201 -0.6939 234.8233 525.8541)" style="fill:#2B3B4E;" width="88.002" height="24"/>
<g>
<path style="fill:#324A5E;" d="M121.6,194.4c-8.8-16.4-2.8-40,14-56.4c50.8-50.4,108.8-52.4,136.8-49.6c4,0.4,3.6,6.4-0.8,8
c-11.6,4-21.2,8.8-29.6,14c-25.2,15.2-34,47.6-17.6,64.8l2.8,2.8c1.2,1.2,0.8,3.2-0.8,4.8l-26,25.2c-1.2,1.2-3.2,1.6-4.4,0.8
c-8.8-7.2-22-8.4-35.2-4C138.8,212.4,127.2,205.2,121.6,194.4z"/>
<path style="fill:#324A5E;" d="M144,228l-18,17.2c-4.8,4.8-12.4,4.4-17.2-0.4l-29.2-30c-4.8-4.8-4.4-12.4,0.4-17.2l18-17.2
c4.8-4.8,12.4-4.4,17.2,0.4l29.2,30C149.2,216,148.8,223.6,144,228z"/>
</g>
<path style="fill:#FFFFFF;" d="M249.6,240.8l7.2-6.8c5.2-4.8,13.6-4,20,1.6L402,353.2c6.8,6.4,7.6,16,2.4,21.2l-19.6,18.8
c-5.6,5.2-15.2,4-21.2-3.2L250.4,260.8C244.8,254.4,244.4,245.6,249.6,240.8z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+81
View File
@@ -0,0 +1,81 @@
---
layout: home
title: Documentation
nav_order: 0
---
# Documentation
[`cmkr`](https://github.com/build-cpp/cmkr), pronounced "cmaker", is a modern build system based on [CMake](https://cmake.org/) and [TOML](https://toml.io).
`cmkr` parses `cmake.toml` files and generates a modern, idiomatic `CMakeLists.txt` for you. A minimal example:
```toml
[project]
name = "cmkr_for_beginners"
[target.hello_world]
type = "executable"
sources = ["src/main.cpp"]
```
`cmkr` can bootstrap itself, and you only need CMake and a C++ compiler to use it.
## Getting started
To get started, run the following commands from your project directory:
```sh
curl https://raw.githubusercontent.com/build-cpp/cmkr/main/cmake/cmkr.cmake -o cmkr.cmake
cmake -P cmkr.cmake
```
After the bootstrapping process finishes, customize [`cmake.toml`](./cmake-toml) for your project and run CMake:
```sh
cmake -B build
cmake --build build
```
Once bootstrapped, `cmkr` does not introduce extra steps to your workflow. After modifying `cmake.toml` you simply build/configure your CMake project and `cmkr` will automatically regenerate `CMakeLists.txt` when necessary.
<sub>**Note**: The `cmake.toml` project file, generated `CMakeLists.txt` and `cmkr.cmake` bootstrapping script are all intended to be added to source control.</sub>
In CI environments the `cmkr` bootstrapping process is skipped, so there is no additional overhead in your pipelines.
## Template repositories
Another way to get started is to use the [cmkr_for_beginners](https://github.com/build-cpp/cmkr_for_beginners) template repository. Either open it in [Gitpod](https://gitpod.io/#https://github.com/build-cpp/cmkr_for_beginners), or clone the repository and run:
```sh
cmake -B build
cmake --build build
```
Check out the [cmkr topic](https://github.com/topics/cmkr), the [build-cpp organization](https://github.com/build-cpp) or the [tests](https://github.com/build-cpp/cmkr/tree/main/tests) for more examples and templates.
## Command line
Optionally you can put a [`cmkr` release](https://github.com/build-cpp/cmkr/releases) in your `PATH` and use it as a utility from the command line:
```
Usage: cmkr [arguments]
arguments:
init [executable|library|shared|static|interface] Create a project.
gen Generates CMakeLists.txt file.
build <extra cmake args> Run cmake and build.
install Run cmake --install.
clean Clean the build directory.
help Show help.
version Current cmkr version.
```
## Credits
- [gulrak/filesystem](https://github.com/gulrak/filesystem)
- [Tessil/ordered-map](https://github.com/Tessil/ordered-map)
- [ToruNiina/toml11](https://github.com/ToruNiina/toml11)
- [mpark/variant](https://github.com/mpark/variant)
- [SVG Repo Hammer](https://www.svgrepo.com/svg/192268/hammer)
- [can1357](https://github.com/can1357) for buying `cmkr.build` ❤️
- [JustasMasiulis](https://github.com/JustasMasiulis) for fixing the dark theme ❤️
+83
View File
@@ -0,0 +1,83 @@
---
layout: page
title: Philosophy
nav_order: 2
published: false
---
# Philosophy
## Problem statement
Similar to writing good C++, writing good CMake is difficult. The main difference is that nobody actually wants to learn CMake. The build system is something that should "just work".
There have been many attempts at creating new build systems (with varying levels of success). Naturally this causes [competing standards](https://xkcd.com/927/), which is undesirable. CMake is pretty much the de facto standard, and it has seen extensive use in complex software projects.
One of the main issues of CMake is the turing-complete scripting language you use to describe your projects. As your project gets more complex this can be very helpful, but it also unnecessarily complicates simple projects. There have been discussions about a declarative language on the [CMake issue tracker](https://gitlab.kitware.com/cmake/cmake/-/issues/19891) to solve this problem, but it looks like a "LISP-like" language is seriously being considered...
## The solution
The way cmkr (pronounced "cmaker") solves this problem is by using [TOML](https://toml.io/). Below is a minimal `cmake.toml` project:
```toml
[project]
name = "cmkr_for_beginners"
[target.hello_world]
type = "executable"
sources = ["src/main.cpp"]
```
The key difference between `cmkr` and other build systems is that it _generates_ CMake. This means that your projects are fully compatible with the CMake ecosystem, and you can try it out without having to rewrite your whole build system.
TODO: link/include more examples? Talk about conditions, packaging (missing)
### Another layer?!
A common issue people have with cmkr is that it introduces an additional layer of indirection to your build system. CMake is already a meta-buildsystem, which means you could call cmkr a "meta-meta-buildsystem".
Presumably the reason for this friction is that additional layers of abstraction introduce additional complexity. Because of this cmkr has been designed to be completely seamless:
- The user doesn't have to install any additional software to use cmkr. All you need is a semi-recent version of CMake and a C++ compiler.
- Modifying `cmake.toml` automatically triggers a regeneration of `CMakeLists.txt`. There is no change to your build process.
- The `CMakeLists.txt` is generated to be human-readable. This means you can easily "eject" from cmkr and go back to CMake.
An additional argument for cmkr is that anecdotally people say it "just works". Because of its simplicity it's also easy to teach, even to people without programming experience.
There is also precedent in the JavaScript community. Bundlers and translators are the norm there and their developer experience is miles ahead of C++.
<sub>Not to say the JavaScript ecosystem is without its flaws, but generators does not appear to be one of them</sub>
### Unsupported features
Because cmkr is still in early in development there are many missing/unfinished features. It was decided that users can bridge the gap by including CMake at arbitrary locations.
This has the advantage that it forces complexity in the build system to be self-contained and modular, a problem all too common in projects as they age.
## Enterprise
Words like "bootstrapping" and "generating code" might worry engineers working in an enterprise environment, and rightly so. From the beginning it has been a priority to make cmkr suitable for use in big corporations with strict protocols for security and reproducibility.
### No additional dependencies
As mentioned above, the only thing you need is a working C++ compiler and a semi-recent version of CMake. It is assumed that you are already building (and executing) C++ projects on your servers, so cmkr does not introduce additional requirements.
All the logic for downloading and compiling the `cmkr` executable is self-contained in a ~250 line `cmkr.cmake` script. You can easily audit it and see if it's up to your standards.
### Reproducibility
Per default the `cmkr.cmake` bootstrapping script contains the exact version of cmkr used to generate your project. As long as the cmkr repository is available you will build the exact same version of cmkr, which will generate the exact same `CMakeLists.txt` file.
This also means that cmkr can decide to break backwards compatibility without affecting legacy projects. An effort will always be made to maintain backwards compatibility though.
### Integrity
As an additional safeguard you can modify `cmkr.cmake` to pin the version tag to a commit hash. This hash is checked to ensure the integrity of the upstream repository.
### Availability
You can easily point `cmkr.cmake` to a mirror of the cmkr repository to ensure availability should something catastrophic happen.
### Not executed in CI
The final (and key) feature is that the bootstrapping process is never executed in CI environments. This means `cmkr` is only ever executed on your developer's machines and not on your infrastructure.
Executable
+2
View File
@@ -0,0 +1,2 @@
bundle install
bundle exec jekyll serve --force_polling --livereload --incremental
-10
View File
@@ -1,6 +1,5 @@
#pragma once
#ifdef __cplusplus
namespace cmkr {
namespace args {
@@ -8,12 +7,3 @@ const char *handle_args(int argc, char **argv);
} // namespace args
} // namespace cmkr
extern "C" {
#endif
const char *cmkr_args_handle_args(int, char **);
#ifdef __cplusplus
}
#endif
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#ifdef __cplusplus
namespace cmkr {
namespace build {
int run(int argc, char **argv);
int clean();
int install();
} // namespace build
} // namespace cmkr
extern "C" {
#endif
int cmkr_build_run(int argc, char **argv);
int cmkr_build_clean(void);
int cmkr_build_install(void);
#ifdef __cplusplus
}
#endif
+13
View File
@@ -0,0 +1,13 @@
#pragma once
namespace cmkr {
namespace build {
int run(int argc, char **argv);
int clean();
int install();
} // namespace build
} // namespace cmkr
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "project_parser.hpp"
namespace cmkr {
namespace gen {
void generate_project(const std::string &type);
void generate_cmake(const char *path, const parser::Project *parent_project = nullptr);
} // namespace gen
} // namespace cmkr
-35
View File
@@ -1,35 +0,0 @@
#pragma once
#ifdef __cplusplus
namespace cmkr {
namespace error {
struct Status {
enum class Code {
Success = 0,
RuntimeError,
InitError,
GenerationError,
BuildError,
CleanError,
InstallError,
};
Status(Code ec) noexcept;
operator int() const noexcept;
Code code() const noexcept;
private:
Code ec_ = Code::Success;
};
} // namespace error
} // namespace cmkr
extern "C" {
#endif
const char *cmkr_error_status_string(int);
#ifdef __cplusplus
}
#endif
+2 -4
View File
@@ -1,8 +1,6 @@
#pragma once
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || \
(defined(__cplusplus) && __cplusplus >= 201703L)) && \
defined(__has_include)
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
@@ -12,4 +10,4 @@ namespace fs = std::filesystem;
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
#endif
-23
View File
@@ -1,23 +0,0 @@
#pragma once
#ifdef __cplusplus
namespace cmkr {
namespace gen {
int generate_project(const char *typ);
int generate_cmake(const char *path, bool root = true);
} // namespace gen
} // namespace cmkr
extern "C" {
#endif
int cmkr_gen_generate_project(const char *typ);
int cmkr_gen_generate_cmake(const char *path);
#ifdef __cplusplus
}
#endif
-12
View File
@@ -1,6 +1,5 @@
#pragma once
#ifdef __cplusplus
namespace cmkr {
namespace help {
@@ -10,14 +9,3 @@ const char *message() noexcept;
} // namespace help
} // namespace cmkr
extern "C" {
#endif
const char *cmkr_help_version(void);
const char *cmkr_help_message(void);
#ifdef __cplusplus
}
#endif
-46
View File
@@ -1,46 +0,0 @@
#pragma once
static const char *hello_world = &R"lit(
#include <iostream>
int %s() {
std::cout << "Hello World!\n";
return 0;
}
)lit"[1]; // skip initial newline
static const char *cmake_toml = &R"lit(
[cmake]
version = "3.15"
# subdirs = []
# build-dir = ""
# cpp-flags = []
# c-flags = []
# link-flags = []
# generator = ""
# arguments = []
[project]
name = "%s"
version = "0.1.0"
# [find-package]
# [fetch-content]
# [options]
[[target]]
name = "%s"
type = "%s"
sources = ["src/*.cpp"]
include-directories = ["include"]
# alias = ""
# compile-features = []
# compile-definitions = []
# link-libraries = []
[[install]]
%s = ["%s"]
destination = "${CMAKE_INSTALL_PREFIX}/%s"
)lit"[1]; // skip initial newline
+100
View File
@@ -0,0 +1,100 @@
#pragma once
static const char *cpp_executable = &R"lit(
#include <iostream>
#include <cstdlib>
int main() {
std::cout << "Hello from cmkr!\n";
return EXIT_SUCCESS;
}
)lit"[1]; // skip initial newline
static const char *cpp_library = &R"lit(
#include <@name/@name.hpp>
#include <iostream>
namespace @name {
void hello() {
std::cout << "Hello from cmkr!\n";
}
} // namespace @name
)lit"[1]; // skip initial newline
static const char *hpp_library = &R"lit(
#pragma once
namespace @name {
void hello();
} // namespace @name
)lit"[1]; // skip initial newline
static const char *hpp_interface = &R"lit(
#pragma once
#include <iostream>
namespace @name {
inline void hello() {
std::cout << "Hello from cmkr!\n";
}
} // namespace @name
)lit"[1]; // skip initial newline
static const char *toml_executable = &R"lit(
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
[project]
name = "@name"
[target.@name]
type = "executable"
sources = ["src/@name/main.cpp"]
compile-features = ["cxx_std_11"]
)lit"[1]; // skip initial newline
static const char *toml_library = &R"lit(
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
[project]
name = "@name"
[target.@name]
type = "@type"
sources = [
"src/@name/@name.cpp",
"include/@name/@name.hpp"
]
include-directories = ["include"]
compile-features = ["cxx_std_11"]
)lit"[1]; // skip initial newline
static const char *toml_interface = &R"lit(
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
[project]
name = "@name"
[target.@name]
type = "interface"
include-directories = ["include"]
compile-features = ["cxx_std_11"]
)lit"[1]; // skip initial newline
static const char *toml_migration = &R"lit(
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
[project]
name = "@name"
# TODO: define a target for each of your executables/libraries like this:
#[target.myexecutable]
#type = "executable" # static, shared
#sources = ["src/@name/*.cpp", "include/@name/*.hpp"]
#include-directories = ["include"]
#compile-features = ["cxx_std_11"]
#link-libraries = ["target-or-library"]
)lit"[1]; // skip initial newline
+225
View File
@@ -0,0 +1,225 @@
#pragma once
#include <vector>
#include <string>
#include <mpark/variant.hpp>
#include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>
namespace cmkr {
namespace parser {
template <typename T>
using Condition = tsl::ordered_map<std::string, T>;
using ConditionVector = Condition<std::vector<std::string>>;
struct Variable {
std::string name;
std::string help;
mpark::variant<bool, std::string> value;
bool cache = false;
bool force = false;
};
struct Option {
std::string name;
std::string help;
mpark::variant<bool, std::string> value;
};
struct Package {
std::string name;
std::string condition;
std::string version;
bool required = true;
bool config = false;
std::vector<std::string> components;
};
struct Vcpkg {
std::string version;
std::string url;
struct Package {
std::string name;
std::vector<std::string> features;
bool default_features = true;
};
std::vector<Package> packages;
// https://github.com/Microsoft/vcpkg-docs/blob/main/vcpkg/users/buildsystems/cmake-integration.md
std::vector<std::string> overlay_ports;
std::vector<std::string> overlay_triplets;
bool enabled() const {
return !packages.empty();
}
};
enum TargetType {
target_executable,
target_library,
target_shared,
target_static,
target_interface,
target_custom,
target_object,
target_template,
target_last,
};
extern const char *targetTypeNames[target_last];
struct Target {
std::string name;
TargetType type = target_last;
std::string type_name;
ConditionVector sources;
// https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#project-commands
ConditionVector compile_definitions;
ConditionVector private_compile_definitions;
ConditionVector compile_features;
ConditionVector private_compile_features;
ConditionVector compile_options;
ConditionVector private_compile_options;
ConditionVector include_directories;
ConditionVector private_include_directories;
ConditionVector link_directories;
ConditionVector private_link_directories;
ConditionVector link_libraries;
ConditionVector private_link_libraries;
ConditionVector link_options;
ConditionVector private_link_options;
ConditionVector precompile_headers;
ConditionVector private_precompile_headers;
ConditionVector dependencies;
std::string condition;
std::string alias;
Condition<tsl::ordered_map<std::string, std::string>> properties;
Condition<std::string> cmake_before;
Condition<std::string> cmake_after;
ConditionVector include_before;
ConditionVector include_after;
};
struct Template {
Target outline;
std::string add_function;
std::vector<std::string> add_arguments;
bool pass_sources_to_add_function = false;
};
struct Test {
std::string name;
std::string condition;
std::vector<std::string> configurations;
std::string working_directory;
std::string command;
std::vector<std::string> arguments;
};
struct Install {
std::string condition;
std::vector<std::string> targets;
std::vector<std::string> files;
std::vector<std::string> dirs;
std::vector<std::string> configs;
std::string destination;
std::string component;
bool optional = false;
};
struct Subdir {
std::string name;
std::string condition;
Condition<std::string> cmake_before;
Condition<std::string> cmake_after;
ConditionVector include_before;
ConditionVector include_after;
};
struct Content {
std::string name;
std::string condition;
tsl::ordered_map<std::string, std::string> arguments;
Condition<std::string> cmake_before;
Condition<std::string> cmake_after;
ConditionVector include_before;
ConditionVector include_after;
bool system = false;
std::string subdir;
};
enum MsvcRuntimeType {
msvc_dynamic,
msvc_static,
msvc_last,
};
extern const char *msvcRuntimeTypeNames[msvc_last];
struct Project {
const Project *parent;
// This is the CMake version required to use all cmkr versions.
std::string cmake_version = "3.15";
std::string cmkr_include = "cmkr.cmake";
std::string build_dir = "build";
std::string generator;
std::string config;
bool allow_in_tree = false;
Condition<std::vector<std::string>> project_subdirs;
std::vector<std::string> cppflags;
std::vector<std::string> cflags;
std::vector<std::string> linkflags;
std::vector<std::string> gen_args;
std::vector<std::string> build_args;
std::string project_name;
std::string project_version;
std::string project_description;
ConditionVector project_languages;
bool project_allow_unknown_languages = false;
MsvcRuntimeType project_msvc_runtime = msvc_last;
Condition<std::string> cmake_before;
Condition<std::string> cmake_after;
ConditionVector include_before;
ConditionVector include_after;
std::vector<Variable> variables;
std::vector<Option> options;
std::vector<Package> packages;
Vcpkg vcpkg;
std::vector<Content> contents;
std::vector<Template> templates;
std::vector<Target> targets;
std::vector<Test> tests;
std::vector<Install> installs;
tsl::ordered_map<std::string, std::string> conditions;
std::vector<Subdir> subdirs;
Project(const Project *parent, const std::string &path, bool build);
const Project *root() const;
bool cmake_minimum_version(int major, int minor) const;
static bool is_condition_name(const std::string &name);
};
bool is_root_path(const std::string &path);
} // namespace parser
} // namespace cmkr
+12 -27
View File
@@ -1,11 +1,9 @@
#include "args.h"
#include "build.h"
#include "gen.h"
#include "help.h"
#include "arguments.hpp"
#include "build.hpp"
#include "cmake_generator.hpp"
#include "help.hpp"
#include "fs.hpp"
#include <exception>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
@@ -21,9 +19,7 @@ const char *handle_args(int argc, char **argv) {
throw std::runtime_error(cmkr::help::message());
std::string main_arg = args[1];
if (main_arg == "gen") {
auto ret = cmkr::gen::generate_cmake(fs::current_path().string().c_str());
if (ret)
return "CMake generation error!";
cmkr::gen::generate_cmake(fs::current_path().string().c_str());
return "CMake generation successful!";
} else if (main_arg == "help") {
return cmkr::help::message();
@@ -33,24 +29,23 @@ const char *handle_args(int argc, char **argv) {
std::string type = "executable";
if (args.size() > 2)
type = args[2];
auto ret = cmkr::gen::generate_project(type.c_str());
if (ret)
return "Initialization failure!";
cmkr::gen::generate_project(type.c_str());
cmkr::gen::generate_cmake(fs::current_path().string().c_str());
return "Directory initialized!";
} else if (main_arg == "build") {
auto ret = build::run(argc, argv);
if (ret)
return "CMake build error!";
return "CMake run completed!";
throw std::runtime_error("CMake build failed!");
return "CMake build completed!";
} else if (main_arg == "install") {
auto ret = build::install();
if (ret)
return "CMake install error!";
throw std::runtime_error("CMake install failed!");
return "CMake install completed!";
} else if (main_arg == "clean") {
auto ret = build::clean();
if (ret)
return "CMake clean error!";
throw std::runtime_error("CMake clean failed!");
return "Cleaned build directory!";
} else {
throw std::runtime_error(cmkr::help::message());
@@ -58,13 +53,3 @@ const char *handle_args(int argc, char **argv) {
}
} // namespace args
} // namespace cmkr
const char *cmkr_args_handle_args(int argc, char **argv) {
try {
return cmkr::args::handle_args(argc, argv);
} catch (const std::exception &e) {
return e.what();
} catch (...) {
return "Unknown error!";
}
}
+62
View File
@@ -0,0 +1,62 @@
#include "build.hpp"
#include "cmake_generator.hpp"
#include "project_parser.hpp"
#include "fs.hpp"
#include <cstdlib>
#include <sstream>
namespace cmkr {
namespace build {
int run(int argc, char **argv) {
parser::Project project(nullptr, ".", true);
if (argc > 2) {
for (int i = 2; i < argc; ++i) {
project.build_args.emplace_back(argv[i]);
}
}
std::stringstream ss;
gen::generate_cmake(fs::current_path().string().c_str());
ss << "cmake -DCMKR_BUILD_SKIP_GENERATION=ON -B" << project.build_dir << " ";
if (!project.generator.empty()) {
ss << "-G \"" << project.generator << "\" ";
}
if (!project.config.empty()) {
ss << "-DCMAKE_BUILD_TYPE=" << project.config << " ";
}
if (!project.gen_args.empty()) {
for (const auto &arg : project.gen_args) {
ss << "-D" << arg << " ";
}
}
ss << "&& cmake --build " << project.build_dir << " --parallel";
if (argc > 2) {
for (const auto &arg : project.build_args) {
ss << " " << arg;
}
}
return ::system(ss.str().c_str());
}
int clean() {
bool success = false;
parser::Project project(nullptr, ".", true);
if (fs::exists(project.build_dir)) {
success = fs::remove_all(project.build_dir);
fs::create_directory(project.build_dir);
}
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
int install() {
parser::Project project(nullptr, ".", false);
auto cmd = "cmake --install " + project.build_dir;
return ::system(cmd.c_str());
}
} // namespace build
} // namespace cmkr
File diff suppressed because it is too large Load Diff
-97
View File
@@ -1,97 +0,0 @@
#include "build.h"
#include "cmake.hpp"
#include "error.h"
#include "gen.h"
#include "fs.hpp"
#include <sstream>
#include <stddef.h>
#include <stdexcept>
#include <stdlib.h>
#include <system_error>
namespace cmkr {
namespace build {
int run(int argc, char **argv) {
cmake::CMake cmake(".", true);
if (argc > 2) {
for (size_t i = 2; i < argc; ++i) {
cmake.build_args.push_back(argv[i]);
}
}
std::stringstream ss;
if (gen::generate_cmake(fs::current_path().string().c_str()))
throw std::runtime_error("CMake generation failure!");
ss << "cmake -S. -B" << cmake.build_dir << " ";
if (!cmake.generator.empty()) {
ss << "-G \"" << cmake.generator << "\" ";
}
if (!cmake.config.empty()) {
ss << "-DCMAKE_BUILD_TYPE=" << cmake.config << " ";
}
if (!cmake.gen_args.empty()) {
for (const auto &arg : cmake.gen_args) {
ss << "-D" << arg << " ";
}
}
ss << "&& cmake --build " << cmake.build_dir << " --parallel";
if (argc > 2) {
for (const auto &arg : cmake.build_args) {
ss << " " << arg;
}
}
return ::system(ss.str().c_str());
}
int clean() {
bool ret = false;
cmake::CMake cmake(".", true);
if (fs::exists(cmake.build_dir)) {
ret = fs::remove_all(cmake.build_dir);
fs::create_directory(cmake.build_dir);
}
return !ret;
}
int install() {
cmake::CMake cmake(".", false);
auto cmd = "cmake --install " + cmake.build_dir;
return ::system(cmd.c_str());
}
} // namespace build
} // namespace cmkr
int cmkr_build_run(int argc, char **argv) {
try {
return cmkr::build::run(argc, argv);
} catch (const std::system_error &e) {
return e.code().value();
} catch (...) {
return cmkr::error::Status(cmkr::error::Status::Code::BuildError);
}
}
int cmkr_build_clean(void) {
try {
return cmkr::build::clean();
} catch (const std::system_error &e) {
return e.code().value();
} catch (...) {
return cmkr::error::Status(cmkr::error::Status::Code::CleanError);
}
}
int cmkr_build_install(void) {
try {
return cmkr::build::install();
} catch (const std::system_error &e) {
return e.code().value();
} catch (...) {
return cmkr::error::Status(cmkr::error::Status::Code::InstallError);
}
}
-256
View File
@@ -1,256 +0,0 @@
#include "cmake.hpp"
#include "enum_helper.hpp"
#include "fs.hpp"
#include <stdexcept>
#include <toml.hpp>
#include <tsl/ordered_map.h>
template <>
const char *enumStrings<cmkr::cmake::TargetType>::data[] = {"executable", "library", "shared", "static", "interface", "custom"};
namespace cmkr {
namespace cmake {
using TomlBasicValue = toml::basic_value<toml::preserve_comments, tsl::ordered_map, std::vector>;
template <typename EnumType>
static EnumType to_enum(const std::string &str, const std::string &help_name) {
EnumType value;
try {
std::stringstream ss(str);
ss >> enumFromString(value);
} catch (std::invalid_argument &) {
std::string supported;
for (const auto &s : enumStrings<EnumType>::data) {
if (!supported.empty()) {
supported += ", ";
}
supported += s;
}
throw std::runtime_error("Unknown " + help_name + "'" + str + "'! Supported types are: " + supported);
}
return value;
}
template <typename T>
static void get_optional(const TomlBasicValue &v, const toml::key &ky, T &destination) {
if (v.contains(ky)) {
destination = toml::find<T>(v, ky);
}
}
CMake::CMake(const std::string &path, bool build) {
if (!fs::exists(fs::path(path) / "cmake.toml")) {
throw std::runtime_error("No cmake.toml was found!");
}
const auto toml = toml::parse<toml::preserve_comments, tsl::ordered_map, std::vector>((fs::path(path) / "cmake.toml").string());
if (build) {
if (toml.contains("cmake")) {
const auto &cmake = toml::find(toml, "cmake");
if (cmake.contains("bin-dir")) {
throw std::runtime_error("bin-dir has been renamed to build-dir");
}
get_optional(cmake, "build-dir", build_dir);
get_optional(cmake, "generator", generator);
get_optional(cmake, "config", config);
get_optional(cmake, "arguments", gen_args);
}
} else {
if (toml.contains("cmake")) {
const auto &cmake = toml::find(toml, "cmake");
cmake_version = toml::find(cmake, "version").as_string();
get_optional(cmake, "cmkr-include", cmkr_include);
get_optional(cmake, "cpp-flags", cppflags);
get_optional(cmake, "c-flags", cflags);
get_optional(cmake, "link-flags", linkflags);
}
if (toml.contains("project")) {
const auto &project = toml::find(toml, "project");
project_name = toml::find(project, "name").as_string();
get_optional(project, "version", project_version);
get_optional(project, "description", project_description);
get_optional(project, "languages", project_languages);
get_optional(project, "cmake-before", cmake_before);
get_optional(project, "cmake-after", cmake_after);
get_optional(project, "include-before", include_before);
get_optional(project, "include-after", include_after);
get_optional(project, "subdirs", subdirs);
}
if (toml.contains("settings")) {
using set_map = std::map<std::string, TomlBasicValue>;
const auto &sets = toml::find<set_map>(toml, "settings");
for (const auto &set : sets) {
Setting s;
s.name = set.first;
if (set.second.is_boolean()) {
s.val = set.second.as_boolean();
} else if (set.second.is_string()) {
s.val = set.second.as_string();
} else {
get_optional(set.second, "comment", s.comment);
if (set.second.contains("value")) {
auto v = toml::find(set.second, "value");
if (v.is_boolean()) {
s.val = v.as_boolean();
} else {
s.val = v.as_string();
}
}
get_optional(set.second, "cache", s.cache);
get_optional(set.second, "force", s.force);
}
settings.push_back(s);
}
}
if (toml.contains("options")) {
using opts_map = tsl::ordered_map<std::string, TomlBasicValue>;
const auto &opts = toml::find<opts_map>(toml, "options");
for (const auto &opt : opts) {
Option o;
o.name = opt.first;
if (opt.second.is_boolean()) {
o.val = opt.second.as_boolean();
} else {
get_optional(opt.second, "comment", o.comment);
get_optional(opt.second, "value", o.val);
}
options.push_back(o);
}
}
if (toml.contains("find-package")) {
using pkg_map = tsl::ordered_map<std::string, TomlBasicValue>;
const auto &pkgs = toml::find<pkg_map>(toml, "find-package");
for (const auto &pkg : pkgs) {
Package p;
p.name = pkg.first;
if (pkg.second.is_string()) {
p.version = pkg.second.as_string();
} else {
get_optional(pkg.second, "version", p.version);
get_optional(pkg.second, "required", p.required);
get_optional(pkg.second, "config", p.config);
get_optional(pkg.second, "components", p.components);
}
packages.push_back(p);
}
}
// TODO: refactor to std::vector<Content> instead of this hacky thing?
get_optional(toml, "fetch-content", contents);
if (toml.contains("bin")) {
throw std::runtime_error("[[bin]] has been renamed to [[target]]");
}
if (toml.contains("target")) {
const auto &ts = toml::find(toml, "target").as_table();
for (const auto &itr : ts) {
const auto &t = itr.second;
Target target;
target.name = itr.first;
target.type = to_enum<TargetType>(toml::find(t, "type").as_string(), "target type");
get_optional(t, "sources", target.sources);
#define renamed(from, to) \
if (t.contains(from)) { \
throw std::runtime_error(from "has been renamed to " to); \
}
renamed("include-dirs", "include-directories");
renamed("link-libs", "link-libraries");
renamed("defines", "compile-definitions");
renamed("features", "compile-features");
#undef renamed
get_optional(t, "compile-definitions", target.compile_definitions);
get_optional(t, "compile-features", target.compile_features);
get_optional(t, "compile-options", target.compile_options);
get_optional(t, "include-directories", target.include_directories);
get_optional(t, "link-directories", target.link_directories);
get_optional(t, "link-libraries", target.link_libraries);
get_optional(t, "link-options", target.link_options);
get_optional(t, "precompile-headers", target.precompile_headers);
if (t.contains("alias")) {
target.alias = toml::find(t, "alias").as_string();
}
if (t.contains("properties")) {
const auto &props = toml::find(t, "properties").as_table();
for (const auto &propKv : props) {
if (propKv.second.is_array()) {
std::string property_list;
for (const auto &list_val : propKv.second.as_array()) {
if (!property_list.empty()) {
property_list += ';';
}
property_list += list_val.as_string();
}
target.properties[propKv.first] = property_list;
} else {
target.properties[propKv.first] = propKv.second.as_string();
}
}
}
get_optional(t, "cmake-before", target.cmake_before);
get_optional(t, "cmake-after", target.cmake_after);
get_optional(t, "include-before", target.include_before);
get_optional(t, "include-after", target.include_after);
targets.push_back(target);
}
}
if (toml.contains("test")) {
const auto &ts = toml::find(toml, "test").as_array();
for (const auto &t : ts) {
Test test;
test.name = toml::find(t, "name").as_string();
get_optional(t, "configurations", test.configurations);
get_optional(t, "working-directory", test.working_directory);
test.command = toml::find(t, "command").as_string();
get_optional(t, "arguments", test.arguments);
tests.push_back(test);
}
}
if (toml.contains("install")) {
const auto &ts = toml::find(toml, "install").as_array();
for (const auto &t : ts) {
Install inst;
get_optional(t, "targets", inst.targets);
get_optional(t, "files", inst.files);
get_optional(t, "dirs", inst.dirs);
get_optional(t, "configs", inst.configs);
inst.destination = toml::find(t, "destination").as_string();
installs.push_back(inst);
}
}
if (toml.contains("vcpkg")) {
const auto &v = toml::find(toml, "vcpkg");
vcpkg.version = toml::find(v, "version").as_string();
vcpkg.packages = toml::find<decltype(vcpkg.packages)>(v, "packages");
// This allows the user to use a custom pmm version if desired
if (contents.count("pmm") == 0) {
contents["pmm"]["url"] = "https://github.com/vector-of-bool/pmm/archive/refs/tags/1.5.1.tar.gz";
// Hack to not execute pmm's example CMakeLists.txt
contents["pmm"]["SOURCE_SUBDIR"] = "pmm";
}
}
}
}
} // namespace cmake
} // namespace cmkr
-122
View File
@@ -1,122 +0,0 @@
#pragma once
#include <map>
#include <mpark/variant.hpp>
#include <stdexcept>
#include <string>
#include <tsl/ordered_map.h>
#include <vector>
namespace cmkr {
namespace cmake {
struct Setting {
std::string name;
std::string comment;
mpark::variant<bool, std::string> val;
bool cache = false;
bool force = false;
};
struct Option {
std::string name;
std::string comment;
bool val = false;
};
struct Package {
std::string name;
std::string version;
bool required = true;
bool config = true;
std::vector<std::string> components;
};
struct Vcpkg {
std::string version;
std::vector<std::string> packages;
};
enum TargetType {
target_executable,
target_library,
target_shared,
target_static,
target_interface,
target_custom,
};
struct Target {
std::string name;
TargetType type = {};
// https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#project-commands
std::vector<std::string> compile_definitions;
std::vector<std::string> compile_features;
std::vector<std::string> compile_options;
std::vector<std::string> include_directories;
std::vector<std::string> link_directories;
std::vector<std::string> link_libraries;
std::vector<std::string> link_options;
std::vector<std::string> precompile_headers;
std::vector<std::string> sources;
std::string alias;
tsl::ordered_map<std::string, std::string> properties;
std::string cmake_before;
std::string cmake_after;
std::vector<std::string> include_before;
std::vector<std::string> include_after;
};
struct Test {
std::string name;
std::vector<std::string> configurations;
std::string working_directory;
std::string command;
std::vector<std::string> arguments;
};
struct Install {
std::vector<std::string> targets;
std::vector<std::string> files;
std::vector<std::string> dirs;
std::vector<std::string> configs;
std::string destination;
};
struct CMake {
// This is the CMake version required to use all cmkr versions.
std::string cmake_version = "3.15";
std::string cmkr_include = "cmkr.cmake";
std::string build_dir = "build";
std::string generator;
std::string config;
std::vector<std::string> subdirs;
std::vector<std::string> cppflags;
std::vector<std::string> cflags;
std::vector<std::string> linkflags;
std::vector<std::string> gen_args;
std::vector<std::string> build_args;
std::string project_name;
std::string project_version;
std::string project_description;
std::vector<std::string> project_languages;
std::string cmake_before;
std::string cmake_after;
std::vector<std::string> include_before;
std::vector<std::string> include_after;
std::vector<Setting> settings;
std::vector<Option> options;
std::vector<Package> packages;
Vcpkg vcpkg;
tsl::ordered_map<std::string, std::map<std::string, std::string>> contents;
std::vector<Target> targets;
std::vector<Test> tests;
std::vector<Install> installs;
CMake(const std::string &path, bool build);
};
} // namespace cmake
} // namespace cmkr
-69
View File
@@ -1,69 +0,0 @@
// https://codereview.stackexchange.com/a/14315
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
// This is the type that will hold all the strings.
// Each enumeration type will declare its own specialization.
// Any enum that does not have a specialization will generate a compiler error
// indicating that there is no definition of this variable (as there should be
// be no definition of a generic version).
template <typename T>
struct enumStrings {
static char const *data[];
};
// This is a utility type.
// Created automatically. Should not be used directly.
template <typename T>
struct enumRefHolder {
T &enumVal;
enumRefHolder(T &enumVal) : enumVal(enumVal) {}
};
template <typename T>
struct enumConstRefHolder {
T const &enumVal;
enumConstRefHolder(T const &enumVal) : enumVal(enumVal) {}
};
// The next two functions do the actual work of reading/writing an
// enum as a string.
template <typename T>
std::ostream &operator<<(std::ostream &str, enumConstRefHolder<T> const &data) {
return str << enumStrings<T>::data[data.enumVal];
}
template <typename T>
std::istream &operator>>(std::istream &str, enumRefHolder<T> const &data) {
std::string value;
str >> value;
// These two can be made easier to read in C++11
// using std::begin() and std::end()
//
static auto begin = std::begin(enumStrings<T>::data);
static auto end = std::end(enumStrings<T>::data);
auto find = std::find(begin, end, value);
if (find != end) {
data.enumVal = static_cast<T>(std::distance(begin, find));
} else {
throw std::invalid_argument("");
}
return str;
}
// This is the public interface:
// use the ability of function to deduce their template type without
// being explicitly told to create the correct type of enumRefHolder<T>
template <typename T>
enumConstRefHolder<T> enumToString(T const &e) {
return enumConstRefHolder<T>(e);
}
template <typename T>
enumRefHolder<T> enumFromString(T &e) {
return enumRefHolder<T>(e);
}
-24
View File
@@ -1,24 +0,0 @@
#include "error.h"
#include <assert.h>
namespace cmkr {
namespace error {
Status::Status(Code ec) noexcept : ec_(ec) {}
Status::operator int() const noexcept { return static_cast<int>(ec_); }
Status::Code Status::code() const noexcept { return ec_; }
} // namespace error
} // namespace cmkr
const char *err_string[] = {
"Success", "Runtime error", "Initialization error", "CMake generation error", "Build error",
};
const char *cmkr_error_status(int i) {
assert(i >= 0 && i < 5);
return err_string[i];
}
-699
View File
@@ -1,699 +0,0 @@
#include "gen.h"
#include "cmake.hpp"
#include "error.h"
#include "literals.h"
#include "fs.hpp"
#include <cassert>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <new>
#include <sstream>
#include <stdexcept>
#include <string>
namespace cmkr {
namespace gen {
inline std::string to_upper(const std::string &str) {
std::string temp;
temp.reserve(str.size());
for (auto c : str) {
temp.push_back(::toupper(c));
}
return temp;
}
template <typename... Args>
std::string format(const char *fmt, Args... args) {
auto sz = snprintf(nullptr, 0, fmt, args...) + 1;
char *buf = new char[sz];
int ret = snprintf(buf, sz, fmt, args...);
if (ret != sz - 1)
throw std::runtime_error("Error formatting string!");
std::string temp(buf, buf + sz - 1);
delete[] buf;
return temp;
}
static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs::path &toml_dir) {
std::vector<std::string> temp;
auto extract_suffix = [](const fs::path &base, const fs::path &full) {
// TODO: delet this
auto fullpath = full.string();
auto base_len = base.string().length();
auto delet = fullpath.substr(base_len + 1, fullpath.length() - base_len);
return delet;
};
auto stem = name.filename().stem().string();
auto ext = name.extension();
if (stem == "*") {
for (const auto &f : fs::directory_iterator(toml_dir / name.parent_path(), fs::directory_options::follow_directory_symlink)) {
if (!f.is_directory() && f.path().extension() == ext) {
temp.push_back(extract_suffix(toml_dir, f));
}
}
} else if (stem == "**") {
for (const auto &f : fs::recursive_directory_iterator(toml_dir / name.parent_path(), fs::directory_options::follow_directory_symlink)) {
if (!f.is_directory() && f.path().extension() == ext) {
temp.push_back(extract_suffix(toml_dir, f.path()));
}
}
} else {
temp.push_back(name.string());
}
// Normalize all paths to work with CMake (it needs a / on Windows as well)
for (auto &path : temp) {
std::replace(path.begin(), path.end(), '\\', '/');
}
// Sort paths alphabetically for consistent cross-OS generation
std::sort(temp.begin(), temp.end());
return temp;
}
static std::vector<std::string> expand_cmake_paths(const std::vector<std::string> &sources, const fs::path &toml_dir) {
// TODO: add duplicate checking
std::vector<std::string> result;
for (const auto &src : sources) {
auto expanded = expand_cmake_path(src, toml_dir);
for (const auto &f : expanded) {
result.push_back(f);
}
}
return result;
}
int generate_project(const char *str) {
fs::create_directory("src");
fs::create_directory("include");
const auto dir_name = fs::current_path().stem().string();
std::string mainbuf;
std::string installed;
std::string target;
std::string dest;
if (!strcmp(str, "executable")) {
mainbuf = format(hello_world, "main");
installed = "targets";
target = dir_name;
dest = "bin";
} else if (!strcmp(str, "static") || !strcmp(str, "shared") || !strcmp(str, "library")) {
mainbuf = format(hello_world, "test");
installed = "targets";
target = dir_name;
dest = "lib";
} else if (!strcmp(str, "interface")) {
installed = "files";
target = "include/*.h";
dest = "include/" + dir_name;
} else {
throw std::runtime_error("Unknown project type " + std::string(str) +
"! Supported types are: executable, library, shared, static, interface");
}
const auto tomlbuf = format(cmake_toml, dir_name.c_str(), dir_name.c_str(), str, installed.c_str(), target.c_str(), dest.c_str());
if (strcmp(str, "interface")) {
std::ofstream ofs("src/main.cpp");
if (ofs.is_open()) {
ofs << mainbuf;
}
ofs.flush();
ofs.close();
}
std::ofstream ofs2("cmake.toml");
if (ofs2.is_open()) {
ofs2 << tomlbuf;
}
ofs2.flush();
ofs2.close();
return 0;
}
struct CommandEndl {
std::stringstream &ss;
CommandEndl(std::stringstream &ss) : ss(ss) {}
void endl() { ss << '\n'; }
};
// Credit: JustMagic
struct Command {
std::stringstream &ss;
int depth = 0;
std::string command;
bool first_arg = true;
bool had_newline = false;
bool generated = false;
Command(std::stringstream &ss, int depth, const std::string &command) : ss(ss), depth(depth), command(command) {}
~Command() {
if (!generated) {
assert(false && "Incorrect usage of cmd()");
}
}
std::string quote(const std::string &str) {
// Don't quote arguments that don't need quoting
if (str.find(' ') == std::string::npos && str.find('\"') == std::string::npos && str.find('/') == std::string::npos &&
str.find(';') == std::string::npos) {
return str;
}
std::string result;
result += "\"";
for (char ch : str) {
switch (ch) {
case '\\':
case '\"':
result += '\\';
default:
result += ch;
break;
}
}
result += "\"";
return result;
}
static std::string indent(int n) {
std::string result;
for (int i = 0; i < n; i++) {
result += '\t';
}
return result;
}
template <class T>
bool print_arg(const std::vector<T> &vec) {
if (vec.empty()) {
return true;
}
had_newline = true;
for (const auto &value : vec) {
print_arg(value);
}
return true;
}
template <class Key, class Value>
bool print_arg(const tsl::ordered_map<Key, Value> &map) {
if (map.empty()) {
return true;
}
for (const auto &itr : map) {
print_arg(itr);
}
return true;
}
template <class K>
bool print_arg(const std::pair<K, std::vector<std::string>> &kv) {
if (kv.second.empty()) {
return true;
}
had_newline = true;
print_arg(kv.first);
depth++;
for (const auto &s : kv.second) {
print_arg(s);
}
depth--;
return true;
}
template <class K, class V>
bool print_arg(const std::pair<K, V> &kv) {
if (kv.second.empty()) {
return true;
}
had_newline = true;
print_arg(kv.first);
depth++;
print_arg(kv.second);
depth--;
return true;
}
template <class T>
bool print_arg(const T &value, bool indentation = true) {
std::stringstream tmp;
tmp << value;
auto str = tmp.str();
if (str.empty()) {
return true;
}
if (indentation) {
if (had_newline) {
first_arg = false;
ss << '\n' << indent(depth + 1);
} else if (first_arg) {
first_arg = false;
} else {
ss << ' ';
}
}
ss << quote(str);
return true;
}
template <class... Ts>
CommandEndl operator()(Ts &&...values) {
generated = true;
ss << indent(depth) << command << '(';
(void)std::initializer_list<bool>{print_arg(values)...};
if (had_newline)
ss << '\n';
ss << ")\n";
return CommandEndl(ss);
}
};
int generate_cmake(const char *path, bool root) {
if (!fs::exists(fs::path(path) / "cmake.toml")) {
throw std::runtime_error("No cmake.toml found!");
}
// Helper lambdas for more convenient CMake generation
std::stringstream ss;
int indent = 0;
auto cmd = [&ss, &indent](const std::string &command) {
if (command.empty())
throw std::invalid_argument("command cannot be empty");
if (command == "if") {
indent++;
return Command(ss, indent - 1, command);
} else if (command == "else" || command == "elseif") {
return Command(ss, indent - 1, command);
} else if (command == "endif") {
indent--;
}
return Command(ss, indent, command);
};
auto comment = [&ss, &indent](const std::string &comment) {
ss << Command::indent(indent) << "# " << comment << '\n';
return CommandEndl(ss);
};
auto endl = [&ss]() { ss << '\n'; };
auto tolf = [](const std::string &str) {
std::string result;
for (char ch : str) {
if (ch != '\r') {
result += ch;
}
}
return result;
};
auto inject_includes = [&cmd, &endl](const std::vector<std::string> &includes) {
if (!includes.empty()) {
for (const auto &file : includes) {
// TODO: warn/error if file doesn't exist?
cmd("include")(file);
}
endl();
}
};
auto inject_cmake = [&ss, &tolf](const std::string &cmake) {
if (!cmake.empty()) {
if (cmake.back() == '\"') {
throw std::runtime_error("Detected additional \" at the end of cmake block");
}
ss << tolf(cmake) << "\n\n";
}
};
// TODO: add link with proper documentation
comment("This file was generated automatically by cmkr.").endl();
cmake::CMake cmake(path, false);
if (root) {
cmd("cmake_minimum_required")("VERSION", cmake.cmake_version).endl();
comment("Regenerate CMakeLists.txt automatically in the root project");
cmd("set")("CMKR_ROOT_PROJECT", "OFF");
// clang-format off
cmd("if")("CMAKE_CURRENT_SOURCE_DIR", "STREQUAL", "CMAKE_SOURCE_DIR");
cmd("set")("CMKR_ROOT_PROJECT", "ON").endl();
comment("Bootstrap cmkr");
cmd("include")(cmake.cmkr_include, "OPTIONAL", "RESULT_VARIABLE", "CMKR_INCLUDE_RESULT");
cmd("if")("CMKR_INCLUDE_RESULT");
cmd("cmkr")();
cmd("endif")().endl();
comment("Enable folder support");
cmd("set_property")("GLOBAL", "PROPERTY", "USE_FOLDERS", "ON");
cmd("endif")().endl();
// clang-format on
}
// clang-format off
comment("Create a configure-time dependency on cmake.toml to improve IDE support");
cmd("if")("CMKR_ROOT_PROJECT");
cmd("configure_file")("cmake.toml", "cmake.toml", "COPYONLY");
cmd("endif")().endl();
// clang-format on
// TODO: remove support and replace with global compile-features
if (!cmake.cppflags.empty()) {
ss << "set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} \"";
for (const auto &flag : cmake.cppflags) {
ss << flag << " ";
}
ss << "\")\n\n";
}
// TODO: remove support and replace with global compile-features
if (!cmake.cflags.empty()) {
ss << "set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} \"";
for (const auto &flag : cmake.cflags) {
ss << flag << " ";
}
ss << "\")\n\n";
}
// TODO: remove support and replace with global linker-flags
if (!cmake.linkflags.empty()) {
ss << "set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} \"";
for (const auto &flag : cmake.linkflags) {
ss << flag << " ";
}
ss << "\")\n\n";
}
inject_includes(cmake.include_before);
inject_cmake(cmake.cmake_before);
if (!cmake.project_name.empty()) {
auto languages = std::make_pair("LANGUAGES", cmake.project_languages);
auto version = std::make_pair("VERSION", cmake.project_version);
auto description = std::make_pair("DESCRIPTION", cmake.project_description);
cmd("project")(cmake.project_name, languages, version, description).endl();
}
inject_includes(cmake.include_after);
inject_cmake(cmake.cmake_after);
if (!cmake.contents.empty()) {
cmd("include")("FetchContent").endl();
for (const auto &dep : cmake.contents) {
cmd("message")("STATUS", "Fetching " + dep.first + "...");
ss << "FetchContent_Declare(\n\t" << dep.first << "\n";
for (const auto &arg : dep.second) {
std::string first_arg = arg.first;
if (first_arg == "git") {
first_arg = "GIT_REPOSITORY";
} else if (first_arg == "tag") {
first_arg = "GIT_TAG";
} else if (first_arg == "svn") {
first_arg = "SVN_REPOSITORY";
} else if (first_arg == "rev") {
first_arg = "SVN_REVISION";
} else if (first_arg == "url") {
first_arg = "URL";
} else if (first_arg == "hash") {
first_arg = "URL_HASH";
} else {
// don't change arg
}
ss << "\t" << first_arg << "\n\t\t" << arg.second << "\n";
}
ss << ")\n";
cmd("FetchContent_MakeAvailable")(dep.first).endl();
}
}
if (!cmake.vcpkg.version.empty()) {
assert("pmm is required in fetch-content for vcpkg to work" && cmake.contents.count("pmm") != 0);
comment("Bootstrap vcpkg");
cmd("include")("${pmm_SOURCE_DIR}/pmm.cmake");
tsl::ordered_map<std::string, std::vector<std::string>> vcpkg_args;
vcpkg_args["REVISION"] = {cmake.vcpkg.version};
vcpkg_args["REQUIRES"] = cmake.vcpkg.packages;
auto vcpkg = std::make_pair("VCPKG", vcpkg_args);
cmd("pmm")(vcpkg).endl();
}
if (!cmake.packages.empty()) {
comment("Packages");
for (const auto &dep : cmake.packages) {
auto version = dep.version;
if (version == "*")
version.clear();
auto required = dep.required ? "REQUIRED" : "";
auto config = dep.config ? "CONFIG" : "";
auto components = std::make_pair("COMPONENTS", dep.components);
cmd("find_package")(dep.name, version, required, config, components).endl();
}
}
if (!cmake.options.empty()) {
comment("Options");
for (const auto &opt : cmake.options) {
cmd("option")(opt.name, opt.comment, opt.val ? "ON" : "OFF");
}
endl();
}
if (!cmake.settings.empty()) {
comment("Settings");
for (const auto &set : cmake.settings) {
std::string set_val;
if (set.val.index() == 1) {
set_val = mpark::get<1>(set.val);
} else {
set_val = mpark::get<0>(set.val) ? "ON" : "OFF";
}
if (set.cache) {
auto typ = set.val.index() == 1 ? "STRING" : "BOOL";
auto force = set.force ? "FORCE" : "";
cmd("set")(set.name, set_val, typ, set.comment, force);
} else {
cmd("set")(set.name, set_val);
}
}
endl();
}
// generate_cmake is called on the subdirectories recursively later
if (!cmake.subdirs.empty()) {
for (const auto &dir : cmake.subdirs) {
// clang-format off
comment(dir);
cmd("set")("CMKR_CMAKE_FOLDER", "${CMAKE_FOLDER}");
cmd("if")("CMAKE_FOLDER");
cmd("set")("CMAKE_FOLDER", "${CMAKE_FOLDER}/" + dir);
cmd("else")();
cmd("set")("CMAKE_FOLDER", dir);
cmd("endif")();
// clang-format on
cmd("add_subdirectory")(dir);
cmd("set")("CMAKE_FOLDER", "${CMKR_CMAKE_FOLDER}").endl();
}
endl();
}
if (!cmake.targets.empty()) {
for (const auto &target : cmake.targets) {
comment("Target " + target.name);
inject_includes(target.include_before);
inject_cmake(target.cmake_before);
if (!target.sources.empty()) {
auto sources = expand_cmake_paths(target.sources, path);
if (sources.empty()) {
throw std::runtime_error(target.name + " sources wildcard found 0 files");
}
if (target.type != cmake::target_interface) {
// Do not add cmake.toml twice
if (std::find(sources.begin(), sources.end(), "cmake.toml") == sources.end()) {
sources.push_back("cmake.toml");
}
}
cmd("set")(target.name + "_SOURCES", sources).endl();
}
std::string add_command;
std::string target_type;
std::string target_scope;
switch (target.type) {
case cmake::target_executable:
add_command = "add_executable";
target_type = "";
target_scope = "PRIVATE";
break;
case cmake::target_library:
add_command = "add_library";
target_type = "";
target_scope = "PUBLIC";
break;
case cmake::target_shared:
add_command = "add_library";
target_type = "SHARED";
target_scope = "PUBLIC";
break;
case cmake::target_static:
add_command = "add_library";
target_type = "STATIC";
target_scope = "PUBLIC";
break;
case cmake::target_interface:
add_command = "add_library";
target_type = "INTERFACE";
target_scope = "INTERFACE";
break;
case cmake::target_custom:
// TODO: add proper support, this is hacky
add_command = "add_custom_target";
target_type = "SOURCES";
target_scope = "PUBLIC";
break;
default:
assert("Unimplemented enum value" && false);
}
cmd(add_command)(target.name, target_type, "${" + target.name + "_SOURCES}").endl();
// The first executable target will become the Visual Studio startup project
if (target.type == cmake::target_executable) {
cmd("get_directory_property")("CMKR_VS_STARTUP_PROJECT", "DIRECTORY", "${PROJECT_SOURCE_DIR}", "DEFINITION", "VS_STARTUP_PROJECT");
// clang-format off
cmd("if")("NOT", "CMKR_VS_STARTUP_PROJECT");
cmd("set_property")("DIRECTORY", "${PROJECT_SOURCE_DIR}", "PROPERTY", "VS_STARTUP_PROJECT", target.name);
cmd("endif")().endl();
// clang-format on
}
if (!target.sources.empty()) {
cmd("source_group")("TREE", "${CMAKE_CURRENT_SOURCE_DIR}", "FILES", "${" + target.name + "_SOURCES}").endl();
}
if (!target.alias.empty()) {
cmd("add_library")(target.alias, "ALIAS", target.name);
}
auto target_cmd = [&](const char *command, const std::vector<std::string> &args) {
if (!args.empty()) {
cmd(command)(target.name, target_scope, args).endl();
}
};
target_cmd("target_compile_definitions", target.compile_definitions);
target_cmd("target_compile_features", target.compile_features);
target_cmd("target_compile_options", target.compile_options);
target_cmd("target_include_directories", target.include_directories);
target_cmd("target_link_directories", target.link_directories);
target_cmd("target_link_libraries", target.link_libraries);
target_cmd("target_precompile_headers", target.precompile_headers);
if (!target.properties.empty()) {
cmd("set_target_properties")(target.name, "PROPERTIES", target.properties).endl();
}
inject_includes(target.include_after);
inject_cmake(target.cmake_after);
}
}
if (!cmake.tests.empty()) {
cmd("enable_testing")().endl();
for (const auto &test : cmake.tests) {
auto name = std::make_pair("NAME", test.name);
auto configurations = std::make_pair("CONFIGURATIONS", test.configurations);
auto working_directory = std::make_pair("WORKING_DIRECTORY", test.working_directory);
auto command = std::make_pair("COMMAND", test.command);
auto arguments = std::make_pair("", test.arguments);
cmd("add_test")(name, configurations, working_directory, command, arguments).endl();
}
}
if (!cmake.installs.empty()) {
for (const auto &inst : cmake.installs) {
auto targets = std::make_pair("TARGETS", inst.targets);
auto dirs = std::make_pair("DIRS", inst.dirs);
std::vector<std::string> files_data;
if (!inst.files.empty()) {
files_data = expand_cmake_paths(inst.files, path);
if (files_data.empty()) {
throw std::runtime_error("[[install]] files wildcard did not resolve to any files");
}
}
auto files = std::make_pair("FILES", inst.files);
auto configs = std::make_pair("CONFIGURATIONS", inst.configs);
auto destination = std::make_pair("DESTINATION", inst.destination);
auto component = std::make_pair("COMPONENT", inst.targets.empty() ? "" : inst.targets.front());
cmd("install")(targets, dirs, files, configs, destination, component);
}
}
// Generate CMakeLists.txt
auto list_path = fs::path(path) / "CMakeLists.txt";
auto should_regenerate = [&list_path, &ss]() {
if (!fs::exists(list_path))
return true;
std::ifstream ifs(list_path, std::ios_base::binary);
if (!ifs.is_open()) {
throw std::runtime_error("Failed to read " + list_path.string());
}
std::string data((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
return data != ss.str();
}();
if (should_regenerate) {
std::ofstream ofs(list_path, std::ios_base::binary);
if (ofs.is_open()) {
ofs << ss.str();
} else {
throw std::runtime_error("Failed to write " + list_path.string());
}
}
for (const auto &sub : cmake.subdirs) {
auto subpath = fs::path(path) / fs::path(sub);
if (fs::exists(subpath / "cmake.toml"))
generate_cmake(subpath.string().c_str(), false);
}
return 0;
}
} // namespace gen
} // namespace cmkr
int cmkr_gen_generate_project(const char *typ) {
try {
return cmkr::gen::generate_project(typ);
} catch (const std::system_error &e) {
return e.code().value();
} catch (...) {
return cmkr::error::Status(cmkr::error::Status::Code::InitError);
}
}
int cmkr_gen_generate_cmake(const char *path) {
try {
return cmkr::gen::generate_cmake(path);
} catch (const std::system_error &e) {
return e.code().value();
} catch (...) {
return cmkr::error::Status(cmkr::error::Status::Code::GenerationError);
}
}
+5 -6
View File
@@ -1,9 +1,12 @@
#include "help.h"
#include "help.hpp"
#include <resources/version.hpp>
namespace cmkr {
namespace help {
const char *version() noexcept { return "cmkr version 0.1.3"; }
const char *version() noexcept {
return "cmkr version " CMKR_VERSION;
}
const char *message() noexcept {
return R"lit(
@@ -20,7 +23,3 @@ arguments:
}
} // namespace help
} // namespace cmkr
const char *cmkr_help_version(void) { return cmkr::help::version(); }
const char *cmkr_help_message(void) { return cmkr::help::message(); }
+1 -1
View File
@@ -1,4 +1,4 @@
#include "args.h"
#include "arguments.hpp"
#include <cstdio>
#include <cstdlib>
+938
View File
@@ -0,0 +1,938 @@
#include "project_parser.hpp"
#include "fs.hpp"
#include <deque>
#include <stdexcept>
#include <toml.hpp>
namespace cmkr {
namespace parser {
const char *targetTypeNames[target_last] = {"executable", "library", "shared", "static", "interface", "custom", "object", "template"};
static TargetType parse_targetType(const std::string &name) {
for (int i = 0; i < target_last; i++) {
if (name == targetTypeNames[i]) {
return static_cast<TargetType>(i);
}
}
return target_last;
}
const char *msvcRuntimeTypeNames[msvc_last] = {"dynamic", "static"};
static MsvcRuntimeType parse_msvcRuntimeType(const std::string &name) {
for (int i = 0; i < msvc_last; i++) {
if (name == msvcRuntimeTypeNames[i]) {
return static_cast<MsvcRuntimeType>(i);
}
}
return msvc_last;
}
using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector>;
static std::string format_key_message(const std::string &message, const toml::key &ky, const TomlBasicValue &value) {
auto loc = value.location();
auto line_number_str = std::to_string(loc.line());
auto line_width = line_number_str.length();
const auto &line_str = loc.line_str();
std::ostringstream oss;
oss << message << "\n";
oss << " --> " << loc.file_name() << ':' << loc.line() << '\n';
oss << std::string(line_width + 2, ' ') << "|\n";
oss << ' ' << line_number_str << " | " << line_str << '\n';
oss << std::string(line_width + 2, ' ') << '|';
auto key_start = line_str.substr(0, loc.column() - 1).rfind(ky);
if (key_start == std::string::npos) {
key_start = line_str.find(ky);
}
if (key_start != std::string::npos) {
oss << std::string(key_start + 1, ' ') << std::string(ky.length(), '~');
}
return oss.str();
}
static void throw_key_error(const std::string &error, const toml::key &ky, const TomlBasicValue &value) {
throw std::runtime_error(format_key_message("[error] " + error, ky, value));
}
static void print_key_warning(const std::string &message, const toml::key &ky, const TomlBasicValue &value) {
puts(format_key_message("[warning] " + message, ky, value).c_str());
}
class TomlChecker {
const TomlBasicValue &m_v;
tsl::ordered_set<toml::key> m_visited;
tsl::ordered_set<toml::key> m_conditionVisited;
public:
TomlChecker(const TomlBasicValue &v, const toml::key &ky) : m_v(toml::find(v, ky)) {
}
explicit TomlChecker(const TomlBasicValue &v) : m_v(v) {
}
TomlChecker(const TomlChecker &) = delete;
TomlChecker(TomlChecker &&) = delete;
template <typename T>
void optional(const toml::key &ky, Condition<T> &destination) {
// TODO: this algorithm in O(n) over the amount of keys, kinda bad
const auto &table = m_v.as_table();
for (const auto &itr : table) {
const auto &key = itr.first;
const auto &value = itr.second;
if (value.is_table()) {
if (value.contains(ky)) {
destination[key] = toml::find<T>(value, ky);
}
} else if (key == ky) {
destination[""] = toml::find<T>(m_v, ky);
}
}
// Handle visiting logic
for (const auto &itr : destination) {
if (!itr.first.empty()) {
m_conditionVisited.emplace(itr.first);
}
}
visit(ky);
}
template <typename T>
void optional(const toml::key &ky, T &destination) {
// TODO: this currently doesn't allow you to get an optional map<string, X>
if (m_v.contains(ky)) {
destination = toml::find<T>(m_v, ky);
}
visit(ky);
}
template <typename T>
void required(const toml::key &ky, T &destination) {
destination = toml::find<T>(m_v, ky);
visit(ky);
}
bool contains(const toml::key &ky) {
visit(ky);
return m_v.contains(ky);
}
const TomlBasicValue &find(const toml::key &ky) {
visit(ky);
return toml::find(m_v, ky);
}
void visit(const toml::key &ky) {
m_visited.emplace(ky);
}
bool visisted(const toml::key &ky) const {
return m_visited.contains(ky);
}
void check(const tsl::ordered_map<std::string, std::string> &conditions) const {
for (const auto &itr : m_v.as_table()) {
const auto &ky = itr.first;
if (m_conditionVisited.contains(ky)) {
if (!conditions.contains(ky) && Project::is_condition_name(ky)) {
throw_key_error("Unknown condition '" + ky + "'", ky, itr.second);
}
for (const auto &jtr : itr.second.as_table()) {
if (!m_visited.contains(jtr.first)) {
throw_key_error("Unknown key '" + jtr.first + "'", jtr.first, jtr.second);
}
}
} else if (!m_visited.contains(ky)) {
if (itr.second.is_table()) {
for (const auto &jtr : itr.second.as_table()) {
if (!m_visited.contains(jtr.first)) {
throw_key_error("Unknown key '" + jtr.first + "'", jtr.first, jtr.second);
}
}
}
throw_key_error("Unknown key '" + ky + "'", ky, itr.second);
} else if (ky == "condition") {
std::string condition = itr.second.as_string();
if (!conditions.contains(condition) && Project::is_condition_name(condition)) {
throw_key_error("Unknown condition '" + condition + "'", condition, itr.second);
}
}
}
}
};
class TomlCheckerRoot {
const TomlBasicValue &m_root;
std::deque<TomlChecker> m_checkers;
tsl::ordered_set<toml::key> m_visisted;
bool m_checked = false;
public:
explicit TomlCheckerRoot(const TomlBasicValue &root) : m_root(root) {
}
TomlCheckerRoot(const TomlCheckerRoot &) = delete;
TomlCheckerRoot(TomlCheckerRoot &&) = delete;
bool contains(const toml::key &ky) {
m_visisted.emplace(ky);
return m_root.contains(ky);
}
TomlChecker &create(const TomlBasicValue &v) {
m_checkers.emplace_back(v);
return m_checkers.back();
}
TomlChecker &create(const TomlBasicValue &v, const toml::key &ky) {
m_checkers.emplace_back(v, ky);
return m_checkers.back();
}
void check(const tsl::ordered_map<std::string, std::string> &conditions, bool check_root) {
if (check_root) {
for (const auto &itr : m_root.as_table()) {
if (!m_visisted.contains(itr.first)) {
throw_key_error("Unknown key '" + itr.first + "'", itr.first, itr.second);
}
}
}
for (const auto &checker : m_checkers) {
checker.check(conditions);
}
}
};
Project::Project(const Project *parent, const std::string &path, bool build) : parent(parent) {
const auto toml_path = fs::path(path) / "cmake.toml";
if (!fs::exists(toml_path)) {
throw std::runtime_error("File not found '" + toml_path.string() + "'");
}
const auto toml = toml::parse<toml::discard_comments, tsl::ordered_map, std::vector>(toml_path.string());
if (toml.size() == 0) {
throw std::runtime_error("Empty TOML '" + toml_path.string() + "'");
}
TomlCheckerRoot checker(toml);
if (checker.contains("cmake")) {
auto &cmake = checker.create(toml, "cmake");
cmake.required("version", cmake_version);
if (cmake.contains("bin-dir")) {
throw_key_error("bin-dir has been renamed to build-dir", "bin-dir", cmake.find("bin-dir"));
}
cmake.optional("build-dir", build_dir);
cmake.optional("generator", generator);
cmake.optional("config", config);
cmake.optional("arguments", gen_args);
cmake.optional("allow-in-tree", allow_in_tree);
if (cmake.contains("cmkr-include")) {
const auto &cmkr_include_kv = cmake.find("cmkr-include");
if (cmkr_include_kv.is_string()) {
cmkr_include = cmkr_include_kv.as_string();
} else {
// Allow disabling this feature with cmkr-include = false
cmkr_include = "";
}
}
cmake.optional("cpp-flags", cppflags);
cmake.optional("c-flags", cflags);
cmake.optional("link-flags", linkflags);
}
// Skip the rest of the parsing when building
if (build) {
checker.check(conditions, false);
return;
}
// Reasonable default conditions (you can override these if you desire)
if (parent == nullptr) {
conditions["windows"] = R"cmake(WIN32)cmake";
conditions["macos"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "Darwin")cmake";
conditions["unix"] = R"cmake(UNIX)cmake";
conditions["bsd"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "BSD")cmake";
conditions["linux"] = conditions["lunix"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "Linux")cmake";
conditions["gcc"] = R"cmake(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "GNU")cmake";
conditions["msvc"] = R"cmake(MSVC)cmake";
conditions["clang"] =
R"cmake((CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$") OR (CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$"))cmake";
conditions["clang-cl"] =
R"cmake((CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$") OR (CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$"))cmake";
conditions["clang-any"] = R"cmake(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "Clang")cmake";
conditions["root"] = R"cmake(CMKR_ROOT_PROJECT)cmake";
conditions["x64"] = R"cmake(CMAKE_SIZEOF_VOID_P EQUAL 8)cmake";
conditions["x32"] = R"cmake(CMAKE_SIZEOF_VOID_P EQUAL 4)cmake";
conditions["android"] = R"cmake(ANDROID)cmake";
conditions["apple"] = R"cmake(APPLE)cmake";
conditions["bsd"] = R"cmake(BSD)cmake";
conditions["cygwin"] = R"cmake(CYGWIN)cmake";
conditions["ios"] = R"cmake(IOS)cmake";
conditions["xcode"] = R"cmake(XCODE)cmake";
conditions["wince"] = R"cmake(WINCE)cmake";
} else {
conditions = parent->conditions;
templates = parent->templates;
}
if (checker.contains("conditions")) {
auto conds = toml::find<decltype(conditions)>(toml, "conditions");
for (const auto &cond : conds) {
if (!is_condition_name(cond.first)) {
throw_key_error("Invalid condition name '" + cond.first + "'", cond.first, toml::find(toml::find(toml, "conditions"), cond.first));
}
conditions[cond.first] = cond.second;
}
}
if (checker.contains("project")) {
auto &project = checker.create(toml, "project");
project.required("name", project_name);
project.optional("version", project_version);
project.optional("description", project_description);
// The implicit default is ["C", "CXX"], so make sure this list isn't
// empty or projects without languages explicitly defined will error.
project_languages[""] = {"C", "CXX"};
project.optional("languages", project_languages);
project.optional("allow-unknown-languages", project_allow_unknown_languages);
project.optional("cmake-before", cmake_before);
project.optional("cmake-after", cmake_after);
project.optional("include-before", include_before);
project.optional("include-after", include_after);
project.optional("subdirs", project_subdirs);
std::string msvc_runtime;
project.optional("msvc-runtime", msvc_runtime);
if (!msvc_runtime.empty()) {
project_msvc_runtime = parse_msvcRuntimeType(msvc_runtime);
if (project_msvc_runtime == msvc_last) {
std::string error = "Unknown runtime '" + msvc_runtime + "'\n";
error += "Available types:\n";
for (std::string type_name : msvcRuntimeTypeNames) {
error += " - " + type_name + "\n";
}
error.pop_back(); // Remove last newline
throw_key_error(error, msvc_runtime, project.find("msvc-runtime"));
}
}
}
if (checker.contains("subdir")) {
const auto &subs = toml::find(toml, "subdir").as_table();
for (const auto &itr : subs) {
Subdir subdir;
subdir.name = itr.first;
auto &sub = checker.create(itr.second);
sub.optional("condition", subdir.condition);
sub.optional("cmake-before", subdir.cmake_before);
sub.optional("cmake-after", subdir.cmake_after);
sub.optional("include-before", subdir.include_before);
sub.optional("include-after", subdir.include_after);
subdirs.push_back(subdir);
}
}
if (checker.contains("variables")) {
using set_map = tsl::ordered_map<std::string, TomlBasicValue>;
auto vars = toml::find<set_map>(toml, "variables");
if (checker.contains("settings")) {
print_key_warning("[settings] has been renamed to [variables]", "settings", toml.at("settings"));
const auto &sets = toml::find<set_map>(toml, "settings");
for (const auto &itr : sets) {
if (!vars.insert(itr).second) {
throw_key_error("Key '" + itr.first + "' shadows existing variable", itr.first, itr.second);
}
}
}
for (const auto &itr : vars) {
Variable s;
s.name = itr.first;
const auto &value = itr.second;
if (value.is_boolean()) {
s.value = value.as_boolean();
} else if (value.is_string()) {
s.value = value.as_string();
} else {
auto &setting = checker.create(value);
setting.optional("help", s.help);
if (setting.contains("value")) {
const auto &v = setting.find("value");
if (v.is_boolean()) {
s.value = v.as_boolean();
} else {
s.value = v.as_string();
}
}
setting.optional("cache", s.cache);
setting.optional("force", s.force);
}
variables.push_back(s);
}
}
if (checker.contains("options")) {
auto normalize = [](const std::string &name) {
std::string normalized;
for (char ch : name) {
if (ch == '_') {
normalized += '-';
} else if (ch >= 'A' && ch <= 'Z') {
ch += ('a' - 'A');
normalized += ch;
} else if (ch == '-' || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z')) {
normalized += ch;
} else {
// Ignore all other characters
}
}
return normalized;
};
auto nproject_prefix = normalize(project_name);
nproject_prefix += '-';
using opts_map = tsl::ordered_map<std::string, TomlBasicValue>;
const auto &opts = toml::find<opts_map>(toml, "options");
for (const auto &itr : opts) {
Option o;
o.name = itr.first;
const auto &value = itr.second;
if (value.is_boolean()) {
o.value = value.as_boolean();
} else if (value.is_string()) {
auto str = std::string(value.as_string());
if (str == "root") {
o.value = std::string("${CMKR_ROOT_PROJECT}");
} else {
throw_key_error("Unsupported option value '" + str + "'", str, value);
}
} else if (value.is_table()) {
auto &option = checker.create(value);
option.optional("help", o.help);
if (option.contains("value")) {
const auto &ovalue = option.find("value");
if (ovalue.is_boolean()) {
o.value = ovalue.as_boolean();
} else if (ovalue.is_string()) {
auto str = std::string(ovalue.as_string());
if (str == "root") {
o.value = std::string("${CMKR_ROOT_PROJECT}");
} else {
throw_key_error("Unsupported option value '" + str + "'", str, value);
}
} else {
throw_key_error(toml::concat_to_string("Unsupported value type: ", ovalue.type()), "value", value);
}
}
} else {
throw_key_error(toml::concat_to_string("Unsupported value type: ", itr.second.type()), itr.first, itr.second);
}
options.push_back(o);
// Add a condition matching the option name
conditions.emplace(o.name, o.name);
// Add an implicit condition for the option
auto ncondition = normalize(o.name);
if (ncondition.find(nproject_prefix) == 0) {
ncondition = ncondition.substr(nproject_prefix.size());
}
if (!ncondition.empty()) {
if (conditions.contains(ncondition)) {
print_key_warning("Option '" + o.name + "' would create a condition '" + ncondition + "' that already exists", o.name, value);
}
conditions.emplace(ncondition, o.name);
}
}
}
if (checker.contains("find-package")) {
using pkg_map = tsl::ordered_map<std::string, TomlBasicValue>;
const auto &pkgs = toml::find<pkg_map>(toml, "find-package");
for (const auto &itr : pkgs) {
Package p;
p.name = itr.first;
const auto &value = itr.second;
if (itr.second.is_string()) {
p.version = itr.second.as_string();
} else {
auto &pkg = checker.create(value);
pkg.optional("condition", p.condition);
pkg.optional("version", p.version);
pkg.optional("required", p.required);
pkg.optional("config", p.config);
pkg.optional("components", p.components);
}
packages.push_back(p);
}
}
if (checker.contains("fetch-content")) {
const auto &fc = toml::find(toml, "fetch-content").as_table();
for (const auto &itr : fc) {
Content content;
content.name = itr.first;
auto &c = checker.create(itr.second);
c.optional("condition", content.condition);
c.optional("cmake-before", content.cmake_before);
c.optional("cmake-after", content.cmake_after);
c.optional("include-before", content.include_before);
c.optional("include-after", content.include_after);
c.optional("system", content.system);
// Check if the minimum version requirement is satisfied (CMake 3.25)
if (c.contains("system") && !this->cmake_minimum_version(3, 25)) {
throw_key_error("The system argument is only supported on CMake version 3.25 and above.\nSet the CMake version in cmake.toml:\n"
"[cmake]\n"
"version = \"3.25\"\n",
"system", "");
}
for (const auto &argItr : itr.second.as_table()) {
std::string value;
if (argItr.second.is_array()) {
for (const auto &list_val : argItr.second.as_array()) {
if (!value.empty()) {
value += ';';
}
value += list_val.as_string();
}
} else if (argItr.second.is_boolean()) {
value = argItr.second.as_boolean() ? "ON" : "OFF";
} else {
value = argItr.second.as_string();
}
auto is_cmake_arg = [](const std::string &s) {
for (auto c : s) {
if (!(std::isdigit(c) || std::isupper(c) || c == '_')) {
return false;
}
}
return true;
};
// https://cmake.org/cmake/help/latest/command/string.html#supported-hash-algorithms
tsl::ordered_set<std::string> hash_algorithms = {
"md5", "sha1", "sha224", "sha256", "sha384", "sha512", "sha3_224", "sha3_256", "sha3_384", "sha3_512",
};
auto key = argItr.first;
if (key == "git") {
key = "GIT_REPOSITORY";
} else if (key == "tag") {
key = "GIT_TAG";
} else if (key == "shallow") {
key = "GIT_SHALLOW";
} else if (key == "svn") {
key = "SVN_REPOSITORY";
} else if (key == "rev") {
key = "SVN_REVISION";
} else if (key == "url") {
key = "URL";
} else if (hash_algorithms.contains(key)) {
std::string algo;
for (auto ch : key) {
if (ch >= 'a' && ch <= 'z') {
ch -= ('a' - 'A');
}
algo.push_back(ch);
}
key = "URL_HASH";
if (value.empty()) {
throw_key_error("Empty hash value", argItr.first, argItr.second);
}
for (char c : value) {
if (!std::isxdigit(c)) {
throw_key_error("Hash value must be a hex string", argItr.first, argItr.second);
}
}
value = algo + "=" + value;
} else if (key == "hash") {
key = "URL_HASH";
} else if (key == "subdir") {
key = "SOURCE_SUBDIR";
} else if (is_cmake_arg(key)) {
// allow passthrough of ExternalProject options
} else if (!c.visisted(key)) {
throw_key_error("Unknown key '" + argItr.first + "'", argItr.first, argItr.second);
}
// Make sure not to emit keys like "condition" in the FetchContent call
if (!c.visisted(key)) {
content.arguments.emplace(key, value);
}
c.visit(argItr.first);
}
contents.emplace_back(std::move(content));
}
}
if (checker.contains("bin")) {
throw_key_error("[[bin]] has been renamed to [target.<name>]", "", toml.at("bin"));
}
auto parse_target = [&](const std::string &name, TomlChecker &t, bool isTemplate) {
Target target;
target.name = name;
t.required("type", target.type_name);
target.type = parse_targetType(target.type_name);
// Users cannot set this target type
if (target.type == target_template) {
target.type = target_last;
}
if (!isTemplate && target.type == target_last) {
for (const auto &tmplate : templates) {
if (target.type_name == tmplate.outline.name) {
target.type = target_template;
break;
}
}
}
if (target.type == target_last) {
std::string error = "Unknown target type '" + target.type_name + "'\n";
error += "Available types:\n";
for (std::string type_name : targetTypeNames) {
if (type_name != "template") {
error += " - " + type_name + "\n";
}
}
if (!isTemplate && !templates.empty()) {
error += "Available templates:\n";
for (const auto &tmplate : templates) {
error += " - " + tmplate.outline.name + "\n";
}
}
error.pop_back(); // Remove last newline
throw_key_error(error, target.type_name, t.find("type"));
}
t.optional("sources", target.sources);
// Merge the headers into the sources
ConditionVector headers;
t.optional("headers", headers);
for (const auto &itr : headers) {
auto &dest = target.sources[itr.first];
for (const auto &jtr : itr.second) {
dest.push_back(jtr);
}
}
t.optional("compile-definitions", target.compile_definitions);
t.optional("private-compile-definitions", target.private_compile_definitions);
t.optional("compile-features", target.compile_features);
t.optional("private-compile-features", target.private_compile_features);
t.optional("compile-options", target.compile_options);
t.optional("private-compile-options", target.private_compile_options);
t.optional("include-directories", target.include_directories);
t.optional("private-include-directories", target.private_include_directories);
t.optional("link-directories", target.link_directories);
t.optional("private-link-directories", target.private_link_directories);
t.optional("link-libraries", target.link_libraries);
t.optional("private-link-libraries", target.private_link_libraries);
// Add support for relative paths for (private-)link-libraries
const auto fix_relative_paths = [&name, &path](ConditionVector &libraries, const char *key) {
for (const auto &library_entries : libraries) {
for (auto &library : libraries[library_entries.first]) {
// Skip processing paths with potential CMake macros in them (this check isn't perfect)
// https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#variable-references
if ((library.find("${") != std::string::npos || library.find("$ENV{") != std::string::npos ||
library.find("$CACHE{") != std::string::npos) &&
library.find('}') != std::string::npos) {
continue;
}
auto library_path = fs::path(path) / library;
if (fs::exists(library_path)) {
if (!fs::is_directory(library_path)) {
// If the file path is relative (and not a directory), prepend ${CMAKE_CURRENT_SOURCE_DIR}
library.insert(0, "${CMAKE_CURRENT_SOURCE_DIR}/");
}
} else if (library.find_first_of(R"(\/)") != std::string::npos) {
// Error if the path contains a directory separator and the file doesn't exist
throw std::runtime_error("Attempted to link against a library file that doesn't exist for target \"" + name + "\" in \"" +
key + "\": " + library);
} else {
// NOTE: We cannot check if system libraries exist, so we leave them as-is
}
}
}
};
fix_relative_paths(target.link_libraries, "link-libraries");
fix_relative_paths(target.private_link_libraries, "private-link-libraries");
t.optional("link-options", target.link_options);
t.optional("private-link-options", target.private_link_options);
t.optional("precompile-headers", target.precompile_headers);
t.optional("private-precompile-headers", target.private_precompile_headers);
t.optional("dependencies", target.dependencies);
Condition<std::string> msvc_runtime;
t.optional("msvc-runtime", msvc_runtime);
for (const auto &cond_itr : msvc_runtime) {
switch (parse_msvcRuntimeType(cond_itr.second)) {
case msvc_dynamic:
target.properties[cond_itr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL";
break;
case msvc_static:
target.properties[cond_itr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>";
break;
default: {
std::string error = "Unknown runtime '" + cond_itr.second + "'\n";
error += "Available types:\n";
for (std::string type_name : msvcRuntimeTypeNames) {
error += " - " + type_name + "\n";
}
error.pop_back(); // Remove last newline
const TomlBasicValue *report;
if (cond_itr.first.empty()) {
report = &t.find("msvc-runtime");
} else {
report = &t.find(cond_itr.first).as_table().find("msvc-runtime").value();
}
throw_key_error(error, cond_itr.second, *report);
}
}
}
t.optional("condition", target.condition);
t.optional("alias", target.alias);
if (t.contains("properties")) {
auto store_property = [&target](const toml::key &k, const TomlBasicValue &v, const std::string &condition) {
if (v.is_array()) {
std::string property_list;
for (const auto &list_val : v.as_array()) {
if (!property_list.empty()) {
property_list += ';';
}
property_list += list_val.as_string();
}
target.properties[condition][k] = property_list;
} else if (v.is_integer()) {
target.properties[condition][k] = std::to_string(v.as_integer());
} else if (v.is_boolean()) {
target.properties[condition][k] = v.as_boolean() ? "ON" : "OFF";
} else {
target.properties[condition][k] = v.as_string();
}
};
const auto &props = t.find("properties").as_table();
for (const auto &propKv : props) {
const auto &k = propKv.first;
const auto &v = propKv.second;
if (v.is_table()) {
for (const auto &condKv : v.as_table()) {
store_property(condKv.first, condKv.second, k);
}
} else {
store_property(k, v, "");
}
}
}
t.optional("cmake-before", target.cmake_before);
t.optional("cmake-after", target.cmake_after);
t.optional("include-before", target.include_before);
t.optional("include-after", target.include_after);
return target;
};
if (checker.contains("template")) {
const auto &ts = toml::find(toml, "template").as_table();
for (const auto &itr : ts) {
auto &t = checker.create(itr.second);
const auto &name = itr.first;
for (const auto &type_name : targetTypeNames) {
if (name == type_name) {
throw_key_error("Reserved template name '" + name + "'", name, itr.second);
}
}
for (const auto &tmplate : templates) {
if (name == tmplate.outline.name) {
throw_key_error("Template '" + name + "' already defined", name, itr.second);
}
}
Template tmplate;
tmplate.outline = parse_target(name, t, true);
t.optional("add-function", tmplate.add_function);
t.optional("add-arguments", tmplate.add_arguments);
t.optional("pass-sources-to-add-function", tmplate.pass_sources_to_add_function);
t.optional("pass-sources", tmplate.pass_sources_to_add_function);
templates.push_back(tmplate);
}
}
if (checker.contains("target")) {
const auto &ts = toml::find(toml, "target").as_table();
for (const auto &itr : ts) {
auto &t = checker.create(itr.second);
targets.push_back(parse_target(itr.first, t, false));
}
}
if (checker.contains("test")) {
const auto &ts = toml::find(toml, "test").as_array();
for (const auto &value : ts) {
auto &t = checker.create(value);
Test test;
t.required("name", test.name);
t.optional("condition", test.condition);
t.optional("configurations", test.configurations);
t.optional("working-directory", test.working_directory);
t.required("command", test.command);
t.optional("arguments", test.arguments);
tests.push_back(test);
}
}
if (checker.contains("install")) {
const auto &is = toml::find(toml, "install").as_array();
for (const auto &value : is) {
auto &i = checker.create(value);
Install inst;
i.optional("condition", inst.condition);
i.optional("targets", inst.targets);
i.optional("files", inst.files);
i.optional("dirs", inst.dirs);
i.optional("configs", inst.configs);
i.required("destination", inst.destination);
i.optional("component", inst.component);
i.optional("optional", inst.optional);
installs.push_back(inst);
}
}
if (checker.contains("vcpkg")) {
auto &v = checker.create(toml, "vcpkg");
v.optional("url", vcpkg.url);
v.optional("version", vcpkg.version);
for (const auto &p : v.find("packages").as_array()) {
Vcpkg::Package package;
const auto &package_str = p.as_string().str;
const auto open_bracket = package_str.find('[');
const auto close_bracket = package_str.find(']', open_bracket);
if (open_bracket == std::string::npos && close_bracket == std::string::npos) {
package.name = package_str;
} else if (close_bracket != std::string::npos) {
package.name = package_str.substr(0, open_bracket);
const auto features = package_str.substr(open_bracket + 1, close_bracket - open_bracket - 1);
std::istringstream feature_stream{features};
std::string feature;
while (std::getline(feature_stream, feature, ',')) {
// Disable default features with package-name[core,feature1]
if (feature == "core") {
package.default_features = false;
} else {
package.features.emplace_back(feature);
}
}
} else {
throw_key_error("Invalid package name '" + package_str + "'", "packages", p);
}
vcpkg.packages.emplace_back(std::move(package));
}
if (v.contains("overlay")) {
std::string overlay;
v.optional("overlay", overlay);
vcpkg.overlay_triplets = vcpkg.overlay_ports = {overlay};
if (v.contains("overlay-ports")) {
throw_key_error("[vcpkg].overlay was already specified", "overlay-ports", v.find("overlay-ports"));
}
if (v.contains("overlay-triplets")) {
throw_key_error("[vcpkg].overlay was already specified", "overlay-triplets", v.find("overlay-triplets"));
}
} else {
v.optional("overlay-ports", vcpkg.overlay_ports);
v.optional("overlay-triplets", vcpkg.overlay_triplets);
}
}
checker.check(conditions, true);
}
const Project *Project::root() const {
auto root = this;
while (root->parent != nullptr)
root = root->parent;
return root;
}
bool Project::cmake_minimum_version(int major, int minor) const {
// NOTE: this code is like pulling teeth, sorry
auto root_version = root()->cmake_version;
auto range_index = root_version.find("...");
if (range_index != std::string::npos) {
root_version.resize(range_index);
}
auto period_index = root_version.find('.');
auto root_major = atoi(root_version.substr(0, period_index).c_str());
int root_minor = 0;
if (period_index != std::string::npos) {
auto end_index = root_version.find('.', period_index + 1);
root_minor = atoi(root_version.substr(period_index + 1, end_index).c_str());
}
return std::tie(root_major, root_minor) >= std::tie(major, minor);
}
bool Project::is_condition_name(const std::string &name) {
for (auto ch : name) {
if (!std::isalnum(ch) && ch != '-' && ch != '_') {
return false;
}
}
return true;
}
bool is_root_path(const std::string &path) {
const auto toml_path = fs::path(path) / "cmake.toml";
if (!fs::exists(toml_path)) {
return false;
}
const auto toml = toml::parse<toml::discard_comments, tsl::ordered_map, std::vector>(toml_path.string());
return toml.contains("project");
}
} // namespace parser
} // namespace cmkr
+4
View File
@@ -0,0 +1,4 @@
# These will be generated by cmkr, so no point in tracking them
**/CMakeLists.txt
**/cmkr.cmake
**/vcpkg.json
+116 -2
View File
@@ -1,4 +1,5 @@
# This file was generated automatically by cmkr.
# This file is automatically generated from cmake.toml - DO NOT EDIT
# See https://github.com/build-cpp/cmkr for more information
# Create a configure-time dependency on cmake.toml to improve IDE support
if(CMKR_ROOT_PROJECT)
@@ -13,7 +14,120 @@ add_test(
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/basic"
COMMAND
$<TARGET_FILE:cmkr>
"$<TARGET_FILE:cmkr>"
build
)
add_test(
NAME
interface
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/interface"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
add_test(
NAME
fetch-content
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/fetch-content"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
add_test(
NAME
conditions
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/conditions"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
add_test(
NAME
vcpkg
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/vcpkg"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
add_test(
NAME
cxx-standard
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/cxx-standard"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
add_test(
NAME
globbing
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/globbing"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
add_test(
NAME
templates
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/templates"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
if(MSVC) # msvc
add_test(
NAME
msvc-runtime
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/msvc-runtime"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
endif()
add_test(
NAME
compile-options
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/compile-options"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
if(WIN32) # windows
add_test(
NAME
relative-paths
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/relative-paths"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
endif()
add_test(
NAME
objective-c
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/objective-c"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
-41
View File
@@ -1,41 +0,0 @@
# This file was generated automatically by cmkr.
cmake_minimum_required(VERSION 3.5)
# Regenerate CMakeLists.txt automatically in the root project
set(CMKR_ROOT_PROJECT OFF)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(CMKR_ROOT_PROJECT ON)
# Bootstrap cmkr
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)
if(CMKR_INCLUDE_RESULT)
cmkr()
endif()
# Enable folder support
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
endif()
# Create a configure-time dependency on cmake.toml to improve IDE support
if(CMKR_ROOT_PROJECT)
configure_file(cmake.toml cmake.toml COPYONLY)
endif()
project(basic)
# Target basic
set(basic_SOURCES
"src/basic.cpp"
cmake.toml
)
add_executable(basic ${basic_SOURCES})
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
if(NOT CMKR_VS_STARTUP_PROJECT)
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT basic)
endif()
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${basic_SOURCES})
+4 -2
View File
@@ -1,9 +1,11 @@
[cmake]
version = "3.5"
# A minimal `cmake.toml` project:
[project]
name = "basic"
description = "Minimal example"
[target.basic]
type = "executable"
sources = ["src/basic.cpp"]
# Declares an executable target called `basic` with `src/basic.cpp` as a source file. Equivalent to CMake's [add_executable](https://cmake.org/cmake/help/latest/command/add_executable.html)`(basic src/basic.cpp)`.
+70 -2
View File
@@ -1,5 +1,73 @@
[[test]]
name = "basic"
working-directory = "basic"
command = "$<TARGET_FILE:cmkr>"
working-directory = "${CMAKE_CURRENT_LIST_DIR}/basic"
arguments = ["build"]
arguments = ["build"]
[[test]]
name = "interface"
working-directory = "interface"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
name = "fetch-content"
working-directory = "fetch-content"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
name = "conditions"
working-directory = "conditions"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
name = "vcpkg"
working-directory = "vcpkg"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
name = "cxx-standard"
working-directory = "cxx-standard"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
name = "globbing"
working-directory = "globbing"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
name = "templates"
working-directory = "templates"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
condition = "msvc"
name = "msvc-runtime"
working-directory = "msvc-runtime"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
name = "compile-options"
working-directory = "compile-options"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
condition = "windows"
name = "relative-paths"
working-directory = "relative-paths"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
name = "objective-c"
working-directory = "objective-c"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
+18
View File
@@ -0,0 +1,18 @@
# Example project that sets compiler flags and preprocessor defines for various platforms.
[project]
name = "compile-options"
description = "Compiler flags"
[target.hello]
type = "executable"
sources = ["src/main.cpp"]
msvc.compile-options = ["/W2"]
msvc.compile-definitions = ["PLATFORM=\"msvc\""]
gcc.compile-options = ["-Wall"]
gcc.compile-definitions = ["PLATFORM=\"gcc\""]
clang.compile-options = ["-Wall"]
clang.compile-definitions = ["PLATFORM=\"clang\""]
# The `hello` target uses [conditions](/cmake-toml#conditions) to set different compiler flags and definitions depending on the platform. See the [targets](/cmake-toml/#targets) documentation for other things you can set.
# _Note_: In general you only want to specify flags _required_ to compile your code without errors.
@@ -1,6 +1,5 @@
#include <cstdio>
int main()
{
puts("Hello from cmkr!");
}
#include <cstdio>
int main() {
puts("Hello from cmkr!");
}
+28
View File
@@ -0,0 +1,28 @@
[project]
name = "conditions"
cmake-after = "set(CUSTOM ON)"
[options]
CONDITIONS_BUILD_TESTS = "root"
[conditions]
custom = "CUSTOM"
[target.example]
type = "executable"
sources = ["src/main.cpp"]
windows.sources = ["src/windows_specific.cpp"]
cmake-after = "message(STATUS cmake-after)"
windows.cmake-after = "message(STATUS win32-after)"
macos.cmake-after = "message(STATUS macos-after)"
linux.cmake-after = "message(STATUS linux-after)"
unix.cmake-after = "message(STATUS unix-after)"
custom.cmake-after = "message(STATUS custom-after)"
build-tests.cmake-after = "message(STATUS build-tests)"
"CONDITIONS_BUILD_TESTS AND $<linux>".cmake-after = "message(STATUS linux-tests)"
[target.example.properties]
AUTOMOC = false
custom.OUTPUT_NAME = "example2"
custom.AUTORCC = true
AUTOGEN = "ON"
+2
View File
@@ -0,0 +1,2 @@
int main() {
}
@@ -0,0 +1,4 @@
#include <Windows.h>
void foo() {
}
+12
View File
@@ -0,0 +1,12 @@
# Require a C++11 compiler for the target `example`.
[project]
name = "cxx-standard"
description = "Changing C++ standard"
[target.example]
type = "executable"
sources = ["src/main.cpp"]
compile-features = ["cxx_std_11"]
# This is equivalent to CMake's [target_compile_features](https://cmake.org/cmake/help/latest/command/target_compile_features.html)`(example PRIVATE cxx_std_11)`. For more information on available C/C++ standards and features see [cmake-compile-features(7)](https://cmake.org/cmake/help/latest/manual/cmake-compile-features.7.html).
+7
View File
@@ -0,0 +1,7 @@
#include <cstdio>
#include <tuple>
int main() {
auto tpl = std::make_tuple(1, 2);
printf("Hello from C++11 %d\n", std::get<0>(tpl));
}
+16
View File
@@ -0,0 +1,16 @@
# Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) from [GitHub](https://github.com) and links an `example` target to it:
[project]
name = "fetch-content"
description = "Fetching from git"
[fetch-content.fmt]
git = "https://github.com/fmtlib/fmt"
tag = "7.1.3"
[target.example]
type = "executable"
sources = ["src/main.cpp"]
link-libraries = ["fmt::fmt"]
# This is equivalent to calling CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html).
+5
View File
@@ -0,0 +1,5 @@
#include <fmt/core.h>
int main() {
fmt::print("Hello, world!\n");
}
+18
View File
@@ -0,0 +1,18 @@
[project]
name = "globbing"
description = "Globbing sources"
# Recursively glob in the mylib/ folder
[target.mylib]
type = "static"
alias = "mylib::mylib"
sources = ["mylib/**.hpp", "mylib/**.cpp"]
include-directories = ["mylib/include"]
# Single-folder glob in example/src/
[target.example]
type = "executable"
sources = ["example/src/*.cpp"]
link-libraries = ["mylib::mylib"]
# As you can see in the example above you can use `**.ext` to glob recursively and `*.ext` to glob non-recursively. This **does not** generate `file(GLOB ...)` commands, but instead globs when cmkr is run. Files are sorted to give deterministic results regardless of the platform used.
+7
View File
@@ -0,0 +1,7 @@
#include <iostream>
#include <mylib/mylib.hpp>
int main() {
std::cout << mylib::message() << std::endl;
return 0;
}
@@ -0,0 +1,7 @@
#pragma once
#include <string>
namespace mylib {
std::string message();
} // namespace mylib
+5
View File
@@ -0,0 +1,5 @@
#include <mylib/mylib.hpp>
std::string mylib::message() {
return "cmkr is awesome!";
}
+13
View File
@@ -0,0 +1,13 @@
[project]
name = "interface"
description = "Header-only library"
[target.mylib]
type = "interface"
include-directories = ["include"]
compile-features = ["cxx_std_11"]
[target.example]
type = "executable"
sources = ["src/main.cpp"]
link-libraries = ["mylib"]
+5
View File
@@ -0,0 +1,5 @@
namespace mylib {
static const char *version() {
return "v1.0";
}
} // namespace mylib
+7
View File
@@ -0,0 +1,7 @@
#include <cstdio>
#include "mylib/mylib.hpp"
int main() {
printf("mylib version: %s\n", mylib::version());
}
+15
View File
@@ -0,0 +1,15 @@
[project]
name = "msvc-runtime"
description = "Static MSVC runtime"
msvc-runtime = "static"
# This target will compile with a static runtime
[target.static-runtime]
type = "executable"
sources = ["src/main.cpp"]
# This target overrides the [project].msvc-runtime
[target.dynamic-runtime]
type = "executable"
sources = ["src/main.cpp"]
msvc-runtime = "dynamic"
+5
View File
@@ -0,0 +1,5 @@
#include <cstdio>
int main() {
puts("Hello from cmkr(msvc-static)!");
}
+13
View File
@@ -0,0 +1,13 @@
# Add Objective-C sources on Apple platforms:
[project]
name = "objective-c"
description = "Objective-C"
languages = ["C"]
apple.languages = ["OBJC"]
[target.hello]
type = "executable"
sources = ["src/main.c"]
apple.sources = ["src/apple.m"]
apple.link-libraries = ["$<LINK_LIBRARY:FRAMEWORK,Foundation>"]
+7
View File
@@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
void platform_specific() {
NSFileHandle *stdout = [NSFileHandle fileHandleWithStandardOutput];
NSString *message = @"Hello from Objective-C!\n";
[stdout writeData:[message dataUsingEncoding:NSUTF8StringEncoding] error:nil];
}
+14
View File
@@ -0,0 +1,14 @@
#include <stdio.h>
#ifdef __APPLE__
void platform_specific();
#else
void platform_specific() {
puts("This is not an Apple platform.");
}
#endif
int main() {
platform_specific();
return 0;
}
+11
View File
@@ -0,0 +1,11 @@
[project]
name = "relative-paths"
[target.test-library]
type = "static"
sources = ["src/library-code.cpp"]
[target.example]
type = "executable"
sources = ["src/main.cpp"]
windows.link-libraries = ["libs/test-library-x64-Release.lib"]

Some files were not shown because too many files have changed in this diff Show More