Compare commits

..

128 Commits

Author SHA1 Message Date
Duncan Ogilvie 3caf593438 Bump to 0.2.42 2024-12-03 15:35:05 +01:00
Duncan Ogilvie c94dbd6416 Merge pull request #168 from build-cpp/target-directory-bug
Fix linking against a target that's also a directory
2024-12-03 13:41:16 +01:00
Duncan Ogilvie a1eaf601c6 Fix linking against a target that's also a directory
Closes #166
2024-12-03 13:39:32 +01:00
Duncan Ogilvie 10320c8e55 Bump to 0.2.41 2024-12-02 15:56:02 +01:00
Duncan Ogilvie 45e12c8d98 Merge pull request #165 from build-cpp/cmake-support
Fix vcpkg support for CMake 3.30
2024-12-02 15:55:43 +01:00
Duncan Ogilvie e12ebc060d Use FetchContent_MakeAvailable for vcpkg 2024-12-02 15:54:19 +01:00
Duncan Ogilvie c6e3fc159f Suppress deprecation warning for CMake <3.10 2024-12-02 15:50:22 +01:00
Duncan Ogilvie dc6f306d9c Bump to 0.2.40 2024-11-28 23:02:34 +01:00
Duncan Ogilvie e08bd5a311 Merge pull request #164 from build-cpp/vcpkg-overlay-bugfix
Use absolute paths for vcpkg overlays
2024-11-28 23:02:17 +01:00
Duncan Ogilvie 068977e2f5 Use absolute paths for vcpkg overlays 2024-11-28 23:01:14 +01:00
Duncan Ogilvie 73147747a4 Bump to 0.2.39 2024-11-28 21:26:27 +01:00
Duncan Ogilvie a64fa9cc34 Merge pull request #163 from build-cpp/vcpkg-fetch-folder
Move vcpkg download location directly in `${CMAKE_BINARY_DIR}/vcpkg`
2024-11-28 21:25:53 +01:00
Duncan Ogilvie eb6ccb39ee Move vcpkg download location directly in ${CMAKE_BINARY_DIR} 2024-11-28 21:24:03 +01:00
Duncan Ogilvie 91dd8ce51f Bump to 0.2.38 2024-11-28 14:40:22 +01:00
Duncan Ogilvie efbfca27bd Merge pull request #160 from build-cpp/vcpkg-triplets
Add support for `[vcpkg].overlay-triplets`
2024-11-28 14:38:46 +01:00
Duncan Ogilvie 78bcf2acf7 Add support for [vcpkg].overlay-triplets 2024-11-28 14:28:10 +01:00
Duncan Ogilvie 83559cc5d4 Improve target reference documentation 2024-11-28 14:28:08 +01:00
Duncan Ogilvie 5d85cc83e3 Ignore generated vcpkg.json 2024-11-28 13:44:11 +01:00
Duncan Ogilvie dea41d80b5 Bump to 0.2.37 2024-11-27 14:17:48 +01:00
Duncan Ogilvie b52cf5b241 Merge pull request #158 from build-cpp/vcpkg-default-features
Allow disabling default features with vcpkg
2024-11-27 14:16:25 +01:00
Duncan Ogilvie e9480a625f Allow disabling default features with vcpkg 2024-11-27 14:13:37 +01:00
Duncan Ogilvie 13a7a8788a Bump to 0.2.36 2024-11-26 13:36:24 +01:00
Duncan Ogilvie 45ca74099c Merge pull request #156 from build-cpp/vcpkg-overlay-ports
Add [vcpkg].overlay-ports feature
2024-11-26 13:35:32 +01:00
Duncan Ogilvie ae3d73896e Add [vcpkg].overlay-ports feature 2024-11-26 12:33:29 +01:00
Duncan Ogilvie 57042565d1 Merge pull request #154 from build-cpp/configure-depends
Use CMAKE_CONFIGURE_DEPENDS when supported
2024-11-03 11:44:02 +01:00
deep d02ee3ed24 Added check to make sure hash is valid hex (#153) 2024-11-03 10:49:33 +01:00
Duncan Ogilvie 4a15d2ba55 Use CMAKE_CONFIGURE_DEPENDS when supported 2024-11-03 10:33:32 +01:00
Duncan Ogilvie 87c0295f93 Fix CI 2024-10-14 13:02:20 +02:00
Duncan Ogilvie a608e6b778 Bump to 0.2.35 2024-10-13 16:16:36 +02:00
Duncan Ogilvie 523f5f4a8a Merge pull request #150 from build-cpp/msvc-runtime-root
Only emit `MSVC_RUNTIME_LIBRARY` in the root project
2024-09-06 14:39:47 +02:00
Duncan Ogilvie 510cf71af5 Only emit MSVC_RUNTIME_LIBRARY in the root project 2024-09-06 14:33:04 +02:00
Duncan Ogilvie 87d90138b4 Merge pull request #149 from build-cpp/relative-libs
Improve relative path functionality for link-libraries
2024-09-06 14:25:33 +02:00
Duncan Ogilvie 50615e0c27 Bump clang-format-lint-action
https://github.com/DoozyX/clang-format-lint-action/issues/73
2024-09-06 14:22:12 +02:00
Duncan Ogilvie 42ed3048b3 Improve relative path functionality for link-libraries 2024-09-06 13:50:43 +02:00
Duncan Ogilvie b0a1d79a42 Bump to 0.2.34 2024-08-05 15:28:58 +02:00
Duncan Ogilvie 5882bc082d Support integer properties
Closes #148
2024-08-05 15:28:38 +02:00
Duncan Ogilvie a90b3c6095 Add RC as a default language 2024-08-05 15:28:16 +02:00
Duncan Ogilvie 0a887c08f8 Bump to 0.2.33 2024-07-06 14:50:39 +02:00
Duncan Ogilvie 9f2cfe4083 Merge pull request #146 from build-cpp/improved-conditions
Improve error-prone condition handling
2024-07-06 14:49:32 +02:00
Duncan Ogilvie 15ad1dc6a7 Support nested condition syntax for named conditions 2024-07-06 14:43:32 +02:00
Duncan Ogilvie dabffeaed9 Add back the option name as a named condition 2024-07-06 14:43:32 +02:00
Duncan Ogilvie 59fe5c38b8 Consider PROJECT_OPTION to be a valid condition 2024-07-06 14:43:32 +02:00
Duncan Ogilvie dcdc7ac410 Add a few more default named conditions 2024-07-06 14:43:32 +02:00
Duncan Ogilvie 88377a8bfb Bump to 0.2.32 2024-07-06 14:03:55 +02:00
Duncan Ogilvie 3a9685be82 Merge pull request #145 from build-cpp/system-bug
Fix uninitialized 'system' field for fetch-content
2024-07-06 14:03:08 +02:00
Duncan Ogilvie 5576789c18 Fix uninitialized 'system' field for fetch-content 2024-07-06 14:02:33 +02:00
Duncan Ogilvie a362978f99 Bump to 0.2.31 2024-06-21 00:33:33 +02:00
Duncan Ogilvie a2f33297e4 Merge pull request #144 from build-cpp/msvc-runtime-subproject
Do not set CMAKE_MSVC_RUNTIME_LIBRARY if it's already set
2024-06-21 00:32:50 +02:00
Duncan Ogilvie 674c976647 Do not set CMAKE_MSVC_RUNTIME_LIBRARY if it's already set 2024-06-21 00:32:30 +02:00
Duncan Ogilvie 714a666e88 Merge pull request #143 from build-cpp/project-improvements
Project improvements
2024-06-01 01:25:26 +02:00
Duncan Ogilvie d613e433d5 Skip linting on pull requests for the same repository 2024-06-01 00:55:31 +02:00
Duncan Ogilvie 7c828d8740 Add custom targets for running cmkr/tests 2024-06-01 00:55:31 +02:00
Duncan Ogilvie 559f750c89 Fix undefined behavior with std::tolower/toupper 2024-06-01 00:55:29 +02:00
Duncan Ogilvie 4b6b72874e Remove nlohmann_json 2024-05-31 22:45:27 +02:00
Duncan Ogilvie 6bffa7cc71 Bump to 0.2.30 2024-05-31 22:36:39 +02:00
Duncan Ogilvie f415b432ed Also run linting on pull requests 2024-05-31 22:34:27 +02:00
Duncan Ogilvie 6c46664336 Merge pull request #142 from anthonyprintup/globbing-extension-fix
Fixed globbing when multiple extensions are present in the file name
2024-05-31 22:31:18 +02:00
Duncan Ogilvie f32aac63aa Review improvements 2024-05-31 22:24:01 +02:00
Anthony Printup 33d4cc4156 Fixed globbing when multiple extensions are present in the file name 2024-05-30 00:36:14 +02:00
Duncan Ogilvie 9288c8a87d Bump to 0.2.29 2024-04-15 03:08:33 +02:00
Duncan Ogilvie e36eee4420 Merge pull request #140 from build-cpp/improved-conditions
Allow arbitrary CMake expressions as conditions
2024-04-15 03:08:02 +02:00
Duncan Ogilvie 53820c9f65 Support $<condition> in unnamed conditions 2024-04-15 03:01:51 +02:00
Duncan Ogilvie ff7e4b8f23 Allow arbitrary CMake expressions as conditions 2024-04-15 02:12:02 +02:00
Duncan Ogilvie 1072cb44e2 Bump to 0.2.28 2024-04-14 00:08:11 +02:00
Duncan Ogilvie 926fc15fa2 Merge pull request #139 from build-cpp/vcpkg-bump
Bump to the latest vcpkg
2024-04-14 00:06:00 +02:00
Duncan Ogilvie e2c929adb0 Fix out-of-the-box vcpkg experience on macos 2024-04-13 23:57:30 +02:00
Duncan Ogilvie 0dec7ca4d5 Bump to the latest vcpkg 2024-04-13 23:21:25 +02:00
Duncan Ogilvie 45e346b4a3 Bump to 0.2.27 2024-03-28 11:38:01 +01:00
Duncan Ogilvie 7165986190 Merge pull request #138 from build-cpp/find-package-first
Generate find-package before fetch-content
2024-03-28 11:37:31 +01:00
Duncan Ogilvie be0ef6d615 Generate find-package before fetch-content 2024-03-28 11:36:15 +01:00
Duncan Ogilvie d607b9028c Bump to 0.2.26 2023-11-09 13:32:05 +01:00
Duncan Ogilvie 099b14552c Merge pull request #131 from build-cpp/fetch-subdir
Add [fetch-content].subdir
2023-11-09 13:31:48 +01:00
Duncan Ogilvie 771c80a41a Add [fetch-content].subdir
Closes #98
2023-11-09 13:28:29 +01:00
Duncan Ogilvie 58c7de1d60 Merge pull request #129 from build-cpp/gitignore-improvement
Improve the default .gitignore that's generated
2023-10-18 13:22:44 +02:00
Duncan Ogilvie a61e4bb999 Merge pull request #128 from build-cpp/language-documentation
Document the supported languages
2023-10-18 13:22:32 +02:00
Duncan Ogilvie 47aaeaf8ce Document the supported languages 2023-10-18 12:27:04 +02:00
Duncan Ogilvie 62609a0088 Improve the default .gitignore that's generated 2023-10-18 12:26:38 +02:00
Duncan Ogilvie e0d8a085db Merge pull request #121 from anthonyprintup/relative-paths
Added support for relative paths in `link-libraries`
2023-09-22 16:13:03 +02:00
Duncan Ogilvie 56da4144ae Merge pull request #125 from anthonyprintup/fix-124
fix(generator): Prevent calling `std::string::back` on an empty string
2023-09-22 16:12:20 +02:00
Duncan Ogilvie 9388b3f29d Merge pull request #123 from anthonyprintup/quotes-fix
Prevent wrapping test command arguments in quotes
2023-09-22 16:12:07 +02:00
Anthony Printup 079644cfeb fix(generator): Prevent calling std::string::back on an empty string
Fixes #124
2023-09-20 02:34:02 +02:00
Anthony Printup a7ca9f04c0 fix(relative-paths): Replaced has_parent_path with a simpler path check 2023-09-20 00:35:41 +02:00
Anthony Printup 339c2aac94 fix(generator): Prevent command arguments from being quoted when generating tests
Fixes #122
2023-09-18 18:36:58 +02:00
Anthony Printup c573c9a76d test(relative-paths): Add the test-library file to libs 2023-09-18 17:49:21 +02:00
Anthony Printup b24a0a2fdc test(relative-paths): Make link-libraries conditional to the Windows platform 2023-09-18 17:49:20 +02:00
Anthony Printup 854e8817c4 test(relative-paths): Remove inlined CMake from cmake.toml 2023-09-18 17:49:11 +02:00
Anthony Printup 1c2947b2fc fix(relative-paths): Prevent processing paths which may contain CMake macros, added a check to see if the library that's being linked exists on disk 2023-09-18 17:35:46 +02:00
Anthony Printup 19e61aa1aa test(relative-paths): Attempt to fix the tests workflow 2023-09-18 16:41:37 +02:00
Anthony Printup bfa1e1fe0d test(relative-paths): Added the latest relative-paths test to the tests workflow 2023-09-18 15:49:17 +02:00
Anthony Printup 56bd78f7ad feat(project-parser): Added support for relative paths in link-libraries
Fixes #116
2023-09-18 15:44:44 +02:00
Anthony Printup 4362b3547f test(relative-paths): Added tests for #116 2023-09-18 15:43:46 +02:00
Duncan Ogilvie 08204d9847 Bump to 0.2.25 2023-09-16 18:51:26 +02:00
Duncan Ogilvie 2202aa8173 Merge pull request #120 from anthonyprintup/new-lines-fix
Trim additional newline characters at the end of CMakeLists.txt
2023-09-16 18:49:45 +02:00
Anthony Printup d3829fb6cd Trim additional new lines at the end of the generated CMakeLists.txt 2023-09-16 18:49:30 +02:00
Duncan Ogilvie 3fb095210a Merge pull request #118 from ZehMatt/vcpkg-errors
Report better error messages for vcpkg projects and features
2023-08-25 22:21:52 +02:00
ζeh Matt 9f99365a25 Report better error messages for vcpkg projects and features 2023-08-25 15:58:24 +03:00
Duncan Ogilvie be387141b5 Add a 'Compiler flags' example to the documentation 2023-07-09 19:26:07 +02:00
Duncan Ogilvie 09ded38f70 Merge pull request #115 from build-cpp/clang-cl-condition
Add `clang-cl` and `clang-any` conditions
2023-07-09 18:01:06 +02:00
Duncan Ogilvie ad90b1ad3e Add 'clang-cl' and 'clang-any' conditions 2023-07-09 16:20:05 +02:00
Duncan Ogilvie 5bfa03d311 Bump to 0.2.24 2023-06-12 19:12:47 +02:00
Duncan Ogilvie bdd9d393d6 Merge pull request #113 from build-cpp/editorconfig
Add `.editorconfig` and linting
2023-06-12 18:28:12 +02:00
Duncan Ogilvie 1deaec2b41 Add .editorconfig and linting
Closes #112
2023-06-12 18:26:13 +02:00
Duncan Ogilvie cfee3bbc14 Merge pull request #111 from anthonyprintup/fetch-content-system
Fix #110
2023-06-12 17:48:54 +02:00
Anthony Printup bcaa60cabe feat: Added SYSTEM flag support to fetch-content 2023-06-12 15:41:20 +02:00
Duncan Ogilvie 7b1d33395e Bump to 0.2.23 2023-03-25 11:25:18 +00:00
Duncan Ogilvie 240fafc102 Merge pull request #101 from build-cpp/minor-cleanup
Cleanup
2023-03-25 11:24:44 +00:00
Duncan Ogilvie 7a7ddf2699 Speed up the pipeline by using Ninja 2023-03-25 11:19:48 +00:00
Duncan Ogilvie 605a04e72d Fix formatting of files 2023-03-24 11:07:02 +00:00
Duncan Ogilvie fd7f078127 Add workflow for checking clang-format 2023-03-24 11:04:58 +00:00
Duncan Ogilvie ee0e0d71d9 Remove a bunch of dead code 2023-03-24 11:03:45 +00:00
Duncan Ogilvie 9d6897b572 Suppress warnings related to DOWNLOAD_EXTRACT_TIMESTAMP 2023-03-24 11:03:40 +00:00
Duncan Ogilvie f8c34e5545 Error when [vcpkg] is used from a non-root project 2023-03-24 10:43:17 +00:00
Duncan Ogilvie e6d783ea20 Fix a few clang-tidy warnings 2023-03-24 10:41:59 +00:00
Duncan Ogilvie ee7fe38a7b Merge pull request #100 from build-cpp/include-subdir-bugfix
Fix a bug where includes in a subdir would not work
2023-03-24 10:13:30 +00:00
Duncan Ogilvie 66b2aad843 Fix a bug where includes in a subdir would not work 2023-03-24 10:04:32 +00:00
Duncan Ogilvie d2e376080a Bump to 0.2.22 2023-03-09 21:36:11 +01:00
Duncan Ogilvie 634908c651 Merge pull request #97 from build-cpp/cmkr-init-regression
Fix a regression where cmkr init wouldn't create any source files
2023-03-09 21:35:25 +01:00
Duncan Ogilvie 33911f3f1b Fix a regression where cmkr init wouldn't create any source files 2023-03-09 21:35:11 +01:00
Duncan Ogilvie e650073bef Bump to 0.2.21 2023-03-08 09:48:40 +01:00
Duncan Ogilvie 96e44f7771 Merge pull request #96 from build-cpp/check-sources
Improve error messages and check if specified sources exist
2023-03-08 09:47:43 +01:00
Duncan Ogilvie cb9ad5cdb3 Improve error messages and check if specified sources exist 2023-03-08 09:41:40 +01:00
Duncan Ogilvie c785b540d3 Document target templates 2023-03-08 09:01:39 +01:00
Duncan Ogilvie 275b73eefa Remove debug print 2023-03-02 08:43:45 +01:00
Duncan Ogilvie ea49a3acb7 Bump to 0.2.20 2023-02-28 21:31:18 +01:00
Duncan Ogilvie 257e14c869 Merge pull request #93 from build-cpp/gitattributes
Automatically generate .gitattributes and .gitignore with cmkr init
2023-02-28 21:30:34 +01:00
Duncan Ogilvie 7508816fe7 Merge pull request #94 from build-cpp/user-experience
Add a special "root" value for `[options]`
2023-02-28 21:27:11 +01:00
Duncan Ogilvie 45678bc5bc Automatically generate .gitattributes and .gitignore with cmkr init 2023-02-28 21:26:07 +01:00
Duncan Ogilvie b869e5646f Add a special "root" value for [options] 2023-02-28 19:34:31 +01:00
61 changed files with 1210 additions and 26057 deletions
+2 -2
View File
@@ -19,7 +19,7 @@ AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
@@ -72,7 +72,7 @@ PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
+24
View File
@@ -0,0 +1,24 @@
root = true
[*]
end_of_line = lf
trim_trailing_whitespace = true
charset = utf-8
[*.{c,h,cpp,hpp,toml}]
indent_style = space
insert_final_newline = true
[{CMakeLists.txt, *.cmake}]
indent_style = tab
tab_width = 8
insert_final_newline = true
# Exclude the third_party folder
[/third_party/**]
charset = unset
end_of_line = unset
insert_final_newline = unset
trim_trailing_whitespace = unset
indent_style = unset
indent_size = unset
+11 -4
View File
@@ -1,22 +1,29 @@
name: CMake
name: build
on: [push, pull_request]
jobs:
build:
cmake:
# Skip building pull requests from the same repository
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-2019, macos-10.15, ubuntu-20.04]
os: [windows-2022, macos-latest, ubuntu-20.04]
env:
BUILD_TYPE: Release
BUILD_TYPE: 'Release'
CMAKE_GENERATOR: 'Ninja'
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Ninja
uses: seanmiddleditch/gha-setup-ninja@6263846cf3c17009dfc81604efabae16044fc074 # master
- name: Visual Studio Development Environment
uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
- name: Tag cmkr.cmake
if: ${{ startsWith(github.ref, 'refs/tags/') }}
run: cmake -P "cmake/replace_tag.cmake"
+41
View File
@@ -0,0 +1,41 @@
name: lint
on: [push, pull_request]
jobs:
clang-format:
# Skip building pull requests from the same repository
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: clang-format
id: clang-format
uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2
with:
exclude: './third_party'
extensions: 'c,h,cpp,hpp'
clangFormatVersion: 15
style: file
- name: clang-format instructions
if: ${{ failure() && steps.clang-format.outcome == 'failure' }}
run: |
# Instructions for fixing the formatting errors
echo -e "\n\033[0;31mTo fix the formatting, run:\nclang-format -style=file -i \$(git ls-files \"*.c\" \"*.h\" \"*.cpp\" \"*.hpp\")\033[0m\n"
exit 1
editorconfig:
# Skip building pull requests from the same repository
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Run editorconfig-checker
uses: editorconfig-checker/action-editorconfig-checker@d4fca16fc71adef10fbe101903b654449fa9570c # master 2022-03-15
+2 -1
View File
@@ -9,4 +9,5 @@ build*/
.idea/
cmake-build*/
CMakeLists.txt.user
.vscode/
.vscode/
.DS_Store
+12 -15
View File
@@ -1,7 +1,7 @@
# This file is automatically generated from cmake.toml - DO NOT EDIT
# See https://github.com/build-cpp/cmkr for more information
cmake_minimum_required(VERSION 2.8...3.8)
cmake_minimum_required(VERSION 2.8...3.31)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build")
@@ -22,7 +22,7 @@ project(cmkr
LANGUAGES
CXX
VERSION
0.2.19
0.2.42
DESCRIPTION
"CMakeLists generator from TOML"
)
@@ -58,24 +58,22 @@ generate_documentation()
# Target: cmkr
set(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"
cmake.toml
"cmake/cmkr.cmake"
"cmake/version.hpp.in"
"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"
cmake.toml
"src/arguments.cpp"
"src/build.cpp"
"src/cmake_generator.cpp"
"src/help.cpp"
"src/main.cpp"
"src/project_parser.cpp"
)
add_executable(cmkr)
@@ -96,7 +94,6 @@ target_link_libraries(cmkr PRIVATE
ghc_filesystem
mpark_variant
ordered_map
nlohmann_json
)
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
@@ -105,7 +102,7 @@ if(NOT CMKR_VS_STARTUP_PROJECT)
endif()
set(CMKR_TARGET cmkr)
generate_resources(${CMKR_TARGET})
include("cmake/custom_targets.cmake")
install(
TARGETS
+3 -6
View File
@@ -1,10 +1,10 @@
[cmake]
version = "2.8...3.8"
version = "2.8...3.31"
cmkr-include = false
[project]
name = "cmkr"
version = "0.2.19"
version = "0.2.42"
description = "CMakeLists generator from TOML"
languages = ["CXX"]
include-after = [
@@ -36,11 +36,8 @@ link-libraries = [
"ghc_filesystem",
"mpark_variant",
"ordered_map",
"nlohmann_json",
]
cmake-after = """
generate_resources(${CMKR_TARGET})
"""
include-after = ["cmake/custom_targets.cmake"]
[[install]]
targets = ["cmkr"]
+77 -77
View File
@@ -1,78 +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
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}")
+1 -1
View File
@@ -2,7 +2,7 @@ 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.19" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
set(CMKR_TAG "v0.2.42" 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
+18
View File
@@ -0,0 +1,18 @@
generate_resources(cmkr)
add_custom_target(regenerate-cmake
COMMAND "$<TARGET_FILE:cmkr>" gen
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
)
if(CMAKE_CONFIGURATION_TYPES)
add_custom_target(run-tests
COMMAND "${CMAKE_CTEST_COMMAND}" -C $<CONFIG>
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/tests"
)
else()
add_custom_target(run-tests
COMMAND "${CMAKE_CTEST_COMMAND}"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/tests"
)
endif()
+5 -5
View File
@@ -15,7 +15,7 @@ function(generate_documentation)
message(FATAL_ERROR "This should not happen (wrong regex?)")
endif()
endforeach()
# Delete previously generated examples
set(example_folder "${PROJECT_SOURCE_DIR}/docs/examples")
file(GLOB example_files "${example_folder}/*.md")
@@ -41,21 +41,21 @@ function(generate_documentation)
# 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)
@@ -64,7 +64,7 @@ function(generate_documentation)
# 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()
+6 -6
View File
@@ -1,7 +1,7 @@
namespace cmkr {
namespace resources {
static const char* @RESOURCE_NAME@ = R"RESOURCE(@RESOURCE_CONTENTS@)RESOURCE";
}
namespace cmkr {
namespace resources {
static const char* @RESOURCE_NAME@ = R"RESOURCE(@RESOURCE_CONTENTS@)RESOURCE";
}
}
+1 -1
View File
@@ -1 +1 @@
cmkr.build
cmkr.build
+122 -20
View File
@@ -39,17 +39,45 @@ include-before = ["cmake/before-project.cmake"]
include-after = ["cmake/after-project.cmake"]
```
### Languages
Supported languages are (see [`enable_language`](https://cmake.org/cmake/help/latest/command/enable_language.html) for more information):
- `C`
- `CXX` → C++
- `CSharp` → C#
- `CUDA`
- `OBJC` → Objective-C
- `OBJCXX` → Objective-C++
- `Fortran`
- `HIP`
- `ISPC`
- `Swift`
- `ASM`
- `ASM_MASM` → [Microsoft Macro Assembler (MASM)](https://learn.microsoft.com/en-US/cpp/assembler/masm/masm-for-x64-ml64-exe)
- `ASM_NASM` → [Netwide Assembler (NASM)](https://www.nasm.us)
- `ASM_MARMASM` [Microsoft ARM Assembler](https://learn.microsoft.com/en-us/cpp/assembler/arm/arm-assembler-command-line-reference)
- `ASM-ATT`
- `Java` (undocumented)
- `RC` (undocumented)
After a language is enabled, adding sources files with the corresponding extension to your target will automatically use the appropriate compiler/assembler for it.
_Note_: It is generally discouraged to disable the `C` language, unless you are absolutely sure it is not used. Sometimes projects added with `fetch-content` implicitly require it and the error messages can be extremely confusing.
## Conditions
You can specify your own conditions and use them in any `condition` field:
You can specify your own named conditions and use them in any `condition` field:
```toml
[conditions]
arch64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
arch32 = "CMAKE_SIZEOF_VOID_P EQUAL 4"
ptr64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
ptr32 = "CMAKE_SIZEOF_VOID_P EQUAL 4"
```
This will make the `arch64` and `arch32` conditions available with their respective CMake expressions.
This will make the `ptr64` and `ptr32` conditions available with their respective CMake expressions.
**Note**: condition names can only contain lower-case alphanumeric characters (`[0-9a-z]`) and dashes (`-`).
You can also prefix most keys with `condition.` to represent a conditional:
@@ -57,9 +85,11 @@ You can also prefix most keys with `condition.` to represent a conditional:
[target]
type = "executable"
sources = ["src/main.cpp"]
windows.sources = ["src/windows_specific.cpp"]
ptr64.sources = ["src/ptr64_only.cpp"]
```
Instead of a named condition you can also specify a [CMake expression](https://cmake.org/cmake/help/latest/command/if.html#condition-syntax) in quotes. Instances of `$<name>` are replaced with the corresponding condition. For example: `"CONDITIONS_BUILD_TESTS AND $<linux>"` becomes `CONDITIONS_BUILD_TESTS AND (CMAKE_SYSTEM_NAME MATCHES "Linux")` in the final `CMakeLists.txt` file.
### Predefined conditions
The following conditions are predefined (you can override them if you desire):
@@ -72,11 +102,20 @@ 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\" AND NOT CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\") OR (CMAKE_C_COMPILER_ID MATCHES \"Clang\" AND NOT CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\")"
msvc = "MSVC"
clang = "(CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" AND NOT CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\") OR (CMAKE_C_COMPILER_ID MATCHES \"Clang\" AND NOT CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\")"
clang-cl = "(CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\") OR (CMAKE_C_COMPILER_ID MATCHES \"Clang\" AND CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES \"^MSVC$\")"
clang-any = "CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" OR CMAKE_C_COMPILER_ID MATCHES \"Clang\""
root = "CMKR_ROOT_PROJECT"
x64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
x32 = "CMAKE_SIZEOF_VOID_P EQUAL 4"
android = "ANDROID"
apple = "APPLE"
bsd = "BSD"
cygwin = "CYGWIN"
ios = "IOS"
xcode = "XCODE"
wince = "WINCE"
```
## Subdirectories
@@ -100,9 +139,12 @@ include-after = ["cmake/after-subdir.cmake"]
[options]
MYPROJECT_BUILD_TESTS = false
MYPROJECT_SPECIAL_OPTION = { value = true, help = "Docstring for this option." }
MYPROJECT_BUILD_EXAMPLES = "root"
```
Options correspond to [CMake cache variables](https://cmake.org/cmake/help/book/mastering-cmake/chapter/CMake%20Cache.html) that can be used to customize your project at configure-time. You can configure with `cmake -DMYPROJECT_BUILD_TESTS=ON` to enable the option. Every options automatically gets a corresponding [condition](#conditions).
Options correspond to [CMake cache variables](https://cmake.org/cmake/help/book/mastering-cmake/chapter/CMake%20Cache.html) that can be used to customize your project at configure-time. You can configure with `cmake -DMYPROJECT_BUILD_TESTS=ON` to enable the option. Every option automatically gets a corresponding [condition](#conditions). Additionally, a normalized condition is created based on the `[project].name` (i.e. `MYPROJECT_BUILD_TESTS` becomes `build-tests`).
The special value `root` can be used to set the option to `true` if the project is compiled as the root project (it will be `false` if someone is including your project via `[fetch-content]` or `[subdir]`).
## Variables
@@ -118,14 +160,18 @@ Variables emit a [`set`](https://cmake.org/cmake/help/latest/command/set.html) a
```toml
[vcpkg]
version = "2021.05.12"
url = "https://github.com/microsoft/vcpkg/archive/refs/tags/2021.05.12.tar.gz"
version = "2024.11.16"
url = "https://github.com/microsoft/vcpkg/archive/refs/tags/2024.11.16.tar.gz"
packages = ["fmt", "zlib"]
overlay-ports = ["my-ports"]
overlay-triplets = ["my-triplets"]
```
The vcpkg `version` will automatically generate the `url` from the [official repository](https://github.com/microsoft/vcpkg/releases). For a custom registry you can specify your own `url` (and omit the `version`). You can browse available packages on [vcpkg.io](https://vcpkg.io/en/packages.html).
The vcpkg `version` will automatically generate the `url` from the [official repository](https://github.com/microsoft/vcpkg/releases). For a custom registry you can specify your own `url` (and omit the `version`). You can browse available packages on [vcpkg.io](https://vcpkg.io/en/packages.html) or [vcpkg.link](https://vcpkg.link).
To specify package features you can use the following syntax: `imgui[docking-experimental,freetype,sdl2-binding,opengl3-binding]`.
To specify package features you can use the following syntax: `imgui[docking-experimental,freetype,sdl2-binding,opengl3-binding]`. To disable the [default features](https://learn.microsoft.com/en-us/vcpkg/concepts/default-features) you can do: `cpp-httplib[core,openssl]`
The `overlay-ports` feature allows you to embed vcpkg ports inside your project, without having to fork the main vcpkg registry or creating a custom registry. You can find more information in the relevant [documentation](https://learn.microsoft.com/en-us/vcpkg/concepts/overlay-ports). The `overlay-triplets` feature allows you to customize triplets and change the default behavior (for example always preferring static libraries on Windows). To specify both in one go you can do `[vcpkg].overlay = "my-overlay"`.
## Packages
@@ -148,6 +194,8 @@ condition = "mycondition"
git = "https://github.com/myuser/gitcontent"
tag = "v0.1"
shallow = false
system = false
subdir = ""
[fetch-content.svncontent]
condition = "mycondition"
@@ -163,34 +211,36 @@ hash = "SHA1 502a4e25b8b209889c99c7fa0732102682c2e4ff"
sha1 = "502a4e25b8b209889c99c7fa0732102682c2e4ff"
```
Table keys that match CMake variable names (`[A-Z_]+`) will be passed to the [`FetchContent_Declare`](https://cmake.org/cmake/help/latest/module/FetchContent.html#command:fetchcontent_declare) command.
## Targets
```toml
[target.mytarget]
condition = "mycondition"
alias = "mytarget::mytarget"
type = "static" # executable, shared (DLL), static, interface, object, library, custom
type = "static" # executable, library, shared (DLL), static, interface, object, custom
headers = ["src/mytarget.h"]
sources = ["src/mytarget.cpp"]
msvc-runtime = "" # dynamic (implicit default), static
# The keys below match the target_xxx CMake commands
# Keys prefixed with private- will get PRIVATE visibility
compile-definitions = [""]
compile-definitions = [""] # preprocessor define (-DFOO)
private-compile-definitions = [""]
compile-features = [""]
compile-features = [""] # C++ standard version (cxx_std_20)
private-compile-features = [""]
compile-options = [""]
compile-options = [""] # compiler flags
private-compile-options = [""]
include-directories = [""]
include-directories = [""] # include paths/directories
private-include-directories = [""]
link-directories = [""]
link-directories = [""] # library directories
private-link-directories = [""]
link-libraries = [""]
link-libraries = [""] # dependencies
private-link-libraries = [""]
link-options = [""]
link-options = [""] # linker flags
private-link-options = [""]
precompile-headers = [""]
precompile-headers = [""] # precompiled headers
private-precompile-headers = [""]
cmake-before = """
@@ -209,6 +259,58 @@ CXX_STANDARD_REQUIRED = true
FOLDER = "MyFolder"
```
A table mapping the cmkr features to the relevant CMake construct and the relevant documentation pages:
| cmkr | CMake construct | Description |
| ---- | ----- | ----------- |
| `alias` | [Alias Libraries](https://cmake.org/cmake/help/latest/command/add_library.html#alias-libraries) | Create an [alias target](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#alias-targets), used for namespacing or clarity. |
| `sources` | [`target_sources`](https://cmake.org/cmake/help/latest/command/target_sources.html) | Source files (`PRIVATE` except `interface` targets). |
| `headers` | [`target_sources`](https://cmake.org/cmake/help/latest/command/target_sources.html) | For readability (and future packaging). |
| `msvc-runtime` | [`MSVC_RUNTIME_LIBRARY`](https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html) | The [CMP0091](https://cmake.org/cmake/help/latest/policy/CMP0091.html) policy is set automatically. |
| `compile-definitions` | [`target_compile_definitions`](https://cmake.org/cmake/help/latest/command/target_compile_definitions.html) | Adds a macro definition (define, `-DMYMACRO=XXX`). |
| `compile-features` | [`target_compile_features`](https://cmake.org/cmake/help/latest/command/target_compile_features.html) | Specifies the C++ standard version (`cxx_std_20`). |
| `compile-options` | [`target_compile_options`](https://cmake.org/cmake/help/latest/command/target_compile_options.html) | Adds compiler flags. |
| `include-directories` | [`target_include_directories`](https://cmake.org/cmake/help/latest/command/target_include_directories.html) | Adds include directories. |
| `link-directories` | [`target_link_directories`](https://cmake.org/cmake/help/latest/command/target_link_directories.html) | Adds library directories. |
| `link-libraries` | [`target_link_libraries`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) | Adds library dependencies. |
| `link-options` | [`target_link_options`](https://cmake.org/cmake/help/latest/command/target_link_options.html) | Adds linker flags. |
| `precompile-headers` | [`target_precompile_headers`](https://cmake.org/cmake/help/latest/command/target_precompile_headers.html) | Specifies precompiled headers. |
| `properties` | [`set_target_properties`](https://cmake.org/cmake/help/latest/command/set_target_properties.html) | See [properties on targets](https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#properties-on-targets) for more information. |
The default [visibility](/basics) is as follows:
| Type | Visibility |
| ------------ | ----------- |
| `executable` | `PRIVATE` |
| `library` | `PUBLIC` |
| `shared` | `PUBLIC` |
| `static` | `PUBLIC` |
| `object` | `PUBLIC` |
| `interface` | `INTERFACE` |
## Templates
To avoid repeating yourself you can create your own target type and use it in your targets:
```toml
[template.example]
condition = "MYPROJECT_BUILD_EXAMPLES"
type = "executable"
link-libraries = ["myproject::mylib"]
add-function = ""
pass-sources = false
# Properties from the template are merged with the ones here
[target.myexample]
type = "example"
sources = ["src/myexample.cpp"]
```
The properties declared on a `template` are the same as the ones you use for targets. The only exceptions are:
- `add-function`: Specifies a custom add function. Projects like [pybind11](https://pybind11.readthedocs.io/en/stable/cmake/index.html#new-findpython-mode) have their own `add_xxx` function, which you can specify here.
- `pass-sources`: Pass sources directly to the add function instead of using `target_sources`.
## Tests and installation (unfinished)
**Note**: The `[[test]]` and `[[install]]` are unfinished features and will likely change in a future release.
+34
View File
@@ -0,0 +1,34 @@
---
# Automatically generated from tests/compile-options/cmake.toml - DO NOT EDIT
layout: default
title: Compiler flags
permalink: /examples/compile-options
parent: Examples
nav_order: 9
---
# Compiler flags
Example project that sets compiler flags and preprocessor defines for various platforms.
```toml
[project]
name = "compile-options"
description = "Compiler flags"
[target.hello]
type = "executable"
sources = ["src/main.cpp"]
msvc.compile-options = ["/W2"]
msvc.compile-definitions = ["PLATFORM=\"msvc\""]
gcc.compile-options = ["-Wall"]
gcc.compile-definitions = ["PLATFORM=\"gcc\""]
clang.compile-options = ["-Wall"]
clang.compile-definitions = ["PLATFORM=\"clang\""]
```
The `hello` target uses [conditions](/cmake-toml#conditions) to set different compiler flags and definitions depending on the platform. See the [targets](/cmake-toml/#targets) documentation for other things you can set.
_Note_: In general you only want to specify flags _required_ to compile your code without errors.
<sup><sub>This page was automatically generated from [tests/compile-options/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/compile-options/cmake.toml).</sub></sup>
+4 -5
View File
@@ -9,7 +9,7 @@ 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:
Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) using [vcpkg](https://github.com/microsoft/vcpkg) and links an `example` target to it:
```toml
[project]
@@ -17,13 +17,12 @@ 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
# See https://vcpkg.io/en/packages or https://vcpkg.link for available packages
[vcpkg]
version = "2022.11.14"
version = "2024.11.16"
packages = ["fmt"]
[find-package]
fmt = {}
[find-package.fmt]
[target.example]
type = "executable"
+9 -9
View File
@@ -1,10 +1,10 @@
---
layout: null
permalink: /getting-started/
---
<html>
<head>
<meta http-equiv="refresh" content="0;url=https://cmkr.build">
</head>
---
layout: null
permalink: /getting-started/
---
<html>
<head>
<meta http-equiv="refresh" content="0;url=https://cmkr.build">
</head>
</html>
-6
View File
@@ -11,9 +11,3 @@ int install();
} // namespace build
} // namespace cmkr
int cmkr_build_run(int argc, char **argv);
int cmkr_build_clean();
int cmkr_build_install();
-27
View File
@@ -1,27 +0,0 @@
#pragma once
namespace cmkr {
namespace error {
struct Status {
enum class Code {
Success = 0,
RuntimeError,
InitError,
GenerationError,
BuildError,
CleanError,
InstallError,
};
Status(Code ec) noexcept;
operator int() const noexcept;
Code code() const noexcept;
private:
Code ec_ = Code::Success;
};
} // namespace error
} // namespace cmkr
const char *cmkr_error_status_string(int);
+2 -4
View File
@@ -1,8 +1,6 @@
#pragma once
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || \
(defined(__cplusplus) && __cplusplus >= 201703L)) && \
defined(__has_include)
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
@@ -12,4 +10,4 @@ namespace fs = std::filesystem;
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
#endif
-4
View File
@@ -9,7 +9,3 @@ const char *message() noexcept;
} // namespace help
} // namespace cmkr
const char *cmkr_help_version(void);
const char *cmkr_help_message(void);
+17 -4
View File
@@ -1,10 +1,11 @@
#pragma once
#include <mpark/variant.hpp>
#include <vector>
#include <string>
#include <mpark/variant.hpp>
#include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>
#include <vector>
namespace cmkr {
namespace parser {
@@ -25,7 +26,7 @@ struct Variable {
struct Option {
std::string name;
std::string help;
bool value = false;
mpark::variant<bool, std::string> value;
};
struct Package {
@@ -44,9 +45,18 @@ struct Vcpkg {
struct Package {
std::string name;
std::vector<std::string> features;
bool default_features = true;
};
std::vector<Package> packages;
// https://github.com/Microsoft/vcpkg-docs/blob/main/vcpkg/users/buildsystems/cmake-integration.md
std::vector<std::string> overlay_ports;
std::vector<std::string> overlay_triplets;
bool enabled() const {
return !packages.empty();
}
};
enum TargetType {
@@ -150,6 +160,8 @@ struct Content {
Condition<std::string> cmake_after;
ConditionVector include_before;
ConditionVector include_after;
bool system = false;
std::string subdir;
};
enum MsvcRuntimeType {
@@ -201,9 +213,10 @@ struct Project {
Project(const Project *parent, const std::string &path, bool build);
const Project *root() const;
bool cmake_minimum_version(int major, int minor) const;
static bool is_condition_name(const std::string &name);
};
bool is_root_path(const std::string &path);
} // namespace parser
} // namespace cmkr
} // namespace cmkr
+1 -3
View File
@@ -2,10 +2,8 @@
#include "build.hpp"
#include "cmake_generator.hpp"
#include "help.hpp"
#include "fs.hpp"
#include <exception>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
+4 -38
View File
@@ -1,14 +1,10 @@
#include "build.hpp"
#include "cmake_generator.hpp"
#include "error.hpp"
#include "project_parser.hpp"
#include "fs.hpp"
#include <cstddef>
#include <cstdlib>
#include <sstream>
#include <stdexcept>
#include <system_error>
namespace cmkr {
namespace build {
@@ -17,7 +13,7 @@ int run(int argc, char **argv) {
parser::Project project(nullptr, ".", true);
if (argc > 2) {
for (int i = 2; i < argc; ++i) {
project.build_args.push_back(argv[i]);
project.build_args.emplace_back(argv[i]);
}
}
std::stringstream ss;
@@ -48,13 +44,13 @@ int run(int argc, char **argv) {
}
int clean() {
bool ret = false;
bool success = false;
parser::Project project(nullptr, ".", true);
if (fs::exists(project.build_dir)) {
ret = fs::remove_all(project.build_dir);
success = fs::remove_all(project.build_dir);
fs::create_directory(project.build_dir);
}
return !ret;
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
int install() {
@@ -64,33 +60,3 @@ int install() {
}
} // namespace build
} // namespace cmkr
int cmkr_build_run(int argc, char **argv) {
try {
return cmkr::build::run(argc, argv);
} catch (const std::system_error &e) {
return e.code().value();
} catch (...) {
return cmkr::error::Status(cmkr::error::Status::Code::BuildError);
}
}
int cmkr_build_clean(void) {
try {
return cmkr::build::clean();
} catch (const std::system_error &e) {
return e.code().value();
} catch (...) {
return cmkr::error::Status(cmkr::error::Status::Code::CleanError);
}
}
int cmkr_build_install(void) {
try {
return cmkr::build::install();
} catch (const std::system_error &e) {
return e.code().value();
} catch (...) {
return cmkr::error::Status(cmkr::error::Status::Code::InstallError);
}
}
+421 -148
View File
@@ -1,15 +1,14 @@
#include "cmake_generator.hpp"
#include "error.hpp"
#include "literals.hpp"
#include <resources/cmkr.hpp>
#include "fs.hpp"
#include "project_parser.hpp"
#include <cstdio>
#include <fstream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <fstream>
namespace cmkr {
namespace gen {
@@ -43,7 +42,7 @@ static tsl::ordered_map<std::string, std::vector<std::string>> known_languages =
{"Swift", {".swift"}},
};
static std::string format(const char *format, tsl::ordered_map<std::string, std::string> variables) {
static std::string format(const char *format, const tsl::ordered_map<std::string, std::string> &variables) {
std::string s = format;
for (const auto &itr : variables) {
size_t start_pos = 0;
@@ -55,57 +54,85 @@ static std::string format(const char *format, tsl::ordered_map<std::string, std:
return s;
}
static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs::path &toml_dir, bool is_root_project) {
std::vector<std::string> temp;
auto extract_suffix = [](const fs::path &base, const fs::path &full) {
auto fullpath = full.string();
auto base_len = base.string().length();
auto delet = fullpath.substr(base_len + 1, fullpath.length() - base_len);
return delet;
static std::vector<fs::path> expand_cmake_path(const fs::path &source_path, const fs::path &toml_dir, bool is_root_project) {
auto is_subdir = [](fs::path p, const fs::path &root) {
while (true) {
if (p == root) {
return true;
}
auto parent = p.parent_path();
if (parent == p) {
break;
}
p = parent;
}
return false;
};
auto stem = name.filename().stem().string();
auto ext = name.extension();
if (is_root_project && stem == "**" && name == name.filename()) {
throw std::runtime_error("Recursive globbing not allowed in project root: " + name.string());
if (!is_subdir(fs::absolute(toml_dir / source_path), toml_dir)) {
throw std::runtime_error("Path traversal is not allowed: " + source_path.string());
}
// Split the path at the first period (since fs::path::stem() and fs::path::extension() split at the last period)
std::string stem, extension;
auto filename = source_path.filename().string();
auto dot_position = filename.find('.');
if (dot_position != std::string::npos) {
stem = filename.substr(0, dot_position);
extension = filename.substr(dot_position);
} else {
stem = filename;
}
if (is_root_project && stem == "**" && !source_path.has_parent_path()) {
throw std::runtime_error("Recursive globbing not allowed in project root: " + source_path.string());
}
auto has_extension = [](const fs::path &file_path, const std::string &extension) {
auto path = file_path.string();
return path.rfind(extension) == path.length() - extension.length();
};
std::vector<fs::path> paths;
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));
for (const auto &f : fs::directory_iterator(toml_dir / source_path.parent_path(), fs::directory_options::follow_directory_symlink)) {
if (!f.is_directory() && has_extension(f.path(), extension)) {
paths.push_back(fs::relative(f, toml_dir));
}
}
} 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()));
for (const auto &f :
fs::recursive_directory_iterator(toml_dir / source_path.parent_path(), fs::directory_options::follow_directory_symlink)) {
if (!f.is_directory() && has_extension(f.path(), extension)) {
paths.push_back(fs::relative(f, toml_dir));
}
}
} else {
temp.push_back(name.string());
paths.push_back(source_path);
}
// 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;
return paths;
}
static std::vector<std::string> expand_cmake_paths(const std::vector<std::string> &sources, const fs::path &toml_dir, bool is_root_project) {
// TODO: add duplicate checking
std::vector<std::string> result;
std::vector<std::string> paths;
for (const auto &src : sources) {
auto expanded = expand_cmake_path(src, toml_dir, is_root_project);
for (const auto &f : expanded) {
result.push_back(f);
paths.push_back(f.string());
}
}
return result;
// Normalize all paths to work with CMake (it needs a / on Windows as well)
for (auto &path : paths) {
std::replace(path.begin(), path.end(), '\\', '/');
}
// Sort paths alphabetically for consistent cross-OS generation
std::sort(paths.begin(), paths.end());
// TODO: remove duplicates
return paths;
}
static void create_file(const fs::path &path, const std::string &contents) {
@@ -119,6 +146,19 @@ static void create_file(const fs::path &path, const std::string &contents) {
ofs << contents;
}
static std::string read_file(const fs::path &path) {
std::ifstream ifs(path, std::ios::binary);
if (!ifs) {
throw std::runtime_error("Failed to read " + path.string());
}
std::string contents;
ifs.seekg(0, std::ios::end);
contents.resize(ifs.tellg());
ifs.seekg(0, std::ios::beg);
ifs.read(&contents[0], contents.size());
return contents;
}
// CMake target name rules: https://cmake.org/cmake/help/latest/policy/CMP0037.html [A-Za-z0-9_.+\-]
// TOML bare keys: non-empty strings composed only of [A-Za-z0-9_-]
// We replace all non-TOML bare key characters with _
@@ -135,18 +175,82 @@ static std::string escape_project_name(const std::string &name) {
return escaped;
}
static void generate_gitfile(const char *gitfile, const std::vector<std::string> &desired_lines) {
// Reference: https://github.com/github/linguist/blob/master/docs/overrides.md#summary
auto lines = desired_lines;
auto generate = [&lines](const char *newline) {
std::string generated;
generated += "# cmkr";
generated += newline;
for (const auto &line : lines) {
generated += line;
generated += newline;
}
return generated;
};
if (!fs::exists(gitfile)) {
create_file(gitfile, generate("\n"));
} else {
auto contents = read_file(gitfile);
std::string line;
auto cr = 0, lf = 0;
auto flush_line = [&line, &lines]() {
auto itr = std::find(lines.begin(), lines.end(), line);
if (itr != lines.end()) {
lines.erase(itr);
}
line.clear();
};
for (size_t i = 0; i < contents.length(); i++) {
if (contents[i] == '\r') {
cr++;
continue;
}
if (contents[i] == '\n') {
lf++;
flush_line();
} else {
line += contents[i];
}
}
if (!line.empty()) {
flush_line();
}
if (!lines.empty()) {
// Append the cmkr .gitattributes using the detected newline
auto newline = cr == lf ? "\r\n" : "\n";
if (!contents.empty() && contents.back() != '\n') {
contents += newline;
}
contents += newline;
contents += generate(newline);
create_file(gitfile, contents);
}
}
}
void generate_project(const std::string &type) {
const auto name = escape_project_name(fs::current_path().stem().string());
if (fs::exists(fs::current_path() / "cmake.toml")) {
throw std::runtime_error("Cannot initialize a project when cmake.toml already exists!");
}
// Check if the folder is empty before creating any files
auto is_empty = fs::is_empty(fs::current_path());
// Automatically generate .gitattributes to not skew the statistics of the repo
generate_gitfile(".gitattributes", {"/**/CMakeLists.txt linguist-generated", "/**/cmkr.cmake linguist-vendored"});
// Generate .gitignore with reasonable defaults for CMake
generate_gitfile(".gitignore", {"build*/", "cmake-build*/", "CMakerLists.txt", "CMakeLists.txt.user"});
tsl::ordered_map<std::string, std::string> variables = {
{"@name", name},
{"@type", type},
};
if (!fs::is_empty(fs::current_path())) {
if (!is_empty) {
// Make a backup of an existing CMakeLists.txt if it exists
std::error_code ec;
fs::rename("CMakeLists.txt", "CMakeLists.txt.bak", ec);
@@ -172,7 +276,7 @@ void generate_project(const std::string &type) {
struct CommandEndl {
std::stringstream &ss;
CommandEndl(std::stringstream &ss) : ss(ss) {
explicit CommandEndl(std::stringstream &ss) : ss(ss) {
}
void endl() {
ss << '\n';
@@ -181,7 +285,7 @@ struct CommandEndl {
struct RawArg {
RawArg() = default;
RawArg(std::string arg) : arg(std::move(arg)) {
explicit RawArg(std::string arg) : arg(std::move(arg)) {
}
std::string arg;
@@ -216,7 +320,7 @@ struct Command {
// https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#unquoted-argument
// NOTE: Normally '/' does not require quoting according to the documentation but this has been the case here
// previously, so for backwards compatibility its still here.
if (str.find_first_of("()#\"\\'> |/;") == str.npos)
if (str.find_first_of("()#\"\\'> |/;") == std::string::npos)
return str;
std::string result;
result += "\"";
@@ -365,14 +469,15 @@ static std::string tolf(const std::string &str) {
}
}
return result;
};
}
struct Generator {
Generator(const parser::Project &project) : project(project) {
Generator(const parser::Project &project, fs::path path) : project(project), path(std::move(path)) {
}
Generator(const Generator &) = delete;
const parser::Project &project;
fs::path path;
std::stringstream ss;
int indent = 0;
@@ -402,8 +507,8 @@ struct Generator {
void inject_includes(const std::vector<std::string> &includes) {
if (!includes.empty()) {
for (const auto &file : includes) {
if (!fs::is_regular_file(file)) {
throw std::runtime_error("Include '" + file + "' does not exist");
if (!fs::exists(path / file)) {
throw std::runtime_error("Include not found: " + file);
}
cmd("include")(file);
}
@@ -416,7 +521,7 @@ struct Generator {
throw std::runtime_error("Detected additional \" at the end of cmake block");
}
auto cmake_lf = tolf(cmake);
while (cmake_lf.back() == '\n')
while (!cmake_lf.empty() && cmake_lf.back() == '\n')
cmake_lf.pop_back();
bool did_indent = false;
for (char ch : cmake_lf) {
@@ -437,15 +542,13 @@ struct Generator {
if (!value.empty()) {
for (const auto &itr : value) {
const auto &condition = itr.first;
if (!condition.empty()) {
cmd("if", condition)(RawArg(project.conditions.at(condition)));
}
auto endif = if_condition(condition);
if (!itr.second.empty()) {
fn(condition, itr.second);
}
if (!condition.empty()) {
if (endif) {
cmd("endif")().endl();
} else if (!itr.second.empty()) {
endl();
@@ -461,6 +564,68 @@ struct Generator {
void conditional_cmake(const parser::Condition<std::string> &cmake) {
handle_condition(cmake, [this](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
}
bool if_condition(const std::string &condition) {
if (condition.empty()) {
return false;
}
auto found = project.conditions.find(condition);
if (found == project.conditions.end()) {
if (cmkr::parser::Project::is_condition_name(condition)) {
// NOTE: this should have been caught by the parser already
throw std::runtime_error("Condition '" + condition + "' is not defined");
}
cmd("if", "NOTE: unnamed condition")(RawArg(cmake_condition(condition)));
} else {
cmd("if", condition)(RawArg(cmake_condition(found->second)));
}
return true;
}
private:
std::string cmake_condition(const std::string &condition) {
// HACK: this replaces '$<name>' with the value of the 'name' condition. We can safely
// reuse the generator expression syntax, because it is not valid in CMake conditions.
// TODO: properly handle quoted arguments (using a simple state machine):
// https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#quoted-argument
std::string result = "";
bool in_replacement = false;
std::string temp;
for (size_t i = 0; i < condition.length(); i++) {
if (in_replacement) {
if (condition[i] == '>') {
in_replacement = false;
if (temp.empty()) {
throw std::runtime_error("Empty replacement in condition '" + condition + "'");
}
auto found = project.conditions.find(temp);
if (found == project.conditions.end()) {
throw std::runtime_error("Unknown condition '" + temp + "' in replacement");
}
auto has_space = found->second.find(' ') != std::string::npos;
if (has_space) {
result += '(';
}
result += found->second;
if (has_space) {
result += ')';
}
temp.clear();
} else {
temp += condition[i];
}
} else if (condition[i] == '$' && i + 1 < condition.length() && condition[i + 1] == '<') {
i++;
in_replacement = true;
} else {
result += condition[i];
}
}
if (!temp.empty()) {
throw std::runtime_error("Unterminated replacement in condition '" + condition + "'");
}
return result;
}
};
struct ConditionScope {
@@ -468,10 +633,7 @@ struct ConditionScope {
bool endif = false;
ConditionScope(Generator &gen, const std::string &condition) : gen(gen) {
if (!condition.empty()) {
gen.cmd("if", condition)(RawArg(gen.project.conditions.at(condition)));
endif = true;
}
endif = gen.if_condition(condition);
}
ConditionScope(const ConditionScope &) = delete;
@@ -485,28 +647,26 @@ struct ConditionScope {
};
static bool vcpkg_valid_identifier(const std::string &name) {
// prn|aux|nul|con|lpt[1-9]|com[1-9]|core|default
auto is_reserved = [](const std::string &s) {
if (s == "prn" || s == "aux" || s == "nul" || s == "con" || s == "core" || s == "default") {
return true;
}
if (s.length() == 4 && (s.compare(0, 3, "lpt") == 0 || s.compare(0, 3, "com") == 0) && (s[3] >= '1' && s[3] <= '9')) {
return true;
// [a-z0-9]+(-[a-z0-9]+)*
for (size_t i = 0; i < name.length(); i++) {
auto c = name[i];
if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (i > 0 && c == '-')) {
continue;
}
return false;
};
// [a-z0-9]+(-[a-z0-9]+)*
auto is_identifier = [](const std::string &s) {
for (size_t i = 0; i < s.length(); i++) {
auto c = s[i];
if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (i > 0 && c == '-')) {
continue;
}
return false;
}
}
return true;
}
static bool vcpkg_identifier_reserved(const std::string &name) {
// prn|aux|nul|con|lpt[1-9]|com[1-9]|core|default
if (name == "prn" || name == "aux" || name == "nul" || name == "con" || name == "core" || name == "default") {
return true;
};
return is_identifier(name) && !is_reserved(name);
}
if (name.length() == 4 && (name.compare(0, 3, "lpt") == 0 || name.compare(0, 3, "com") == 0) && (name[3] >= '1' && name[3] <= '9')) {
return true;
}
return false;
}
static std::string vcpkg_escape_identifier(const std::string &name) {
@@ -521,12 +681,17 @@ static std::string vcpkg_escape_identifier(const std::string &name) {
ch = '-';
}
escaped += std::tolower(ch);
if (ch >= 'A' && ch <= 'Z') {
ch += ('a' - 'A');
}
escaped += ch;
}
if (!vcpkg_valid_identifier(escaped)) {
throw std::runtime_error("The escaped project name '" + escaped + "' is not usable with [vcpkg]");
}
if (vcpkg_identifier_reserved(escaped)) {
throw std::runtime_error("The escaped project name '" + escaped + "' is a reserved name [vcpkg]");
}
return escaped;
}
@@ -540,17 +705,17 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
parser::Project project(parent_project, path, false);
for (auto const &lang : project.project_languages) {
for (const auto &lang : project.project_languages) {
if (known_languages.find(lang) == known_languages.end()) {
if (project.project_allow_unknown_languages) {
printf("Unknown language '%s' specified\n", lang.c_str());
printf("[warning] Unknown language '%s' specified\n", lang.c_str());
} else {
throw std::runtime_error("Unknown language '" + lang + "' specified");
}
}
}
Generator gen(project);
Generator gen(project, path);
// Helper lambdas for more convenient CMake generation
auto &ss = gen.ss;
@@ -566,24 +731,6 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
if (is_root_project) {
cmd("cmake_minimum_required")("VERSION", project.cmake_version).endl();
if (project.project_msvc_runtime != parser::msvc_last) {
comment("Enable support for MSVC_RUNTIME_LIBRARY");
cmd("cmake_policy")("SET", "CMP0091", "NEW");
switch (project.project_msvc_runtime) {
case parser::msvc_dynamic:
cmd("set")("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL");
break;
case parser::msvc_static:
cmd("set")("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreaded$<$<CONFIG:Debug>:Debug>");
break;
default:
break;
}
endl();
}
// clang-format on
if (!project.allow_in_tree) {
// clang-format off
cmd("if")("CMAKE_SOURCE_DIR", "STREQUAL", "CMAKE_BINARY_DIR");
@@ -592,6 +739,11 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
// clang-format on
}
if (project.project_msvc_runtime != parser::msvc_last) {
comment("Enable support for MSVC_RUNTIME_LIBRARY");
cmd("cmake_policy")("SET", "CMP0091", "NEW").endl();
}
cmd("set")("CMKR_ROOT_PROJECT", "OFF");
// clang-format off
cmd("if")("CMAKE_CURRENT_SOURCE_DIR", "STREQUAL", "CMAKE_SOURCE_DIR");
@@ -609,7 +761,26 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
cmd("set_property")("GLOBAL", "PROPERTY", "USE_FOLDERS", "ON").endl();
comment("Create a configure-time dependency on cmake.toml to improve IDE support");
cmd("configure_file")("cmake.toml", "cmake.toml", "COPYONLY");
if (project.cmake_minimum_version(3, 0)) {
cmd("set_property")("DIRECTORY", "APPEND", "PROPERTY", "CMAKE_CONFIGURE_DEPENDS", "cmake.toml");
} else {
cmd("configure_file")("cmake.toml", "cmake.toml", "COPYONLY");
}
if (project.project_msvc_runtime != parser::msvc_last) {
cmd("if")("NOT", "DEFINED", "CMAKE_MSVC_RUNTIME_LIBRARY");
switch (project.project_msvc_runtime) {
case parser::msvc_dynamic:
cmd("set")("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL");
break;
case parser::msvc_static:
cmd("set")("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreaded$<$<CONFIG:Debug>:Debug>");
break;
default:
break;
}
cmd("endif")().endl();
}
cmd("endif")().endl();
// clang-format on
@@ -618,12 +789,14 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
create_file(cmkr_include, resources::cmkr);
}
} else {
// clang-format off
comment("Create a configure-time dependency on cmake.toml to improve IDE support");
cmd("if")("CMKR_ROOT_PROJECT");
if (project.cmake_minimum_version(3, 0)) {
cmd("set_property")("DIRECTORY", "APPEND", "PROPERTY", "CMAKE_CONFIGURE_DEPENDS", "cmake.toml");
} else {
cmd("configure_file")("cmake.toml", "cmake.toml", "COPYONLY");
}
cmd("endif")().endl();
// clang-format on
}
// TODO: remove support and replace with global compile-features
@@ -656,7 +829,13 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
if (!project.options.empty()) {
comment("Options");
for (const auto &opt : project.options) {
cmd("option")(opt.name, RawArg(Command::quote(opt.help)), opt.value ? "ON" : "OFF");
std::string default_val;
if (opt.value.index() == 0) {
default_val = mpark::get<0>(opt.value) ? "ON" : "OFF";
} else {
default_val = mpark::get<1>(opt.value);
}
cmd("option")(opt.name, RawArg(Command::quote(opt.help)), default_val);
}
endl();
}
@@ -682,6 +861,27 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
endl();
}
if (project.vcpkg.enabled()) {
comment("vcpkg settings");
auto emit_overlay = [&cmd](const std::string &name, const std::vector<std::string> &overlay) {
if (!overlay.empty()) {
std::vector<std::string> set_args;
for (const auto &directory : overlay) {
if (!fs::path(directory).is_relative()) {
throw std::runtime_error("[vcpkg] overlay is not a relative path: " + directory);
}
if (!fs::is_directory(directory)) {
throw std::runtime_error("[vcpkg] overlay is not a directory: " + directory);
}
set_args.emplace_back("${CMAKE_CURRENT_SOURCE_DIR}/" + directory);
}
cmd("set")(name, set_args);
}
};
emit_overlay("VCPKG_OVERLAY_PORTS", project.vcpkg.overlay_ports);
emit_overlay("VCPKG_OVERLAY_TRIPLETS", project.vcpkg.overlay_triplets);
}
gen.conditional_includes(project.include_before);
gen.conditional_cmake(project.cmake_before);
@@ -702,7 +902,11 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
gen.conditional_includes(project.include_after);
gen.conditional_cmake(project.cmake_after);
if (!project.vcpkg.packages.empty()) {
if (project.vcpkg.enabled()) {
if (!is_root_project) {
throw std::runtime_error("[vcpkg] is only supported in the root project");
}
// Allow the user to specify a url or derive it from the version
auto url = project.vcpkg.url;
auto version_name = url;
@@ -715,24 +919,35 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
}
// Show a nicer error than vcpkg when specifying an invalid package name
for (const auto &package : project.vcpkg.packages) {
const auto &packages = project.vcpkg.packages;
for (const auto &package : packages) {
if (!vcpkg_valid_identifier(package.name)) {
throw std::runtime_error("Invalid [vcpkg].packages name '" + package.name + "' (needs to be lowercase alphanumeric)");
}
}
tsl::ordered_map<std::string, std::string> vcpkg_args = {
{"URL", url},
{"SUBBUILD_DIR", "CMakeFiles/vcpkg-subbuild"},
{"SOURCE_DIR", "vcpkg"},
{"BINARY_DIR", "CMakeFiles/vcpkg-build"},
};
// CMake to bootstrap vcpkg and download the packages
// clang-format off
cmd("if")("CMKR_ROOT_PROJECT", "AND", "NOT", "CMKR_DISABLE_VCPKG");
cmd("include")("FetchContent");
cmd("message")("STATUS", "Fetching vcpkg (" + version_name + ")...");
cmd("FetchContent_Declare")("vcpkg", "URL", url);
// Not using FetchContent_MakeAvailable here in case vcpkg adds CMakeLists.txt
cmd("FetchContent_GetProperties")("vcpkg");
cmd("if")("NOT", "vcpkg_POPULATED");
cmd("FetchContent_Populate")("vcpkg");
cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
comment("Fix warnings about DOWNLOAD_EXTRACT_TIMESTAMP");
cmd("if")("POLICY", "CMP0135");
cmd("cmake_policy")("SET", "CMP0135", "NEW");
cmd("endif")();
cmd("message")("STATUS", "Fetching vcpkg (" + version_name + ")...");
cmd("FetchContent_Declare")("vcpkg", vcpkg_args);
cmd("FetchContent_MakeAvailable")("vcpkg").endl();
cmd("if")("CMAKE_HOST_SYSTEM_NAME", "STREQUAL", "Darwin", "AND", "CMAKE_OSX_ARCHITECTURES", "STREQUAL", RawArg("\"\""));
cmd("set")("CMAKE_OSX_ARCHITECTURES", "${CMAKE_HOST_SYSTEM_PROCESSOR}", "CACHE", "STRING", RawArg("\"\""), "FORCE");
cmd("endif")();
cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
cmd("endif")();
endl();
// clang-format on
@@ -745,33 +960,41 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
ofs << R"({
"$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",
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"dependencies": [
)";
const auto &packages = project.vcpkg.packages;
for (size_t i = 0; i < packages.size(); i++) {
const auto &package = packages[i];
const auto &features = package.features;
if (!vcpkg_valid_identifier(package.name)) {
throw std::runtime_error("Invalid vcpkg package name '" + package.name + "'");
throw std::runtime_error("Invalid vcpkg package name '" + package.name + "', name is not valid");
}
if (vcpkg_identifier_reserved(package.name)) {
throw std::runtime_error("Invalid vcpkg package name '" + package.name + "', name is reserved");
}
for (const auto &feature : features) {
if (!vcpkg_valid_identifier(feature)) {
throw std::runtime_error("Invalid vcpkg package feature '" + feature + "'");
throw std::runtime_error("Invalid vcpkg package feature '" + feature + "', name is not valid");
}
if (vcpkg_identifier_reserved(feature)) {
throw std::runtime_error("Invalid vcpkg package feature '" + feature + "', name is reserved");
}
}
if (features.empty()) {
if (features.empty() && package.default_features) {
ofs << " \"" << package.name << '\"';
} else {
ofs << " {\n";
ofs << " \"name\": \"" << package.name << "\",\n";
if (!package.default_features) {
ofs << " \"default-features\": false,\n";
}
ofs << " \"features\": [";
for (size_t j = 0; j < features.size(); j++) {
const auto &feature = features[j];
ofs << '\"' << feature << '\"';
if (j + 1 < features.size()) {
ofs << ',';
ofs << ", ";
}
}
ofs << "]\n";
@@ -797,33 +1020,10 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
ofs << " ],\n";
ofs << " \"description\": \"" << escape(project.project_description) << "\",\n";
ofs << " \"name\": \"" << escape(vcpkg_escape_identifier(project.project_name)) << "\",\n";
ofs << R"( "version-string": "")" << '\n';
ofs << " \"version-string\": \"none\"\n";
ofs << "}\n";
}
if (!project.contents.empty()) {
cmd("include")("FetchContent").endl();
for (const auto &content : project.contents) {
ConditionScope cs(gen, content.condition);
gen.conditional_includes(content.include_before);
gen.conditional_cmake(content.cmake_before);
std::string version_info = "";
if (content.arguments.contains("GIT_TAG")) {
version_info = " (" + content.arguments.at("GIT_TAG") + ")";
} else if (content.arguments.contains("SVN_REVISION")) {
version_info = " (" + content.arguments.at("SVN_REVISION") + ")";
}
cmd("message")("STATUS", "Fetching " + content.name + version_info + "...");
cmd("FetchContent_Declare")(content.name, content.arguments);
cmd("FetchContent_MakeAvailable")(content.name).endl();
gen.conditional_includes(content.include_after);
gen.conditional_cmake(content.cmake_after);
}
}
if (!project.packages.empty()) {
comment("Packages");
for (const auto &dep : project.packages) {
@@ -838,6 +1038,41 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
}
}
if (!project.contents.empty()) {
cmd("include")("FetchContent").endl();
if (!project.root()->vcpkg.enabled()) {
comment("Fix warnings about DOWNLOAD_EXTRACT_TIMESTAMP");
// clang-format off
cmd("if")("POLICY", "CMP0135");
cmd("cmake_policy")("SET", "CMP0135", "NEW");
cmd("endif")();
// clang-format on
}
for (const auto &content : project.contents) {
ConditionScope cs(gen, content.condition);
gen.conditional_includes(content.include_before);
gen.conditional_cmake(content.cmake_before);
std::string version_info;
if (content.arguments.contains("GIT_TAG")) {
version_info = " (" + content.arguments.at("GIT_TAG") + ")";
} else if (content.arguments.contains("SVN_REVISION")) {
version_info = " (" + content.arguments.at("SVN_REVISION") + ")";
}
cmd("message")("STATUS", "Fetching " + content.name + version_info + "...");
if (content.system) {
cmd("FetchContent_Declare")(content.name, "SYSTEM", content.arguments);
} else {
cmd("FetchContent_Declare")(content.name, content.arguments);
}
cmd("FetchContent_MakeAvailable")(content.name).endl();
gen.conditional_includes(content.include_after);
gen.conditional_cmake(content.cmake_after);
}
}
auto add_subdir = [&](const std::string &dir) {
// clang-format off
comment("Subdirectory: " + dir);
@@ -883,6 +1118,9 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
if (project_languages.empty())
project_languages = {"C", "CXX"};
// Reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24340#note_1304703
project_languages.push_back("RC");
// All acceptable extensions based off our given languages.
tsl::ordered_set<std::string> project_extensions;
for (const auto &language : project_languages) {
@@ -892,7 +1130,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
}
}
auto contains_language_source = [&project_extensions](const std::vector<std::string>& sources) {
auto contains_language_source = [&project_extensions](const std::vector<std::string> &sources) {
for (const auto &source : sources) {
auto extension = fs::path(source).extension().string();
if (project_extensions.count(extension) > 0) {
@@ -906,6 +1144,9 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
auto project_root = project.root();
for (size_t i = 0; i < project.targets.size(); i++) {
const auto &target = project.targets[i];
auto throw_target_error = [&target](const std::string &message) { throw std::runtime_error("[target." + target.name + "] " + message); };
const parser::Template *tmplate = nullptr;
std::unique_ptr<ConditionScope> tmplate_cs{};
@@ -1009,7 +1250,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
auto sources = expand_cmake_paths(condition_sources, path, is_root_project);
if (sources.empty()) {
auto source_key = condition.empty() ? "sources" : (condition + ".sources");
throw std::runtime_error(target.name + " " + source_key + " wildcard found 0 files");
throw_target_error(source_key + " wildcard found 0 files");
}
// Make sure there are source files for the languages used by the project
@@ -1020,7 +1261,25 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
case parser::target_static:
case parser::target_object:
if (!contains_language_source(sources)) {
throw std::runtime_error("There were no source files linked within the target " + target.name);
std::string extensions;
for (const auto &language : project_extensions) {
if (!extensions.empty()) {
extensions += " ";
}
extensions += language;
}
throw_target_error("No sources found with valid extensions (" + extensions + ")");
}
// Make sure relative source files exist
for (const auto &source : sources) {
auto var_index = source.find("${");
if (var_index != std::string::npos)
continue;
const auto &source_path = fs::path(path) / source;
if (!fs::exists(source_path)) {
throw_target_error("Source file not found: " + source);
}
}
break;
default:
@@ -1030,7 +1289,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
if (sources_with_set) {
// This is a sanity check to make sure the unconditional sources are first
if (!condition.empty()) {
throw std::runtime_error("Unreachable code, make sure unconditional sources are first");
throw_target_error("Unreachable code, make sure unconditional sources are first");
}
cmd("set")(sources_var, sources);
sources_with_set = false;
@@ -1043,7 +1302,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
if (tmplate != nullptr) {
if (target_type != parser::target_template) {
throw std::runtime_error("Unreachable code, unexpected target type for template");
throw_target_error("Unreachable code, unexpected target type for template");
}
target_type = tmplate->outline.type;
}
@@ -1091,7 +1350,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
target_scope = "PUBLIC";
break;
default:
throw std::runtime_error("Unimplemented enum value");
throw_target_error("Unimplemented enum value");
}
// Handle custom add commands from templates.
@@ -1172,7 +1431,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
for (const auto &propItr : properties) {
if (propItr.first == "MSVC_RUNTIME_LIBRARY") {
if (project_root->project_msvc_runtime == parser::msvc_last) {
throw std::runtime_error("You cannot set [target].msvc-runtime without setting the root [project].msvc-runtime");
throw_target_error("You cannot set msvc-runtime without setting the root [project].msvc-runtime");
}
}
}
@@ -1215,7 +1474,12 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
}
auto working_directory = std::make_pair("WORKING_DIRECTORY", dir);
auto command = std::make_pair("COMMAND", test.command);
auto arguments = std::make_pair("", test.arguments);
// Transform the provided arguments into raw arguments to prevent them from being quoted when the generator runs
std::vector<RawArg> raw_arguments{};
for (const auto &argument : test.arguments)
raw_arguments.emplace_back(argument);
auto arguments = std::make_pair("", raw_arguments);
ConditionScope cs(gen, test.condition);
cmd("add_test")(name, configurations, working_directory, command, arguments).endl();
}
@@ -1246,10 +1510,19 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
}
}
// Fetch the generated CMakeLists.txt output from the stringstream buffer
auto generated_cmake = ss.str();
// Make sure the file ends in a single newline
while (!generated_cmake.empty() && std::isspace(generated_cmake.back())) {
generated_cmake.pop_back();
}
generated_cmake += '\n';
// Generate CMakeLists.txt
auto list_path = fs::path(path) / "CMakeLists.txt";
auto should_regenerate = [&list_path, &ss]() {
auto should_regenerate = [&list_path, &generated_cmake]() {
if (!fs::exists(list_path))
return true;
@@ -1259,11 +1532,11 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
}
std::string data((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
return data != ss.str();
return data != generated_cmake;
}();
if (should_regenerate) {
create_file(list_path, ss.str());
create_file(list_path, generated_cmake);
}
auto generate_subdir = [path, &project](const fs::path &sub) {
-31
View File
@@ -1,31 +0,0 @@
#include "error.hpp"
#include <cassert>
#include <cstddef>
namespace cmkr {
namespace error {
Status::Status(Code ec) noexcept : ec_(ec) {
}
Status::operator int() const noexcept {
return static_cast<int>(ec_);
}
Status::Code Status::code() const noexcept {
return ec_;
}
} // namespace error
} // namespace cmkr
// 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 && static_cast<size_t>(i) < (sizeof(err_string) / sizeof(*(err_string))));
return err_string[i];
}
-8
View File
@@ -23,11 +23,3 @@ arguments:
}
} // namespace help
} // namespace cmkr
const char *cmkr_help_version(void) {
return cmkr::help::version();
}
const char *cmkr_help_message(void) {
return cmkr::help::message();
}
+172 -20
View File
@@ -36,7 +36,7 @@ static std::string format_key_message(const std::string &message, const toml::ke
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();
const auto &line_str = loc.line_str();
std::ostringstream oss;
oss << message << "\n";
@@ -73,7 +73,7 @@ class TomlChecker {
public:
TomlChecker(const TomlBasicValue &v, const toml::key &ky) : m_v(toml::find(v, ky)) {
}
TomlChecker(const TomlBasicValue &v) : m_v(v) {
explicit TomlChecker(const TomlBasicValue &v) : m_v(v) {
}
TomlChecker(const TomlChecker &) = delete;
TomlChecker(TomlChecker &&) = delete;
@@ -140,7 +140,7 @@ class TomlChecker {
for (const auto &itr : m_v.as_table()) {
const auto &ky = itr.first;
if (m_conditionVisited.contains(ky)) {
if (!conditions.contains(ky)) {
if (!conditions.contains(ky) && Project::is_condition_name(ky)) {
throw_key_error("Unknown condition '" + ky + "'", ky, itr.second);
}
@@ -160,7 +160,7 @@ class TomlChecker {
throw_key_error("Unknown key '" + ky + "'", ky, itr.second);
} else if (ky == "condition") {
std::string condition = itr.second.as_string();
if (!conditions.contains(condition)) {
if (!conditions.contains(condition) && Project::is_condition_name(condition)) {
throw_key_error("Unknown condition '" + condition + "'", condition, itr.second);
}
}
@@ -175,7 +175,7 @@ class TomlCheckerRoot {
bool m_checked = false;
public:
TomlCheckerRoot(const TomlBasicValue &root) : m_root(root) {
explicit TomlCheckerRoot(const TomlBasicValue &root) : m_root(root) {
}
TomlCheckerRoot(const TomlCheckerRoot &) = delete;
TomlCheckerRoot(TomlCheckerRoot &&) = delete;
@@ -265,12 +265,22 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
conditions["bsd"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "BSD")cmake";
conditions["linux"] = conditions["lunix"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "Linux")cmake";
conditions["gcc"] = R"cmake(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "GNU")cmake";
conditions["msvc"] = R"cmake(MSVC)cmake";
conditions["clang"] =
R"cmake((CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$") OR (CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$"))cmake";
conditions["msvc"] = R"cmake(MSVC)cmake";
conditions["clang-cl"] =
R"cmake((CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$") OR (CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$"))cmake";
conditions["clang-any"] = R"cmake(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "Clang")cmake";
conditions["root"] = R"cmake(CMKR_ROOT_PROJECT)cmake";
conditions["x64"] = R"cmake(CMAKE_SIZEOF_VOID_P EQUAL 8)cmake";
conditions["x32"] = R"cmake(CMAKE_SIZEOF_VOID_P EQUAL 4)cmake";
conditions["android"] = R"cmake(ANDROID)cmake";
conditions["apple"] = R"cmake(APPLE)cmake";
conditions["bsd"] = R"cmake(BSD)cmake";
conditions["cygwin"] = R"cmake(CYGWIN)cmake";
conditions["ios"] = R"cmake(IOS)cmake";
conditions["xcode"] = R"cmake(XCODE)cmake";
conditions["wince"] = R"cmake(WINCE)cmake";
} else {
conditions = parent->conditions;
templates = parent->templates;
@@ -279,6 +289,9 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
if (checker.contains("conditions")) {
auto conds = toml::find<decltype(conditions)>(toml, "conditions");
for (const auto &cond : conds) {
if (!is_condition_name(cond.first)) {
throw_key_error("Invalid condition name '" + cond.first + "'", cond.first, toml::find(toml::find(toml, "conditions"), cond.first));
}
conditions[cond.first] = cond.second;
}
}
@@ -369,6 +382,25 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
}
if (checker.contains("options")) {
auto normalize = [](const std::string &name) {
std::string normalized;
for (char ch : name) {
if (ch == '_') {
normalized += '-';
} else if (ch >= 'A' && ch <= 'Z') {
ch += ('a' - 'A');
normalized += ch;
} else if (ch == '-' || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z')) {
normalized += ch;
} else {
// Ignore all other characters
}
}
return normalized;
};
auto nproject_prefix = normalize(project_name);
nproject_prefix += '-';
using opts_map = tsl::ordered_map<std::string, TomlBasicValue>;
const auto &opts = toml::find<opts_map>(toml, "options");
for (const auto &itr : opts) {
@@ -377,13 +409,50 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
const auto &value = itr.second;
if (value.is_boolean()) {
o.value = value.as_boolean();
} else {
} else if (value.is_string()) {
auto str = std::string(value.as_string());
if (str == "root") {
o.value = std::string("${CMKR_ROOT_PROJECT}");
} else {
throw_key_error("Unsupported option value '" + str + "'", str, value);
}
} else if (value.is_table()) {
auto &option = checker.create(value);
option.optional("help", o.help);
option.optional("value", o.value);
if (option.contains("value")) {
const auto &ovalue = option.find("value");
if (ovalue.is_boolean()) {
o.value = ovalue.as_boolean();
} else if (ovalue.is_string()) {
auto str = std::string(ovalue.as_string());
if (str == "root") {
o.value = std::string("${CMKR_ROOT_PROJECT}");
} else {
throw_key_error("Unsupported option value '" + str + "'", str, value);
}
} else {
throw_key_error(toml::concat_to_string("Unsupported value type: ", ovalue.type()), "value", value);
}
}
} else {
throw_key_error(toml::concat_to_string("Unsupported value type: ", itr.second.type()), itr.first, itr.second);
}
options.push_back(o);
// Add a condition matching the option name
conditions.emplace(o.name, o.name);
// Add an implicit condition for the option
auto ncondition = normalize(o.name);
if (ncondition.find(nproject_prefix) == 0) {
ncondition = ncondition.substr(nproject_prefix.size());
}
if (!ncondition.empty()) {
if (conditions.contains(ncondition)) {
print_key_warning("Option '" + o.name + "' would create a condition '" + ncondition + "' that already exists", o.name, value);
}
conditions.emplace(ncondition, o.name);
}
}
}
@@ -420,6 +489,15 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
c.optional("cmake-after", content.cmake_after);
c.optional("include-before", content.include_before);
c.optional("include-after", content.include_after);
c.optional("system", content.system);
// Check if the minimum version requirement is satisfied (CMake 3.25)
if (c.contains("system") && !this->cmake_minimum_version(3, 25)) {
throw_key_error("The system argument is only supported on CMake version 3.25 and above.\nSet the CMake version in cmake.toml:\n"
"[cmake]\n"
"version = \"3.25\"\n",
"system", "");
}
for (const auto &argItr : itr.second.as_table()) {
std::string value;
@@ -465,13 +543,26 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
key = "URL";
} else if (hash_algorithms.contains(key)) {
std::string algo;
for (auto c : key) {
algo.push_back(std::toupper(c));
for (auto ch : key) {
if (ch >= 'a' && ch <= 'z') {
ch -= ('a' - 'A');
}
algo.push_back(ch);
}
key = "URL_HASH";
if (value.empty()) {
throw_key_error("Empty hash value", argItr.first, argItr.second);
}
for (char c : value) {
if (!std::isxdigit(c)) {
throw_key_error("Hash value must be a hex string", argItr.first, argItr.second);
}
}
value = algo + "=" + value;
} else if (key == "hash") {
key = "URL_HASH";
} else if (key == "subdir") {
key = "SOURCE_SUBDIR";
} else if (is_cmake_arg(key)) {
// allow passthrough of ExternalProject options
} else if (!c.visisted(key)) {
@@ -562,6 +653,37 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
t.optional("link-libraries", target.link_libraries);
t.optional("private-link-libraries", target.private_link_libraries);
// Add support for relative paths for (private-)link-libraries
const auto fix_relative_paths = [&name, &path](ConditionVector &libraries, const char *key) {
for (const auto &library_entries : libraries) {
for (auto &library : libraries[library_entries.first]) {
// Skip processing paths with potential CMake macros in them (this check isn't perfect)
// https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#variable-references
if ((library.find("${") != std::string::npos || library.find("$ENV{") != std::string::npos ||
library.find("$CACHE{") != std::string::npos) &&
library.find('}') != std::string::npos) {
continue;
}
auto library_path = fs::path(path) / library;
if (fs::exists(library_path)) {
if (!fs::is_directory(library_path)) {
// If the file path is relative (and not a directory), prepend ${CMAKE_CURRENT_SOURCE_DIR}
library.insert(0, "${CMAKE_CURRENT_SOURCE_DIR}/");
}
} else if (library.find_first_of(R"(\/)") != std::string::npos) {
// Error if the path contains a directory separator and the file doesn't exist
throw std::runtime_error("Attempted to link against a library file that doesn't exist for target \"" + name + "\" in \"" +
key + "\": " + library);
} else {
// NOTE: We cannot check if system libraries exist, so we leave them as-is
}
}
}
};
fix_relative_paths(target.link_libraries, "link-libraries");
fix_relative_paths(target.private_link_libraries, "private-link-libraries");
t.optional("link-options", target.link_options);
t.optional("private-link-options", target.private_link_options);
@@ -570,28 +692,28 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
Condition<std::string> msvc_runtime;
t.optional("msvc-runtime", msvc_runtime);
for (const auto &condItr : msvc_runtime) {
switch (parse_msvcRuntimeType(condItr.second)) {
for (const auto &cond_itr : msvc_runtime) {
switch (parse_msvcRuntimeType(cond_itr.second)) {
case msvc_dynamic:
target.properties[condItr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL";
target.properties[cond_itr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL";
break;
case msvc_static:
target.properties[condItr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>";
target.properties[cond_itr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>";
break;
default: {
std::string error = "Unknown runtime '" + condItr.second + "'\n";
std::string error = "Unknown runtime '" + cond_itr.second + "'\n";
error += "Available types:\n";
for (std::string type_name : msvcRuntimeTypeNames) {
error += " - " + type_name + "\n";
}
error.pop_back(); // Remove last newline
const TomlBasicValue *report;
if (condItr.first.empty()) {
if (cond_itr.first.empty()) {
report = &t.find("msvc-runtime");
} else {
report = &t.find(condItr.first).as_table().find("msvc-runtime").value();
report = &t.find(cond_itr.first).as_table().find("msvc-runtime").value();
}
throw_key_error(error, condItr.second, *report);
throw_key_error(error, cond_itr.second, *report);
}
}
}
@@ -610,6 +732,8 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
property_list += list_val.as_string();
}
target.properties[condition][k] = property_list;
} else if (v.is_integer()) {
target.properties[condition][k] = std::to_string(v.as_integer());
} else if (v.is_boolean()) {
target.properties[condition][k] = v.as_boolean() ? "ON" : "OFF";
} else {
@@ -726,13 +850,33 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
std::istringstream feature_stream{features};
std::string feature;
while (std::getline(feature_stream, feature, ',')) {
package.features.emplace_back(feature);
// Disable default features with package-name[core,feature1]
if (feature == "core") {
package.default_features = false;
} else {
package.features.emplace_back(feature);
}
}
} else {
throw_key_error("Invalid package name '" + package_str + "'", "packages", p);
}
vcpkg.packages.emplace_back(std::move(package));
}
if (v.contains("overlay")) {
std::string overlay;
v.optional("overlay", overlay);
vcpkg.overlay_triplets = vcpkg.overlay_ports = {overlay};
if (v.contains("overlay-ports")) {
throw_key_error("[vcpkg].overlay was already specified", "overlay-ports", v.find("overlay-ports"));
}
if (v.contains("overlay-triplets")) {
throw_key_error("[vcpkg].overlay was already specified", "overlay-triplets", v.find("overlay-triplets"));
}
} else {
v.optional("overlay-ports", vcpkg.overlay_ports);
v.optional("overlay-triplets", vcpkg.overlay_triplets);
}
}
checker.check(conditions, true);
@@ -748,7 +892,6 @@ const Project *Project::root() const {
bool Project::cmake_minimum_version(int major, int minor) const {
// NOTE: this code is like pulling teeth, sorry
auto root_version = root()->cmake_version;
puts(root_version.c_str());
auto range_index = root_version.find("...");
if (range_index != std::string::npos) {
root_version.resize(range_index);
@@ -765,6 +908,15 @@ bool Project::cmake_minimum_version(int major, int minor) const {
return std::tie(root_major, root_minor) >= std::tie(major, minor);
}
bool Project::is_condition_name(const std::string &name) {
for (auto ch : name) {
if (!std::isalnum(ch) && ch != '-' && ch != '_') {
return false;
}
}
return true;
}
bool is_root_path(const std::string &path) {
const auto toml_path = fs::path(path) / "cmake.toml";
if (!fs::exists(toml_path)) {
+2 -1
View File
@@ -1,3 +1,4 @@
# These will be generated by cmkr, so no point in tracking them
**/CMakeLists.txt
**/cmkr.cmake
**/cmkr.cmake
**/vcpkg.json
+22
View File
@@ -100,3 +100,25 @@ if(MSVC) # msvc
)
endif()
add_test(
NAME
compile-options
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/compile-options"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
if(WIN32) # windows
add_test(
NAME
relative-paths
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/relative-paths"
COMMAND
"$<TARGET_FILE:cmkr>"
build
)
endif()
+1 -1
View File
@@ -8,4 +8,4 @@ description = "Minimal example"
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)`.
# 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)`.
+14 -1
View File
@@ -51,4 +51,17 @@ condition = "msvc"
name = "msvc-runtime"
working-directory = "msvc-runtime"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
arguments = ["build"]
[[test]]
name = "compile-options"
working-directory = "compile-options"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
[[test]]
condition = "windows"
name = "relative-paths"
working-directory = "relative-paths"
command = "$<TARGET_FILE:cmkr>"
arguments = ["build"]
+18
View File
@@ -0,0 +1,18 @@
# Example project that sets compiler flags and preprocessor defines for various platforms.
[project]
name = "compile-options"
description = "Compiler flags"
[target.hello]
type = "executable"
sources = ["src/main.cpp"]
msvc.compile-options = ["/W2"]
msvc.compile-definitions = ["PLATFORM=\"msvc\""]
gcc.compile-options = ["-Wall"]
gcc.compile-definitions = ["PLATFORM=\"gcc\""]
clang.compile-options = ["-Wall"]
clang.compile-definitions = ["PLATFORM=\"clang\""]
# The `hello` target uses [conditions](/cmake-toml#conditions) to set different compiler flags and definitions depending on the platform. See the [targets](/cmake-toml/#targets) documentation for other things you can set.
# _Note_: In general you only want to specify flags _required_ to compile your code without errors.
+5
View File
@@ -0,0 +1,5 @@
#include <cstdio>
int main() {
puts("Hello from cmkr!");
}
+28 -23
View File
@@ -1,23 +1,28 @@
[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"
[project]
name = "conditions"
cmake-after = "set(CUSTOM ON)"
[options]
CONDITIONS_BUILD_TESTS = "root"
[conditions]
custom = "CUSTOM"
[target.example]
type = "executable"
sources = ["src/main.cpp"]
windows.sources = ["src/windows_specific.cpp"]
cmake-after = "message(STATUS cmake-after)"
windows.cmake-after = "message(STATUS win32-after)"
macos.cmake-after = "message(STATUS macos-after)"
linux.cmake-after = "message(STATUS linux-after)"
unix.cmake-after = "message(STATUS unix-after)"
custom.cmake-after = "message(STATUS custom-after)"
build-tests.cmake-after = "message(STATUS build-tests)"
"CONDITIONS_BUILD_TESTS AND $<linux>".cmake-after = "message(STATUS linux-tests)"
[target.example.properties]
AUTOMOC = false
custom.OUTPUT_NAME = "example2"
custom.AUTORCC = true
AUTOGEN = "ON"
+2 -1
View File
@@ -1 +1,2 @@
int main() { }
int main() {
}
+4 -3
View File
@@ -1,3 +1,4 @@
#include <Windows.h>
void foo() { }
#include <Windows.h>
void foo() {
}
+12 -12
View File
@@ -1,12 +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).
# Require a C++11 compiler for the target `example`.
[project]
name = "cxx-standard"
description = "Changing C++ standard"
[target.example]
type = "executable"
sources = ["src/main.cpp"]
compile-features = ["cxx_std_11"]
# This is equivalent to CMake's [target_compile_features](https://cmake.org/cmake/help/latest/command/target_compile_features.html)`(example PRIVATE cxx_std_11)`. For more information on available C/C++ standards and features see [cmake-compile-features(7)](https://cmake.org/cmake/help/latest/manual/cmake-compile-features.7.html).
+7 -8
View File
@@ -1,8 +1,7 @@
#include <cstdio>
#include <tuple>
int main()
{
auto tpl = std::make_tuple(1, 2);
printf("Hello from C++11 %d\n", std::get<0>(tpl));
}
#include <cstdio>
#include <tuple>
int main() {
auto tpl = std::make_tuple(1, 2);
printf("Hello from C++11 %d\n", std::get<0>(tpl));
}
+1 -1
View File
@@ -12,4 +12,4 @@ 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).
# This is equivalent to calling CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html).
+2 -3
View File
@@ -1,6 +1,5 @@
#include <fmt/core.h>
int main()
{
int main() {
fmt::print("Hello, world!\n");
}
}
+18 -18
View File
@@ -1,18 +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.
[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 -7
View File
@@ -1,7 +1,7 @@
#include <iostream>
#include <mylib/mylib.hpp>
int main() {
std::cout << mylib::message() << std::endl;
return 0;
}
#include <iostream>
#include <mylib/mylib.hpp>
int main() {
std::cout << mylib::message() << std::endl;
return 0;
}
+7 -8
View File
@@ -1,8 +1,7 @@
#pragma once
#include <string>
namespace mylib
{
std::string message();
}
#pragma once
#include <string>
namespace mylib {
std::string message();
} // namespace mylib
+5 -6
View File
@@ -1,6 +1,5 @@
#include <mylib/mylib.hpp>
std::string mylib::message()
{
return "cmkr is awesome!";
}
#include <mylib/mylib.hpp>
std::string mylib::message() {
return "cmkr is awesome!";
}
+13 -13
View File
@@ -1,13 +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"]
[project]
name = "interface"
description = "Header-only library"
[target.mylib]
type = "interface"
include-directories = ["include"]
compile-features = ["cxx_std_11"]
[target.example]
type = "executable"
sources = ["src/main.cpp"]
link-libraries = ["mylib"]
+5 -4
View File
@@ -1,4 +1,5 @@
namespace mylib
{
static const char* version() { return "v1.0"; }
} // namespace mylib
namespace mylib {
static const char *version() {
return "v1.0";
}
} // namespace mylib
+7 -8
View File
@@ -1,8 +1,7 @@
#include <cstdio>
#include "mylib/mylib.hpp"
int main()
{
printf("mylib version: %s\n", mylib::version());
}
#include <cstdio>
#include "mylib/mylib.hpp"
int main() {
printf("mylib version: %s\n", mylib::version());
}
+1 -1
View File
@@ -12,4 +12,4 @@ sources = ["src/main.cpp"]
[target.dynamic-runtime]
type = "executable"
sources = ["src/main.cpp"]
msvc-runtime = "dynamic"
msvc-runtime = "dynamic"
+11
View File
@@ -0,0 +1,11 @@
[project]
name = "relative-paths"
[target.test-library]
type = "static"
sources = ["src/library-code.cpp"]
[target.example]
type = "executable"
sources = ["src/main.cpp"]
windows.link-libraries = ["libs/test-library-x64-Release.lib"]
@@ -0,0 +1,6 @@
// Created by Anthony Printup on 9/18/2023.
#include <cstdio>
extern "C" void library_function() {
std::puts("Hello from library_function!");
}
+12
View File
@@ -0,0 +1,12 @@
// Created by Anthony Printup on 9/18/2023.
#include <cstdio>
#ifdef WIN32
extern "C" void library_function();
#endif
int main() {
puts("Hello from cmkr(relative-paths)!");
#ifdef WIN32
library_function();
#endif
}
+1 -1
View File
@@ -22,4 +22,4 @@ compile-definitions = ["APP_A"]
type = "app"
compile-definitions = ["APP_B"]
# **Note**: In most cases you probably want to use an [interface](/examples/interface) target instead.
# **Note**: In most cases you probably want to use an [interface](/examples/interface) target instead.
+5 -6
View File
@@ -1,17 +1,16 @@
# Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) using [vcpkg](https://vcpkg.io/) and links an `example` target to it:
# Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) using [vcpkg](https://github.com/microsoft/vcpkg) and links an `example` target to it:
[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
# See https://vcpkg.io/en/packages or https://vcpkg.link for available packages
[vcpkg]
version = "2022.11.14"
version = "2024.11.16"
packages = ["fmt"]
[find-package]
fmt = {}
[find-package.fmt]
[target.example]
type = "executable"
@@ -19,4 +18,4 @@ 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]`.
# To specify package features you can use the following syntax: `imgui[docking-experimental,freetype,sdl2-binding,opengl3-binding]`.
+2 -3
View File
@@ -1,6 +1,5 @@
#include <fmt/core.h>
int main()
{
int main() {
fmt::print("Hello, world!\n");
}
}
-11
View File
@@ -1,11 +0,0 @@
{
"$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": ""
}
+3
View File
@@ -0,0 +1,3 @@
# Disable clang-format in this folder
DisableFormat: true
SortIncludes: Never
Generated Vendored
-4
View File
@@ -16,7 +16,3 @@ 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
@@ -1,21 +0,0 @@
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