Compare commits

..

189 Commits

Author SHA1 Message Date
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
90 changed files with 29510 additions and 1759 deletions
+1
View File
@@ -0,0 +1 @@
CMakeLists.txt linguist-generated
+1
View File
@@ -0,0 +1 @@
github: [mrexodia]
+44 -3
View File
@@ -4,21 +4,62 @@ on: [push, pull_request]
jobs:
build:
# 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-2019, macos-10.15, ubuntu-20.04]
env:
BUILD_TYPE: Release
steps:
- name: Checkout
uses: actions/checkout@v2
- 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@v2
with:
name: ${{ github.event.repository.name }}-${{ matrix.os }}
path: install/bin/*
- name: Get lowercase OS name
id: osname
uses: ASzc/change-string-case-action@v1
with:
string: ${{ runner.os }}
- name: Compress artifacts
uses: vimtor/action-zip@v1
with:
files: install/bin/
dest: ${{ github.event.repository.name }}-${{ steps.osname.outputs.lowercase }}.zip
- name: Release
uses: softprops/action-gh-release@v1
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
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-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.
+70 -51
View File
@@ -1,18 +1,17 @@
# 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)
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()
@@ -22,20 +21,18 @@ if(CMKR_ROOT_PROJECT)
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.12
DESCRIPTION
"CMakeLists generator from TOML"
)
include("cmake/generate_documentation.cmake")
include("cmake/generate_resources.cmake")
# third_party
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
if(CMAKE_FOLDER)
@@ -57,52 +54,57 @@ add_subdirectory(tests)
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
# 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"
cmake.toml
)
add_library(cmkrlib STATIC ${cmkrlib_SOURCES})
# Target cmkr_generate_documentation
set(CMKR_TARGET cmkr_generate_documentation)
set(cmkr_generate_documentation_SOURCES "")
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkrlib_SOURCES})
set(CMKR_SOURCES ${cmkr_generate_documentation_SOURCES})
add_library(cmkr_generate_documentation INTERFACE)
target_compile_features(cmkrlib PUBLIC
cxx_std_11
)
if(cmkr_generate_documentation_SOURCES)
target_sources(cmkr_generate_documentation INTERFACE ${cmkr_generate_documentation_SOURCES})
endif()
target_include_directories(cmkrlib PUBLIC
include
)
generate_documentation()
target_link_libraries(cmkrlib PUBLIC
toml11
ghc_filesystem
mpark_variant
ordered_map
)
unset(CMKR_TARGET)
unset(CMKR_SOURCES)
# Target cmkr
set(cmkr_SOURCES
set(CMKR_TARGET cmkr)
set(cmkr_SOURCES "")
list(APPEND cmkr_SOURCES
"src/arguments.cpp"
"src/build.cpp"
"src/cmake_generator.cpp"
"src/error.cpp"
"src/help.cpp"
"src/main.cpp"
"src/project_parser.cpp"
"include/arguments.hpp"
"include/build.hpp"
"include/cmake_generator.hpp"
"include/error.hpp"
"include/fs.hpp"
"include/help.hpp"
"include/literals.hpp"
"include/project_parser.hpp"
"cmake/cmkr.cmake"
"cmake/version.hpp.in"
)
list(APPEND cmkr_SOURCES
cmake.toml
)
add_executable(cmkr ${cmkr_SOURCES})
set(CMKR_SOURCES ${cmkr_SOURCES})
add_executable(cmkr)
if(cmkr_SOURCES)
target_sources(cmkr PRIVATE ${cmkr_SOURCES})
endif()
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
if(NOT CMKR_VS_STARTUP_PROJECT)
@@ -111,15 +113,32 @@ endif()
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkr_SOURCES})
target_link_libraries(cmkr PRIVATE
cmkrlib
target_compile_features(cmkr PRIVATE
cxx_std_11
)
target_include_directories(cmkr PRIVATE
include
)
target_link_libraries(cmkr PRIVATE
toml11
ghc_filesystem
mpark_variant
ordered_map
nlohmann_json
)
generate_resources(${CMKR_TARGET})
unset(CMKR_TARGET)
unset(CMKR_SOURCES)
install(
TARGETS
cmkr
DESTINATION
"${CMAKE_INSTALL_PREFIX}/bin"
bin
COMPONENT
cmkr
)
+40 -128
View File
@@ -1,127 +1,55 @@
# cmkr
cmkr, pronounced "cmaker", is A CMakeLists.txt generator from TOML.
`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:
## 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
```
## 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 from CMake and you only need CMake 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, modify [`cmake.toml`](https://build-cpp.github.io/cmkr/cmake-toml) and open the project in your favorite IDE or build with 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`.
In CI settings the `cmkr` bootstrapping process is skipped so there is no extra configure-time 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:
@@ -133,28 +61,12 @@ arguments:
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!
- https://github.com/gulrak/filesystem
- https://github.com/Tessil/ordered-map
- https://github.com/ToruNiina/toml11
- https://github.com/mpark/variant
- https://www.svgrepo.com/svg/192268/hammer
- https://github.com/can1357 for buying `cmkr.build` ❤️
+32 -15
View File
@@ -1,30 +1,47 @@
[cmake]
version = "2.8...3.8"
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.12"
description = "CMakeLists generator from TOML"
languages = ["CXX"]
subdirs = ["third_party", "tests"]
include-after = [
"cmake/generate_documentation.cmake",
"cmake/generate_resources.cmake"
]
[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",
"nlohmann_json",
]
cmake-after = """
generate_resources(${CMKR_TARGET})
"""
[[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"]
+236 -147
View File
@@ -1,147 +1,236 @@
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.12" 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} AND EXISTS "$ENV{CMKR_CACHE}")
set(CMKR_DIRECTORY_PREFIX "$ENV{CMKR_CACHE}")
string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
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}")
# Handle upgrading logic
if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE)
if(CMKR_EXECUTABLE MATCHES "^${CMAKE_CURRENT_BINARY_DIR}/_cmkr")
if(DEFINED ENV{CMKR_CACHE} AND EXISTS "$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 EXISTS "$ENV{CMKR_CACHE}" AND CMKR_EXECUTABLE MATCHES "^${CMKR_DIRECTORY_PREFIX}")
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()
+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})
set(CMKR_TESTS "" CACHE INTERNAL "List of test directories in the order declared in tests/cmake.toml")
if(CMKR_GENERATE_DOCUMENTATION)
# Hook the add_test function to capture the tests in the order declared in tests/cmake.toml
function(add_test)
cmake_parse_arguments(TEST "" "WORKING_DIRECTORY" "" ${ARGN})
get_filename_component(TEST_WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}" NAME)
list(APPEND CMKR_TESTS "${TEST_WORKING_DIRECTORY}")
set(CMKR_TESTS "${CMKR_TESTS}" CACHE INTERNAL "")
_add_test(${test} ${ARGN})
endfunction()
endif()
function(generate_documentation)
if(CMKR_GENERATE_DOCUMENTATION)
message(STATUS "[cmkr] Generating documentation...")
# 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";
}
}
-6
View File
@@ -1,6 +0,0 @@
#include <cstdio>
int main()
{
puts("Hello from cmkr!");
}
+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
+24
View File
@@ -0,0 +1,24 @@
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
production_url : https://cmkr.build
+206
View File
@@ -0,0 +1,206 @@
---
layout: page
title: Reference
permalink: /cmake-toml/
nav_order: 1
---
# 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).
See the [examples](/examples) section for concrete examples.
## 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"]
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"]
```
## Conditions
You can specify your own conditions and use them in any `condition` field:
```toml
[conditions]
arch64 = "CMAKE_SIZEOF_VOID_P EQUALS 8"
arch32 = "CMAKE_SIZEOF_VOID_P EQUALS 4"
```
This will make the `arch64` and `arch32` conditions available with their respective CMake expressions.
You can also prefix most keys with `condition.` to represent a conditional:
```toml
[target]
type = "executable"
sources = ["src/main.cpp"]
windows.sources = ["src/windows_specific.cpp"]
```
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\""
clang = "CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" OR CMAKE_C_COMPILER_ID MATCHES \"Clang\""
msvc = "MSVC"
root = "CMKR_ROOT_PROJECT"
x64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
x32 = "CMAKE_SIZEOF_VOID_P EQUAL 4"
```
## 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"]
```
## Vcpkg
```toml
[vcpkg]
version = "2021.05.12"
url = "https://github.com/microsoft/vcpkg/archive/refs/tags/2021.05.12.tar.gz"
packages = ["fmt", "zlib"]
```
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).
To specify package features you can use the following syntax: `imgui[docking-experimental,freetype,sdl2-binding,opengl3-binding]`.
## 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
[fetch-content.gitcontent]
condition = "mycondition"
git = "https://github.com/myuser/gitcontent"
tag = "v0.1"
[fetch-content.svncontent]
condition = "mycondition"
svn = "https://svn-host.com/url"
rev = "svn_rev"
[fetch-content.urlcontent]
condition = "mycondition"
url = "https://content-host.com/urlcontent.zip"
hash = "123123123123"
```
## Targets
```toml
[target.mytarget]
condition = "mycondition"
alias = "mytarget::mytarget"
type = "static" # executable, shared (DLL), static, interface, object, library, custom
headers = ["src/mytarget.h"]
sources = ["src/mytarget.cpp"]
# The keys below match the target_xxx CMake commands
# Keys prefixed with private- will get PRIVATE visibility
compile-definitions = [""]
private-compile-definitions = [""]
compile-features = [""]
private-compile-features = [""]
compile-options = [""]
private-compile-options = [""]
include-directories = [""]
private-include-directories = [""]
link-directories = [""]
private-link-directories = [""]
link-libraries = [""]
private-link-libraries = [""]
link-options = [""]
private-link-options = [""]
precompile-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"
```
## 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"]
files = ["content/my.png"]
dirs = [""]
configs = [""]
```
+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>
+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>
+30
View File
@@ -0,0 +1,30 @@
---
# 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>
+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
[template.app.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>
+38
View File
@@ -0,0 +1,38 @@
---
# 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://vcpkg.io/) 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.html for available packages
[vcpkg]
version = "2021.05.12"
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

+77
View File
@@ -0,0 +1,77 @@
---
layout: home
title: Index
nav_order: 0
---
# Index
`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 from CMake and you only need CMake 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, modify [`cmake.toml`](https://build-cpp.github.io/cmkr/cmake-toml) and open the project in your favorite IDE or build with 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`.
In CI settings the `cmkr` bootstrapping process is skipped so there is no extra configure-time 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.
gen Generates CMakeLists.txt file.
build <extra cmake args> Run cmake and build.
install Run cmake --install. Needs admin privileges.
clean Clean the build directory.
help Show help.
version Current cmkr version.
```
## Credits
- https://github.com/gulrak/filesystem
- https://github.com/Tessil/ordered-map
- https://github.com/ToruNiina/toml11
- https://github.com/mpark/variant
- https://www.svgrepo.com/svg/192268/hammer
View File
+2
View File
@@ -0,0 +1,2 @@
bundle exec just-the-docs rake search:init
bundle exec jekyll serve --livereload
+2
View File
@@ -0,0 +1,2 @@
bundle install
bundle exec jekyll serve --force_polling --livereload --incremental
-8
View File
@@ -1,6 +1,5 @@
#pragma once
#ifdef __cplusplus
namespace cmkr {
namespace args {
@@ -9,11 +8,4 @@ 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
+2 -10
View File
@@ -1,7 +1,5 @@
#pragma once
#ifdef __cplusplus
namespace cmkr {
namespace build {
@@ -13,15 +11,9 @@ 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_clean();
int cmkr_build_install(void);
#ifdef __cplusplus
}
#endif
int cmkr_build_install();
+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
-8
View File
@@ -1,6 +1,5 @@
#pragma once
#ifdef __cplusplus
namespace cmkr {
namespace error {
@@ -25,11 +24,4 @@ struct Status {
} // namespace error
} // namespace cmkr
extern "C" {
#endif
const char *cmkr_error_status_string(int);
#ifdef __cplusplus
}
#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
-8
View File
@@ -1,6 +1,5 @@
#pragma once
#ifdef __cplusplus
namespace cmkr {
namespace help {
@@ -11,13 +10,6 @@ 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
+194
View File
@@ -0,0 +1,194 @@
#pragma once
#include <mpark/variant.hpp>
#include <string>
#include <tsl/ordered_map.h>
#include <vector>
namespace cmkr {
namespace parser {
template <typename T>
using Condition = tsl::ordered_map<std::string, T>;
using ConditionVector = Condition<std::vector<std::string>>;
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 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;
};
std::vector<Package> packages;
};
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 headers;
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;
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;
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;
};
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;
};
struct Project {
// 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;
std::vector<std::string> project_languages;
Condition<std::string> cmake_before;
Condition<std::string> cmake_after;
ConditionVector include_before;
ConditionVector include_after;
std::vector<Setting> settings;
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);
};
bool is_root_path(const std::string &path);
} // namespace parser
} // namespace cmkr
+8 -11
View File
@@ -1,7 +1,7 @@
#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>
@@ -21,9 +21,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,15 +31,14 @@ 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!";
return "CMake build completed!";
} else if (main_arg == "install") {
auto ret = build::install();
if (ret)
+26 -27
View File
@@ -1,46 +1,45 @@
#include "build.h"
#include "cmake.hpp"
#include "error.h"
#include "gen.h"
#include "build.hpp"
#include "cmake_generator.hpp"
#include "error.hpp"
#include "project_parser.hpp"
#include "fs.hpp"
#include <cstddef>
#include <cstdlib>
#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);
parser::Project project(nullptr, ".", true);
if (argc > 2) {
for (size_t i = 2; i < argc; ++i) {
cmake.build_args.push_back(argv[i]);
for (int i = 2; i < argc; ++i) {
project.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!");
gen::generate_cmake(fs::current_path().string().c_str());
ss << "cmake -S. -B" << cmake.build_dir << " ";
ss << "cmake -DCMKR_BUILD_SKIP_GENERATION=ON -B" << project.build_dir << " ";
if (!cmake.generator.empty()) {
ss << "-G \"" << cmake.generator << "\" ";
if (!project.generator.empty()) {
ss << "-G \"" << project.generator << "\" ";
}
if (!cmake.config.empty()) {
ss << "-DCMAKE_BUILD_TYPE=" << cmake.config << " ";
if (!project.config.empty()) {
ss << "-DCMAKE_BUILD_TYPE=" << project.config << " ";
}
if (!cmake.gen_args.empty()) {
for (const auto &arg : cmake.gen_args) {
if (!project.gen_args.empty()) {
for (const auto &arg : project.gen_args) {
ss << "-D" << arg << " ";
}
}
ss << "&& cmake --build " << cmake.build_dir << " --parallel";
ss << "&& cmake --build " << project.build_dir << " --parallel";
if (argc > 2) {
for (const auto &arg : cmake.build_args) {
for (const auto &arg : project.build_args) {
ss << " " << arg;
}
}
@@ -50,17 +49,17 @@ int run(int argc, char **argv) {
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);
parser::Project project(nullptr, ".", true);
if (fs::exists(project.build_dir)) {
ret = fs::remove_all(project.build_dir);
fs::create_directory(project.build_dir);
}
return !ret;
}
int install() {
cmake::CMake cmake(".", false);
auto cmd = "cmake --install " + cmake.build_dir;
parser::Project project(nullptr, ".", false);
auto cmd = "cmake --install " + project.build_dir;
return ::system(cmd.c_str());
}
} // namespace build
@@ -94,4 +93,4 @@ int cmkr_build_install(void) {
} catch (...) {
return cmkr::error::Status(cmkr::error::Status::Code::InstallError);
}
}
}
File diff suppressed because it is too large Load Diff
-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);
}
-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);
}
}
+7 -6
View File
@@ -1,6 +1,6 @@
#include "error.h"
#include "error.hpp"
#include <assert.h>
#include <cassert>
namespace cmkr {
namespace error {
@@ -14,11 +14,12 @@ 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",
// strings for cmkr::error::Status::Code
static const char *err_string[] = {
"Success", "Runtime error", "Initialization error", "CMake generation error", "Build error", "Clean error", "Install error",
};
const char *cmkr_error_status(int i) {
assert(i >= 0 && i < 5);
assert(i >= 0 && i < (sizeof(err_string) / sizeof(*(err_string))));
return err_string[i];
}
}
+3 -2
View File
@@ -1,9 +1,10 @@
#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(
+1 -1
View File
@@ -1,4 +1,4 @@
#include "args.h"
#include "arguments.hpp"
#include <cstdio>
#include <cstdlib>
+665
View File
@@ -0,0 +1,665 @@
#include "project_parser.hpp"
#include "fs.hpp"
#include <deque>
#include <stdexcept>
#include <toml.hpp>
#include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>
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;
}
using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector>;
static std::string format_key_error(const std::string &error, 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();
auto line_str = loc.line_str();
std::ostringstream oss;
oss << "[error] " << error << '\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();
}
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)) {}
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)) {
throw std::runtime_error(format_key_error("Unknown condition '" + ky + "'", ky, itr.second));
}
for (const auto &jtr : itr.second.as_table()) {
if (!m_visited.contains(jtr.first)) {
throw std::runtime_error(format_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 std::runtime_error(format_key_error("Unknown key '" + jtr.first + "'", jtr.first, jtr.second));
}
}
}
throw std::runtime_error(format_key_error("Unknown key '" + ky + "'", ky, itr.second));
} else if (ky == "condition") {
std::string condition = itr.second.as_string();
if (!conditions.contains(condition)) {
throw std::runtime_error(format_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:
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 std::runtime_error(format_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) {
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 std::runtime_error("bin-dir has been renamed to build-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["clang"] = R"cmake(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "Clang")cmake";
conditions["msvc"] = R"cmake(MSVC)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";
} else {
conditions = parent->conditions;
templates = parent->templates;
}
if (checker.contains("conditions")) {
auto conds = toml::find<decltype(conditions)>(toml, "conditions");
for (const auto &cond : conds) {
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);
project.optional("languages", project_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);
}
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("settings")) {
using set_map = tsl::ordered_map<std::string, TomlBasicValue>;
const auto &sets = toml::find<set_map>(toml, "settings");
for (const auto &itr : sets) {
Setting s;
s.name = itr.first;
const auto &value = itr.second;
if (value.is_boolean()) {
s.val = value.as_boolean();
} else if (value.is_string()) {
s.val = value.as_string();
} else {
auto &setting = checker.create(value);
setting.optional("comment", s.comment);
if (setting.contains("value")) {
const auto &v = setting.find("value");
if (v.is_boolean()) {
s.val = v.as_boolean();
} else {
s.val = v.as_string();
}
}
setting.optional("cache", s.cache);
setting.optional("force", s.force);
}
settings.push_back(s);
}
}
if (checker.contains("options")) {
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.val = value.as_boolean();
} else {
auto &option = checker.create(value);
option.optional("comment", o.comment);
option.optional("value", o.val);
}
options.push_back(o);
}
}
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);
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 c : key) {
algo.push_back(std::toupper(c));
}
key = "URL_HASH";
value = algo + "=" + value;
} else if (key == "hash") {
key = "URL_HASH";
} else if (is_cmake_arg(key)) {
// allow passthrough of ExternalProject options
} else if (!c.visisted(key)) {
throw std::runtime_error(format_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 std::runtime_error("[[bin]] has been renamed to [[target]]");
}
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 std::runtime_error(format_key_error(error, target.type_name, t.find("type")));
}
t.optional("headers", target.headers);
t.optional("sources", target.sources);
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);
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);
if (!target.headers.empty()) {
auto &sources = target.sources.nth(0).value();
const auto &headers = target.headers.nth(0)->second;
sources.insert(sources.end(), headers.begin(), headers.end());
}
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_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 std::runtime_error(format_key_error("Reserved template name '" + name + "'", name, itr.second));
}
}
for (const auto &tmplate : templates) {
if (name == tmplate.outline.name) {
throw std::runtime_error(format_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("pass-sources-to-add-function", 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);
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, ',')) {
package.features.emplace_back(feature);
}
} else {
throw std::runtime_error("Invalid vcpkg package '" + package_str + "'");
}
vcpkg.packages.emplace_back(std::move(package));
}
}
checker.check(conditions, 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
+3
View File
@@ -0,0 +1,3 @@
# These will be generated by cmkr, so no point in tracking them
**/CMakeLists.txt
**/cmkr.cmake
+72 -1
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)
@@ -17,3 +18,73 @@ add_test(
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
)
-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)`.
+44 -2
View File
@@ -1,5 +1,47 @@
[[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"]
+23
View File
@@ -0,0 +1,23 @@
[project]
name = "conditions"
cmake-after = "set(CUSTOM ON)"
[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)"
[target.example.properties]
AUTOMOC = false
custom.OUTPUT_NAME = "example2"
custom.AUTORCC = true
AUTOGEN = "ON"
+1
View File
@@ -0,0 +1 @@
int main() { }
+3
View File
@@ -0,0 +1,3 @@
#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).
+8
View File
@@ -0,0 +1,8 @@
#include <cstdio>
#include <tuple>
int main()
{
auto tpl = std::make_tuple(1, 2);
printf("Hello from C++11 %d\n", std::get<0>(tpl));
}
+15
View File
@@ -0,0 +1,15 @@
# 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).
+6
View File
@@ -0,0 +1,6 @@
#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,8 @@
#pragma once
#include <string>
namespace mylib
{
std::string message();
}
+6
View File
@@ -0,0 +1,6 @@
#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"]
+4
View File
@@ -0,0 +1,4 @@
namespace mylib
{
static const char* version() { return "v1.0"; }
} // namespace mylib
+8
View File
@@ -0,0 +1,8 @@
#include <cstdio>
#include "mylib/mylib.hpp"
int main()
{
printf("mylib version: %s\n", mylib::version())
}
+25
View File
@@ -0,0 +1,25 @@
# 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.
[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
[template.app.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.
+13
View File
@@ -0,0 +1,13 @@
#include <cstdio>
#if !defined(IS_APP)
#error Something went wrong with the template
#endif // IS_APP
int main() {
#if defined(APP_A)
puts("Hello from app A!");
#elif defined(APP_B)
puts("Hello from app B!");
#endif
}
+22
View File
@@ -0,0 +1,22 @@
# Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) using [vcpkg](https://vcpkg.io/) and links an `example` target to it:
[project]
name = "vcpkg"
description = "Dependencies from vcpkg"
# See https://github.com/microsoft/vcpkg/releases for vcpkg versions
# See https://vcpkg.io/en/packages.html for available packages
[vcpkg]
version = "2021.05.12"
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]`.
+6
View File
@@ -0,0 +1,6 @@
#include <fmt/core.h>
int main()
{
fmt::print("Hello, world!\n");
}
+11
View File
@@ -0,0 +1,11 @@
{
"$cmkr": "This file is automatically generated from cmake.toml - DO NOT EDIT",
"$cmkr-url": "https://github.com/build-cpp/cmkr",
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
"dependencies": [
"fmt"
],
"description": "Dependencies from vcpkg",
"name": "vcpkg",
"version-string": ""
}
Generated Vendored
+4
View File
@@ -16,3 +16,7 @@ target_include_directories(toml11 INTERFACE toml11-3.6.0)
# https://github.com/mpark/variant (BSL-1.0)
add_library(mpark_variant INTERFACE)
target_include_directories(mpark_variant INTERFACE variant-1.4.0/include)
# https://github.com/nlohmann/json (MIT)
add_library(nlohmann_json INTERFACE)
target_include_directories(nlohmann_json INTERFACE nlohmann-3.9.1/include)
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2013-2021 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
File diff suppressed because it is too large Load Diff