mirror of
https://github.com/build-cpp/cmkr
synced 2026-06-08 13:22:55 +00:00
Compare commits
235 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 43c72160b5 | |||
| ef3c1a288a | |||
| 26acf23989 | |||
| 15886fc340 | |||
| d5e34b0bcc | |||
| 916ae11cae | |||
| eaa361611a | |||
| 2300612ba9 | |||
| 25f015bc83 | |||
| fc674b4c6b | |||
| 433dbb0500 | |||
| 4772a2b683 | |||
| fb4931df1f | |||
| e96cd30217 | |||
| 2db8d1ee1d | |||
| 645737afd4 | |||
| 98c2e962c0 | |||
| 438feccf0f | |||
| 80cc29b8e1 | |||
| 1a62034a8a | |||
| c12472cd8f | |||
| 228553d43a | |||
| 8f4b376e42 | |||
| fcbf937c49 | |||
| e609c8a48f | |||
| 735898dbac | |||
| f7126b0158 | |||
| b6702714eb | |||
| efa4f716c2 | |||
| 76b7b8e778 | |||
| 501b26ced5 | |||
| 5bc36275ad | |||
| 35c837a181 | |||
| 710dfa4963 | |||
| c49ee6bafe | |||
| 368273bab2 | |||
| ffe08ae60c | |||
| b1249af365 | |||
| ea2ff31b5a | |||
| a32eb66df4 | |||
| 9b85833240 | |||
| ccb3d0b9ef | |||
| 49cdab39bd | |||
| e318139314 | |||
| 0f2a9a55fb | |||
| 38cec2d5d1 | |||
| 3caf593438 | |||
| c94dbd6416 | |||
| a1eaf601c6 | |||
| 10320c8e55 | |||
| 45e12c8d98 | |||
| e12ebc060d | |||
| c6e3fc159f | |||
| dc6f306d9c | |||
| e08bd5a311 | |||
| 068977e2f5 | |||
| 73147747a4 | |||
| a64fa9cc34 | |||
| eb6ccb39ee | |||
| 91dd8ce51f | |||
| efbfca27bd | |||
| 78bcf2acf7 | |||
| 83559cc5d4 | |||
| 5d85cc83e3 | |||
| dea41d80b5 | |||
| b52cf5b241 | |||
| e9480a625f | |||
| 13a7a8788a | |||
| 45ca74099c | |||
| ae3d73896e | |||
| 57042565d1 | |||
| d02ee3ed24 | |||
| 4a15d2ba55 | |||
| 87c0295f93 | |||
| a608e6b778 | |||
| 523f5f4a8a | |||
| 510cf71af5 | |||
| 87d90138b4 | |||
| 50615e0c27 | |||
| 42ed3048b3 | |||
| b0a1d79a42 | |||
| 5882bc082d | |||
| a90b3c6095 | |||
| 0a887c08f8 | |||
| 9f2cfe4083 | |||
| 15ad1dc6a7 | |||
| dabffeaed9 | |||
| 59fe5c38b8 | |||
| dcdc7ac410 | |||
| 88377a8bfb | |||
| 3a9685be82 | |||
| 5576789c18 | |||
| a362978f99 | |||
| a2f33297e4 | |||
| 674c976647 | |||
| 714a666e88 | |||
| d613e433d5 | |||
| 7c828d8740 | |||
| 559f750c89 | |||
| 4b6b72874e | |||
| 6bffa7cc71 | |||
| f415b432ed | |||
| 6c46664336 | |||
| f32aac63aa | |||
| 33d4cc4156 | |||
| 9288c8a87d | |||
| e36eee4420 | |||
| 53820c9f65 | |||
| ff7e4b8f23 | |||
| 1072cb44e2 | |||
| 926fc15fa2 | |||
| e2c929adb0 | |||
| 0dec7ca4d5 | |||
| 45e346b4a3 | |||
| 7165986190 | |||
| be0ef6d615 | |||
| d607b9028c | |||
| 099b14552c | |||
| 771c80a41a | |||
| 58c7de1d60 | |||
| a61e4bb999 | |||
| 47aaeaf8ce | |||
| 62609a0088 | |||
| e0d8a085db | |||
| 56da4144ae | |||
| 9388b3f29d | |||
| 079644cfeb | |||
| a7ca9f04c0 | |||
| 339c2aac94 | |||
| c573c9a76d | |||
| b24a0a2fdc | |||
| 854e8817c4 | |||
| 1c2947b2fc | |||
| 19e61aa1aa | |||
| bfa1e1fe0d | |||
| 56bd78f7ad | |||
| 4362b3547f | |||
| 08204d9847 | |||
| 2202aa8173 | |||
| d3829fb6cd | |||
| 3fb095210a | |||
| 9f99365a25 | |||
| be387141b5 | |||
| 09ded38f70 | |||
| ad90b1ad3e | |||
| 5bfa03d311 | |||
| bdd9d393d6 | |||
| 1deaec2b41 | |||
| cfee3bbc14 | |||
| bcaa60cabe | |||
| 7b1d33395e | |||
| 240fafc102 | |||
| 7a7ddf2699 | |||
| 605a04e72d | |||
| fd7f078127 | |||
| ee0e0d71d9 | |||
| 9d6897b572 | |||
| f8c34e5545 | |||
| e6d783ea20 | |||
| ee7fe38a7b | |||
| 66b2aad843 | |||
| d2e376080a | |||
| 634908c651 | |||
| 33911f3f1b | |||
| e650073bef | |||
| 96e44f7771 | |||
| cb9ad5cdb3 | |||
| c785b540d3 | |||
| 275b73eefa | |||
| ea49a3acb7 | |||
| 257e14c869 | |||
| 7508816fe7 | |||
| 45678bc5bc | |||
| b869e5646f | |||
| a499df84b1 | |||
| 49440f99e0 | |||
| 0c19c3da0c | |||
| 233cadadd0 | |||
| 58a5a935e5 | |||
| e69427bf94 | |||
| bc6359805d | |||
| 8dcc11e349 | |||
| 51dc49e6f1 | |||
| 7d27c28b59 | |||
| ae6bea3b58 | |||
| 5a0eda7abc | |||
| f17923c18b | |||
| ad17890e23 | |||
| c0b98b3ef4 | |||
| 2c6fc569af | |||
| 12ee23a44c | |||
| 82342a6b6f | |||
| 1d95fab0ce | |||
| 44a77329bf | |||
| e68c5fccdc | |||
| e2722d2c09 | |||
| 2627864383 | |||
| 05e21f734a | |||
| 1fd18503cd | |||
| 8b19441d34 | |||
| 2437eb90fe | |||
| 6e4006ec07 | |||
| 697b638723 | |||
| 109c4bc99f | |||
| cad85f0bb1 | |||
| 53c88ceafa | |||
| d2aa15b1c7 | |||
| e6ded077cf | |||
| 3615ccab94 | |||
| 73622aa5ba | |||
| 69d844a152 | |||
| af9a117f50 | |||
| 5fe8220728 | |||
| 28f541cd3c | |||
| 2f3fd7b95e | |||
| 07d99c582d | |||
| 5af2385cc3 | |||
| 981c48dbc5 | |||
| 153bdbe591 | |||
| 97f1c5c1cc | |||
| 5b6d9c3826 | |||
| a90988b81a | |||
| 3a1298f4e8 | |||
| 534f955827 | |||
| ef537ce084 | |||
| 9cdd0f7344 | |||
| e69cf4d2b9 | |||
| e98a906231 | |||
| 9a82f8c796 | |||
| 13255c68cf | |||
| 5768460827 | |||
| 50d4a905b6 | |||
| f957cec2dc | |||
| 232e49e087 | |||
| 7408d42160 |
+4
-3
@@ -10,16 +10,17 @@ AlignTrailingComments: true
|
|||||||
AllowAllParametersOfDeclarationOnNextLine: true
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
AllowShortBlocksOnASingleLine: false
|
AllowShortBlocksOnASingleLine: false
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
AllowShortFunctionsOnASingleLine: true
|
AllowShortFunctionsOnASingleLine: false
|
||||||
AllowShortIfStatementsOnASingleLine: false
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
AllowShortLoopsOnASingleLine: false
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AllowShortLambdasOnASingleLine: None
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
AlwaysBreakAfterReturnType: None
|
AlwaysBreakAfterReturnType: None
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
AlwaysBreakTemplateDeclarations: true
|
AlwaysBreakTemplateDeclarations: true
|
||||||
BinPackArguments: true
|
BinPackArguments: true
|
||||||
BinPackParameters: true
|
BinPackParameters: true
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterClass: false
|
AfterClass: false
|
||||||
AfterControlStatement: false
|
AfterControlStatement: false
|
||||||
AfterEnum: false
|
AfterEnum: false
|
||||||
@@ -72,7 +73,7 @@ PenaltyExcessCharacter: 1000000
|
|||||||
PenaltyReturnTypeOnItsOwnLine: 60
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
ReflowComments: true
|
ReflowComments: true
|
||||||
SortIncludes: true
|
SortIncludes: false
|
||||||
SortUsingDeclarations: true
|
SortUsingDeclarations: true
|
||||||
SpaceAfterCStyleCast: false
|
SpaceAfterCStyleCast: false
|
||||||
SpaceAfterTemplateKeyword: true
|
SpaceAfterTemplateKeyword: true
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
[*.{c,h,cpp,hpp,toml}]
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[{CMakeLists.txt, *.cmake}]
|
||||||
|
indent_style = tab
|
||||||
|
tab_width = 8
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# Exclude the third_party folder
|
||||||
|
[/third_party/**]
|
||||||
|
charset = unset
|
||||||
|
end_of_line = unset
|
||||||
|
insert_final_newline = unset
|
||||||
|
trim_trailing_whitespace = unset
|
||||||
|
indent_style = unset
|
||||||
|
indent_size = unset
|
||||||
@@ -1,21 +1,25 @@
|
|||||||
name: CMake
|
name: build
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
cmake:
|
||||||
# Skip building pull requests from the same repository
|
# 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) }}
|
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [windows-2019, macos-10.15, ubuntu-20.04]
|
os: [windows-2022, macos-latest, ubuntu-22.04]
|
||||||
env:
|
env:
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: 'Release'
|
||||||
|
CMAKE_GENERATOR: 'Ninja'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Visual Studio Development Environment
|
||||||
|
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.1
|
||||||
|
|
||||||
- name: Tag cmkr.cmake
|
- name: Tag cmkr.cmake
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
@@ -38,28 +42,31 @@ jobs:
|
|||||||
ctest -C ${{ env.BUILD_TYPE }} --verbose
|
ctest -C ${{ env.BUILD_TYPE }} --verbose
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.event.repository.name }}-${{ matrix.os }}
|
name: ${{ github.event.repository.name }}-${{ matrix.os }}
|
||||||
path: install/bin/*
|
path: install/bin/*
|
||||||
|
|
||||||
- name: Get lowercase OS name
|
- name: Get lowercase OS name
|
||||||
id: osname
|
id: osname
|
||||||
uses: ASzc/change-string-case-action@v1
|
uses: ASzc/change-string-case-action@ccb130a4e483d3e86287289183704dc9bf53e77e # master 2024-04-05
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
with:
|
with:
|
||||||
string: ${{ runner.os }}
|
string: ${{ runner.os }}
|
||||||
|
|
||||||
- name: Compress artifacts
|
- name: Compress artifacts
|
||||||
uses: vimtor/action-zip@v1
|
uses: vimtor/action-zip@1379ea20d4c5705669ba81fd626dd01b1c738f26 # v1.2
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
with:
|
with:
|
||||||
files: install/bin/
|
files: install/bin/
|
||||||
dest: ${{ github.event.repository.name }}-${{ steps.osname.outputs.lowercase }}.zip
|
dest: ${{ github.event.repository.name }}-${{ steps.osname.outputs.lowercase }}.zip
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
with:
|
with:
|
||||||
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') || contains(github.ref, '-pre') }}
|
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') || contains(github.ref, '-pre') }}
|
||||||
files: ${{ github.event.repository.name }}-${{ steps.osname.outputs.lowercase }}.zip
|
files: ${{ github.event.repository.name }}-${{ steps.osname.outputs.lowercase }}.zip
|
||||||
|
generate_release_notes: true
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: lint
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang-format:
|
||||||
|
# Skip building pull requests from the same repository
|
||||||
|
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: clang-format
|
||||||
|
id: clang-format
|
||||||
|
uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2
|
||||||
|
with:
|
||||||
|
exclude: './third_party'
|
||||||
|
extensions: 'c,h,cpp,hpp'
|
||||||
|
clangFormatVersion: 15
|
||||||
|
style: file
|
||||||
|
|
||||||
|
- name: clang-format instructions
|
||||||
|
if: ${{ failure() && steps.clang-format.outcome == 'failure' }}
|
||||||
|
run: |
|
||||||
|
# Instructions for fixing the formatting errors
|
||||||
|
echo -e "\n\033[0;31mTo fix the formatting, run:\nclang-format -style=file -i \$(git ls-files \"*.c\" \"*.h\" \"*.cpp\" \"*.hpp\")\033[0m\n"
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
editorconfig:
|
||||||
|
# Skip building pull requests from the same repository
|
||||||
|
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run editorconfig-checker
|
||||||
|
uses: editorconfig-checker/action-editorconfig-checker@27dd658c2b1282c7f1f4dc242cdf0f6d8af728ab # master 2025-05-30
|
||||||
@@ -9,3 +9,5 @@ build*/
|
|||||||
.idea/
|
.idea/
|
||||||
cmake-build*/
|
cmake-build*/
|
||||||
CMakeLists.txt.user
|
CMakeLists.txt.user
|
||||||
|
.vscode/
|
||||||
|
.DS_Store
|
||||||
Generated
+25
-55
@@ -1,23 +1,20 @@
|
|||||||
# This file is automatically generated from cmake.toml - DO NOT EDIT
|
# This file is automatically generated from cmake.toml - DO NOT EDIT
|
||||||
# See https://github.com/build-cpp/cmkr for more information
|
# 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)
|
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")
|
message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Regenerate CMakeLists.txt automatically in the root project
|
|
||||||
set(CMKR_ROOT_PROJECT OFF)
|
set(CMKR_ROOT_PROJECT OFF)
|
||||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
set(CMKR_ROOT_PROJECT ON)
|
set(CMKR_ROOT_PROJECT ON)
|
||||||
|
|
||||||
# Enable folder support
|
# Enable folder support
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
endif()
|
|
||||||
|
|
||||||
# Create a configure-time dependency on cmake.toml to improve IDE support
|
# Create a configure-time dependency on cmake.toml to improve IDE support
|
||||||
if(CMKR_ROOT_PROJECT)
|
|
||||||
configure_file(cmake.toml cmake.toml COPYONLY)
|
configure_file(cmake.toml cmake.toml COPYONLY)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -25,7 +22,7 @@ project(cmkr
|
|||||||
LANGUAGES
|
LANGUAGES
|
||||||
CXX
|
CXX
|
||||||
VERSION
|
VERSION
|
||||||
0.2.12
|
0.2.46
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
"CMakeLists generator from TOML"
|
"CMakeLists generator from TOML"
|
||||||
)
|
)
|
||||||
@@ -33,7 +30,7 @@ project(cmkr
|
|||||||
include("cmake/generate_documentation.cmake")
|
include("cmake/generate_documentation.cmake")
|
||||||
include("cmake/generate_resources.cmake")
|
include("cmake/generate_resources.cmake")
|
||||||
|
|
||||||
# third_party
|
# Subdirectory: third_party
|
||||||
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
|
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
|
||||||
if(CMAKE_FOLDER)
|
if(CMAKE_FOLDER)
|
||||||
set(CMAKE_FOLDER "${CMAKE_FOLDER}/third_party")
|
set(CMAKE_FOLDER "${CMAKE_FOLDER}/third_party")
|
||||||
@@ -43,7 +40,7 @@ endif()
|
|||||||
add_subdirectory(third_party)
|
add_subdirectory(third_party)
|
||||||
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
|
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
|
||||||
|
|
||||||
# tests
|
# Subdirectory: tests
|
||||||
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
|
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
|
||||||
if(CMAKE_FOLDER)
|
if(CMAKE_FOLDER)
|
||||||
set(CMAKE_FOLDER "${CMAKE_FOLDER}/tests")
|
set(CMAKE_FOLDER "${CMAKE_FOLDER}/tests")
|
||||||
@@ -53,64 +50,35 @@ endif()
|
|||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
|
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
|
||||||
|
|
||||||
|
# Target: cmkr_generate_documentation
|
||||||
|
|
||||||
# Target cmkr_generate_documentation
|
|
||||||
set(CMKR_TARGET cmkr_generate_documentation)
|
|
||||||
set(cmkr_generate_documentation_SOURCES "")
|
|
||||||
|
|
||||||
set(CMKR_SOURCES ${cmkr_generate_documentation_SOURCES})
|
|
||||||
add_library(cmkr_generate_documentation INTERFACE)
|
add_library(cmkr_generate_documentation INTERFACE)
|
||||||
|
|
||||||
if(cmkr_generate_documentation_SOURCES)
|
set(CMKR_TARGET cmkr_generate_documentation)
|
||||||
target_sources(cmkr_generate_documentation INTERFACE ${cmkr_generate_documentation_SOURCES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
generate_documentation()
|
generate_documentation()
|
||||||
|
|
||||||
unset(CMKR_TARGET)
|
# Target: cmkr
|
||||||
unset(CMKR_SOURCES)
|
set(cmkr_SOURCES
|
||||||
|
cmake.toml
|
||||||
# Target cmkr
|
"cmake/cmkr.cmake"
|
||||||
set(CMKR_TARGET cmkr)
|
"cmake/version.hpp.in"
|
||||||
set(cmkr_SOURCES "")
|
|
||||||
|
|
||||||
list(APPEND cmkr_SOURCES
|
|
||||||
"src/arguments.cpp"
|
|
||||||
"src/build.cpp"
|
|
||||||
"src/cmake_generator.cpp"
|
|
||||||
"src/error.cpp"
|
|
||||||
"src/help.cpp"
|
|
||||||
"src/main.cpp"
|
|
||||||
"src/project_parser.cpp"
|
|
||||||
"include/arguments.hpp"
|
"include/arguments.hpp"
|
||||||
"include/build.hpp"
|
"include/build.hpp"
|
||||||
"include/cmake_generator.hpp"
|
"include/cmake_generator.hpp"
|
||||||
"include/error.hpp"
|
|
||||||
"include/fs.hpp"
|
"include/fs.hpp"
|
||||||
"include/help.hpp"
|
"include/help.hpp"
|
||||||
"include/literals.hpp"
|
"include/literals.hpp"
|
||||||
"include/project_parser.hpp"
|
"include/project_parser.hpp"
|
||||||
"cmake/cmkr.cmake"
|
"src/arguments.cpp"
|
||||||
"cmake/version.hpp.in"
|
"src/build.cpp"
|
||||||
|
"src/cmake_generator.cpp"
|
||||||
|
"src/help.cpp"
|
||||||
|
"src/main.cpp"
|
||||||
|
"src/project_parser.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND cmkr_SOURCES
|
|
||||||
cmake.toml
|
|
||||||
)
|
|
||||||
|
|
||||||
set(CMKR_SOURCES ${cmkr_SOURCES})
|
|
||||||
add_executable(cmkr)
|
add_executable(cmkr)
|
||||||
|
|
||||||
if(cmkr_SOURCES)
|
target_sources(cmkr PRIVATE ${cmkr_SOURCES})
|
||||||
target_sources(cmkr PRIVATE ${cmkr_SOURCES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
|
|
||||||
if(NOT CMKR_VS_STARTUP_PROJECT)
|
|
||||||
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT cmkr)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkr_SOURCES})
|
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkr_SOURCES})
|
||||||
|
|
||||||
target_compile_features(cmkr PRIVATE
|
target_compile_features(cmkr PRIVATE
|
||||||
@@ -126,13 +94,15 @@ target_link_libraries(cmkr PRIVATE
|
|||||||
ghc_filesystem
|
ghc_filesystem
|
||||||
mpark_variant
|
mpark_variant
|
||||||
ordered_map
|
ordered_map
|
||||||
nlohmann_json
|
|
||||||
)
|
)
|
||||||
|
|
||||||
generate_resources(${CMKR_TARGET})
|
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
|
||||||
|
if(NOT CMKR_VS_STARTUP_PROJECT)
|
||||||
|
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT cmkr)
|
||||||
|
endif()
|
||||||
|
|
||||||
unset(CMKR_TARGET)
|
set(CMKR_TARGET cmkr)
|
||||||
unset(CMKR_SOURCES)
|
include("cmake/custom_targets.cmake")
|
||||||
|
|
||||||
install(
|
install(
|
||||||
TARGETS
|
TARGETS
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# cmkr
|
# cmkr
|
||||||
|
|
||||||
|
[](https://deepwiki.com/build-cpp/cmkr)
|
||||||
|
|
||||||
`cmkr`, pronounced "cmaker", is a modern build system based on [CMake](https://cmake.org/) and [TOML](https://toml.io).
|
`cmkr`, pronounced "cmaker", is a modern build system based on [CMake](https://cmake.org/) and [TOML](https://toml.io).
|
||||||
|
|
||||||
`cmkr` parses `cmake.toml` files and generates a modern, idiomatic `CMakeLists.txt` for you. A minimal example:
|
`cmkr` parses `cmake.toml` files and generates a modern, idiomatic `CMakeLists.txt` for you. A minimal example:
|
||||||
@@ -13,27 +15,29 @@ type = "executable"
|
|||||||
sources = ["src/main.cpp"]
|
sources = ["src/main.cpp"]
|
||||||
```
|
```
|
||||||
|
|
||||||
`cmkr` can bootstrap itself from CMake and you only need CMake to use it.
|
`cmkr` can bootstrap itself and you only need CMake and a C++ compiler to use it.
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
To get started run the following commands from your project directory:
|
To get started, run the following commands from your project directory:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl https://raw.githubusercontent.com/build-cpp/cmkr/main/cmake/cmkr.cmake -o cmkr.cmake
|
curl https://raw.githubusercontent.com/build-cpp/cmkr/main/cmake/cmkr.cmake -o cmkr.cmake
|
||||||
cmake -P cmkr.cmake
|
cmake -P cmkr.cmake
|
||||||
```
|
```
|
||||||
|
|
||||||
After the bootstrapping process finishes, modify [`cmake.toml`](https://build-cpp.github.io/cmkr/cmake-toml) and open the project in your favorite IDE or build with CMake:
|
After the bootstrapping process finishes, customize [`cmake.toml`](https://build-cpp.github.io/cmkr/cmake-toml) for your project and run CMake:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cmake -B build
|
cmake -B build
|
||||||
cmake --build build
|
cmake --build build
|
||||||
```
|
```
|
||||||
|
|
||||||
Once bootstrapped, `cmkr` does not introduce extra steps to your workflow. After modifying `cmake.toml` you simply build/configure your CMake project and `cmkr` will automatically regenerate `CMakeLists.txt`.
|
Once bootstrapped, `cmkr` does not introduce extra steps to your workflow. After modifying `cmake.toml` you simply build/configure your CMake project and `cmkr` will automatically regenerate `CMakeLists.txt` when necessary.
|
||||||
|
|
||||||
In CI settings the `cmkr` bootstrapping process is skipped so there is no extra configure-time overhead in your pipelines.
|
<sub>**Note**: The `cmake.toml` project file, generated `CMakeLists.txt` and `cmkr.cmake` bootstrapping script are all intended to be added to source control.</sub>
|
||||||
|
|
||||||
|
In CI environments the `cmkr` bootstrapping process is skipped, so there is no additional overhead in your pipelines.
|
||||||
|
|
||||||
## Template repositories
|
## Template repositories
|
||||||
|
|
||||||
@@ -53,10 +57,10 @@ Optionally you can put a [`cmkr` release](https://github.com/build-cpp/cmkr/rele
|
|||||||
```
|
```
|
||||||
Usage: cmkr [arguments]
|
Usage: cmkr [arguments]
|
||||||
arguments:
|
arguments:
|
||||||
init [executable|library|shared|static|interface] Starts a new project in the same directory.
|
init [executable|library|shared|static|interface] Create a project.
|
||||||
gen Generates CMakeLists.txt file.
|
gen Generates CMakeLists.txt file.
|
||||||
build <extra cmake args> Run cmake and build.
|
build <extra cmake args> Run cmake and build.
|
||||||
install Run cmake --install. Needs admin privileges.
|
install Run cmake --install.
|
||||||
clean Clean the build directory.
|
clean Clean the build directory.
|
||||||
help Show help.
|
help Show help.
|
||||||
version Current cmkr version.
|
version Current cmkr version.
|
||||||
@@ -64,9 +68,10 @@ arguments:
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
- https://github.com/gulrak/filesystem
|
- [gulrak/filesystem](https://github.com/gulrak/filesystem)
|
||||||
- https://github.com/Tessil/ordered-map
|
- [Tessil/ordered-map](https://github.com/Tessil/ordered-map)
|
||||||
- https://github.com/ToruNiina/toml11
|
- [ToruNiina/toml11](https://github.com/ToruNiina/toml11)
|
||||||
- https://github.com/mpark/variant
|
- [mpark/variant](https://github.com/mpark/variant)
|
||||||
- https://www.svgrepo.com/svg/192268/hammer
|
- [SVG Repo Hammer](https://www.svgrepo.com/svg/192268/hammer)
|
||||||
- https://github.com/can1357 for buying `cmkr.build` ❤️
|
- [can1357](https://github.com/can1357) for buying `cmkr.build` ❤️
|
||||||
|
- [JustasMasiulis](https://github.com/JustasMasiulis) for fixing the dark theme ❤️
|
||||||
|
|||||||
+4
-7
@@ -1,17 +1,17 @@
|
|||||||
[cmake]
|
[cmake]
|
||||||
version = "2.8...3.8"
|
version = "2.8...3.31"
|
||||||
cmkr-include = false
|
cmkr-include = false
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "cmkr"
|
name = "cmkr"
|
||||||
version = "0.2.12"
|
version = "0.2.46"
|
||||||
description = "CMakeLists generator from TOML"
|
description = "CMakeLists generator from TOML"
|
||||||
languages = ["CXX"]
|
languages = ["CXX"]
|
||||||
subdirs = ["third_party", "tests"]
|
|
||||||
include-after = [
|
include-after = [
|
||||||
"cmake/generate_documentation.cmake",
|
"cmake/generate_documentation.cmake",
|
||||||
"cmake/generate_resources.cmake"
|
"cmake/generate_resources.cmake"
|
||||||
]
|
]
|
||||||
|
subdirs = ["third_party", "tests"]
|
||||||
|
|
||||||
[target.cmkr_generate_documentation]
|
[target.cmkr_generate_documentation]
|
||||||
type = "interface"
|
type = "interface"
|
||||||
@@ -36,11 +36,8 @@ link-libraries = [
|
|||||||
"ghc_filesystem",
|
"ghc_filesystem",
|
||||||
"mpark_variant",
|
"mpark_variant",
|
||||||
"ordered_map",
|
"ordered_map",
|
||||||
"nlohmann_json",
|
|
||||||
]
|
]
|
||||||
cmake-after = """
|
include-after = ["cmake/custom_targets.cmake"]
|
||||||
generate_resources(${CMKR_TARGET})
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[install]]
|
[[install]]
|
||||||
targets = ["cmkr"]
|
targets = ["cmkr"]
|
||||||
|
|||||||
+77
-77
@@ -1,78 +1,78 @@
|
|||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
if(NOT CMAKE_SCRIPT_MODE_FILE)
|
if(NOT CMAKE_SCRIPT_MODE_FILE)
|
||||||
message(FATAL_ERROR "Usage: cmake -P bump_version.cmake [1.2.3]")
|
message(FATAL_ERROR "Usage: cmake -P bump_version.cmake [1.2.3]")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake.toml")
|
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake.toml")
|
||||||
message(FATAL_ERROR "Cannot find cmake.toml")
|
message(FATAL_ERROR "Cannot find cmake.toml")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake/cmkr.cmake")
|
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake/cmkr.cmake")
|
||||||
message(FATAL_ERROR "Cannot find cmkr.cmake")
|
message(FATAL_ERROR "Cannot find cmkr.cmake")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Validate branch
|
# Validate branch
|
||||||
find_package(Git REQUIRED)
|
find_package(Git REQUIRED)
|
||||||
execute_process(COMMAND "${GIT_EXECUTABLE}" branch --show-current OUTPUT_VARIABLE GIT_BRANCH)
|
execute_process(COMMAND "${GIT_EXECUTABLE}" branch --show-current OUTPUT_VARIABLE GIT_BRANCH)
|
||||||
string(STRIP "${GIT_BRANCH}" GIT_BRANCH)
|
string(STRIP "${GIT_BRANCH}" GIT_BRANCH)
|
||||||
if(NOT GIT_BRANCH STREQUAL "main")
|
if(NOT GIT_BRANCH STREQUAL "main")
|
||||||
message(FATAL_ERROR "You need to be on the main branch, you are on: ${GIT_BRANCH}")
|
message(FATAL_ERROR "You need to be on the main branch, you are on: ${GIT_BRANCH}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(READ "${CMAKE_SOURCE_DIR}/cmake.toml" CMAKE_TOML)
|
file(READ "${CMAKE_SOURCE_DIR}/cmake.toml" CMAKE_TOML)
|
||||||
string(FIND "${CMAKE_TOML}" "[project]" PROJECT_INDEX)
|
string(FIND "${CMAKE_TOML}" "[project]" PROJECT_INDEX)
|
||||||
string(SUBSTRING "${CMAKE_TOML}" ${PROJECT_INDEX} -1 CMAKE_TOML_PROJECT)
|
string(SUBSTRING "${CMAKE_TOML}" ${PROJECT_INDEX} -1 CMAKE_TOML_PROJECT)
|
||||||
set(SEMVER_REGEX "([0-9]+)\\.([0-9]+)\\.([0-9]+)")
|
set(SEMVER_REGEX "([0-9]+)\\.([0-9]+)\\.([0-9]+)")
|
||||||
set(VERSION_REGEX "version = \"${SEMVER_REGEX}\"")
|
set(VERSION_REGEX "version = \"${SEMVER_REGEX}\"")
|
||||||
if(CMAKE_TOML_PROJECT MATCHES "${VERSION_REGEX}")
|
if(CMAKE_TOML_PROJECT MATCHES "${VERSION_REGEX}")
|
||||||
set(MAJOR "${CMAKE_MATCH_1}")
|
set(MAJOR "${CMAKE_MATCH_1}")
|
||||||
set(MINOR "${CMAKE_MATCH_2}")
|
set(MINOR "${CMAKE_MATCH_2}")
|
||||||
set(PATCH "${CMAKE_MATCH_3}")
|
set(PATCH "${CMAKE_MATCH_3}")
|
||||||
set(OLDVERSION "${MAJOR}.${MINOR}.${PATCH}")
|
set(OLDVERSION "${MAJOR}.${MINOR}.${PATCH}")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Failed to match semantic version in cmake.toml")
|
message(FATAL_ERROR "Failed to match semantic version in cmake.toml")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_ARGV3)
|
if(CMAKE_ARGV3)
|
||||||
if(NOT CMAKE_ARGV3 MATCHES "${SEMVER_REGEX}")
|
if(NOT CMAKE_ARGV3 MATCHES "${SEMVER_REGEX}")
|
||||||
message(FATAL_ERROR "Invalid semantic version number '${CMAKE_ARGV3}'")
|
message(FATAL_ERROR "Invalid semantic version number '${CMAKE_ARGV3}'")
|
||||||
endif()
|
endif()
|
||||||
set(NEWVERSION "${CMAKE_ARGV3}")
|
set(NEWVERSION "${CMAKE_ARGV3}")
|
||||||
else()
|
else()
|
||||||
math(EXPR NEWPATCH "${PATCH} + 1")
|
math(EXPR NEWPATCH "${PATCH} + 1")
|
||||||
set(NEWVERSION "${MAJOR}.${MINOR}.${NEWPATCH}")
|
set(NEWVERSION "${MAJOR}.${MINOR}.${NEWPATCH}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
message(STATUS "Version ${OLDVERSION} -> ${NEWVERSION}")
|
message(STATUS "Version ${OLDVERSION} -> ${NEWVERSION}")
|
||||||
|
|
||||||
find_program(CMKR_EXECUTABLE "cmkr" PATHS "${CMAKE_SOURCE_DIR}/build" PATH_SUFFIXES Debug Release RelWithDebInfo MinSizeRel NO_CACHE REQUIRED)
|
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}")
|
message(STATUS "Found cmkr: ${CMKR_EXECUTABLE}")
|
||||||
|
|
||||||
# Replace version in cmake.toml
|
# Replace version in cmake.toml
|
||||||
string(REPLACE "version = \"${OLDVERSION}\"" "version = \"${NEWVERSION}\"" CMAKE_TOML "${CMAKE_TOML}")
|
string(REPLACE "version = \"${OLDVERSION}\"" "version = \"${NEWVERSION}\"" CMAKE_TOML "${CMAKE_TOML}")
|
||||||
file(CONFIGURE
|
file(CONFIGURE
|
||||||
OUTPUT "${CMAKE_SOURCE_DIR}/cmake.toml"
|
OUTPUT "${CMAKE_SOURCE_DIR}/cmake.toml"
|
||||||
CONTENT "${CMAKE_TOML}"
|
CONTENT "${CMAKE_TOML}"
|
||||||
@ONLY
|
@ONLY
|
||||||
NEWLINE_STYLE LF
|
NEWLINE_STYLE LF
|
||||||
)
|
)
|
||||||
|
|
||||||
# Run cmkr gen
|
# Run cmkr gen
|
||||||
execute_process(COMMAND "${CMKR_EXECUTABLE}" gen RESULT_VARIABLE CMKR_EXEC_RESULT)
|
execute_process(COMMAND "${CMKR_EXECUTABLE}" gen RESULT_VARIABLE CMKR_EXEC_RESULT)
|
||||||
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||||
message(FATAL_ERROR "cmkr gen failed (exit code ${CMKR_EXEC_RESULT})")
|
message(FATAL_ERROR "cmkr gen failed (exit code ${CMKR_EXEC_RESULT})")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Replace version in cmkr.cmake
|
# Replace version in cmkr.cmake
|
||||||
file(READ "${CMAKE_SOURCE_DIR}/cmake/cmkr.cmake" 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}")
|
string(REGEX REPLACE "CMKR_TAG \"[^\"]+\"" "CMKR_TAG \"v${NEWVERSION}\"" CMKR_CMAKE "${CMKR_CMAKE}")
|
||||||
file(CONFIGURE
|
file(CONFIGURE
|
||||||
OUTPUT "${CMAKE_SOURCE_DIR}/cmake/cmkr.cmake"
|
OUTPUT "${CMAKE_SOURCE_DIR}/cmake/cmkr.cmake"
|
||||||
CONTENT "${CMKR_CMAKE}"
|
CONTENT "${CMKR_CMAKE}"
|
||||||
@ONLY
|
@ONLY
|
||||||
NEWLINE_STYLE LF
|
NEWLINE_STYLE LF
|
||||||
)
|
)
|
||||||
|
|
||||||
# Print git commands
|
# 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}")
|
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}")
|
||||||
+30
-5
@@ -2,7 +2,7 @@ include_guard()
|
|||||||
|
|
||||||
# Change these defaults to point to your infrastructure if desired
|
# 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_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE)
|
||||||
set(CMKR_TAG "v0.2.12" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
set(CMKR_TAG "v0.2.46" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||||
set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE)
|
set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE)
|
||||||
|
|
||||||
# To bootstrap/generate a cmkr project: cmake -P cmkr.cmake
|
# To bootstrap/generate a cmkr project: cmake -P cmkr.cmake
|
||||||
@@ -10,6 +10,7 @@ if(CMAKE_SCRIPT_MODE_FILE)
|
|||||||
set(CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}/build")
|
set(CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}/build")
|
||||||
set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}")
|
set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}")
|
||||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}")
|
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||||
|
file(WRITE "${CMAKE_BINARY_DIR}/.gitignore" "# This file is autogenerated by cmkr.\n*\n")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set these from the command line to customize for development/debugging purposes
|
# Set these from the command line to customize for development/debugging purposes
|
||||||
@@ -58,9 +59,16 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Use cached cmkr if found
|
# Use cached cmkr if found
|
||||||
if(DEFINED ENV{CMKR_CACHE} AND EXISTS "$ENV{CMKR_CACHE}")
|
if(DEFINED ENV{CMKR_CACHE})
|
||||||
set(CMKR_DIRECTORY_PREFIX "$ENV{CMKR_CACHE}")
|
set(CMKR_DIRECTORY_PREFIX "$ENV{CMKR_CACHE}")
|
||||||
string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
|
string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
|
||||||
|
if(CMKR_DIRECTORY_PREFIX MATCHES "^~")
|
||||||
|
if(WIN32)
|
||||||
|
string(REGEX REPLACE "^~" "$ENV{USERPROFILE}" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
|
||||||
|
elseif(UNIX)
|
||||||
|
string(REGEX REPLACE "^~" "$ENV{HOME}" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
if(NOT CMKR_DIRECTORY_PREFIX MATCHES "\\/$")
|
if(NOT CMKR_DIRECTORY_PREFIX MATCHES "\\/$")
|
||||||
set(CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}/")
|
set(CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}/")
|
||||||
endif()
|
endif()
|
||||||
@@ -72,10 +80,27 @@ endif()
|
|||||||
set(CMKR_DIRECTORY "${CMKR_DIRECTORY_PREFIX}${CMKR_TAG}")
|
set(CMKR_DIRECTORY "${CMKR_DIRECTORY_PREFIX}${CMKR_TAG}")
|
||||||
set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}")
|
set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}")
|
||||||
|
|
||||||
|
# Helper function to check if a string starts with a prefix
|
||||||
|
# Cannot use MATCHES, see: https://github.com/build-cpp/cmkr/issues/61
|
||||||
|
function(cmkr_startswith str prefix result)
|
||||||
|
string(LENGTH "${prefix}" prefix_length)
|
||||||
|
string(LENGTH "${str}" str_length)
|
||||||
|
if(prefix_length LESS_EQUAL str_length)
|
||||||
|
string(SUBSTRING "${str}" 0 ${prefix_length} str_prefix)
|
||||||
|
if(prefix STREQUAL str_prefix)
|
||||||
|
set("${result}" ON PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
set("${result}" OFF PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
# Handle upgrading logic
|
# Handle upgrading logic
|
||||||
if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE)
|
if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE)
|
||||||
if(CMKR_EXECUTABLE MATCHES "^${CMAKE_CURRENT_BINARY_DIR}/_cmkr")
|
cmkr_startswith("${CMKR_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/_cmkr" CMKR_STARTSWITH_BUILD)
|
||||||
if(DEFINED ENV{CMKR_CACHE} AND EXISTS "$ENV{CMKR_CACHE}")
|
cmkr_startswith("${CMKR_EXECUTABLE}" "${CMKR_DIRECTORY_PREFIX}" CMKR_STARTSWITH_CACHE)
|
||||||
|
if(CMKR_STARTSWITH_BUILD)
|
||||||
|
if(DEFINED ENV{CMKR_CACHE})
|
||||||
message(AUTHOR_WARNING "[cmkr] Switching to cached cmkr: '${CMKR_CACHED_EXECUTABLE}'")
|
message(AUTHOR_WARNING "[cmkr] Switching to cached cmkr: '${CMKR_CACHED_EXECUTABLE}'")
|
||||||
if(EXISTS "${CMKR_CACHED_EXECUTABLE}")
|
if(EXISTS "${CMKR_CACHED_EXECUTABLE}")
|
||||||
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
|
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
|
||||||
@@ -86,7 +111,7 @@ if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE)
|
|||||||
message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
||||||
unset(CMKR_EXECUTABLE CACHE)
|
unset(CMKR_EXECUTABLE CACHE)
|
||||||
endif()
|
endif()
|
||||||
elseif(DEFINED ENV{CMKR_CACHE} AND EXISTS "$ENV{CMKR_CACHE}" AND CMKR_EXECUTABLE MATCHES "^${CMKR_DIRECTORY_PREFIX}")
|
elseif(DEFINED ENV{CMKR_CACHE} AND CMKR_STARTSWITH_CACHE)
|
||||||
message(AUTHOR_WARNING "[cmkr] Upgrading cached '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
message(AUTHOR_WARNING "[cmkr] Upgrading cached '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
||||||
unset(CMKR_EXECUTABLE CACHE)
|
unset(CMKR_EXECUTABLE CACHE)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
option(CMKR_GENERATE_DOCUMENTATION "Generate cmkr documentation" ${CMKR_ROOT_PROJECT})
|
option(CMKR_GENERATE_DOCUMENTATION "Generate cmkr documentation" ${CMKR_ROOT_PROJECT})
|
||||||
set(CMKR_TESTS "" CACHE INTERNAL "List of test directories in the order declared in tests/cmake.toml")
|
|
||||||
|
|
||||||
if(CMKR_GENERATE_DOCUMENTATION)
|
|
||||||
# Hook the add_test function to capture the tests in the order declared in tests/cmake.toml
|
|
||||||
function(add_test)
|
|
||||||
cmake_parse_arguments(TEST "" "WORKING_DIRECTORY" "" ${ARGN})
|
|
||||||
get_filename_component(TEST_WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}" NAME)
|
|
||||||
list(APPEND CMKR_TESTS "${TEST_WORKING_DIRECTORY}")
|
|
||||||
set(CMKR_TESTS "${CMKR_TESTS}" CACHE INTERNAL "")
|
|
||||||
_add_test(${test} ${ARGN})
|
|
||||||
endfunction()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
function(generate_documentation)
|
function(generate_documentation)
|
||||||
if(CMKR_GENERATE_DOCUMENTATION)
|
if(CMKR_GENERATE_DOCUMENTATION)
|
||||||
message(STATUS "[cmkr] Generating documentation...")
|
message(STATUS "[cmkr] Generating documentation...")
|
||||||
|
|
||||||
|
# Extract the order of the tests
|
||||||
|
set(CMKR_TESTS "")
|
||||||
|
file(READ "${PROJECT_SOURCE_DIR}/tests/cmake.toml" tests_toml NO_HEX_CONVERSION)
|
||||||
|
string(REGEX MATCHALL "working-directory = \"([^\"]+)\"" tests_match "${tests_toml}")
|
||||||
|
foreach(match ${tests_match})
|
||||||
|
if(match MATCHES "working-directory = \"([^\"]+)\"")
|
||||||
|
list(APPEND CMKR_TESTS "${CMAKE_MATCH_1}")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "This should not happen (wrong regex?)")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
# Delete previously generated examples
|
# Delete previously generated examples
|
||||||
set(example_folder "${PROJECT_SOURCE_DIR}/docs/examples")
|
set(example_folder "${PROJECT_SOURCE_DIR}/docs/examples")
|
||||||
file(GLOB example_files "${example_folder}/*.md")
|
file(GLOB example_files "${example_folder}/*.md")
|
||||||
@@ -41,21 +41,21 @@ function(generate_documentation)
|
|||||||
# Read cmake.toml file
|
# Read cmake.toml file
|
||||||
file(READ "${test_toml}" test_contents NO_HEX_CONVERSION)
|
file(READ "${test_toml}" test_contents NO_HEX_CONVERSION)
|
||||||
string(LENGTH "${test_contents}" toml_length)
|
string(LENGTH "${test_contents}" toml_length)
|
||||||
|
|
||||||
# Extract header text
|
# Extract header text
|
||||||
string(REGEX MATCH "^(\n*(#[^\n]+\n)+\n*)" EXAMPLE_HEADER "${test_contents}")
|
string(REGEX MATCH "^(\n*(#[^\n]+\n)+\n*)" EXAMPLE_HEADER "${test_contents}")
|
||||||
string(LENGTH "${EXAMPLE_HEADER}" header_length)
|
string(LENGTH "${EXAMPLE_HEADER}" header_length)
|
||||||
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
|
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
|
||||||
string(REGEX REPLACE "\n# ?" "\n\n" EXAMPLE_HEADER "\n${EXAMPLE_HEADER}")
|
string(REGEX REPLACE "\n# ?" "\n\n" EXAMPLE_HEADER "\n${EXAMPLE_HEADER}")
|
||||||
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
|
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
|
||||||
|
|
||||||
# Extract footer text
|
# Extract footer text
|
||||||
string(REGEX MATCH "(((#[^\n]+)(\n+|$))+)$" EXAMPLE_FOOTER "${test_contents}")
|
string(REGEX MATCH "(((#[^\n]+)(\n+|$))+)$" EXAMPLE_FOOTER "${test_contents}")
|
||||||
string(LENGTH "${EXAMPLE_FOOTER}" footer_length)
|
string(LENGTH "${EXAMPLE_FOOTER}" footer_length)
|
||||||
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
|
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
|
||||||
string(REGEX REPLACE "\n# ?" "\n\n" EXAMPLE_FOOTER "\n${EXAMPLE_FOOTER}")
|
string(REGEX REPLACE "\n# ?" "\n\n" EXAMPLE_FOOTER "\n${EXAMPLE_FOOTER}")
|
||||||
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
|
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
|
||||||
|
|
||||||
# Extract toml body
|
# Extract toml body
|
||||||
math(EXPR toml_length "${toml_length}-${header_length}-${footer_length}")
|
math(EXPR toml_length "${toml_length}-${header_length}-${footer_length}")
|
||||||
string(SUBSTRING "${test_contents}" ${header_length} ${toml_length} EXAMPLE_TOML)
|
string(SUBSTRING "${test_contents}" ${header_length} ${toml_length} EXAMPLE_TOML)
|
||||||
@@ -64,7 +64,7 @@ function(generate_documentation)
|
|||||||
# Extract title from description
|
# Extract title from description
|
||||||
if("${EXAMPLE_TOML}" MATCHES "description *= *\"([^\"]+)\"")
|
if("${EXAMPLE_TOML}" MATCHES "description *= *\"([^\"]+)\"")
|
||||||
set(EXAMPLE_TITLE "${CMAKE_MATCH_1}")
|
set(EXAMPLE_TITLE "${CMAKE_MATCH_1}")
|
||||||
|
|
||||||
# Generate documentation markdown page
|
# Generate documentation markdown page
|
||||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/example.md.in" "${example_folder}/${EXAMPLE_PERMALINK}.md" @ONLY NEWLINE_STYLE LF)
|
configure_file("${PROJECT_SOURCE_DIR}/cmake/example.md.in" "${example_folder}/${EXAMPLE_PERMALINK}.md" @ONLY NEWLINE_STYLE LF)
|
||||||
else()
|
else()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace cmkr {
|
namespace cmkr {
|
||||||
namespace resources {
|
namespace resources {
|
||||||
|
|
||||||
static const char* @RESOURCE_NAME@ = R"RESOURCE(@RESOURCE_CONTENTS@)RESOURCE";
|
static const char* @RESOURCE_NAME@ = R"RESOURCE(@RESOURCE_CONTENTS@)RESOURCE";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
cmkr.build
|
cmkr.build
|
||||||
|
|||||||
+19
-1
@@ -21,4 +21,22 @@ gh_edit_branch: "main"
|
|||||||
gh_edit_view_mode: "edit"
|
gh_edit_view_mode: "edit"
|
||||||
gh_edit_source: docs
|
gh_edit_source: docs
|
||||||
|
|
||||||
production_url : https://cmkr.build
|
ga_tracking: G-DY172KY7Z9
|
||||||
|
|
||||||
|
production_url : https://cmkr.build
|
||||||
|
footer_content: |
|
||||||
|
<script src="https://giscus.app/client.js"
|
||||||
|
data-repo="build-cpp/cmkr"
|
||||||
|
data-repo-id="MDEwOlJlcG9zaXRvcnkyOTQwMDc3MzY="
|
||||||
|
data-category="Documentation"
|
||||||
|
data-category-id="DIC_kwDOEYYzuM4CTXeA"
|
||||||
|
data-mapping="pathname"
|
||||||
|
data-strict="1"
|
||||||
|
data-reactions-enabled="1"
|
||||||
|
data-emit-metadata="0"
|
||||||
|
data-input-position="top"
|
||||||
|
data-theme="preferred_color_scheme"
|
||||||
|
data-lang="en"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
async>
|
||||||
|
</script>
|
||||||
+143
@@ -0,0 +1,143 @@
|
|||||||
|
---
|
||||||
|
layout: page
|
||||||
|
title: Basics
|
||||||
|
nav_order: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Basics
|
||||||
|
|
||||||
|
To effectively use cmkr it helps to understand the basic concepts of CMake. This page serves as an introduction to CMake for beginners. Links to the CMake documentation are included for reference.
|
||||||
|
|
||||||
|
## Projects
|
||||||
|
|
||||||
|
A CMake **project** is a collection of targets. In the context of libraries the project usually corresponds to the **package** that other projects can depend on.
|
||||||
|
|
||||||
|
<sub>Visual Studio: a CMake **project** corresponds to a _solution_.</sub>
|
||||||
|
|
||||||
|
## Targets
|
||||||
|
|
||||||
|
The basic unit of CMake is called a **target**. A target (also referred to as [binary target](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#binary-targets) in the CMake documentation) corresponds to an executable or static/dynamic library you can build.
|
||||||
|
|
||||||
|
<sub>Visual Studio: a **target** corresponds to a _project_.</sub>
|
||||||
|
|
||||||
|
Most important target types:
|
||||||
|
|
||||||
|
|Type|Purpose|
|
||||||
|
|-|-|
|
||||||
|
|Executable|Program you run on your computer (`.exe`)|
|
||||||
|
|Static library|Library code _compiled into_ the final executable (`.lib`, `.a`)|
|
||||||
|
|Dynamic library|Library code loaded at runtime (`.dll`, `.so`, `.dylib`)|
|
||||||
|
|Interface|Used for organizational purposes (common flags/includes/libraries)|
|
||||||
|
|
||||||
|
There are also other [pseudo targets](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#pseudo-targets), but they are not important for now.
|
||||||
|
|
||||||
|
## Target Properties
|
||||||
|
|
||||||
|
Targets have a collection of **properties** that describe how the compiler builds them.
|
||||||
|
|
||||||
|
The most commonly-used properties:
|
||||||
|
|
||||||
|
- [_Sources_](https://cmake.org/cmake/help/latest/command/target_sources.html): the `*.cpp` files used to build the target.
|
||||||
|
- [_Include directories_](https://cmake.org/cmake/help/latest/command/target_include_directories.html): Paths to directories the compiler will search when doing `#include`.
|
||||||
|
- [_Compile definitions_](https://cmake.org/cmake/help/latest/command/target_compile_definitions.html): Preprocessor macro definitions used for compilation (`-DMYOPTION`).
|
||||||
|
- [_Compile options_](https://cmake.org/cmake/help/latest/command/target_compile_options.html): Command line flags for the compiler (platform/compiler specific).
|
||||||
|
- [_Compile features_](https://cmake.org/cmake/help/latest/command/target_compile_features.html): C/C++ standard version to build with.
|
||||||
|
- [_Link libraries_](https://cmake.org/cmake/help/latest/command/target_link_libraries.html): The **dependencies** required to build this target.
|
||||||
|
- [_Link options_](https://cmake.org/cmake/help/latest/command/target_link_options.html): Command line flags for the linker (platform/linker specific).
|
||||||
|
|
||||||
|
<sub>See the [CMake documentation](https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#properties-on-targets) for an exhaustive list of target properties.</sub>
|
||||||
|
|
||||||
|
**Important**: The term **link** has a slightly different meaning in CMake than you might expect. In addition to adding a library to the command line, CMake also (transitively) propagates properties of the target you link to based on their _visibility_.
|
||||||
|
|
||||||
|
You should think of **linking** in CMake as _depending on_.
|
||||||
|
{:.info}
|
||||||
|
|
||||||
|
The propagation of properties depends on their **visibility**:
|
||||||
|
|
||||||
|
- **Private**: properties that are only used when building the target itself.
|
||||||
|
- **Interface**: properties that are used when depending on this target.
|
||||||
|
- **Public**: combination of private and interface.
|
||||||
|
|
||||||
|
In practice you default to **private**, unless consumers of your library _require_ the property to build their target. In that case you use **public**.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
The most intuitive example is with _include directories_. Imagine there are two targets:
|
||||||
|
|
||||||
|
1. `StringUtils`: A library with string utilities.
|
||||||
|
- _Sources_: `StringUtils/src/stringutils.cpp`
|
||||||
|
- _Include directories_: `StringUtils/include`
|
||||||
|
2. `DataProcessor`: An executable that uses functionality from `StringUtils` to process some data.
|
||||||
|
- _Sources_: `DataProcessor/src/main.cpp`
|
||||||
|
- _Link libraries_: `StringUtils`
|
||||||
|
|
||||||
|
The _include directories_ property of `StringUtils` has to be **public**. If it was **private**, the `DataProcessor` target would fail to `#include <stringutils.hpp>` since the _include directories_ property is not propagated.
|
||||||
|
|
||||||
|
The `cmake.toml` for this example would look something like this:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project]
|
||||||
|
name = "DataProcessor"
|
||||||
|
|
||||||
|
[target.StringUtils]
|
||||||
|
type = "static"
|
||||||
|
sources = ["StringUtils/src/stringutils.cpp"]
|
||||||
|
headers = ["StringUtils/include/stringutils.hpp"]
|
||||||
|
include-directories = ["StringUtils/include"] # public (default for libraries)
|
||||||
|
|
||||||
|
[target.DataProcessor]
|
||||||
|
type = "executable"
|
||||||
|
sources = ["DataProcessor/src/main.cpp"]
|
||||||
|
link-libraries = ["StringUtils"] # private (default for executables)
|
||||||
|
```
|
||||||
|
|
||||||
|
The generated `CMakeLists.txt` (simplified) looks like this:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
project(DataProcessor)
|
||||||
|
|
||||||
|
# Target: StringUtils
|
||||||
|
add_library(StringUtils STATIC
|
||||||
|
"StringUtils/include/stringutils.hpp"
|
||||||
|
"StringUtils/src/stringutils.cpp"
|
||||||
|
)
|
||||||
|
target_include_directories(StringUtils PUBLIC
|
||||||
|
"StringUtils/include"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Target: DataProcessor
|
||||||
|
add_executable(DataProcessor
|
||||||
|
"DataProcessor/src/main.cpp"
|
||||||
|
)
|
||||||
|
target_link_libraries(DataProcessor PRIVATE
|
||||||
|
StringUtils
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## CMake Phases
|
||||||
|
|
||||||
|
CMake works in three phases:
|
||||||
|
1. **Configure**: Execute `CMakeLists.txt` (find dependencies, create targets, OS/compiler-specific conditions, etc).
|
||||||
|
2. **Generate**: Generate build files (propagates target properties and handles [_generator expressions_](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html)).
|
||||||
|
3. **Build**: Execute the compiler to produce executables/libraries.
|
||||||
|
|
||||||
|
CMake keeps generated files separate from your source in a **build directory**. You specify a [**generator**](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) (Visual Studio/Ninja) and [**build type**](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations) (Debug/Release) during configuration.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Configure project and generate build files in build directory
|
||||||
|
cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
|
# Build the project
|
||||||
|
cmake --build build --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
We specify both `CMAKE_BUILD_TYPE` and `--config` to be compatible with generators that support multiple configurations at once ((like Visual Studio/Xcode/Ninja Multi-Config).
|
||||||
|
{:.info}
|
||||||
|
|
||||||
|
**Build Types**:
|
||||||
|
- `Debug`: No optimization, debug symbols
|
||||||
|
- `Release`: Full optimization, no debug symbols
|
||||||
|
- `RelWithDebInfo`: Medium optimizations, debug symbols
|
||||||
|
- `MinSizeRel`: Optimize for size, no debug symbols
|
||||||
|
|
||||||
|
**Generators**: CMake auto-detects (Makefiles on Linux/macOS, Visual Studio on Windows), but you can specify explicitly with `-G` during the _configure_ step.
|
||||||
+167
-28
@@ -2,14 +2,15 @@
|
|||||||
layout: page
|
layout: page
|
||||||
title: Reference
|
title: Reference
|
||||||
permalink: /cmake-toml/
|
permalink: /cmake-toml/
|
||||||
nav_order: 1
|
nav_order: 3
|
||||||
---
|
---
|
||||||
|
|
||||||
# Reference
|
# Reference
|
||||||
|
|
||||||
This page is a reference for the options in the `cmake.toml` file. If you think anything is missing or unclear, please [edit this page](https://github.com/build-cpp/cmkr/edit/main/docs/cmake-toml.md) or open an [issue](https://github.com/build-cpp/cmkr/issues).
|
This page is a reference for the options in the `cmake.toml` file. If you think anything is missing or unclear, please [edit this page](https://github.com/build-cpp/cmkr/edit/main/docs/cmake-toml.md) or open an [issue](https://github.com/build-cpp/cmkr/issues).
|
||||||
|
|
||||||
See the [examples](/examples) section for concrete examples.
|
This is a reference page. Check out the [examples](/examples) and the [cmkr topic](https://github.com/topics/cmkr) as well.
|
||||||
|
{:.info}
|
||||||
|
|
||||||
## CMake configuration
|
## CMake configuration
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ name = "myproject"
|
|||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
description = "Description of the project"
|
description = "Description of the project"
|
||||||
languages = ["C", "CXX"]
|
languages = ["C", "CXX"]
|
||||||
|
msvc-runtime = "" # dynamic (implicit default), static
|
||||||
cmake-before = """
|
cmake-before = """
|
||||||
message(STATUS "CMake injected before the project() call")
|
message(STATUS "CMake injected before the project() call")
|
||||||
"""
|
"""
|
||||||
@@ -37,17 +39,45 @@ include-before = ["cmake/before-project.cmake"]
|
|||||||
include-after = ["cmake/after-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
|
## 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
|
```toml
|
||||||
[conditions]
|
[conditions]
|
||||||
arch64 = "CMAKE_SIZEOF_VOID_P EQUALS 8"
|
ptr64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
|
||||||
arch32 = "CMAKE_SIZEOF_VOID_P EQUALS 4"
|
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:
|
You can also prefix most keys with `condition.` to represent a conditional:
|
||||||
|
|
||||||
@@ -55,9 +85,13 @@ You can also prefix most keys with `condition.` to represent a conditional:
|
|||||||
[target]
|
[target]
|
||||||
type = "executable"
|
type = "executable"
|
||||||
sources = ["src/main.cpp"]
|
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):
|
The following conditions are predefined (you can override them if you desire):
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
@@ -68,11 +102,20 @@ unix = "UNIX"
|
|||||||
bsd = "CMAKE_SYSTEM_NAME MATCHES \"BSD\""
|
bsd = "CMAKE_SYSTEM_NAME MATCHES \"BSD\""
|
||||||
linux = "CMAKE_SYSTEM_NAME MATCHES \"Linux\""
|
linux = "CMAKE_SYSTEM_NAME MATCHES \"Linux\""
|
||||||
gcc = "CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" OR CMAKE_C_COMPILER_ID STREQUAL \"GNU\""
|
gcc = "CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" OR CMAKE_C_COMPILER_ID STREQUAL \"GNU\""
|
||||||
clang = "CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" OR CMAKE_C_COMPILER_ID MATCHES \"Clang\""
|
|
||||||
msvc = "MSVC"
|
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"
|
root = "CMKR_ROOT_PROJECT"
|
||||||
x64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
|
x64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
|
||||||
x32 = "CMAKE_SIZEOF_VOID_P EQUAL 4"
|
x32 = "CMAKE_SIZEOF_VOID_P EQUAL 4"
|
||||||
|
android = "ANDROID"
|
||||||
|
apple = "APPLE"
|
||||||
|
bsd = "BSD"
|
||||||
|
cygwin = "CYGWIN"
|
||||||
|
ios = "IOS"
|
||||||
|
xcode = "XCODE"
|
||||||
|
wince = "WINCE"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Subdirectories
|
## Subdirectories
|
||||||
@@ -90,18 +133,47 @@ include-before = ["cmake/before-subdir.cmake"]
|
|||||||
include-after = ["cmake/after-subdir.cmake"]
|
include-after = ["cmake/after-subdir.cmake"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[options]
|
||||||
|
MYPROJECT_BUILD_TESTS = false
|
||||||
|
MYPROJECT_SPECIAL_OPTION = { value = true, help = "Docstring for this option." }
|
||||||
|
MYPROJECT_BUILD_EXAMPLES = "root"
|
||||||
|
```
|
||||||
|
|
||||||
|
Options correspond to [CMake cache variables](https://cmake.org/cmake/help/book/mastering-cmake/chapter/CMake%20Cache.html) that can be used to customize your project at configure-time. You can configure with `cmake -DMYPROJECT_BUILD_TESTS=ON` to enable the option. Every option automatically gets a corresponding [condition](#conditions). Additionally, a normalized condition is created based on the `[project].name` (i.e. `MYPROJECT_BUILD_TESTS` becomes `build-tests`).
|
||||||
|
|
||||||
|
The special value `root` can be used to set the option to `true` if the project is compiled as the root project (it will be `false` if someone is including your project via `[fetch-content]` or `[subdir]`).
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[variables]
|
||||||
|
MYBOOL = true
|
||||||
|
MYSTRING = "hello"
|
||||||
|
```
|
||||||
|
|
||||||
|
Variables emit a [`set`](https://cmake.org/cmake/help/latest/command/set.html) and can be used to configure subprojects and packages.
|
||||||
|
|
||||||
## Vcpkg
|
## Vcpkg
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[vcpkg]
|
[vcpkg]
|
||||||
version = "2021.05.12"
|
version = "2024.11.16"
|
||||||
url = "https://github.com/microsoft/vcpkg/archive/refs/tags/2021.05.12.tar.gz"
|
url = "https://github.com/microsoft/vcpkg/archive/refs/tags/2024.11.16.tar.gz"
|
||||||
packages = ["fmt", "zlib"]
|
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 = "vcpkg-overlay"`.
|
||||||
|
|
||||||
|
For a concrete example of all the features, take a look at the [vcpkg_template](https://github.com/build-cpp/vcpkg_template) repository.
|
||||||
|
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
@@ -119,49 +191,60 @@ components = ["mycomponent"]
|
|||||||
**Note**: The `[fetch-content]` feature is unpolished and will likely change in a future release.
|
**Note**: The `[fetch-content]` feature is unpolished and will likely change in a future release.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
# Include CMake project from git
|
||||||
[fetch-content.gitcontent]
|
[fetch-content.gitcontent]
|
||||||
condition = "mycondition"
|
condition = "mycondition"
|
||||||
git = "https://github.com/myuser/gitcontent"
|
git = "https://github.com/myuser/gitcontent"
|
||||||
tag = "v0.1"
|
tag = "v0.1"
|
||||||
|
shallow = false # shallow clone (--depth 1)
|
||||||
|
system = false
|
||||||
|
subdir = "" # folder containing CMakeLists.txt
|
||||||
|
|
||||||
|
# Include a CMake project from a URL
|
||||||
|
[fetch-content.urlcontent]
|
||||||
|
condition = "mycondition"
|
||||||
|
url = "https://content-host.com/urlcontent.zip"
|
||||||
|
# Other supported algorithms:
|
||||||
|
# md5, sha1, sha224, sha256, sha384, sha512, sha3_224, sha3_256, sha3_384, sha3_512
|
||||||
|
hash = "SHA1 502a4e25b8b209889c99c7fa0732102682c2e4ff"
|
||||||
|
sha1 = "502a4e25b8b209889c99c7fa0732102682c2e4ff"
|
||||||
|
|
||||||
[fetch-content.svncontent]
|
[fetch-content.svncontent]
|
||||||
condition = "mycondition"
|
condition = "mycondition"
|
||||||
svn = "https://svn-host.com/url"
|
svn = "https://svn-host.com/url"
|
||||||
rev = "svn_rev"
|
rev = "svn_rev"
|
||||||
|
|
||||||
[fetch-content.urlcontent]
|
|
||||||
condition = "mycondition"
|
|
||||||
url = "https://content-host.com/urlcontent.zip"
|
|
||||||
hash = "123123123123"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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
|
## Targets
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[target.mytarget]
|
[target.mytarget]
|
||||||
condition = "mycondition"
|
condition = "mycondition"
|
||||||
alias = "mytarget::mytarget"
|
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"]
|
headers = ["src/mytarget.h"]
|
||||||
sources = ["src/mytarget.cpp"]
|
sources = ["src/mytarget.cpp"]
|
||||||
|
msvc-runtime = "" # dynamic (implicit default), static
|
||||||
|
|
||||||
# The keys below match the target_xxx CMake commands
|
# The keys below match the target_xxx CMake commands
|
||||||
# Keys prefixed with private- will get PRIVATE visibility
|
# Keys prefixed with private- will get PRIVATE visibility
|
||||||
compile-definitions = [""]
|
compile-definitions = [""] # preprocessor define (-DFOO)
|
||||||
private-compile-definitions = [""]
|
private-compile-definitions = [""]
|
||||||
compile-features = [""]
|
compile-features = [""] # C++ standard version (cxx_std_20)
|
||||||
private-compile-features = [""]
|
private-compile-features = [""]
|
||||||
compile-options = [""]
|
compile-options = [""] # compiler flags
|
||||||
private-compile-options = [""]
|
private-compile-options = [""]
|
||||||
include-directories = [""]
|
include-directories = [""] # include paths/directories
|
||||||
private-include-directories = [""]
|
private-include-directories = [""]
|
||||||
link-directories = [""]
|
link-directories = [""] # library directories
|
||||||
private-link-directories = [""]
|
private-link-directories = [""]
|
||||||
link-libraries = [""]
|
link-libraries = [""] # dependencies
|
||||||
private-link-libraries = [""]
|
private-link-libraries = [""]
|
||||||
link-options = [""]
|
link-options = [""] # linker flags
|
||||||
private-link-options = [""]
|
private-link-options = [""]
|
||||||
precompile-headers = [""]
|
precompile-headers = [""] # precompiled headers
|
||||||
private-precompile-headers = [""]
|
private-precompile-headers = [""]
|
||||||
|
|
||||||
cmake-before = """
|
cmake-before = """
|
||||||
@@ -180,6 +263,60 @@ CXX_STANDARD_REQUIRED = true
|
|||||||
FOLDER = "MyFolder"
|
FOLDER = "MyFolder"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A table mapping the cmkr features to the relevant CMake construct and the relevant documentation pages:
|
||||||
|
|
||||||
|
| cmkr | CMake construct | Description |
|
||||||
|
| ---- | ----- | ----------- |
|
||||||
|
| `alias` | [Alias Libraries](https://cmake.org/cmake/help/latest/command/add_library.html#alias-libraries) | Create an [alias target](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#alias-targets), used for namespacing or clarity. |
|
||||||
|
| `sources` | [`target_sources`](https://cmake.org/cmake/help/latest/command/target_sources.html) | Source files (`PRIVATE` except `interface` targets). |
|
||||||
|
| `headers` | [`target_sources`](https://cmake.org/cmake/help/latest/command/target_sources.html) | For readability (and future packaging). |
|
||||||
|
| `msvc-runtime` | [`MSVC_RUNTIME_LIBRARY`](https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html) | The [CMP0091](https://cmake.org/cmake/help/latest/policy/CMP0091.html) policy is set automatically. |
|
||||||
|
| `compile-definitions` | [`target_compile_definitions`](https://cmake.org/cmake/help/latest/command/target_compile_definitions.html) | Adds a macro definition (define, `-DMYMACRO=XXX`). |
|
||||||
|
| `compile-features` | [`target_compile_features`](https://cmake.org/cmake/help/latest/command/target_compile_features.html) | Specifies the C++ standard version (`cxx_std_20`). |
|
||||||
|
| `compile-options` | [`target_compile_options`](https://cmake.org/cmake/help/latest/command/target_compile_options.html) | Adds compiler flags. |
|
||||||
|
| `include-directories` | [`target_include_directories`](https://cmake.org/cmake/help/latest/command/target_include_directories.html) | Adds include directories. |
|
||||||
|
| `link-directories` | [`target_link_directories`](https://cmake.org/cmake/help/latest/command/target_link_directories.html) | Adds library directories. |
|
||||||
|
| `link-libraries` | [`target_link_libraries`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) | Adds library dependencies. Use `::mylib` to make sure a target exists. |
|
||||||
|
| `link-options` | [`target_link_options`](https://cmake.org/cmake/help/latest/command/target_link_options.html) | Adds linker flags. |
|
||||||
|
| `precompile-headers` | [`target_precompile_headers`](https://cmake.org/cmake/help/latest/command/target_precompile_headers.html) | Specifies precompiled headers. |
|
||||||
|
| `properties` | [`set_target_properties`](https://cmake.org/cmake/help/latest/command/set_target_properties.html) | See [properties on targets](https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#properties-on-targets) for more information. |
|
||||||
|
|
||||||
|
The default [visibility](/basics) is as follows:
|
||||||
|
|
||||||
|
| Type | Visibility |
|
||||||
|
| ------------ | ----------- |
|
||||||
|
| `executable` | `PRIVATE` |
|
||||||
|
| `library` | `PUBLIC` |
|
||||||
|
| `shared` | `PUBLIC` |
|
||||||
|
| `static` | `PUBLIC` |
|
||||||
|
| `object` | `PUBLIC` |
|
||||||
|
| `interface` | `INTERFACE` |
|
||||||
|
|
||||||
|
## Templates
|
||||||
|
|
||||||
|
To avoid repeating yourself you can create your own target type and use it in your targets:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[template.example]
|
||||||
|
condition = "MYPROJECT_BUILD_EXAMPLES"
|
||||||
|
type = "executable"
|
||||||
|
link-libraries = ["myproject::mylib"]
|
||||||
|
add-function = ""
|
||||||
|
add-arguments = ["myoption"]
|
||||||
|
pass-sources = false
|
||||||
|
|
||||||
|
# Properties from the template are merged with the ones here
|
||||||
|
[target.myexample]
|
||||||
|
type = "example"
|
||||||
|
sources = ["src/myexample.cpp"]
|
||||||
|
```
|
||||||
|
|
||||||
|
The properties declared on a `template` are the same as the ones you use for targets. The only exceptions are:
|
||||||
|
|
||||||
|
- `add-function`: Specifies a custom add function. Projects like [pybind11](https://pybind11.readthedocs.io/en/stable/cmake/index.html#new-findpython-mode) have their own `add_xxx` function, which you can specify here.
|
||||||
|
- `add-arguments`: Arguments to pass to the `add-function` before the list of sources. See [cmake_parse_arguments](https://cmake.org/cmake/help/latest/command/cmake_parse_arguments.html) for more details.
|
||||||
|
- `pass-sources`: Pass sources directly to the add function instead of using `target_sources`.
|
||||||
|
|
||||||
## Tests and installation (unfinished)
|
## Tests and installation (unfinished)
|
||||||
|
|
||||||
**Note**: The `[[test]]` and `[[install]]` are unfinished features and will likely change in a future release.
|
**Note**: The `[[test]]` and `[[install]]` are unfinished features and will likely change in a future release.
|
||||||
@@ -200,7 +337,9 @@ working-directory = "mytest-dir"
|
|||||||
condition = "mycondition"
|
condition = "mycondition"
|
||||||
targets = ["mytarget", "mytest"]
|
targets = ["mytarget", "mytest"]
|
||||||
destination = ["bin"]
|
destination = ["bin"]
|
||||||
|
component = "mycomponent"
|
||||||
files = ["content/my.png"]
|
files = ["content/my.png"]
|
||||||
dirs = [""]
|
dirs = ["include"]
|
||||||
configs = [""]
|
configs = ["Release", "Debug"]
|
||||||
|
optional = false
|
||||||
```
|
```
|
||||||
@@ -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>
|
||||||
@@ -16,8 +16,9 @@ Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) from [GitHub](https://github.com)
|
|||||||
name = "fetch-content"
|
name = "fetch-content"
|
||||||
description = "Fetching from git"
|
description = "Fetching from git"
|
||||||
|
|
||||||
[fetch-content]
|
[fetch-content.fmt]
|
||||||
fmt = { git = "https://github.com/fmtlib/fmt", tag = "7.1.3" }
|
git = "https://github.com/fmtlib/fmt"
|
||||||
|
tag = "7.1.3"
|
||||||
|
|
||||||
[target.example]
|
[target.example]
|
||||||
type = "executable"
|
type = "executable"
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
# Automatically generated from tests/msvc-runtime/cmake.toml - DO NOT EDIT
|
||||||
|
layout: default
|
||||||
|
title: Static MSVC runtime
|
||||||
|
permalink: /examples/msvc-runtime
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 8
|
||||||
|
---
|
||||||
|
|
||||||
|
# Static MSVC runtime
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project]
|
||||||
|
name = "msvc-runtime"
|
||||||
|
description = "Static MSVC runtime"
|
||||||
|
msvc-runtime = "static"
|
||||||
|
|
||||||
|
# This target will compile with a static runtime
|
||||||
|
[target.static-runtime]
|
||||||
|
type = "executable"
|
||||||
|
sources = ["src/main.cpp"]
|
||||||
|
|
||||||
|
# This target overrides the [project].msvc-runtime
|
||||||
|
[target.dynamic-runtime]
|
||||||
|
type = "executable"
|
||||||
|
sources = ["src/main.cpp"]
|
||||||
|
msvc-runtime = "dynamic"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<sup><sub>This page was automatically generated from [tests/msvc-runtime/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/msvc-runtime/cmake.toml).</sub></sup>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
# Automatically generated from tests/objective-c/cmake.toml - DO NOT EDIT
|
||||||
|
layout: default
|
||||||
|
title: Objective-C
|
||||||
|
permalink: /examples/objective-c
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 11
|
||||||
|
---
|
||||||
|
|
||||||
|
# Objective-C
|
||||||
|
|
||||||
|
Add Objective-C sources on Apple platforms:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project]
|
||||||
|
name = "objective-c"
|
||||||
|
description = "Objective-C"
|
||||||
|
languages = ["C"]
|
||||||
|
apple.languages = ["OBJC"]
|
||||||
|
|
||||||
|
[target.hello]
|
||||||
|
type = "executable"
|
||||||
|
sources = ["src/main.c"]
|
||||||
|
apple.sources = ["src/apple.m"]
|
||||||
|
apple.link-libraries = ["$<LINK_LIBRARY:FRAMEWORK,Foundation>"]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<sup><sub>This page was automatically generated from [tests/objective-c/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/objective-c/cmake.toml).</sub></sup>
|
||||||
@@ -20,11 +20,11 @@ description = "Target templates"
|
|||||||
type = "executable"
|
type = "executable"
|
||||||
sources = ["src/templates.cpp"]
|
sources = ["src/templates.cpp"]
|
||||||
compile-definitions = ["IS_APP"]
|
compile-definitions = ["IS_APP"]
|
||||||
|
|
||||||
# Unlike interface targets you can also inherit properties
|
# Unlike interface targets you can also inherit properties
|
||||||
[template.app.properties]
|
properties = {
|
||||||
CXX_STANDARD = "11"
|
CXX_STANDARD = "11",
|
||||||
CXX_STANDARD_REQUIRED = true
|
CXX_STANDARD_REQUIRED = true,
|
||||||
|
}
|
||||||
|
|
||||||
[target.app-a]
|
[target.app-a]
|
||||||
type = "app"
|
type = "app"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ nav_order: 4
|
|||||||
|
|
||||||
# Dependencies from vcpkg
|
# 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
|
```toml
|
||||||
[project]
|
[project]
|
||||||
@@ -17,13 +17,12 @@ name = "vcpkg"
|
|||||||
description = "Dependencies from vcpkg"
|
description = "Dependencies from vcpkg"
|
||||||
|
|
||||||
# See https://github.com/microsoft/vcpkg/releases for vcpkg versions
|
# 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]
|
[vcpkg]
|
||||||
version = "2021.05.12"
|
version = "2024.11.16"
|
||||||
packages = ["fmt"]
|
packages = ["fmt"]
|
||||||
|
|
||||||
[find-package]
|
[find-package.fmt]
|
||||||
fmt = {}
|
|
||||||
|
|
||||||
[target.example]
|
[target.example]
|
||||||
type = "executable"
|
type = "executable"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
layout: null
|
layout: null
|
||||||
permalink: /getting-started/
|
permalink: /getting-started/
|
||||||
---
|
---
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="refresh" content="0;url=https://cmkr.build">
|
<meta http-equiv="refresh" content="0;url=https://cmkr.build">
|
||||||
</head>
|
</head>
|
||||||
</html>
|
</html>
|
||||||
+19
-15
@@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
layout: home
|
layout: home
|
||||||
title: Index
|
title: Documentation
|
||||||
nav_order: 0
|
nav_order: 0
|
||||||
---
|
---
|
||||||
|
|
||||||
# Index
|
# Documentation
|
||||||
|
|
||||||
`cmkr`, pronounced "cmaker", is a modern build system based on [CMake](https://cmake.org/) and [TOML](https://toml.io).
|
[`cmkr`](https://github.com/build-cpp/cmkr), pronounced "cmaker", is a modern build system based on [CMake](https://cmake.org/) and [TOML](https://toml.io).
|
||||||
|
|
||||||
`cmkr` parses `cmake.toml` files and generates a modern, idiomatic `CMakeLists.txt` for you. A minimal example:
|
`cmkr` parses `cmake.toml` files and generates a modern, idiomatic `CMakeLists.txt` for you. A minimal example:
|
||||||
|
|
||||||
@@ -19,27 +19,29 @@ type = "executable"
|
|||||||
sources = ["src/main.cpp"]
|
sources = ["src/main.cpp"]
|
||||||
```
|
```
|
||||||
|
|
||||||
`cmkr` can bootstrap itself from CMake and you only need CMake to use it.
|
`cmkr` can bootstrap itself, and you only need CMake and a C++ compiler to use it.
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
To get started run the following commands from your project directory:
|
To get started, run the following commands from your project directory:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl https://raw.githubusercontent.com/build-cpp/cmkr/main/cmake/cmkr.cmake -o cmkr.cmake
|
curl https://raw.githubusercontent.com/build-cpp/cmkr/main/cmake/cmkr.cmake -o cmkr.cmake
|
||||||
cmake -P cmkr.cmake
|
cmake -P cmkr.cmake
|
||||||
```
|
```
|
||||||
|
|
||||||
After the bootstrapping process finishes, modify [`cmake.toml`](https://build-cpp.github.io/cmkr/cmake-toml) and open the project in your favorite IDE or build with CMake:
|
After the bootstrapping process finishes, customize [`cmake.toml`](./cmake-toml) for your project and run CMake:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cmake -B build
|
cmake -B build
|
||||||
cmake --build build
|
cmake --build build
|
||||||
```
|
```
|
||||||
|
|
||||||
Once bootstrapped, `cmkr` does not introduce extra steps to your workflow. After modifying `cmake.toml` you simply build/configure your CMake project and `cmkr` will automatically regenerate `CMakeLists.txt`.
|
Once bootstrapped, `cmkr` does not introduce extra steps to your workflow. After modifying `cmake.toml` you simply build/configure your CMake project and `cmkr` will automatically regenerate `CMakeLists.txt` when necessary.
|
||||||
|
|
||||||
In CI settings the `cmkr` bootstrapping process is skipped so there is no extra configure-time overhead in your pipelines.
|
<sub>**Note**: The `cmake.toml` project file, generated `CMakeLists.txt` and `cmkr.cmake` bootstrapping script are all intended to be added to source control.</sub>
|
||||||
|
|
||||||
|
In CI environments the `cmkr` bootstrapping process is skipped, so there is no additional overhead in your pipelines.
|
||||||
|
|
||||||
## Template repositories
|
## Template repositories
|
||||||
|
|
||||||
@@ -59,10 +61,10 @@ Optionally you can put a [`cmkr` release](https://github.com/build-cpp/cmkr/rele
|
|||||||
```
|
```
|
||||||
Usage: cmkr [arguments]
|
Usage: cmkr [arguments]
|
||||||
arguments:
|
arguments:
|
||||||
init [executable|library|shared|static|interface] Starts a new project in the same directory.
|
init [executable|library|shared|static|interface] Create a project.
|
||||||
gen Generates CMakeLists.txt file.
|
gen Generates CMakeLists.txt file.
|
||||||
build <extra cmake args> Run cmake and build.
|
build <extra cmake args> Run cmake and build.
|
||||||
install Run cmake --install. Needs admin privileges.
|
install Run cmake --install.
|
||||||
clean Clean the build directory.
|
clean Clean the build directory.
|
||||||
help Show help.
|
help Show help.
|
||||||
version Current cmkr version.
|
version Current cmkr version.
|
||||||
@@ -70,8 +72,10 @@ arguments:
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
- https://github.com/gulrak/filesystem
|
- [gulrak/filesystem](https://github.com/gulrak/filesystem)
|
||||||
- https://github.com/Tessil/ordered-map
|
- [Tessil/ordered-map](https://github.com/Tessil/ordered-map)
|
||||||
- https://github.com/ToruNiina/toml11
|
- [ToruNiina/toml11](https://github.com/ToruNiina/toml11)
|
||||||
- https://github.com/mpark/variant
|
- [mpark/variant](https://github.com/mpark/variant)
|
||||||
- https://www.svgrepo.com/svg/192268/hammer
|
- [SVG Repo Hammer](https://www.svgrepo.com/svg/192268/hammer)
|
||||||
|
- [can1357](https://github.com/can1357) for buying `cmkr.build` ❤️
|
||||||
|
- [JustasMasiulis](https://github.com/JustasMasiulis) for fixing the dark theme ❤️
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
layout: page
|
||||||
|
title: Philosophy
|
||||||
|
nav_order: 2
|
||||||
|
published: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# Philosophy
|
||||||
|
|
||||||
|
## Problem statement
|
||||||
|
|
||||||
|
Similar to writing good C++, writing good CMake is difficult. The main difference is that nobody actually wants to learn CMake. The build system is something that should "just work".
|
||||||
|
|
||||||
|
There have been many attempts at creating new build systems (with varying levels of success). Naturally this causes [competing standards](https://xkcd.com/927/), which is undesirable. CMake is pretty much the de facto standard, and it has seen extensive use in complex software projects.
|
||||||
|
|
||||||
|
One of the main issues of CMake is the turing-complete scripting language you use to describe your projects. As your project gets more complex this can be very helpful, but it also unnecessarily complicates simple projects. There have been discussions about a declarative language on the [CMake issue tracker](https://gitlab.kitware.com/cmake/cmake/-/issues/19891) to solve this problem, but it looks like a "LISP-like" language is seriously being considered...
|
||||||
|
|
||||||
|
## The solution
|
||||||
|
|
||||||
|
The way cmkr (pronounced "cmaker") solves this problem is by using [TOML](https://toml.io/). Below is a minimal `cmake.toml` project:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project]
|
||||||
|
name = "cmkr_for_beginners"
|
||||||
|
|
||||||
|
[target.hello_world]
|
||||||
|
type = "executable"
|
||||||
|
sources = ["src/main.cpp"]
|
||||||
|
```
|
||||||
|
|
||||||
|
The key difference between `cmkr` and other build systems is that it _generates_ CMake. This means that your projects are fully compatible with the CMake ecosystem, and you can try it out without having to rewrite your whole build system.
|
||||||
|
|
||||||
|
TODO: link/include more examples? Talk about conditions, packaging (missing)
|
||||||
|
|
||||||
|
### Another layer?!
|
||||||
|
|
||||||
|
A common issue people have with cmkr is that it introduces an additional layer of indirection to your build system. CMake is already a meta-buildsystem, which means you could call cmkr a "meta-meta-buildsystem".
|
||||||
|
|
||||||
|
Presumably the reason for this friction is that additional layers of abstraction introduce additional complexity. Because of this cmkr has been designed to be completely seamless:
|
||||||
|
|
||||||
|
- The user doesn't have to install any additional software to use cmkr. All you need is a semi-recent version of CMake and a C++ compiler.
|
||||||
|
- Modifying `cmake.toml` automatically triggers a regeneration of `CMakeLists.txt`. There is no change to your build process.
|
||||||
|
- The `CMakeLists.txt` is generated to be human-readable. This means you can easily "eject" from cmkr and go back to CMake.
|
||||||
|
|
||||||
|
An additional argument for cmkr is that anecdotally people say it "just works". Because of its simplicity it's also easy to teach, even to people without programming experience.
|
||||||
|
|
||||||
|
There is also precedent in the JavaScript community. Bundlers and translators are the norm there and their developer experience is miles ahead of C++.
|
||||||
|
|
||||||
|
<sub>Not to say the JavaScript ecosystem is without its flaws, but generators does not appear to be one of them</sub>
|
||||||
|
|
||||||
|
### Unsupported features
|
||||||
|
|
||||||
|
Because cmkr is still in early in development there are many missing/unfinished features. It was decided that users can bridge the gap by including CMake at arbitrary locations.
|
||||||
|
|
||||||
|
This has the advantage that it forces complexity in the build system to be self-contained and modular, a problem all too common in projects as they age.
|
||||||
|
|
||||||
|
## Enterprise
|
||||||
|
|
||||||
|
Words like "bootstrapping" and "generating code" might worry engineers working in an enterprise environment, and rightly so. From the beginning it has been a priority to make cmkr suitable for use in big corporations with strict protocols for security and reproducibility.
|
||||||
|
|
||||||
|
### No additional dependencies
|
||||||
|
|
||||||
|
As mentioned above, the only thing you need is a working C++ compiler and a semi-recent version of CMake. It is assumed that you are already building (and executing) C++ projects on your servers, so cmkr does not introduce additional requirements.
|
||||||
|
|
||||||
|
All the logic for downloading and compiling the `cmkr` executable is self-contained in a ~250 line `cmkr.cmake` script. You can easily audit it and see if it's up to your standards.
|
||||||
|
|
||||||
|
### Reproducibility
|
||||||
|
|
||||||
|
Per default the `cmkr.cmake` bootstrapping script contains the exact version of cmkr used to generate your project. As long as the cmkr repository is available you will build the exact same version of cmkr, which will generate the exact same `CMakeLists.txt` file.
|
||||||
|
|
||||||
|
This also means that cmkr can decide to break backwards compatibility without affecting legacy projects. An effort will always be made to maintain backwards compatibility though.
|
||||||
|
|
||||||
|
### Integrity
|
||||||
|
|
||||||
|
As an additional safeguard you can modify `cmkr.cmake` to pin the version tag to a commit hash. This hash is checked to ensure the integrity of the upstream repository.
|
||||||
|
|
||||||
|
### Availability
|
||||||
|
|
||||||
|
You can easily point `cmkr.cmake` to a mirror of the cmkr repository to ensure availability should something catastrophic happen.
|
||||||
|
|
||||||
|
### Not executed in CI
|
||||||
|
|
||||||
|
The final (and key) feature is that the bootstrapping process is never executed in CI environments. This means `cmkr` is only ever executed on your developer's machines and not on your infrastructure.
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
bundle exec just-the-docs rake search:init
|
|
||||||
bundle exec jekyll serve --livereload
|
|
||||||
Regular → Executable
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
bundle install
|
bundle install
|
||||||
bundle exec jekyll serve --force_polling --livereload --incremental
|
bundle exec jekyll serve --force_polling --livereload --incremental
|
||||||
@@ -7,5 +7,3 @@ const char *handle_args(int argc, char **argv);
|
|||||||
|
|
||||||
} // namespace args
|
} // namespace args
|
||||||
} // namespace cmkr
|
} // namespace cmkr
|
||||||
|
|
||||||
const char *cmkr_args_handle_args(int, char **);
|
|
||||||
|
|||||||
@@ -11,9 +11,3 @@ int install();
|
|||||||
|
|
||||||
} // namespace build
|
} // namespace build
|
||||||
} // namespace cmkr
|
} // namespace cmkr
|
||||||
|
|
||||||
int cmkr_build_run(int argc, char **argv);
|
|
||||||
|
|
||||||
int cmkr_build_clean();
|
|
||||||
|
|
||||||
int cmkr_build_install();
|
|
||||||
|
|||||||
@@ -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
@@ -1,8 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || \
|
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
|
||||||
(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)
|
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
|
||||||
#define GHC_USE_STD_FS
|
#define GHC_USE_STD_FS
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@@ -12,4 +10,4 @@ namespace fs = std::filesystem;
|
|||||||
#ifndef GHC_USE_STD_FS
|
#ifndef GHC_USE_STD_FS
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/filesystem.hpp>
|
||||||
namespace fs = ghc::filesystem;
|
namespace fs = ghc::filesystem;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,7 +9,3 @@ const char *message() noexcept;
|
|||||||
|
|
||||||
} // namespace help
|
} // namespace help
|
||||||
} // namespace cmkr
|
} // namespace cmkr
|
||||||
|
|
||||||
const char *cmkr_help_version(void);
|
|
||||||
|
|
||||||
const char *cmkr_help_message(void);
|
|
||||||
|
|||||||
+43
-12
@@ -1,9 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mpark/variant.hpp>
|
|
||||||
#include <string>
|
|
||||||
#include <tsl/ordered_map.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <mpark/variant.hpp>
|
||||||
|
#include <tsl/ordered_map.h>
|
||||||
|
#include <tsl/ordered_set.h>
|
||||||
|
|
||||||
namespace cmkr {
|
namespace cmkr {
|
||||||
namespace parser {
|
namespace parser {
|
||||||
@@ -13,18 +15,18 @@ using Condition = tsl::ordered_map<std::string, T>;
|
|||||||
|
|
||||||
using ConditionVector = Condition<std::vector<std::string>>;
|
using ConditionVector = Condition<std::vector<std::string>>;
|
||||||
|
|
||||||
struct Setting {
|
struct Variable {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string comment;
|
std::string help;
|
||||||
mpark::variant<bool, std::string> val;
|
mpark::variant<bool, std::string> value;
|
||||||
bool cache = false;
|
bool cache = false;
|
||||||
bool force = false;
|
bool force = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Option {
|
struct Option {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string comment;
|
std::string help;
|
||||||
bool val = false;
|
mpark::variant<bool, std::string> value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Package {
|
struct Package {
|
||||||
@@ -43,9 +45,18 @@ struct Vcpkg {
|
|||||||
struct Package {
|
struct Package {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<std::string> features;
|
std::vector<std::string> features;
|
||||||
|
bool default_features = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Package> packages;
|
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 {
|
enum TargetType {
|
||||||
@@ -67,7 +78,6 @@ struct Target {
|
|||||||
TargetType type = target_last;
|
TargetType type = target_last;
|
||||||
std::string type_name;
|
std::string type_name;
|
||||||
|
|
||||||
ConditionVector headers;
|
|
||||||
ConditionVector sources;
|
ConditionVector sources;
|
||||||
|
|
||||||
// https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#project-commands
|
// https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#project-commands
|
||||||
@@ -95,6 +105,8 @@ struct Target {
|
|||||||
ConditionVector precompile_headers;
|
ConditionVector precompile_headers;
|
||||||
ConditionVector private_precompile_headers;
|
ConditionVector private_precompile_headers;
|
||||||
|
|
||||||
|
ConditionVector dependencies;
|
||||||
|
|
||||||
std::string condition;
|
std::string condition;
|
||||||
std::string alias;
|
std::string alias;
|
||||||
Condition<tsl::ordered_map<std::string, std::string>> properties;
|
Condition<tsl::ordered_map<std::string, std::string>> properties;
|
||||||
@@ -108,6 +120,7 @@ struct Target {
|
|||||||
struct Template {
|
struct Template {
|
||||||
Target outline;
|
Target outline;
|
||||||
std::string add_function;
|
std::string add_function;
|
||||||
|
std::vector<std::string> add_arguments;
|
||||||
bool pass_sources_to_add_function = false;
|
bool pass_sources_to_add_function = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -128,6 +141,7 @@ struct Install {
|
|||||||
std::vector<std::string> configs;
|
std::vector<std::string> configs;
|
||||||
std::string destination;
|
std::string destination;
|
||||||
std::string component;
|
std::string component;
|
||||||
|
bool optional = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Subdir {
|
struct Subdir {
|
||||||
@@ -149,9 +163,21 @@ struct Content {
|
|||||||
Condition<std::string> cmake_after;
|
Condition<std::string> cmake_after;
|
||||||
ConditionVector include_before;
|
ConditionVector include_before;
|
||||||
ConditionVector include_after;
|
ConditionVector include_after;
|
||||||
|
bool system = false;
|
||||||
|
std::string subdir;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MsvcRuntimeType {
|
||||||
|
msvc_dynamic,
|
||||||
|
msvc_static,
|
||||||
|
msvc_last,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char *msvcRuntimeTypeNames[msvc_last];
|
||||||
|
|
||||||
struct Project {
|
struct Project {
|
||||||
|
const Project *parent;
|
||||||
|
|
||||||
// This is the CMake version required to use all cmkr versions.
|
// This is the CMake version required to use all cmkr versions.
|
||||||
std::string cmake_version = "3.15";
|
std::string cmake_version = "3.15";
|
||||||
std::string cmkr_include = "cmkr.cmake";
|
std::string cmkr_include = "cmkr.cmake";
|
||||||
@@ -168,12 +194,14 @@ struct Project {
|
|||||||
std::string project_name;
|
std::string project_name;
|
||||||
std::string project_version;
|
std::string project_version;
|
||||||
std::string project_description;
|
std::string project_description;
|
||||||
std::vector<std::string> project_languages;
|
ConditionVector project_languages;
|
||||||
|
bool project_allow_unknown_languages = false;
|
||||||
|
MsvcRuntimeType project_msvc_runtime = msvc_last;
|
||||||
Condition<std::string> cmake_before;
|
Condition<std::string> cmake_before;
|
||||||
Condition<std::string> cmake_after;
|
Condition<std::string> cmake_after;
|
||||||
ConditionVector include_before;
|
ConditionVector include_before;
|
||||||
ConditionVector include_after;
|
ConditionVector include_after;
|
||||||
std::vector<Setting> settings;
|
std::vector<Variable> variables;
|
||||||
std::vector<Option> options;
|
std::vector<Option> options;
|
||||||
std::vector<Package> packages;
|
std::vector<Package> packages;
|
||||||
Vcpkg vcpkg;
|
Vcpkg vcpkg;
|
||||||
@@ -186,9 +214,12 @@ struct Project {
|
|||||||
std::vector<Subdir> subdirs;
|
std::vector<Subdir> subdirs;
|
||||||
|
|
||||||
Project(const Project *parent, const std::string &path, bool build);
|
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);
|
bool is_root_path(const std::string &path);
|
||||||
|
|
||||||
} // namespace parser
|
} // namespace parser
|
||||||
} // namespace cmkr
|
} // namespace cmkr
|
||||||
|
|||||||
+4
-16
@@ -2,10 +2,8 @@
|
|||||||
#include "build.hpp"
|
#include "build.hpp"
|
||||||
#include "cmake_generator.hpp"
|
#include "cmake_generator.hpp"
|
||||||
#include "help.hpp"
|
#include "help.hpp"
|
||||||
|
|
||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include <exception>
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -37,17 +35,17 @@ const char *handle_args(int argc, char **argv) {
|
|||||||
} else if (main_arg == "build") {
|
} else if (main_arg == "build") {
|
||||||
auto ret = build::run(argc, argv);
|
auto ret = build::run(argc, argv);
|
||||||
if (ret)
|
if (ret)
|
||||||
return "CMake build error!";
|
throw std::runtime_error("CMake build failed!");
|
||||||
return "CMake build completed!";
|
return "CMake build completed!";
|
||||||
} else if (main_arg == "install") {
|
} else if (main_arg == "install") {
|
||||||
auto ret = build::install();
|
auto ret = build::install();
|
||||||
if (ret)
|
if (ret)
|
||||||
return "CMake install error!";
|
throw std::runtime_error("CMake install failed!");
|
||||||
return "CMake install completed!";
|
return "CMake install completed!";
|
||||||
} else if (main_arg == "clean") {
|
} else if (main_arg == "clean") {
|
||||||
auto ret = build::clean();
|
auto ret = build::clean();
|
||||||
if (ret)
|
if (ret)
|
||||||
return "CMake clean error!";
|
throw std::runtime_error("CMake clean failed!");
|
||||||
return "Cleaned build directory!";
|
return "Cleaned build directory!";
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error(cmkr::help::message());
|
throw std::runtime_error(cmkr::help::message());
|
||||||
@@ -55,13 +53,3 @@ const char *handle_args(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
} // namespace args
|
} // namespace args
|
||||||
} // namespace cmkr
|
} // namespace cmkr
|
||||||
|
|
||||||
const char *cmkr_args_handle_args(int argc, char **argv) {
|
|
||||||
try {
|
|
||||||
return cmkr::args::handle_args(argc, argv);
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
return e.what();
|
|
||||||
} catch (...) {
|
|
||||||
return "Unknown error!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+4
-38
@@ -1,14 +1,10 @@
|
|||||||
#include "build.hpp"
|
#include "build.hpp"
|
||||||
#include "cmake_generator.hpp"
|
#include "cmake_generator.hpp"
|
||||||
#include "error.hpp"
|
|
||||||
#include "project_parser.hpp"
|
#include "project_parser.hpp"
|
||||||
|
|
||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
|
||||||
#include <system_error>
|
|
||||||
|
|
||||||
namespace cmkr {
|
namespace cmkr {
|
||||||
namespace build {
|
namespace build {
|
||||||
@@ -17,7 +13,7 @@ int run(int argc, char **argv) {
|
|||||||
parser::Project project(nullptr, ".", true);
|
parser::Project project(nullptr, ".", true);
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
for (int i = 2; i < argc; ++i) {
|
for (int i = 2; i < argc; ++i) {
|
||||||
project.build_args.push_back(argv[i]);
|
project.build_args.emplace_back(argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
@@ -48,13 +44,13 @@ int run(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int clean() {
|
int clean() {
|
||||||
bool ret = false;
|
bool success = false;
|
||||||
parser::Project project(nullptr, ".", true);
|
parser::Project project(nullptr, ".", true);
|
||||||
if (fs::exists(project.build_dir)) {
|
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);
|
fs::create_directory(project.build_dir);
|
||||||
}
|
}
|
||||||
return !ret;
|
return success ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int install() {
|
int install() {
|
||||||
@@ -64,33 +60,3 @@ int install() {
|
|||||||
}
|
}
|
||||||
} // namespace build
|
} // namespace build
|
||||||
} // namespace cmkr
|
} // 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+767
-225
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
|||||||
#include "error.hpp"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
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 && i < (sizeof(err_string) / sizeof(*(err_string))));
|
|
||||||
return err_string[i];
|
|
||||||
}
|
|
||||||
+3
-5
@@ -4,7 +4,9 @@
|
|||||||
namespace cmkr {
|
namespace cmkr {
|
||||||
namespace help {
|
namespace help {
|
||||||
|
|
||||||
const char *version() noexcept { return "cmkr version " CMKR_VERSION; }
|
const char *version() noexcept {
|
||||||
|
return "cmkr version " CMKR_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
const char *message() noexcept {
|
const char *message() noexcept {
|
||||||
return R"lit(
|
return R"lit(
|
||||||
@@ -21,7 +23,3 @@ arguments:
|
|||||||
}
|
}
|
||||||
} // namespace help
|
} // namespace help
|
||||||
} // namespace cmkr
|
} // namespace cmkr
|
||||||
|
|
||||||
const char *cmkr_help_version(void) { return cmkr::help::version(); }
|
|
||||||
|
|
||||||
const char *cmkr_help_message(void) { return cmkr::help::message(); }
|
|
||||||
+323
-49
@@ -4,8 +4,6 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <toml.hpp>
|
#include <toml.hpp>
|
||||||
#include <tsl/ordered_map.h>
|
|
||||||
#include <tsl/ordered_set.h>
|
|
||||||
|
|
||||||
namespace cmkr {
|
namespace cmkr {
|
||||||
namespace parser {
|
namespace parser {
|
||||||
@@ -21,16 +19,27 @@ static TargetType parse_targetType(const std::string &name) {
|
|||||||
return target_last;
|
return target_last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *msvcRuntimeTypeNames[msvc_last] = {"dynamic", "static"};
|
||||||
|
|
||||||
|
static MsvcRuntimeType parse_msvcRuntimeType(const std::string &name) {
|
||||||
|
for (int i = 0; i < msvc_last; i++) {
|
||||||
|
if (name == msvcRuntimeTypeNames[i]) {
|
||||||
|
return static_cast<MsvcRuntimeType>(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return msvc_last;
|
||||||
|
}
|
||||||
|
|
||||||
using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector>;
|
using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector>;
|
||||||
|
|
||||||
static std::string format_key_error(const std::string &error, const toml::key &ky, const TomlBasicValue &value) {
|
static std::string format_key_message(const std::string &message, const toml::key &ky, const TomlBasicValue &value) {
|
||||||
auto loc = value.location();
|
auto loc = value.location();
|
||||||
auto line_number_str = std::to_string(loc.line());
|
auto line_number_str = std::to_string(loc.line());
|
||||||
auto line_width = line_number_str.length();
|
auto line_width = line_number_str.length();
|
||||||
auto line_str = loc.line_str();
|
const auto &line_str = loc.line_str();
|
||||||
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "[error] " << error << '\n';
|
oss << message << "\n";
|
||||||
oss << " --> " << loc.file_name() << ':' << loc.line() << '\n';
|
oss << " --> " << loc.file_name() << ':' << loc.line() << '\n';
|
||||||
|
|
||||||
oss << std::string(line_width + 2, ' ') << "|\n";
|
oss << std::string(line_width + 2, ' ') << "|\n";
|
||||||
@@ -48,14 +57,24 @@ static std::string format_key_error(const std::string &error, const toml::key &k
|
|||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void throw_key_error(const std::string &error, const toml::key &ky, const TomlBasicValue &value) {
|
||||||
|
throw std::runtime_error(format_key_message("[error] " + error, ky, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_key_warning(const std::string &message, const toml::key &ky, const TomlBasicValue &value) {
|
||||||
|
puts(format_key_message("[warning] " + message, ky, value).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
class TomlChecker {
|
class TomlChecker {
|
||||||
const TomlBasicValue &m_v;
|
const TomlBasicValue &m_v;
|
||||||
tsl::ordered_set<toml::key> m_visited;
|
tsl::ordered_set<toml::key> m_visited;
|
||||||
tsl::ordered_set<toml::key> m_conditionVisited;
|
tsl::ordered_set<toml::key> m_conditionVisited;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TomlChecker(const TomlBasicValue &v, const toml::key &ky) : m_v(toml::find(v, ky)) {}
|
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(const TomlChecker &) = delete;
|
||||||
TomlChecker(TomlChecker &&) = delete;
|
TomlChecker(TomlChecker &&) = delete;
|
||||||
|
|
||||||
@@ -109,36 +128,40 @@ class TomlChecker {
|
|||||||
return toml::find(m_v, ky);
|
return toml::find(m_v, ky);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const toml::key &ky) { m_visited.emplace(ky); }
|
void visit(const toml::key &ky) {
|
||||||
|
m_visited.emplace(ky);
|
||||||
|
}
|
||||||
|
|
||||||
bool visisted(const toml::key &ky) const { return m_visited.contains(ky); }
|
bool visisted(const toml::key &ky) const {
|
||||||
|
return m_visited.contains(ky);
|
||||||
|
}
|
||||||
|
|
||||||
void check(const tsl::ordered_map<std::string, std::string> &conditions) const {
|
void check(const tsl::ordered_map<std::string, std::string> &conditions) const {
|
||||||
for (const auto &itr : m_v.as_table()) {
|
for (const auto &itr : m_v.as_table()) {
|
||||||
const auto &ky = itr.first;
|
const auto &ky = itr.first;
|
||||||
if (m_conditionVisited.contains(ky)) {
|
if (m_conditionVisited.contains(ky)) {
|
||||||
if (!conditions.contains(ky)) {
|
if (!conditions.contains(ky) && Project::is_condition_name(ky)) {
|
||||||
throw std::runtime_error(format_key_error("Unknown condition '" + ky + "'", ky, itr.second));
|
throw_key_error("Unknown condition '" + ky + "'", ky, itr.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &jtr : itr.second.as_table()) {
|
for (const auto &jtr : itr.second.as_table()) {
|
||||||
if (!m_visited.contains(jtr.first)) {
|
if (!m_visited.contains(jtr.first)) {
|
||||||
throw std::runtime_error(format_key_error("Unknown key '" + jtr.first + "'", jtr.first, jtr.second));
|
throw_key_error("Unknown key '" + jtr.first + "'", jtr.first, jtr.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!m_visited.contains(ky)) {
|
} else if (!m_visited.contains(ky)) {
|
||||||
if (itr.second.is_table()) {
|
if (itr.second.is_table()) {
|
||||||
for (const auto &jtr : itr.second.as_table()) {
|
for (const auto &jtr : itr.second.as_table()) {
|
||||||
if (!m_visited.contains(jtr.first)) {
|
if (!m_visited.contains(jtr.first)) {
|
||||||
throw std::runtime_error(format_key_error("Unknown key '" + jtr.first + "'", jtr.first, jtr.second));
|
throw_key_error("Unknown key '" + jtr.first + "'", jtr.first, jtr.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::runtime_error(format_key_error("Unknown key '" + ky + "'", ky, itr.second));
|
throw_key_error("Unknown key '" + ky + "'", ky, itr.second);
|
||||||
} else if (ky == "condition") {
|
} else if (ky == "condition") {
|
||||||
std::string condition = itr.second.as_string();
|
std::string condition = itr.second.as_string();
|
||||||
if (!conditions.contains(condition)) {
|
if (!conditions.contains(condition) && Project::is_condition_name(condition)) {
|
||||||
throw std::runtime_error(format_key_error("Unknown condition '" + condition + "'", condition, itr.second));
|
throw_key_error("Unknown condition '" + condition + "'", condition, itr.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,7 +175,8 @@ class TomlCheckerRoot {
|
|||||||
bool m_checked = false;
|
bool m_checked = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TomlCheckerRoot(const TomlBasicValue &root) : m_root(root) {}
|
explicit TomlCheckerRoot(const TomlBasicValue &root) : m_root(root) {
|
||||||
|
}
|
||||||
TomlCheckerRoot(const TomlCheckerRoot &) = delete;
|
TomlCheckerRoot(const TomlCheckerRoot &) = delete;
|
||||||
TomlCheckerRoot(TomlCheckerRoot &&) = delete;
|
TomlCheckerRoot(TomlCheckerRoot &&) = delete;
|
||||||
|
|
||||||
@@ -175,7 +199,7 @@ class TomlCheckerRoot {
|
|||||||
if (check_root) {
|
if (check_root) {
|
||||||
for (const auto &itr : m_root.as_table()) {
|
for (const auto &itr : m_root.as_table()) {
|
||||||
if (!m_visisted.contains(itr.first)) {
|
if (!m_visisted.contains(itr.first)) {
|
||||||
throw std::runtime_error(format_key_error("Unknown key '" + itr.first + "'", itr.first, itr.second));
|
throw_key_error("Unknown key '" + itr.first + "'", itr.first, itr.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,7 +209,7 @@ class TomlCheckerRoot {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Project::Project(const Project *parent, const std::string &path, bool build) {
|
Project::Project(const Project *parent, const std::string &path, bool build) : parent(parent) {
|
||||||
const auto toml_path = fs::path(path) / "cmake.toml";
|
const auto toml_path = fs::path(path) / "cmake.toml";
|
||||||
if (!fs::exists(toml_path)) {
|
if (!fs::exists(toml_path)) {
|
||||||
throw std::runtime_error("File not found '" + toml_path.string() + "'");
|
throw std::runtime_error("File not found '" + toml_path.string() + "'");
|
||||||
@@ -203,7 +227,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
cmake.required("version", cmake_version);
|
cmake.required("version", cmake_version);
|
||||||
|
|
||||||
if (cmake.contains("bin-dir")) {
|
if (cmake.contains("bin-dir")) {
|
||||||
throw std::runtime_error("bin-dir has been renamed to build-dir");
|
throw_key_error("bin-dir has been renamed to build-dir", "bin-dir", cmake.find("bin-dir"));
|
||||||
}
|
}
|
||||||
|
|
||||||
cmake.optional("build-dir", build_dir);
|
cmake.optional("build-dir", build_dir);
|
||||||
@@ -241,11 +265,22 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
conditions["bsd"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "BSD")cmake";
|
conditions["bsd"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "BSD")cmake";
|
||||||
conditions["linux"] = conditions["lunix"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "Linux")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["gcc"] = R"cmake(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "GNU")cmake";
|
||||||
conditions["clang"] = R"cmake(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "Clang")cmake";
|
|
||||||
conditions["msvc"] = R"cmake(MSVC)cmake";
|
conditions["msvc"] = R"cmake(MSVC)cmake";
|
||||||
|
conditions["clang"] =
|
||||||
|
R"cmake((CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$") OR (CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$"))cmake";
|
||||||
|
conditions["clang-cl"] =
|
||||||
|
R"cmake((CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$") OR (CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES "^MSVC$"))cmake";
|
||||||
|
conditions["clang-any"] = R"cmake(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "Clang")cmake";
|
||||||
conditions["root"] = R"cmake(CMKR_ROOT_PROJECT)cmake";
|
conditions["root"] = R"cmake(CMKR_ROOT_PROJECT)cmake";
|
||||||
conditions["x64"] = R"cmake(CMAKE_SIZEOF_VOID_P EQUAL 8)cmake";
|
conditions["x64"] = R"cmake(CMAKE_SIZEOF_VOID_P EQUAL 8)cmake";
|
||||||
conditions["x32"] = R"cmake(CMAKE_SIZEOF_VOID_P EQUAL 4)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 {
|
} else {
|
||||||
conditions = parent->conditions;
|
conditions = parent->conditions;
|
||||||
templates = parent->templates;
|
templates = parent->templates;
|
||||||
@@ -254,6 +289,9 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
if (checker.contains("conditions")) {
|
if (checker.contains("conditions")) {
|
||||||
auto conds = toml::find<decltype(conditions)>(toml, "conditions");
|
auto conds = toml::find<decltype(conditions)>(toml, "conditions");
|
||||||
for (const auto &cond : conds) {
|
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;
|
conditions[cond.first] = cond.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,12 +301,33 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
project.required("name", project_name);
|
project.required("name", project_name);
|
||||||
project.optional("version", project_version);
|
project.optional("version", project_version);
|
||||||
project.optional("description", project_description);
|
project.optional("description", project_description);
|
||||||
|
|
||||||
|
// The implicit default is ["C", "CXX"], so make sure this list isn't
|
||||||
|
// empty or projects without languages explicitly defined will error.
|
||||||
|
project_languages[""] = {"C", "CXX"};
|
||||||
|
|
||||||
project.optional("languages", project_languages);
|
project.optional("languages", project_languages);
|
||||||
|
project.optional("allow-unknown-languages", project_allow_unknown_languages);
|
||||||
project.optional("cmake-before", cmake_before);
|
project.optional("cmake-before", cmake_before);
|
||||||
project.optional("cmake-after", cmake_after);
|
project.optional("cmake-after", cmake_after);
|
||||||
project.optional("include-before", include_before);
|
project.optional("include-before", include_before);
|
||||||
project.optional("include-after", include_after);
|
project.optional("include-after", include_after);
|
||||||
project.optional("subdirs", project_subdirs);
|
project.optional("subdirs", project_subdirs);
|
||||||
|
|
||||||
|
std::string msvc_runtime;
|
||||||
|
project.optional("msvc-runtime", msvc_runtime);
|
||||||
|
if (!msvc_runtime.empty()) {
|
||||||
|
project_msvc_runtime = parse_msvcRuntimeType(msvc_runtime);
|
||||||
|
if (project_msvc_runtime == msvc_last) {
|
||||||
|
std::string error = "Unknown runtime '" + msvc_runtime + "'\n";
|
||||||
|
error += "Available types:\n";
|
||||||
|
for (std::string type_name : msvcRuntimeTypeNames) {
|
||||||
|
error += " - " + type_name + "\n";
|
||||||
|
}
|
||||||
|
error.pop_back(); // Remove last newline
|
||||||
|
throw_key_error(error, msvc_runtime, project.find("msvc-runtime"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checker.contains("subdir")) {
|
if (checker.contains("subdir")) {
|
||||||
@@ -288,36 +347,65 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checker.contains("settings")) {
|
if (checker.contains("variables")) {
|
||||||
using set_map = tsl::ordered_map<std::string, TomlBasicValue>;
|
using set_map = tsl::ordered_map<std::string, TomlBasicValue>;
|
||||||
const auto &sets = toml::find<set_map>(toml, "settings");
|
auto vars = toml::find<set_map>(toml, "variables");
|
||||||
for (const auto &itr : sets) {
|
if (checker.contains("settings")) {
|
||||||
Setting s;
|
print_key_warning("[settings] has been renamed to [variables]", "settings", toml.at("settings"));
|
||||||
|
const auto &sets = toml::find<set_map>(toml, "settings");
|
||||||
|
for (const auto &itr : sets) {
|
||||||
|
if (!vars.insert(itr).second) {
|
||||||
|
throw_key_error("Key '" + itr.first + "' shadows existing variable", itr.first, itr.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &itr : vars) {
|
||||||
|
Variable s;
|
||||||
s.name = itr.first;
|
s.name = itr.first;
|
||||||
const auto &value = itr.second;
|
const auto &value = itr.second;
|
||||||
if (value.is_boolean()) {
|
if (value.is_boolean()) {
|
||||||
s.val = value.as_boolean();
|
s.value = value.as_boolean();
|
||||||
} else if (value.is_string()) {
|
} else if (value.is_string()) {
|
||||||
s.val = value.as_string();
|
s.value = value.as_string();
|
||||||
} else {
|
} else {
|
||||||
auto &setting = checker.create(value);
|
auto &setting = checker.create(value);
|
||||||
setting.optional("comment", s.comment);
|
setting.optional("help", s.help);
|
||||||
if (setting.contains("value")) {
|
if (setting.contains("value")) {
|
||||||
const auto &v = setting.find("value");
|
const auto &v = setting.find("value");
|
||||||
if (v.is_boolean()) {
|
if (v.is_boolean()) {
|
||||||
s.val = v.as_boolean();
|
s.value = v.as_boolean();
|
||||||
} else {
|
} else {
|
||||||
s.val = v.as_string();
|
s.value = v.as_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setting.optional("cache", s.cache);
|
setting.optional("cache", s.cache);
|
||||||
setting.optional("force", s.force);
|
setting.optional("force", s.force);
|
||||||
}
|
}
|
||||||
settings.push_back(s);
|
variables.push_back(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checker.contains("options")) {
|
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>;
|
using opts_map = tsl::ordered_map<std::string, TomlBasicValue>;
|
||||||
const auto &opts = toml::find<opts_map>(toml, "options");
|
const auto &opts = toml::find<opts_map>(toml, "options");
|
||||||
for (const auto &itr : opts) {
|
for (const auto &itr : opts) {
|
||||||
@@ -325,13 +413,52 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
o.name = itr.first;
|
o.name = itr.first;
|
||||||
const auto &value = itr.second;
|
const auto &value = itr.second;
|
||||||
if (value.is_boolean()) {
|
if (value.is_boolean()) {
|
||||||
o.val = value.as_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);
|
auto &option = checker.create(value);
|
||||||
option.optional("comment", o.comment);
|
option.optional("help", o.help);
|
||||||
option.optional("value", o.val);
|
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);
|
options.push_back(o);
|
||||||
|
|
||||||
|
// Add a condition matching the option name
|
||||||
|
if (!conditions.emplace(o.name, o.name).second) {
|
||||||
|
print_key_warning("Option '" + o.name + "' would create a condition '" + o.name + "' that already exists", o.name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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() && ncondition != o.name) {
|
||||||
|
if (!conditions.emplace(ncondition, o.name).second) {
|
||||||
|
print_key_warning("Option '" + o.name + "' would create a condition '" + ncondition + "' that already exists", o.name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,6 +495,15 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
c.optional("cmake-after", content.cmake_after);
|
c.optional("cmake-after", content.cmake_after);
|
||||||
c.optional("include-before", content.include_before);
|
c.optional("include-before", content.include_before);
|
||||||
c.optional("include-after", content.include_after);
|
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()) {
|
for (const auto &argItr : itr.second.as_table()) {
|
||||||
std::string value;
|
std::string value;
|
||||||
@@ -413,17 +549,30 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
key = "URL";
|
key = "URL";
|
||||||
} else if (hash_algorithms.contains(key)) {
|
} else if (hash_algorithms.contains(key)) {
|
||||||
std::string algo;
|
std::string algo;
|
||||||
for (auto c : key) {
|
for (auto ch : key) {
|
||||||
algo.push_back(std::toupper(c));
|
if (ch >= 'a' && ch <= 'z') {
|
||||||
|
ch -= ('a' - 'A');
|
||||||
|
}
|
||||||
|
algo.push_back(ch);
|
||||||
}
|
}
|
||||||
key = "URL_HASH";
|
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;
|
value = algo + "=" + value;
|
||||||
} else if (key == "hash") {
|
} else if (key == "hash") {
|
||||||
key = "URL_HASH";
|
key = "URL_HASH";
|
||||||
|
} else if (key == "subdir") {
|
||||||
|
key = "SOURCE_SUBDIR";
|
||||||
} else if (is_cmake_arg(key)) {
|
} else if (is_cmake_arg(key)) {
|
||||||
// allow passthrough of ExternalProject options
|
// allow passthrough of ExternalProject options
|
||||||
} else if (!c.visisted(key)) {
|
} else if (!c.visisted(key)) {
|
||||||
throw std::runtime_error(format_key_error("Unknown key '" + argItr.first + "'", argItr.first, argItr.second));
|
throw_key_error("Unknown key '" + argItr.first + "'", argItr.first, argItr.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure not to emit keys like "condition" in the FetchContent call
|
// Make sure not to emit keys like "condition" in the FetchContent call
|
||||||
@@ -438,7 +587,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (checker.contains("bin")) {
|
if (checker.contains("bin")) {
|
||||||
throw std::runtime_error("[[bin]] has been renamed to [[target]]");
|
throw_key_error("[[bin]] has been renamed to [target.<name>]", "", toml.at("bin"));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parse_target = [&](const std::string &name, TomlChecker &t, bool isTemplate) {
|
auto parse_target = [&](const std::string &name, TomlChecker &t, bool isTemplate) {
|
||||||
@@ -477,12 +626,21 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
error.pop_back(); // Remove last newline
|
error.pop_back(); // Remove last newline
|
||||||
throw std::runtime_error(format_key_error(error, target.type_name, t.find("type")));
|
throw_key_error(error, target.type_name, t.find("type"));
|
||||||
}
|
}
|
||||||
|
|
||||||
t.optional("headers", target.headers);
|
|
||||||
t.optional("sources", target.sources);
|
t.optional("sources", target.sources);
|
||||||
|
|
||||||
|
// Merge the headers into the sources
|
||||||
|
ConditionVector headers;
|
||||||
|
t.optional("headers", headers);
|
||||||
|
for (const auto &itr : headers) {
|
||||||
|
auto &dest = target.sources[itr.first];
|
||||||
|
for (const auto &jtr : itr.second) {
|
||||||
|
dest.push_back(jtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
t.optional("compile-definitions", target.compile_definitions);
|
t.optional("compile-definitions", target.compile_definitions);
|
||||||
t.optional("private-compile-definitions", target.private_compile_definitions);
|
t.optional("private-compile-definitions", target.private_compile_definitions);
|
||||||
|
|
||||||
@@ -501,16 +659,71 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
t.optional("link-libraries", target.link_libraries);
|
t.optional("link-libraries", target.link_libraries);
|
||||||
t.optional("private-link-libraries", target.private_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("link-options", target.link_options);
|
||||||
t.optional("private-link-options", target.private_link_options);
|
t.optional("private-link-options", target.private_link_options);
|
||||||
|
|
||||||
t.optional("precompile-headers", target.precompile_headers);
|
t.optional("precompile-headers", target.precompile_headers);
|
||||||
t.optional("private-precompile-headers", target.private_precompile_headers);
|
t.optional("private-precompile-headers", target.private_precompile_headers);
|
||||||
|
|
||||||
if (!target.headers.empty()) {
|
t.optional("dependencies", target.dependencies);
|
||||||
auto &sources = target.sources.nth(0).value();
|
|
||||||
const auto &headers = target.headers.nth(0)->second;
|
Condition<std::string> msvc_runtime;
|
||||||
sources.insert(sources.end(), headers.begin(), headers.end());
|
t.optional("msvc-runtime", msvc_runtime);
|
||||||
|
for (const auto &cond_itr : msvc_runtime) {
|
||||||
|
switch (parse_msvcRuntimeType(cond_itr.second)) {
|
||||||
|
case msvc_dynamic:
|
||||||
|
target.properties[cond_itr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL";
|
||||||
|
break;
|
||||||
|
case msvc_static:
|
||||||
|
target.properties[cond_itr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>";
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
std::string error = "Unknown runtime '" + cond_itr.second + "'\n";
|
||||||
|
error += "Available types:\n";
|
||||||
|
for (std::string type_name : msvcRuntimeTypeNames) {
|
||||||
|
error += " - " + type_name + "\n";
|
||||||
|
}
|
||||||
|
error.pop_back(); // Remove last newline
|
||||||
|
const TomlBasicValue *report;
|
||||||
|
if (cond_itr.first.empty()) {
|
||||||
|
report = &t.find("msvc-runtime");
|
||||||
|
} else {
|
||||||
|
report = &t.find(cond_itr.first).as_table().find("msvc-runtime").value();
|
||||||
|
}
|
||||||
|
throw_key_error(error, cond_itr.second, *report);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.optional("condition", target.condition);
|
t.optional("condition", target.condition);
|
||||||
@@ -527,6 +740,8 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
property_list += list_val.as_string();
|
property_list += list_val.as_string();
|
||||||
}
|
}
|
||||||
target.properties[condition][k] = property_list;
|
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()) {
|
} else if (v.is_boolean()) {
|
||||||
target.properties[condition][k] = v.as_boolean() ? "ON" : "OFF";
|
target.properties[condition][k] = v.as_boolean() ? "ON" : "OFF";
|
||||||
} else {
|
} else {
|
||||||
@@ -564,13 +779,13 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
|
|
||||||
for (const auto &type_name : targetTypeNames) {
|
for (const auto &type_name : targetTypeNames) {
|
||||||
if (name == type_name) {
|
if (name == type_name) {
|
||||||
throw std::runtime_error(format_key_error("Reserved template name '" + name + "'", name, itr.second));
|
throw_key_error("Reserved template name '" + name + "'", name, itr.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &tmplate : templates) {
|
for (const auto &tmplate : templates) {
|
||||||
if (name == tmplate.outline.name) {
|
if (name == tmplate.outline.name) {
|
||||||
throw std::runtime_error(format_key_error("Template '" + name + "' already defined", name, itr.second));
|
throw_key_error("Template '" + name + "' already defined", name, itr.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,7 +793,9 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
tmplate.outline = parse_target(name, t, true);
|
tmplate.outline = parse_target(name, t, true);
|
||||||
|
|
||||||
t.optional("add-function", tmplate.add_function);
|
t.optional("add-function", tmplate.add_function);
|
||||||
|
t.optional("add-arguments", tmplate.add_arguments);
|
||||||
t.optional("pass-sources-to-add-function", tmplate.pass_sources_to_add_function);
|
t.optional("pass-sources-to-add-function", tmplate.pass_sources_to_add_function);
|
||||||
|
t.optional("pass-sources", tmplate.pass_sources_to_add_function);
|
||||||
|
|
||||||
templates.push_back(tmplate);
|
templates.push_back(tmplate);
|
||||||
}
|
}
|
||||||
@@ -619,6 +836,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
i.optional("configs", inst.configs);
|
i.optional("configs", inst.configs);
|
||||||
i.required("destination", inst.destination);
|
i.required("destination", inst.destination);
|
||||||
i.optional("component", inst.component);
|
i.optional("component", inst.component);
|
||||||
|
i.optional("optional", inst.optional);
|
||||||
installs.push_back(inst);
|
installs.push_back(inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -627,6 +845,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
auto &v = checker.create(toml, "vcpkg");
|
auto &v = checker.create(toml, "vcpkg");
|
||||||
v.optional("url", vcpkg.url);
|
v.optional("url", vcpkg.url);
|
||||||
v.optional("version", vcpkg.version);
|
v.optional("version", vcpkg.version);
|
||||||
|
|
||||||
for (const auto &p : v.find("packages").as_array()) {
|
for (const auto &p : v.find("packages").as_array()) {
|
||||||
Vcpkg::Package package;
|
Vcpkg::Package package;
|
||||||
const auto &package_str = p.as_string().str;
|
const auto &package_str = p.as_string().str;
|
||||||
@@ -640,18 +859,73 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
|||||||
std::istringstream feature_stream{features};
|
std::istringstream feature_stream{features};
|
||||||
std::string feature;
|
std::string feature;
|
||||||
while (std::getline(feature_stream, 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 {
|
} else {
|
||||||
throw std::runtime_error("Invalid vcpkg package '" + package_str + "'");
|
throw_key_error("Invalid package name '" + package_str + "'", "packages", p);
|
||||||
}
|
}
|
||||||
vcpkg.packages.emplace_back(std::move(package));
|
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);
|
checker.check(conditions, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Project *Project::root() const {
|
||||||
|
auto root = this;
|
||||||
|
while (root->parent != nullptr)
|
||||||
|
root = root->parent;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Project::cmake_minimum_version(int major, int minor) const {
|
||||||
|
// NOTE: this code is like pulling teeth, sorry
|
||||||
|
auto root_version = root()->cmake_version;
|
||||||
|
auto range_index = root_version.find("...");
|
||||||
|
if (range_index != std::string::npos) {
|
||||||
|
root_version.resize(range_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto period_index = root_version.find('.');
|
||||||
|
auto root_major = atoi(root_version.substr(0, period_index).c_str());
|
||||||
|
int root_minor = 0;
|
||||||
|
if (period_index != std::string::npos) {
|
||||||
|
auto end_index = root_version.find('.', period_index + 1);
|
||||||
|
root_minor = atoi(root_version.substr(period_index + 1, end_index).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::tie(root_major, root_minor) >= std::tie(major, minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Project::is_condition_name(const std::string &name) {
|
||||||
|
for (auto ch : name) {
|
||||||
|
if (!std::isalnum(ch) && ch != '-' && ch != '_') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_root_path(const std::string &path) {
|
bool is_root_path(const std::string &path) {
|
||||||
const auto toml_path = fs::path(path) / "cmake.toml";
|
const auto toml_path = fs::path(path) / "cmake.toml";
|
||||||
if (!fs::exists(toml_path)) {
|
if (!fs::exists(toml_path)) {
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
# These will be generated by cmkr, so no point in tracking them
|
# These will be generated by cmkr, so no point in tracking them
|
||||||
**/CMakeLists.txt
|
**/CMakeLists.txt
|
||||||
**/cmkr.cmake
|
**/cmkr.cmake
|
||||||
|
**/vcpkg.json
|
||||||
Generated
+51
-8
@@ -14,7 +14,7 @@ add_test(
|
|||||||
WORKING_DIRECTORY
|
WORKING_DIRECTORY
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/basic"
|
"${CMAKE_CURRENT_LIST_DIR}/basic"
|
||||||
COMMAND
|
COMMAND
|
||||||
$<TARGET_FILE:cmkr>
|
"$<TARGET_FILE:cmkr>"
|
||||||
build
|
build
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ add_test(
|
|||||||
WORKING_DIRECTORY
|
WORKING_DIRECTORY
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/interface"
|
"${CMAKE_CURRENT_LIST_DIR}/interface"
|
||||||
COMMAND
|
COMMAND
|
||||||
$<TARGET_FILE:cmkr>
|
"$<TARGET_FILE:cmkr>"
|
||||||
build
|
build
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ add_test(
|
|||||||
WORKING_DIRECTORY
|
WORKING_DIRECTORY
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/fetch-content"
|
"${CMAKE_CURRENT_LIST_DIR}/fetch-content"
|
||||||
COMMAND
|
COMMAND
|
||||||
$<TARGET_FILE:cmkr>
|
"$<TARGET_FILE:cmkr>"
|
||||||
build
|
build
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ add_test(
|
|||||||
WORKING_DIRECTORY
|
WORKING_DIRECTORY
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/conditions"
|
"${CMAKE_CURRENT_LIST_DIR}/conditions"
|
||||||
COMMAND
|
COMMAND
|
||||||
$<TARGET_FILE:cmkr>
|
"$<TARGET_FILE:cmkr>"
|
||||||
build
|
build
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ add_test(
|
|||||||
WORKING_DIRECTORY
|
WORKING_DIRECTORY
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/vcpkg"
|
"${CMAKE_CURRENT_LIST_DIR}/vcpkg"
|
||||||
COMMAND
|
COMMAND
|
||||||
$<TARGET_FILE:cmkr>
|
"$<TARGET_FILE:cmkr>"
|
||||||
build
|
build
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ add_test(
|
|||||||
WORKING_DIRECTORY
|
WORKING_DIRECTORY
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/cxx-standard"
|
"${CMAKE_CURRENT_LIST_DIR}/cxx-standard"
|
||||||
COMMAND
|
COMMAND
|
||||||
$<TARGET_FILE:cmkr>
|
"$<TARGET_FILE:cmkr>"
|
||||||
build
|
build
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ add_test(
|
|||||||
WORKING_DIRECTORY
|
WORKING_DIRECTORY
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/globbing"
|
"${CMAKE_CURRENT_LIST_DIR}/globbing"
|
||||||
COMMAND
|
COMMAND
|
||||||
$<TARGET_FILE:cmkr>
|
"$<TARGET_FILE:cmkr>"
|
||||||
build
|
build
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -84,7 +84,50 @@ add_test(
|
|||||||
WORKING_DIRECTORY
|
WORKING_DIRECTORY
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/templates"
|
"${CMAKE_CURRENT_LIST_DIR}/templates"
|
||||||
COMMAND
|
COMMAND
|
||||||
$<TARGET_FILE:cmkr>
|
"$<TARGET_FILE:cmkr>"
|
||||||
build
|
build
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(MSVC) # msvc
|
||||||
|
add_test(
|
||||||
|
NAME
|
||||||
|
msvc-runtime
|
||||||
|
WORKING_DIRECTORY
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/msvc-runtime"
|
||||||
|
COMMAND
|
||||||
|
"$<TARGET_FILE:cmkr>"
|
||||||
|
build
|
||||||
|
)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
add_test(
|
||||||
|
NAME
|
||||||
|
compile-options
|
||||||
|
WORKING_DIRECTORY
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/compile-options"
|
||||||
|
COMMAND
|
||||||
|
"$<TARGET_FILE:cmkr>"
|
||||||
|
build
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32) # windows
|
||||||
|
add_test(
|
||||||
|
NAME
|
||||||
|
relative-paths
|
||||||
|
WORKING_DIRECTORY
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/relative-paths"
|
||||||
|
COMMAND
|
||||||
|
"$<TARGET_FILE:cmkr>"
|
||||||
|
build
|
||||||
|
)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
add_test(
|
||||||
|
NAME
|
||||||
|
objective-c
|
||||||
|
WORKING_DIRECTORY
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/objective-c"
|
||||||
|
COMMAND
|
||||||
|
"$<TARGET_FILE:cmkr>"
|
||||||
|
build
|
||||||
|
)
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ description = "Minimal example"
|
|||||||
type = "executable"
|
type = "executable"
|
||||||
sources = ["src/basic.cpp"]
|
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)`.
|
||||||
|
|||||||
@@ -45,3 +45,29 @@ name = "templates"
|
|||||||
working-directory = "templates"
|
working-directory = "templates"
|
||||||
command = "$<TARGET_FILE:cmkr>"
|
command = "$<TARGET_FILE:cmkr>"
|
||||||
arguments = ["build"]
|
arguments = ["build"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
condition = "msvc"
|
||||||
|
name = "msvc-runtime"
|
||||||
|
working-directory = "msvc-runtime"
|
||||||
|
command = "$<TARGET_FILE:cmkr>"
|
||||||
|
arguments = ["build"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "compile-options"
|
||||||
|
working-directory = "compile-options"
|
||||||
|
command = "$<TARGET_FILE:cmkr>"
|
||||||
|
arguments = ["build"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
condition = "windows"
|
||||||
|
name = "relative-paths"
|
||||||
|
working-directory = "relative-paths"
|
||||||
|
command = "$<TARGET_FILE:cmkr>"
|
||||||
|
arguments = ["build"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "objective-c"
|
||||||
|
working-directory = "objective-c"
|
||||||
|
command = "$<TARGET_FILE:cmkr>"
|
||||||
|
arguments = ["build"]
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
puts("Hello from cmkr!");
|
||||||
|
}
|
||||||
+28
-23
@@ -1,23 +1,28 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "conditions"
|
name = "conditions"
|
||||||
cmake-after = "set(CUSTOM ON)"
|
cmake-after = "set(CUSTOM ON)"
|
||||||
|
|
||||||
[conditions]
|
[options]
|
||||||
custom = "CUSTOM"
|
CONDITIONS_BUILD_TESTS = "root"
|
||||||
|
|
||||||
[target.example]
|
[conditions]
|
||||||
type = "executable"
|
custom = "CUSTOM"
|
||||||
sources = ["src/main.cpp"]
|
|
||||||
windows.sources = ["src/windows_specific.cpp"]
|
[target.example]
|
||||||
cmake-after = "message(STATUS cmake-after)"
|
type = "executable"
|
||||||
windows.cmake-after = "message(STATUS win32-after)"
|
sources = ["src/main.cpp"]
|
||||||
macos.cmake-after = "message(STATUS macos-after)"
|
windows.sources = ["src/windows_specific.cpp"]
|
||||||
linux.cmake-after = "message(STATUS linux-after)"
|
cmake-after = "message(STATUS cmake-after)"
|
||||||
unix.cmake-after = "message(STATUS unix-after)"
|
windows.cmake-after = "message(STATUS win32-after)"
|
||||||
custom.cmake-after = "message(STATUS custom-after)"
|
macos.cmake-after = "message(STATUS macos-after)"
|
||||||
|
linux.cmake-after = "message(STATUS linux-after)"
|
||||||
[target.example.properties]
|
unix.cmake-after = "message(STATUS unix-after)"
|
||||||
AUTOMOC = false
|
custom.cmake-after = "message(STATUS custom-after)"
|
||||||
custom.OUTPUT_NAME = "example2"
|
build-tests.cmake-after = "message(STATUS build-tests)"
|
||||||
custom.AUTORCC = true
|
"CONDITIONS_BUILD_TESTS AND $<linux>".cmake-after = "message(STATUS linux-tests)"
|
||||||
AUTOGEN = "ON"
|
|
||||||
|
[target.example.properties]
|
||||||
|
AUTOMOC = false
|
||||||
|
custom.OUTPUT_NAME = "example2"
|
||||||
|
custom.AUTORCC = true
|
||||||
|
AUTOGEN = "ON"
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
int main() { }
|
int main() {
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
void foo() { }
|
void foo() {
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
# Require a C++11 compiler for the target `example`.
|
# Require a C++11 compiler for the target `example`.
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "cxx-standard"
|
name = "cxx-standard"
|
||||||
description = "Changing C++ standard"
|
description = "Changing C++ standard"
|
||||||
|
|
||||||
[target.example]
|
[target.example]
|
||||||
type = "executable"
|
type = "executable"
|
||||||
sources = ["src/main.cpp"]
|
sources = ["src/main.cpp"]
|
||||||
compile-features = ["cxx_std_11"]
|
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).
|
# 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).
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
int main()
|
int main() {
|
||||||
{
|
auto tpl = std::make_tuple(1, 2);
|
||||||
auto tpl = std::make_tuple(1, 2);
|
printf("Hello from C++11 %d\n", std::get<0>(tpl));
|
||||||
printf("Hello from C++11 %d\n", std::get<0>(tpl));
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,12 +4,13 @@
|
|||||||
name = "fetch-content"
|
name = "fetch-content"
|
||||||
description = "Fetching from git"
|
description = "Fetching from git"
|
||||||
|
|
||||||
[fetch-content]
|
[fetch-content.fmt]
|
||||||
fmt = { git = "https://github.com/fmtlib/fmt", tag = "7.1.3" }
|
git = "https://github.com/fmtlib/fmt"
|
||||||
|
tag = "7.1.3"
|
||||||
|
|
||||||
[target.example]
|
[target.example]
|
||||||
type = "executable"
|
type = "executable"
|
||||||
sources = ["src/main.cpp"]
|
sources = ["src/main.cpp"]
|
||||||
link-libraries = ["fmt::fmt"]
|
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).
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
int main()
|
int main() {
|
||||||
{
|
|
||||||
fmt::print("Hello, world!\n");
|
fmt::print("Hello, world!\n");
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-18
@@ -1,18 +1,18 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "globbing"
|
name = "globbing"
|
||||||
description = "Globbing sources"
|
description = "Globbing sources"
|
||||||
|
|
||||||
# Recursively glob in the mylib/ folder
|
# Recursively glob in the mylib/ folder
|
||||||
[target.mylib]
|
[target.mylib]
|
||||||
type = "static"
|
type = "static"
|
||||||
alias = "mylib::mylib"
|
alias = "mylib::mylib"
|
||||||
sources = ["mylib/**.hpp", "mylib/**.cpp"]
|
sources = ["mylib/**.hpp", "mylib/**.cpp"]
|
||||||
include-directories = ["mylib/include"]
|
include-directories = ["mylib/include"]
|
||||||
|
|
||||||
# Single-folder glob in example/src/
|
# Single-folder glob in example/src/
|
||||||
[target.example]
|
[target.example]
|
||||||
type = "executable"
|
type = "executable"
|
||||||
sources = ["example/src/*.cpp"]
|
sources = ["example/src/*.cpp"]
|
||||||
link-libraries = ["mylib::mylib"]
|
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.
|
# 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.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mylib/mylib.hpp>
|
#include <mylib/mylib.hpp>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::cout << mylib::message() << std::endl;
|
std::cout << mylib::message() << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace mylib
|
namespace mylib {
|
||||||
{
|
std::string message();
|
||||||
std::string message();
|
} // namespace mylib
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include <mylib/mylib.hpp>
|
#include <mylib/mylib.hpp>
|
||||||
|
|
||||||
std::string mylib::message()
|
std::string mylib::message() {
|
||||||
{
|
return "cmkr is awesome!";
|
||||||
return "cmkr is awesome!";
|
}
|
||||||
}
|
|
||||||
|
|||||||
+13
-13
@@ -1,13 +1,13 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "interface"
|
name = "interface"
|
||||||
description = "Header-only library"
|
description = "Header-only library"
|
||||||
|
|
||||||
[target.mylib]
|
[target.mylib]
|
||||||
type = "interface"
|
type = "interface"
|
||||||
include-directories = ["include"]
|
include-directories = ["include"]
|
||||||
compile-features = ["cxx_std_11"]
|
compile-features = ["cxx_std_11"]
|
||||||
|
|
||||||
[target.example]
|
[target.example]
|
||||||
type = "executable"
|
type = "executable"
|
||||||
sources = ["src/main.cpp"]
|
sources = ["src/main.cpp"]
|
||||||
link-libraries = ["mylib"]
|
link-libraries = ["mylib"]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
namespace mylib
|
namespace mylib {
|
||||||
{
|
static const char *version() {
|
||||||
static const char* version() { return "v1.0"; }
|
return "v1.0";
|
||||||
} // namespace mylib
|
}
|
||||||
|
} // namespace mylib
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "mylib/mylib.hpp"
|
#include "mylib/mylib.hpp"
|
||||||
|
|
||||||
int main()
|
int main() {
|
||||||
{
|
printf("mylib version: %s\n", mylib::version());
|
||||||
printf("mylib version: %s\n", mylib::version())
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[project]
|
||||||
|
name = "msvc-runtime"
|
||||||
|
description = "Static MSVC runtime"
|
||||||
|
msvc-runtime = "static"
|
||||||
|
|
||||||
|
# This target will compile with a static runtime
|
||||||
|
[target.static-runtime]
|
||||||
|
type = "executable"
|
||||||
|
sources = ["src/main.cpp"]
|
||||||
|
|
||||||
|
# This target overrides the [project].msvc-runtime
|
||||||
|
[target.dynamic-runtime]
|
||||||
|
type = "executable"
|
||||||
|
sources = ["src/main.cpp"]
|
||||||
|
msvc-runtime = "dynamic"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
puts("Hello from cmkr(msvc-static)!");
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Add Objective-C sources on Apple platforms:
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "objective-c"
|
||||||
|
description = "Objective-C"
|
||||||
|
languages = ["C"]
|
||||||
|
apple.languages = ["OBJC"]
|
||||||
|
|
||||||
|
[target.hello]
|
||||||
|
type = "executable"
|
||||||
|
sources = ["src/main.c"]
|
||||||
|
apple.sources = ["src/apple.m"]
|
||||||
|
apple.link-libraries = ["$<LINK_LIBRARY:FRAMEWORK,Foundation>"]
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
void platform_specific() {
|
||||||
|
NSFileHandle *stdout = [NSFileHandle fileHandleWithStandardOutput];
|
||||||
|
NSString *message = @"Hello from Objective-C!\n";
|
||||||
|
[stdout writeData:[message dataUsingEncoding:NSUTF8StringEncoding] error:nil];
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
void platform_specific();
|
||||||
|
#else
|
||||||
|
void platform_specific() {
|
||||||
|
puts("This is not an Apple platform.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
platform_specific();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -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"]
|
||||||
Binary file not shown.
@@ -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!");
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -8,11 +8,11 @@ description = "Target templates"
|
|||||||
type = "executable"
|
type = "executable"
|
||||||
sources = ["src/templates.cpp"]
|
sources = ["src/templates.cpp"]
|
||||||
compile-definitions = ["IS_APP"]
|
compile-definitions = ["IS_APP"]
|
||||||
|
|
||||||
# Unlike interface targets you can also inherit properties
|
# Unlike interface targets you can also inherit properties
|
||||||
[template.app.properties]
|
properties = {
|
||||||
CXX_STANDARD = "11"
|
CXX_STANDARD = "11",
|
||||||
CXX_STANDARD_REQUIRED = true
|
CXX_STANDARD_REQUIRED = true,
|
||||||
|
}
|
||||||
|
|
||||||
[target.app-a]
|
[target.app-a]
|
||||||
type = "app"
|
type = "app"
|
||||||
@@ -22,4 +22,4 @@ compile-definitions = ["APP_A"]
|
|||||||
type = "app"
|
type = "app"
|
||||||
compile-definitions = ["APP_B"]
|
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.
|
||||||
|
|||||||
@@ -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]
|
[project]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
description = "Dependencies from vcpkg"
|
description = "Dependencies from vcpkg"
|
||||||
|
|
||||||
# See https://github.com/microsoft/vcpkg/releases for vcpkg versions
|
# 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]
|
[vcpkg]
|
||||||
version = "2021.05.12"
|
version = "2024.11.16"
|
||||||
packages = ["fmt"]
|
packages = ["fmt"]
|
||||||
|
|
||||||
[find-package]
|
[find-package.fmt]
|
||||||
fmt = {}
|
|
||||||
|
|
||||||
[target.example]
|
[target.example]
|
||||||
type = "executable"
|
type = "executable"
|
||||||
@@ -19,4 +18,4 @@ sources = ["src/main.cpp"]
|
|||||||
link-libraries = ["fmt::fmt"]
|
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`.
|
# 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]`.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
int main()
|
int main() {
|
||||||
{
|
|
||||||
fmt::print("Hello, world!\n");
|
fmt::print("Hello, world!\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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": ""
|
|
||||||
}
|
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
# Disable clang-format in this folder
|
||||||
|
DisableFormat: true
|
||||||
|
SortIncludes: Never
|
||||||
+4
-7
@@ -9,14 +9,11 @@ add_library(ordered_map INTERFACE)
|
|||||||
target_include_directories(ordered_map INTERFACE ordered-map-1.0.0/include)
|
target_include_directories(ordered_map INTERFACE ordered-map-1.0.0/include)
|
||||||
target_compile_definitions(ordered_map INTERFACE NOMINMAX)
|
target_compile_definitions(ordered_map INTERFACE NOMINMAX)
|
||||||
|
|
||||||
# https://github.com/ToruNiina/toml11 (MIT)
|
# https://github.com/ToruNiina/toml11 (MIT)
|
||||||
add_library(toml11 INTERFACE)
|
add_library(toml11 INTERFACE)
|
||||||
target_include_directories(toml11 INTERFACE toml11-3.6.0)
|
target_include_directories(toml11 INTERFACE toml11-3.8.1)
|
||||||
|
target_compile_definitions(toml11 INTERFACE TOML11_USE_UNRELEASED_TOML_FEATURES)
|
||||||
|
|
||||||
# https://github.com/mpark/variant (BSL-1.0)
|
# https://github.com/mpark/variant (BSL-1.0)
|
||||||
add_library(mpark_variant INTERFACE)
|
add_library(mpark_variant INTERFACE)
|
||||||
target_include_directories(mpark_variant INTERFACE variant-1.4.0/include)
|
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)
|
|
||||||
Vendored
-21
@@ -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.
|
|
||||||
-25447
File diff suppressed because it is too large
Load Diff
@@ -25,21 +25,14 @@
|
|||||||
#ifndef TOML_FOR_MODERN_CPP
|
#ifndef TOML_FOR_MODERN_CPP
|
||||||
#define TOML_FOR_MODERN_CPP
|
#define TOML_FOR_MODERN_CPP
|
||||||
|
|
||||||
#ifndef __cplusplus
|
|
||||||
# error "__cplusplus is not defined"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __cplusplus < 201103L && _MSC_VER < 1900
|
|
||||||
# error "toml11 requires C++11 or later."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TOML11_VERSION_MAJOR 3
|
#define TOML11_VERSION_MAJOR 3
|
||||||
#define TOML11_VERSION_MINOR 5
|
#define TOML11_VERSION_MINOR 8
|
||||||
#define TOML11_VERSION_PATCH 0
|
#define TOML11_VERSION_PATCH 1
|
||||||
|
|
||||||
#include "toml/parser.hpp"
|
#include "toml/parser.hpp"
|
||||||
#include "toml/literal.hpp"
|
#include "toml/literal.hpp"
|
||||||
#include "toml/serializer.hpp"
|
#include "toml/serializer.hpp"
|
||||||
#include "toml/get.hpp"
|
#include "toml/get.hpp"
|
||||||
|
#include "toml/macros.hpp"
|
||||||
|
|
||||||
#endif// TOML_FOR_MODERN_CPP
|
#endif// TOML_FOR_MODERN_CPP
|
||||||
+45
@@ -17,11 +17,41 @@ namespace color_ansi
|
|||||||
{
|
{
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
inline int colorize_index()
|
inline int colorize_index()
|
||||||
{
|
{
|
||||||
static const int index = std::ios_base::xalloc();
|
static const int index = std::ios_base::xalloc();
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Control color mode globally
|
||||||
|
class color_mode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline void enable()
|
||||||
|
{
|
||||||
|
should_color_ = true;
|
||||||
|
}
|
||||||
|
inline void disable()
|
||||||
|
{
|
||||||
|
should_color_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool should_color() const
|
||||||
|
{
|
||||||
|
return should_color_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static color_mode& status()
|
||||||
|
{
|
||||||
|
static color_mode status_;
|
||||||
|
return status_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool should_color_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
inline std::ostream& colorize(std::ostream& os)
|
inline std::ostream& colorize(std::ostream& os)
|
||||||
@@ -55,6 +85,21 @@ inline std::ostream& cyan (std::ostream& os)
|
|||||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;}
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;}
|
||||||
inline std::ostream& white (std::ostream& os)
|
inline std::ostream& white (std::ostream& os)
|
||||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;}
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;}
|
||||||
|
|
||||||
|
inline void enable()
|
||||||
|
{
|
||||||
|
return detail::color_mode::status().enable();
|
||||||
|
}
|
||||||
|
inline void disable()
|
||||||
|
{
|
||||||
|
return detail::color_mode::status().disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool should_color()
|
||||||
|
{
|
||||||
|
return detail::color_mode::status().should_color();
|
||||||
|
}
|
||||||
|
|
||||||
} // color_ansi
|
} // color_ansi
|
||||||
|
|
||||||
// ANSI escape sequence is the only and default colorization method currently
|
// ANSI escape sequence is the only and default colorization method currently
|
||||||
Vendored
+2
-2
@@ -29,7 +29,7 @@ namespace detail
|
|||||||
// to output character as an error message.
|
// to output character as an error message.
|
||||||
inline std::string show_char(const char c)
|
inline std::string show_char(const char c)
|
||||||
{
|
{
|
||||||
// It supress an error that occurs only in Debug mode of MSVC++ on Windows.
|
// It suppresses an error that occurs only in Debug mode of MSVC++ on Windows.
|
||||||
// I'm not completely sure but they check the value of char to be in the
|
// I'm not completely sure but they check the value of char to be in the
|
||||||
// range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes
|
// range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes
|
||||||
// has negative value (if char has sign). So here it re-interprets c as
|
// has negative value (if char has sign). So here it re-interprets c as
|
||||||
@@ -154,7 +154,7 @@ struct sequence<Head, Tail...>
|
|||||||
invoke(location& loc)
|
invoke(location& loc)
|
||||||
{
|
{
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
const auto rslt = Head::invoke(loc);
|
auto rslt = Head::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.reset(first);
|
loc.reset(first);
|
||||||
+26
-7
@@ -4,11 +4,18 @@
|
|||||||
#define TOML11_COMMENTS_HPP
|
#define TOML11_COMMENTS_HPP
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT
|
||||||
|
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments
|
||||||
|
#else
|
||||||
|
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments
|
||||||
|
#endif
|
||||||
|
|
||||||
// This file provides mainly two classes, `preserve_comments` and `discard_comments`.
|
// This file provides mainly two classes, `preserve_comments` and `discard_comments`.
|
||||||
// Those two are a container that have the same interface as `std::vector<std::string>`
|
// Those two are a container that have the same interface as `std::vector<std::string>`
|
||||||
// but bahaves in the opposite way. `preserve_comments` is just the same as
|
// but bahaves in the opposite way. `preserve_comments` is just the same as
|
||||||
@@ -339,7 +346,7 @@ operator+(const empty_iterator<T, C>& lhs, typename empty_iterator<T, C>::differ
|
|||||||
//
|
//
|
||||||
// Why this is chose as the default type is because the last version (2.x.y)
|
// Why this is chose as the default type is because the last version (2.x.y)
|
||||||
// does not contain any comments in a value. To minimize the impact on the
|
// does not contain any comments in a value. To minimize the impact on the
|
||||||
// efficiency, this is choosed as a default.
|
// efficiency, this is chosen as a default.
|
||||||
//
|
//
|
||||||
// To reduce the memory footprint, later we can try empty base optimization (EBO).
|
// To reduce the memory footprint, later we can try empty base optimization (EBO).
|
||||||
struct discard_comments
|
struct discard_comments
|
||||||
@@ -418,14 +425,14 @@ struct discard_comments
|
|||||||
// empty, so accessing through operator[], front/back, data causes address
|
// empty, so accessing through operator[], front/back, data causes address
|
||||||
// error.
|
// error.
|
||||||
|
|
||||||
reference operator[](const size_type) noexcept {return *data();}
|
reference operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");}
|
||||||
const_reference operator[](const size_type) const noexcept {return *data();}
|
const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");}
|
||||||
reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");}
|
reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");}
|
||||||
const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
|
const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
|
||||||
reference front() noexcept {return *data();}
|
reference front() noexcept {never_call("toml::discard_comment::front");}
|
||||||
const_reference front() const noexcept {return *data();}
|
const_reference front() const noexcept {never_call("toml::discard_comment::front");}
|
||||||
reference back() noexcept {return *data();}
|
reference back() noexcept {never_call("toml::discard_comment::back");}
|
||||||
const_reference back() const noexcept {return *data();}
|
const_reference back() const noexcept {never_call("toml::discard_comment::back");}
|
||||||
|
|
||||||
pointer data() noexcept {return nullptr;}
|
pointer data() noexcept {return nullptr;}
|
||||||
const_pointer data() const noexcept {return nullptr;}
|
const_pointer data() const noexcept {return nullptr;}
|
||||||
@@ -443,6 +450,18 @@ struct discard_comments
|
|||||||
const_reverse_iterator rend() const noexcept {return const_iterator{};}
|
const_reverse_iterator rend() const noexcept {return const_iterator{};}
|
||||||
const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
|
const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
|
||||||
const_reverse_iterator crend() const noexcept {return const_iterator{};}
|
const_reverse_iterator crend() const noexcept {return const_iterator{};}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
[[noreturn]] static void never_call(const char *const this_function)
|
||||||
|
{
|
||||||
|
#ifdef __has_builtin
|
||||||
|
# if __has_builtin(__builtin_unreachable)
|
||||||
|
__builtin_unreachable();
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
throw std::logic_error{this_function};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}
|
inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}
|
||||||
+32
-32
@@ -21,22 +21,7 @@ namespace toml
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
// TODO: find more sophisticated way to handle this
|
// TODO: find more sophisticated way to handle this
|
||||||
#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
#if defined(_MSC_VER)
|
||||||
inline std::tm localtime_s(const std::time_t* src)
|
|
||||||
{
|
|
||||||
std::tm dst;
|
|
||||||
const auto result = ::localtime_r(src, &dst);
|
|
||||||
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
inline std::tm gmtime_s(const std::time_t* src)
|
|
||||||
{
|
|
||||||
std::tm dst;
|
|
||||||
const auto result = ::gmtime_r(src, &dst);
|
|
||||||
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
inline std::tm localtime_s(const std::time_t* src)
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
{
|
{
|
||||||
std::tm dst;
|
std::tm dst;
|
||||||
@@ -51,6 +36,21 @@ inline std::tm gmtime_s(const std::time_t* src)
|
|||||||
if (result) { throw std::runtime_error("gmtime_s failed."); }
|
if (result) { throw std::runtime_error("gmtime_s failed."); }
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||||
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
|
{
|
||||||
|
std::tm dst;
|
||||||
|
const auto result = ::localtime_r(src, &dst);
|
||||||
|
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
inline std::tm gmtime_s(const std::time_t* src)
|
||||||
|
{
|
||||||
|
std::tm dst;
|
||||||
|
const auto result = ::gmtime_r(src, &dst);
|
||||||
|
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
#else // fallback. not threadsafe
|
#else // fallback. not threadsafe
|
||||||
inline std::tm localtime_s(const std::time_t* src)
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
{
|
{
|
||||||
@@ -85,9 +85,9 @@ enum class month_t : std::uint8_t
|
|||||||
|
|
||||||
struct local_date
|
struct local_date
|
||||||
{
|
{
|
||||||
std::int16_t year; // A.D. (like, 2018)
|
std::int16_t year{}; // A.D. (like, 2018)
|
||||||
std::uint8_t month; // [0, 11]
|
std::uint8_t month{}; // [0, 11]
|
||||||
std::uint8_t day; // [1, 31]
|
std::uint8_t day{}; // [1, 31]
|
||||||
|
|
||||||
local_date(int y, month_t m, int d)
|
local_date(int y, month_t m, int d)
|
||||||
: year (static_cast<std::int16_t>(y)),
|
: year (static_cast<std::int16_t>(y)),
|
||||||
@@ -181,12 +181,12 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
|
|||||||
|
|
||||||
struct local_time
|
struct local_time
|
||||||
{
|
{
|
||||||
std::uint8_t hour; // [0, 23]
|
std::uint8_t hour{}; // [0, 23]
|
||||||
std::uint8_t minute; // [0, 59]
|
std::uint8_t minute{}; // [0, 59]
|
||||||
std::uint8_t second; // [0, 60]
|
std::uint8_t second{}; // [0, 60]
|
||||||
std::uint16_t millisecond; // [0, 999]
|
std::uint16_t millisecond{}; // [0, 999]
|
||||||
std::uint16_t microsecond; // [0, 999]
|
std::uint16_t microsecond{}; // [0, 999]
|
||||||
std::uint16_t nanosecond; // [0, 999]
|
std::uint16_t nanosecond{}; // [0, 999]
|
||||||
|
|
||||||
local_time(int h, int m, int s,
|
local_time(int h, int m, int s,
|
||||||
int ms = 0, int us = 0, int ns = 0)
|
int ms = 0, int us = 0, int ns = 0)
|
||||||
@@ -297,8 +297,8 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_time& time)
|
|||||||
|
|
||||||
struct time_offset
|
struct time_offset
|
||||||
{
|
{
|
||||||
std::int8_t hour; // [-12, 12]
|
std::int8_t hour{}; // [-12, 12]
|
||||||
std::int8_t minute; // [-59, 59]
|
std::int8_t minute{}; // [-59, 59]
|
||||||
|
|
||||||
time_offset(int h, int m)
|
time_offset(int h, int m)
|
||||||
: hour (static_cast<std::int8_t>(h)),
|
: hour (static_cast<std::int8_t>(h)),
|
||||||
@@ -364,8 +364,8 @@ operator<<(std::basic_ostream<charT, traits>& os, const time_offset& offset)
|
|||||||
|
|
||||||
struct local_datetime
|
struct local_datetime
|
||||||
{
|
{
|
||||||
local_date date;
|
local_date date{};
|
||||||
local_time time;
|
local_time time{};
|
||||||
|
|
||||||
local_datetime(local_date d, local_time t): date(d), time(t) {}
|
local_datetime(local_date d, local_time t): date(d), time(t) {}
|
||||||
|
|
||||||
@@ -478,9 +478,9 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_datetime& dt)
|
|||||||
|
|
||||||
struct offset_datetime
|
struct offset_datetime
|
||||||
{
|
{
|
||||||
local_date date;
|
local_date date{};
|
||||||
local_time time;
|
local_time time{};
|
||||||
time_offset offset;
|
time_offset offset{};
|
||||||
|
|
||||||
offset_datetime(local_date d, local_time t, time_offset o)
|
offset_datetime(local_date d, local_time t, time_offset o)
|
||||||
: date(d), time(t), offset(o)
|
: date(d), time(t), offset(o)
|
||||||
+19
-1
@@ -2,14 +2,32 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_EXCEPTION_HPP
|
#ifndef TOML11_EXCEPTION_HPP
|
||||||
#define TOML11_EXCEPTION_HPP
|
#define TOML11_EXCEPTION_HPP
|
||||||
#include <stdexcept>
|
|
||||||
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "source_location.hpp"
|
#include "source_location.hpp"
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct file_io_error : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
file_io_error(int errnum, const std::string& msg, const std::string& fname)
|
||||||
|
: std::runtime_error(msg + " \"" + fname + "\": errno = " + std::to_string(errnum)),
|
||||||
|
errno_(errnum)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int get_errno() const noexcept {return errno_;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int errno_;
|
||||||
|
};
|
||||||
|
|
||||||
struct exception : public std::exception
|
struct exception : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
-1
@@ -2,7 +2,6 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_FROM_HPP
|
#ifndef TOML11_FROM_HPP
|
||||||
#define TOML11_FROM_HPP
|
#define TOML11_FROM_HPP
|
||||||
#include "traits.hpp"
|
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
+101
-13
@@ -140,7 +140,7 @@ get(basic_value<C, M, V>&& v)
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
// std::string_view
|
// std::string_view
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
inline detail::enable_if_t<std::is_same<T, std::string_view>::value, std::string_view>
|
inline detail::enable_if_t<std::is_same<T, std::string_view>::value, std::string_view>
|
||||||
@@ -215,6 +215,7 @@ template<typename T, typename C,
|
|||||||
detail::enable_if_t<detail::conjunction<
|
detail::enable_if_t<detail::conjunction<
|
||||||
detail::is_container<T>, // T is a container
|
detail::is_container<T>, // T is a container
|
||||||
detail::negation<detail::has_push_back_method<T>>, // w/o push_back(...)
|
detail::negation<detail::has_push_back_method<T>>, // w/o push_back(...)
|
||||||
|
detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
|
||||||
detail::negation< // not toml::array
|
detail::negation< // not toml::array
|
||||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||||
>::value, T>
|
>::value, T>
|
||||||
@@ -255,19 +256,37 @@ get(const basic_value<C, M, V>&);
|
|||||||
|
|
||||||
// toml::from<T>::from_toml(v)
|
// toml::from<T>::from_toml(v)
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V,
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
std::size_t S = sizeof(::toml::from<T>)>
|
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||||
T get(const basic_value<C, M, V>&);
|
get(const basic_value<C, M, V>&);
|
||||||
|
|
||||||
// T(const toml::value&) and T is not toml::basic_value
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||||
|
get(basic_value<C, M, V>&);
|
||||||
|
|
||||||
|
// T(const toml::value&) and T is not toml::basic_value,
|
||||||
|
// and it does not have `from<T>` nor `from_toml`.
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
detail::enable_if_t<detail::conjunction<
|
detail::enable_if_t<detail::conjunction<
|
||||||
detail::negation<detail::is_basic_value<T>>,
|
detail::negation<detail::is_basic_value<T>>,
|
||||||
std::is_constructible<T, const basic_value<C, M, V>&>
|
std::is_constructible<T, const basic_value<C, M, V>&>,
|
||||||
|
detail::negation<detail::has_from_toml_method<T, C, M, V>>,
|
||||||
|
detail::negation<detail::has_specialized_from<T>>
|
||||||
>::value, T>
|
>::value, T>
|
||||||
get(const basic_value<C, M, V>&);
|
get(const basic_value<C, M, V>&);
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<detail::conjunction<
|
||||||
|
detail::negation<detail::is_basic_value<T>>,
|
||||||
|
std::is_constructible<T, basic_value<C, M, V>&>,
|
||||||
|
detail::negation<detail::has_from_toml_method<T, C, M, V>>,
|
||||||
|
detail::negation<detail::has_specialized_from<T>>
|
||||||
|
>::value, T>
|
||||||
|
get(basic_value<C, M, V>&);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// array-like types; most likely STL container, like std::vector, etc.
|
// array-like types; most likely STL container, like std::vector, etc.
|
||||||
|
|
||||||
@@ -321,6 +340,7 @@ template<typename T, typename C,
|
|||||||
detail::enable_if_t<detail::conjunction<
|
detail::enable_if_t<detail::conjunction<
|
||||||
detail::is_container<T>, // T is a container
|
detail::is_container<T>, // T is a container
|
||||||
detail::negation<detail::has_push_back_method<T>>, // w/o push_back
|
detail::negation<detail::has_push_back_method<T>>, // w/o push_back
|
||||||
|
detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
|
||||||
detail::negation< // T is not toml::array
|
detail::negation< // T is not toml::array
|
||||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||||
>::value, T>
|
>::value, T>
|
||||||
@@ -338,8 +358,10 @@ get(const basic_value<C, M, V>& v)
|
|||||||
{v.location(), "here"}
|
{v.location(), "here"}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
std::transform(ar.cbegin(), ar.cend(), container.begin(),
|
for(std::size_t i=0; i<ar.size(); ++i)
|
||||||
[](const value& x){return ::toml::get<value_type>(x);});
|
{
|
||||||
|
container[i] = ::toml::get<value_type>(ar[i]);
|
||||||
|
}
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,9 +460,16 @@ get(const basic_value<C, M, V>& v)
|
|||||||
return ud;
|
return ud;
|
||||||
}
|
}
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V,
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
std::size_t>
|
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||||
T get(const basic_value<C, M, V>& v)
|
get(const basic_value<C, M, V>& v)
|
||||||
|
{
|
||||||
|
return ::toml::from<T>::from_toml(v);
|
||||||
|
}
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||||
|
get(basic_value<C, M, V>& v)
|
||||||
{
|
{
|
||||||
return ::toml::from<T>::from_toml(v);
|
return ::toml::from<T>::from_toml(v);
|
||||||
}
|
}
|
||||||
@@ -448,14 +477,29 @@ T get(const basic_value<C, M, V>& v)
|
|||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
detail::enable_if_t<detail::conjunction<
|
detail::enable_if_t<detail::conjunction<
|
||||||
detail::negation<detail::is_basic_value<T>>,
|
detail::negation<detail::is_basic_value<T>>, // T is not a toml::value
|
||||||
std::is_constructible<T, const basic_value<C, M, V>&>
|
std::is_constructible<T, const basic_value<C, M, V>&>, // T is constructible from toml::value
|
||||||
|
detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
|
||||||
|
detail::negation<detail::has_specialized_from<T>> // and T does not have toml::from<T>{};
|
||||||
>::value, T>
|
>::value, T>
|
||||||
get(const basic_value<C, M, V>& v)
|
get(const basic_value<C, M, V>& v)
|
||||||
{
|
{
|
||||||
return T(v);
|
return T(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<detail::conjunction<
|
||||||
|
detail::negation<detail::is_basic_value<T>>, // T is not a toml::value
|
||||||
|
std::is_constructible<T, basic_value<C, M, V>&>, // T is constructible from toml::value
|
||||||
|
detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
|
||||||
|
detail::negation<detail::has_specialized_from<T>> // and T does not have toml::from<T>{};
|
||||||
|
>::value, T>
|
||||||
|
get(basic_value<C, M, V>& v)
|
||||||
|
{
|
||||||
|
return T(v);
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// find
|
// find
|
||||||
|
|
||||||
@@ -1031,6 +1075,50 @@ find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
|
|||||||
return get_or(tab.at(ky), std::forward<T>(opt));
|
return get_or(tab.at(ky), std::forward<T>(opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// recursive find-or with type deduction (find_or(value, keys, opt))
|
||||||
|
|
||||||
|
template<typename Value, typename ... Ks,
|
||||||
|
typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
|
||||||
|
// here we need to add SFINAE in the template parameter to avoid
|
||||||
|
// infinite recursion in type deduction on gcc
|
||||||
|
auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
|
||||||
|
-> decltype(find_or(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
|
||||||
|
{
|
||||||
|
if(!v.is_table())
|
||||||
|
{
|
||||||
|
return detail::last_one(std::forward<Ks>(keys)...);
|
||||||
|
}
|
||||||
|
auto&& tab = std::forward<Value>(v).as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
return detail::last_one(std::forward<Ks>(keys)...);
|
||||||
|
}
|
||||||
|
return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// recursive find_or with explicit type specialization, find_or<int>(value, keys...)
|
||||||
|
|
||||||
|
template<typename T, typename Value, typename ... Ks,
|
||||||
|
typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
|
||||||
|
// here we need to add SFINAE in the template parameter to avoid
|
||||||
|
// infinite recursion in type deduction on gcc
|
||||||
|
auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
|
||||||
|
-> decltype(find_or<T>(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
|
||||||
|
{
|
||||||
|
if(!v.is_table())
|
||||||
|
{
|
||||||
|
return detail::last_one(std::forward<Ks>(keys)...);
|
||||||
|
}
|
||||||
|
auto&& tab = std::forward<Value>(v).as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
return detail::last_one(std::forward<Ks>(keys)...);
|
||||||
|
}
|
||||||
|
return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// expect
|
// expect
|
||||||
|
|
||||||
-1
@@ -2,7 +2,6 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_INTO_HPP
|
#ifndef TOML11_INTO_HPP
|
||||||
#define TOML11_INTO_HPP
|
#define TOML11_INTO_HPP
|
||||||
#include "traits.hpp"
|
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
+39
-15
@@ -5,7 +5,6 @@
|
|||||||
#include <istream>
|
#include <istream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#include "combinator.hpp"
|
#include "combinator.hpp"
|
||||||
|
|
||||||
@@ -119,8 +118,8 @@ using lex_local_time = lex_partial_time;
|
|||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
using lex_quotation_mark = character<'"'>;
|
using lex_quotation_mark = character<'"'>;
|
||||||
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab)
|
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab) is allowed
|
||||||
in_range<0x0a, 0x1F>, // is allowed
|
in_range<0x0A, 0x1F>,
|
||||||
character<0x22>, character<0x5C>,
|
character<0x22>, character<0x5C>,
|
||||||
character<0x7F>>>;
|
character<0x7F>>>;
|
||||||
|
|
||||||
@@ -133,6 +132,9 @@ using lex_escape_seq_char = either<character<'"'>, character<'\\'>,
|
|||||||
character<'b'>, character<'f'>,
|
character<'b'>, character<'f'>,
|
||||||
character<'n'>, character<'r'>,
|
character<'n'>, character<'r'>,
|
||||||
character<'t'>,
|
character<'t'>,
|
||||||
|
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||||
|
character<'e'>, // ESC (0x1B)
|
||||||
|
#endif
|
||||||
lex_escape_unicode_short,
|
lex_escape_unicode_short,
|
||||||
lex_escape_unicode_long
|
lex_escape_unicode_long
|
||||||
>;
|
>;
|
||||||
@@ -166,7 +168,7 @@ using lex_basic_string = sequence<lex_quotation_mark,
|
|||||||
// | ^- expected newline, but got '"'.
|
// | ^- expected newline, but got '"'.
|
||||||
// ```
|
// ```
|
||||||
// As a quick workaround for this problem, `lex_ml_basic_string_delim` was
|
// As a quick workaround for this problem, `lex_ml_basic_string_delim` was
|
||||||
// splitted into two, `lex_ml_basic_string_open` and `lex_ml_basic_string_close`.
|
// split into two, `lex_ml_basic_string_open` and `lex_ml_basic_string_close`.
|
||||||
// `lex_ml_basic_string_open` allows only `"""`. `_close` allows 3-5 `"`s.
|
// `lex_ml_basic_string_open` allows only `"""`. `_close` allows 3-5 `"`s.
|
||||||
// In parse_ml_basic_string() function, the trailing `"`s will be attached to
|
// In parse_ml_basic_string() function, the trailing `"`s will be attached to
|
||||||
// the string body.
|
// the string body.
|
||||||
@@ -178,8 +180,8 @@ using lex_ml_basic_string_close = sequence<
|
|||||||
maybe<lex_quotation_mark>, maybe<lex_quotation_mark>
|
maybe<lex_quotation_mark>, maybe<lex_quotation_mark>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09
|
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 is tab
|
||||||
in_range<0x0a, 0x1F>, // is tab
|
in_range<0x0A, 0x1F>,
|
||||||
character<0x5C>, // backslash
|
character<0x5C>, // backslash
|
||||||
character<0x7F>, // DEL
|
character<0x7F>, // DEL
|
||||||
lex_ml_basic_string_delim>>;
|
lex_ml_basic_string_delim>>;
|
||||||
@@ -196,8 +198,8 @@ using lex_ml_basic_string = sequence<lex_ml_basic_string_open,
|
|||||||
lex_ml_basic_body,
|
lex_ml_basic_body,
|
||||||
lex_ml_basic_string_close>;
|
lex_ml_basic_string_close>;
|
||||||
|
|
||||||
using lex_literal_char = exclude<either<in_range<0x00, 0x08>,
|
using lex_literal_char = exclude<either<in_range<0x00, 0x08>, in_range<0x0A, 0x1F>,
|
||||||
in_range<0x10, 0x19>, character<0x27>>>;
|
character<0x7F>, character<0x27>>>;
|
||||||
using lex_apostrophe = character<'\''>;
|
using lex_apostrophe = character<'\''>;
|
||||||
using lex_literal_string = sequence<lex_apostrophe,
|
using lex_literal_string = sequence<lex_apostrophe,
|
||||||
repeat<lex_literal_char, unlimited>,
|
repeat<lex_literal_char, unlimited>,
|
||||||
@@ -212,7 +214,7 @@ using lex_ml_literal_string_close = sequence<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
|
using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||||
in_range<0x10, 0x1F>,
|
in_range<0x0A, 0x1F>,
|
||||||
character<0x7F>,
|
character<0x7F>,
|
||||||
lex_ml_literal_string_delim>>;
|
lex_ml_literal_string_delim>>;
|
||||||
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
|
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
|
||||||
@@ -225,12 +227,6 @@ using lex_string = either<lex_ml_basic_string, lex_basic_string,
|
|||||||
lex_ml_literal_string, lex_literal_string>;
|
lex_ml_literal_string, lex_literal_string>;
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
using lex_comment_start_symbol = character<'#'>;
|
|
||||||
using lex_non_eol = either<character<'\t'>, exclude<in_range<0x00, 0x19>>>;
|
|
||||||
using lex_comment = sequence<lex_comment_start_symbol,
|
|
||||||
repeat<lex_non_eol, unlimited>>;
|
|
||||||
|
|
||||||
using lex_dot_sep = sequence<maybe<lex_ws>, character<'.'>, maybe<lex_ws>>;
|
using lex_dot_sep = sequence<maybe<lex_ws>, character<'.'>, maybe<lex_ws>>;
|
||||||
|
|
||||||
using lex_unquoted_key = repeat<either<lex_alpha, lex_digit,
|
using lex_unquoted_key = repeat<either<lex_alpha, lex_digit,
|
||||||
@@ -265,6 +261,34 @@ using lex_array_table = sequence<lex_array_table_open,
|
|||||||
maybe<lex_ws>,
|
maybe<lex_ws>,
|
||||||
lex_array_table_close>;
|
lex_array_table_close>;
|
||||||
|
|
||||||
|
using lex_utf8_1byte = in_range<0x00, 0x7F>;
|
||||||
|
using lex_utf8_2byte = sequence<
|
||||||
|
in_range<'\xC2', '\xDF'>,
|
||||||
|
in_range<'\x80', '\xBF'>
|
||||||
|
>;
|
||||||
|
using lex_utf8_3byte = sequence<either<
|
||||||
|
sequence<character<'\xE0'>, in_range<'\xA0', '\xBF'>>,
|
||||||
|
sequence<in_range<'\xE1', '\xEC'>, in_range<'\x80', '\xBF'>>,
|
||||||
|
sequence<character<'\xED'>, in_range<'\x80', '\x9F'>>,
|
||||||
|
sequence<in_range<'\xEE', '\xEF'>, in_range<'\x80', '\xBF'>>
|
||||||
|
>, in_range<'\x80', '\xBF'>>;
|
||||||
|
using lex_utf8_4byte = sequence<either<
|
||||||
|
sequence<character<'\xF0'>, in_range<'\x90', '\xBF'>>,
|
||||||
|
sequence<in_range<'\xF1', '\xF3'>, in_range<'\x80', '\xBF'>>,
|
||||||
|
sequence<character<'\xF4'>, in_range<'\x80', '\x8F'>>
|
||||||
|
>, in_range<'\x80', '\xBF'>, in_range<'\x80', '\xBF'>>;
|
||||||
|
using lex_utf8_code = either<
|
||||||
|
lex_utf8_1byte,
|
||||||
|
lex_utf8_2byte,
|
||||||
|
lex_utf8_3byte,
|
||||||
|
lex_utf8_4byte
|
||||||
|
>;
|
||||||
|
|
||||||
|
using lex_comment_start_symbol = character<'#'>;
|
||||||
|
using lex_non_eol_ascii = either<character<0x09>, in_range<0x20, 0x7E>>;
|
||||||
|
using lex_comment = sequence<lex_comment_start_symbol, repeat<either<
|
||||||
|
lex_non_eol_ascii, lex_utf8_2byte, lex_utf8_3byte, lex_utf8_4byte>, unlimited>>;
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
} // toml
|
} // toml
|
||||||
#endif // TOML_LEXER_HPP
|
#endif // TOML_LEXER_HPP
|
||||||
+11
-5
@@ -12,8 +12,11 @@ inline namespace toml_literals
|
|||||||
{
|
{
|
||||||
|
|
||||||
// implementation
|
// implementation
|
||||||
inline ::toml::value literal_internal_impl(::toml::detail::location loc)
|
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
|
||||||
|
literal_internal_impl(::toml::detail::location loc)
|
||||||
{
|
{
|
||||||
|
using value_type = ::toml::basic_value<
|
||||||
|
TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>;
|
||||||
// if there are some comments or empty lines, skip them.
|
// if there are some comments or empty lines, skip them.
|
||||||
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
|
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
|
||||||
::toml::detail::maybe<::toml::detail::lex_ws>,
|
::toml::detail::maybe<::toml::detail::lex_ws>,
|
||||||
@@ -50,7 +53,7 @@ inline ::toml::value literal_internal_impl(::toml::detail::location loc)
|
|||||||
// If it is neither a table-key or a array-of-table-key, it may be a value.
|
// If it is neither a table-key or a array-of-table-key, it may be a value.
|
||||||
if(!is_table_key && !is_aots_key)
|
if(!is_table_key && !is_aots_key)
|
||||||
{
|
{
|
||||||
if(auto data = ::toml::detail::parse_value<::toml::value>(loc))
|
if(auto data = ::toml::detail::parse_value<value_type>(loc, 0))
|
||||||
{
|
{
|
||||||
return data.unwrap();
|
return data.unwrap();
|
||||||
}
|
}
|
||||||
@@ -67,7 +70,7 @@ inline ::toml::value literal_internal_impl(::toml::detail::location loc)
|
|||||||
// It is a valid toml file.
|
// It is a valid toml file.
|
||||||
// It should be parsed as if we parse a file with this content.
|
// It should be parsed as if we parse a file with this content.
|
||||||
|
|
||||||
if(auto data = ::toml::detail::parse_toml_file<::toml::value>(loc))
|
if(auto data = ::toml::detail::parse_toml_file<value_type>(loc))
|
||||||
{
|
{
|
||||||
return data.unwrap();
|
return data.unwrap();
|
||||||
}
|
}
|
||||||
@@ -78,11 +81,13 @@ inline ::toml::value literal_internal_impl(::toml::detail::location loc)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
|
||||||
|
operator"" _toml(const char* str, std::size_t len)
|
||||||
{
|
{
|
||||||
::toml::detail::location loc(
|
::toml::detail::location loc(
|
||||||
std::string("TOML literal encoded in a C++ code"),
|
std::string("TOML literal encoded in a C++ code"),
|
||||||
std::vector<char>(str, str + len));
|
std::vector<char>(str, str + len));
|
||||||
|
// literal length does not include the null character at the end.
|
||||||
return literal_internal_impl(std::move(loc));
|
return literal_internal_impl(std::move(loc));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +96,8 @@ inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
|||||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||||
// value of u8"" literal has been changed from char to char8_t and char8_t is
|
// value of u8"" literal has been changed from char to char8_t and char8_t is
|
||||||
// NOT compatible to char
|
// NOT compatible to char
|
||||||
inline ::toml::value operator"" _toml(const char8_t* str, std::size_t len)
|
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
|
||||||
|
operator"" _toml(const char8_t* str, std::size_t len)
|
||||||
{
|
{
|
||||||
::toml::detail::location loc(
|
::toml::detail::location loc(
|
||||||
std::string("TOML literal encoded in a C++ code"),
|
std::string("TOML literal encoded in a C++ code"),
|
||||||
+121
@@ -0,0 +1,121 @@
|
|||||||
|
#ifndef TOML11_MACROS_HPP
|
||||||
|
#define TOML11_MACROS_HPP
|
||||||
|
|
||||||
|
#define TOML11_STRINGIZE_AUX(x) #x
|
||||||
|
#define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x)
|
||||||
|
|
||||||
|
#define TOML11_CONCATENATE_AUX(x, y) x##y
|
||||||
|
#define TOML11_CONCATENATE(x, y) TOML11_CONCATENATE_AUX(x, y)
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
|
||||||
|
|
||||||
|
#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// TOML11_ARGS_SIZE
|
||||||
|
|
||||||
|
#define TOML11_INDEX_RSEQ() \
|
||||||
|
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
|
||||||
|
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||||
|
#define TOML11_ARGS_SIZE_IMPL(\
|
||||||
|
ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8, ARG9, ARG10, \
|
||||||
|
ARG11, ARG12, ARG13, ARG14, ARG15, ARG16, ARG17, ARG18, ARG19, ARG20, \
|
||||||
|
ARG21, ARG22, ARG23, ARG24, ARG25, ARG26, ARG27, ARG28, ARG29, ARG30, \
|
||||||
|
ARG31, ARG32, N, ...) N
|
||||||
|
#define TOML11_ARGS_SIZE_AUX(...) TOML11_ARGS_SIZE_IMPL(__VA_ARGS__)
|
||||||
|
#define TOML11_ARGS_SIZE(...) TOML11_ARGS_SIZE_AUX(__VA_ARGS__, TOML11_INDEX_RSEQ())
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// TOML11_FOR_EACH_VA_ARGS
|
||||||
|
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, ARG1 ) FUNCTOR(ARG1)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, __VA_ARGS__)
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS_AUX_32(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\
|
||||||
|
TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__)
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
|
||||||
|
|
||||||
|
// use it in the following way.
|
||||||
|
// ```cpp
|
||||||
|
// namespace foo
|
||||||
|
// {
|
||||||
|
// struct Foo
|
||||||
|
// {
|
||||||
|
// std::string s;
|
||||||
|
// double d;
|
||||||
|
// int i;
|
||||||
|
// };
|
||||||
|
// } // foo
|
||||||
|
//
|
||||||
|
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i)
|
||||||
|
// ```
|
||||||
|
// And then you can use `toml::find<foo::Foo>(file, "foo");`
|
||||||
|
//
|
||||||
|
#define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\
|
||||||
|
obj.VAR_NAME = toml::find<decltype(obj.VAR_NAME)>(v, TOML11_STRINGIZE(VAR_NAME));
|
||||||
|
|
||||||
|
#define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME)\
|
||||||
|
v[TOML11_STRINGIZE(VAR_NAME)] = obj.VAR_NAME;
|
||||||
|
|
||||||
|
#define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\
|
||||||
|
namespace toml { \
|
||||||
|
template<> \
|
||||||
|
struct from<NAME> \
|
||||||
|
{ \
|
||||||
|
template<typename C, template<typename ...> class T, \
|
||||||
|
template<typename ...> class A> \
|
||||||
|
static NAME from_toml(const basic_value<C, T, A>& v) \
|
||||||
|
{ \
|
||||||
|
NAME obj; \
|
||||||
|
TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \
|
||||||
|
return obj; \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
template<> \
|
||||||
|
struct into<NAME> \
|
||||||
|
{ \
|
||||||
|
static value into_toml(const NAME& obj) \
|
||||||
|
{ \
|
||||||
|
::toml::value v = ::toml::table{}; \
|
||||||
|
TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \
|
||||||
|
return v; \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
} /* toml */
|
||||||
|
|
||||||
|
#endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
|
||||||
|
|
||||||
|
#endif// TOML11_MACROS_HPP
|
||||||
+624
-117
File diff suppressed because it is too large
Load Diff
+13
-14
@@ -70,16 +70,16 @@ struct region_base
|
|||||||
struct location final : public region_base
|
struct location final : public region_base
|
||||||
{
|
{
|
||||||
using const_iterator = typename std::vector<char>::const_iterator;
|
using const_iterator = typename std::vector<char>::const_iterator;
|
||||||
using difference_type = typename const_iterator::difference_type;
|
using difference_type = typename std::iterator_traits<const_iterator>::difference_type;
|
||||||
using source_ptr = std::shared_ptr<const std::vector<char>>;
|
using source_ptr = std::shared_ptr<const std::vector<char>>;
|
||||||
|
|
||||||
location(std::string name, std::vector<char> cont)
|
location(std::string source_name, std::vector<char> cont)
|
||||||
: source_(std::make_shared<std::vector<char>>(std::move(cont))),
|
: source_(std::make_shared<std::vector<char>>(std::move(cont))),
|
||||||
line_number_(1), source_name_(std::move(name)), iter_(source_->cbegin())
|
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
|
||||||
{}
|
{}
|
||||||
location(std::string name, const std::string& cont)
|
location(std::string source_name, const std::string& cont)
|
||||||
: source_(std::make_shared<std::vector<char>>(cont.begin(), cont.end())),
|
: source_(std::make_shared<std::vector<char>>(cont.begin(), cont.end())),
|
||||||
line_number_(1), source_name_(std::move(name)), iter_(source_->cbegin())
|
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
location(const location&) = default;
|
location(const location&) = default;
|
||||||
@@ -92,7 +92,7 @@ struct location final : public region_base
|
|||||||
char front() const noexcept override {return *iter_;}
|
char front() const noexcept override {return *iter_;}
|
||||||
|
|
||||||
// this const prohibits codes like `++(loc.iter())`.
|
// this const prohibits codes like `++(loc.iter())`.
|
||||||
const const_iterator iter() const noexcept {return iter_;}
|
std::add_const<const_iterator>::type iter() const noexcept {return iter_;}
|
||||||
|
|
||||||
const_iterator begin() const noexcept {return source_->cbegin();}
|
const_iterator begin() const noexcept {return source_->cbegin();}
|
||||||
const_iterator end() const noexcept {return source_->cend();}
|
const_iterator end() const noexcept {return source_->cend();}
|
||||||
@@ -227,8 +227,7 @@ struct region final : public region_base
|
|||||||
region& operator+=(const region& other)
|
region& operator+=(const region& other)
|
||||||
{
|
{
|
||||||
// different regions cannot be concatenated
|
// different regions cannot be concatenated
|
||||||
assert(this->begin() == other.begin() && this->end() == other.end() &&
|
assert(this->source_ == other.source_ && this->last_ == other.first_);
|
||||||
this->last_ == other.first_);
|
|
||||||
|
|
||||||
this->last_ = other.last_;
|
this->last_ = other.last_;
|
||||||
return *this;
|
return *this;
|
||||||
@@ -343,9 +342,9 @@ struct region final : public region_base
|
|||||||
}))
|
}))
|
||||||
{
|
{
|
||||||
// unwrap the first '#' by std::next.
|
// unwrap the first '#' by std::next.
|
||||||
auto str = make_string(std::next(comment_found), iter);
|
auto s = make_string(std::next(comment_found), iter);
|
||||||
if(str.back() == '\r') {str.pop_back();}
|
if(!s.empty() && s.back() == '\r') {s.pop_back();}
|
||||||
com.push_back(std::move(str));
|
com.push_back(std::move(s));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -396,9 +395,9 @@ struct region final : public region_base
|
|||||||
}))
|
}))
|
||||||
{
|
{
|
||||||
// unwrap the first '#' by std::next.
|
// unwrap the first '#' by std::next.
|
||||||
auto str = make_string(std::next(comment_found), this->line_end());
|
auto s = make_string(std::next(comment_found), this->line_end());
|
||||||
if(str.back() == '\r') {str.pop_back();}
|
if(!s.empty() && s.back() == '\r') {s.pop_back();}
|
||||||
com.push_back(std::move(str));
|
com.push_back(std::move(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vendored
+342
-136
@@ -2,10 +2,19 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_SERIALIZER_HPP
|
#ifndef TOML11_SERIALIZER_HPP
|
||||||
#define TOML11_SERIALIZER_HPP
|
#define TOML11_SERIALIZER_HPP
|
||||||
|
#include <cmath>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <locale.h>
|
||||||
|
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||||
|
#include <xlocale.h>
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include <locale.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "lexer.hpp"
|
#include "lexer.hpp"
|
||||||
#include "value.hpp"
|
#include "value.hpp"
|
||||||
|
|
||||||
@@ -26,19 +35,24 @@ namespace toml
|
|||||||
// a `"` and escaping some special character is boring.
|
// a `"` and escaping some special character is boring.
|
||||||
template<typename charT, typename traits, typename Alloc>
|
template<typename charT, typename traits, typename Alloc>
|
||||||
std::basic_string<charT, traits, Alloc>
|
std::basic_string<charT, traits, Alloc>
|
||||||
format_key(const std::basic_string<charT, traits, Alloc>& key)
|
format_key(const std::basic_string<charT, traits, Alloc>& k)
|
||||||
{
|
{
|
||||||
|
if(k.empty())
|
||||||
|
{
|
||||||
|
return std::string("\"\"");
|
||||||
|
}
|
||||||
|
|
||||||
// check the key can be a bare (unquoted) key
|
// check the key can be a bare (unquoted) key
|
||||||
detail::location loc(key, std::vector<char>(key.begin(), key.end()));
|
detail::location loc(k, std::vector<char>(k.begin(), k.end()));
|
||||||
detail::lex_unquoted_key::invoke(loc);
|
detail::lex_unquoted_key::invoke(loc);
|
||||||
if(loc.iter() == loc.end())
|
if(loc.iter() == loc.end())
|
||||||
{
|
{
|
||||||
return key; // all the tokens are consumed. the key is unquoted-key.
|
return k; // all the tokens are consumed. the key is unquoted-key.
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it includes special characters, then format it in a "quoted" key.
|
//if it includes special characters, then format it in a "quoted" key.
|
||||||
std::basic_string<charT, traits, Alloc> serialized("\"");
|
std::basic_string<charT, traits, Alloc> serialized("\"");
|
||||||
for(const char c : key)
|
for(const char c : k)
|
||||||
{
|
{
|
||||||
switch(c)
|
switch(c)
|
||||||
{
|
{
|
||||||
@@ -49,7 +63,19 @@ format_key(const std::basic_string<charT, traits, Alloc>& key)
|
|||||||
case '\f': {serialized += "\\f"; break;}
|
case '\f': {serialized += "\\f"; break;}
|
||||||
case '\n': {serialized += "\\n"; break;}
|
case '\n': {serialized += "\\n"; break;}
|
||||||
case '\r': {serialized += "\\r"; break;}
|
case '\r': {serialized += "\\r"; break;}
|
||||||
default : {serialized += c; break;}
|
default: {
|
||||||
|
if (c >= 0x00 && c < 0x20)
|
||||||
|
{
|
||||||
|
std::array<char, 7> buf;
|
||||||
|
std::snprintf(buf.data(), buf.size(), "\\u00%02x", static_cast<int>(c));
|
||||||
|
serialized += buf.data();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serialized += c;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serialized += "\"";
|
serialized += "\"";
|
||||||
@@ -60,9 +86,12 @@ template<typename charT, typename traits, typename Alloc>
|
|||||||
std::basic_string<charT, traits, Alloc>
|
std::basic_string<charT, traits, Alloc>
|
||||||
format_keys(const std::vector<std::basic_string<charT, traits, Alloc>>& keys)
|
format_keys(const std::vector<std::basic_string<charT, traits, Alloc>>& keys)
|
||||||
{
|
{
|
||||||
std::basic_string<charT, traits, Alloc> serialized;
|
if(keys.empty())
|
||||||
if(keys.empty()) {return serialized;}
|
{
|
||||||
|
return std::string("\"\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::basic_string<charT, traits, Alloc> serialized;
|
||||||
for(const auto& ky : keys)
|
for(const auto& ky : keys)
|
||||||
{
|
{
|
||||||
serialized += format_key(ky);
|
serialized += format_key(ky);
|
||||||
@@ -97,8 +126,10 @@ struct serializer
|
|||||||
const int float_prec = std::numeric_limits<toml::floating>::max_digits10,
|
const int float_prec = std::numeric_limits<toml::floating>::max_digits10,
|
||||||
const bool can_be_inlined = false,
|
const bool can_be_inlined = false,
|
||||||
const bool no_comment = false,
|
const bool no_comment = false,
|
||||||
std::vector<toml::key> ks = {})
|
std::vector<toml::key> ks = {},
|
||||||
|
const bool value_has_comment = false)
|
||||||
: can_be_inlined_(can_be_inlined), no_comment_(no_comment),
|
: can_be_inlined_(can_be_inlined), no_comment_(no_comment),
|
||||||
|
value_has_comment_(value_has_comment && !no_comment),
|
||||||
float_prec_(float_prec), width_(w), keys_(std::move(ks))
|
float_prec_(float_prec), width_(w), keys_(std::move(ks))
|
||||||
{}
|
{}
|
||||||
~serializer() = default;
|
~serializer() = default;
|
||||||
@@ -109,18 +140,93 @@ struct serializer
|
|||||||
}
|
}
|
||||||
std::string operator()(const integer_type i) const
|
std::string operator()(const integer_type i) const
|
||||||
{
|
{
|
||||||
return std::to_string(i);
|
#if defined(_WIN32)
|
||||||
|
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||||
|
const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
|
||||||
|
setlocale(LC_NUMERIC, "C");
|
||||||
|
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||||
|
const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
|
||||||
|
locale_t original_locale(0);
|
||||||
|
if(c_locale != locale_t(0))
|
||||||
|
{
|
||||||
|
original_locale = uselocale(c_locale);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const auto str = std::to_string(i);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
setlocale(LC_NUMERIC, original_locale.c_str());
|
||||||
|
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
||||||
|
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||||
|
if(original_locale != locale_t(0))
|
||||||
|
{
|
||||||
|
uselocale(original_locale);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
std::string operator()(const floating_type f) const
|
std::string operator()(const floating_type f) const
|
||||||
{
|
{
|
||||||
|
if(std::isnan(f))
|
||||||
|
{
|
||||||
|
if(std::signbit(f))
|
||||||
|
{
|
||||||
|
return std::string("-nan");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::string("nan");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!std::isfinite(f))
|
||||||
|
{
|
||||||
|
if(std::signbit(f))
|
||||||
|
{
|
||||||
|
return std::string("-inf");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::string("inf");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set locale to "C".
|
||||||
|
// To make it thread-local, we use OS-specific features.
|
||||||
|
// If we set process-global locale, it can break other thread that also
|
||||||
|
// outputs something simultaneously.
|
||||||
|
#if defined(_WIN32)
|
||||||
|
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||||
|
const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
|
||||||
|
setlocale(LC_NUMERIC, "C");
|
||||||
|
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||||
|
const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
|
||||||
|
locale_t original_locale(0);
|
||||||
|
if(c_locale != locale_t(0))
|
||||||
|
{
|
||||||
|
original_locale = uselocale(c_locale);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const auto fmt = "%.*g";
|
const auto fmt = "%.*g";
|
||||||
const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f);
|
const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f);
|
||||||
// +1 for null character(\0)
|
// +1 for null character(\0)
|
||||||
std::vector<char> buf(static_cast<std::size_t>(bsz + 1), '\0');
|
std::vector<char> buf(static_cast<std::size_t>(bsz + 1), '\0');
|
||||||
std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f);
|
std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f);
|
||||||
|
|
||||||
|
// restore the original locale
|
||||||
|
#if defined(_WIN32)
|
||||||
|
setlocale(LC_NUMERIC, original_locale.c_str());
|
||||||
|
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
||||||
|
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||||
|
if(original_locale != locale_t(0))
|
||||||
|
{
|
||||||
|
uselocale(original_locale);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
std::string token(buf.begin(), std::prev(buf.end()));
|
std::string token(buf.begin(), std::prev(buf.end()));
|
||||||
if(token.back() == '.') // 1. => 1.0
|
if(!token.empty() && token.back() == '.') // 1. => 1.0
|
||||||
{
|
{
|
||||||
token += '0';
|
token += '0';
|
||||||
}
|
}
|
||||||
@@ -144,8 +250,9 @@ struct serializer
|
|||||||
{
|
{
|
||||||
if(s.kind == string_t::basic)
|
if(s.kind == string_t::basic)
|
||||||
{
|
{
|
||||||
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
if((std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
||||||
std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend())
|
std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend()) &&
|
||||||
|
this->width_ != (std::numeric_limits<std::size_t>::max)())
|
||||||
{
|
{
|
||||||
// if linefeed or double-quote is contained,
|
// if linefeed or double-quote is contained,
|
||||||
// make it multiline basic string.
|
// make it multiline basic string.
|
||||||
@@ -244,92 +351,18 @@ struct serializer
|
|||||||
|
|
||||||
std::string operator()(const array_type& v) const
|
std::string operator()(const array_type& v) const
|
||||||
{
|
{
|
||||||
if(!v.empty() && v.front().is_table())// v is an array of tables
|
|
||||||
{
|
|
||||||
// if it's not inlined, we need to add `[[table.key]]`.
|
|
||||||
// but if it can be inlined,
|
|
||||||
// ```
|
|
||||||
// table.key = [
|
|
||||||
// {...},
|
|
||||||
// # comment
|
|
||||||
// {...},
|
|
||||||
// ]
|
|
||||||
// ```
|
|
||||||
if(this->can_be_inlined_)
|
|
||||||
{
|
|
||||||
std::string token;
|
|
||||||
if(!keys_.empty())
|
|
||||||
{
|
|
||||||
token += format_key(keys_.back());
|
|
||||||
token += " = ";
|
|
||||||
}
|
|
||||||
bool failed = false;
|
|
||||||
token += "[\n";
|
|
||||||
for(const auto& item : v)
|
|
||||||
{
|
|
||||||
// if an element of the table has a comment, the table
|
|
||||||
// cannot be inlined.
|
|
||||||
if(this->has_comment_inside(item.as_table()))
|
|
||||||
{
|
|
||||||
failed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!no_comment_)
|
|
||||||
{
|
|
||||||
for(const auto& c : item.comments())
|
|
||||||
{
|
|
||||||
token += '#';
|
|
||||||
token += c;
|
|
||||||
token += '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto t = this->make_inline_table(item.as_table());
|
|
||||||
|
|
||||||
if(t.size() + 1 > width_ || // +1 for the last comma {...},
|
|
||||||
std::find(t.cbegin(), t.cend(), '\n') != t.cend())
|
|
||||||
{
|
|
||||||
failed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
token += t;
|
|
||||||
token += ",\n";
|
|
||||||
}
|
|
||||||
if(!failed)
|
|
||||||
{
|
|
||||||
token += "]\n";
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
// if failed, serialize them as [[array.of.tables]].
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string token;
|
|
||||||
for(const auto& item : v)
|
|
||||||
{
|
|
||||||
if(!no_comment_)
|
|
||||||
{
|
|
||||||
for(const auto& c : item.comments())
|
|
||||||
{
|
|
||||||
token += '#';
|
|
||||||
token += c;
|
|
||||||
token += '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
token += "[[";
|
|
||||||
token += format_keys(keys_);
|
|
||||||
token += "]]\n";
|
|
||||||
token += this->make_multiline_table(item.as_table());
|
|
||||||
}
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
if(v.empty())
|
if(v.empty())
|
||||||
{
|
{
|
||||||
return std::string("[]");
|
return std::string("[]");
|
||||||
}
|
}
|
||||||
|
if(this->is_array_of_tables(v))
|
||||||
|
{
|
||||||
|
return make_array_of_tables(v);
|
||||||
|
}
|
||||||
|
|
||||||
// not an array of tables. normal array.
|
// not an array of tables. normal array.
|
||||||
// first, try to make it inline if none of the elements have a comment.
|
// first, try to make it inline if none of the elements have a comment.
|
||||||
if(!this->has_comment_inside(v))
|
if( ! this->has_comment_inside(v))
|
||||||
{
|
{
|
||||||
const auto inl = this->make_inline_array(v);
|
const auto inl = this->make_inline_array(v);
|
||||||
if(inl.size() < this->width_ &&
|
if(inl.size() < this->width_ &&
|
||||||
@@ -350,7 +383,7 @@ struct serializer
|
|||||||
token += "[\n";
|
token += "[\n";
|
||||||
for(const auto& item : v)
|
for(const auto& item : v)
|
||||||
{
|
{
|
||||||
if(!item.comments().empty() && !no_comment_)
|
if( ! item.comments().empty() && !no_comment_)
|
||||||
{
|
{
|
||||||
// if comment exists, the element must be the only element in the line.
|
// if comment exists, the element must be the only element in the line.
|
||||||
// e.g. the following is not allowed.
|
// e.g. the following is not allowed.
|
||||||
@@ -376,15 +409,25 @@ struct serializer
|
|||||||
token += '\n';
|
token += '\n';
|
||||||
}
|
}
|
||||||
token += toml::visit(*this, item);
|
token += toml::visit(*this, item);
|
||||||
if(token.back() == '\n') {token.pop_back();}
|
if(!token.empty() && token.back() == '\n') {token.pop_back();}
|
||||||
token += ",\n";
|
token += ",\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::string next_elem;
|
std::string next_elem;
|
||||||
next_elem += toml::visit(*this, item);
|
if(item.is_table())
|
||||||
|
{
|
||||||
|
serializer ser(*this);
|
||||||
|
ser.can_be_inlined_ = true;
|
||||||
|
ser.width_ = (std::numeric_limits<std::size_t>::max)();
|
||||||
|
next_elem += toml::visit(ser, item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
next_elem += toml::visit(*this, item);
|
||||||
|
}
|
||||||
|
|
||||||
// comma before newline.
|
// comma before newline.
|
||||||
if(next_elem.back() == '\n') {next_elem.pop_back();}
|
if(!next_elem.empty() && next_elem.back() == '\n') {next_elem.pop_back();}
|
||||||
|
|
||||||
// if current line does not exceeds the width limit, continue.
|
// if current line does not exceeds the width limit, continue.
|
||||||
if(current_line.size() + next_elem.size() + 1 < this->width_)
|
if(current_line.size() + next_elem.size() + 1 < this->width_)
|
||||||
@@ -411,7 +454,10 @@ struct serializer
|
|||||||
}
|
}
|
||||||
if(!current_line.empty())
|
if(!current_line.empty())
|
||||||
{
|
{
|
||||||
if(current_line.back() != '\n') {current_line += '\n';}
|
if(!current_line.empty() && current_line.back() != '\n')
|
||||||
|
{
|
||||||
|
current_line += '\n';
|
||||||
|
}
|
||||||
token += current_line;
|
token += current_line;
|
||||||
}
|
}
|
||||||
token += "]\n";
|
token += "]\n";
|
||||||
@@ -467,7 +513,19 @@ struct serializer
|
|||||||
case '\f': {retval += "\\f"; break;}
|
case '\f': {retval += "\\f"; break;}
|
||||||
case '\n': {retval += "\\n"; break;}
|
case '\n': {retval += "\\n"; break;}
|
||||||
case '\r': {retval += "\\r"; break;}
|
case '\r': {retval += "\\r"; break;}
|
||||||
default : {retval += c; break;}
|
default :
|
||||||
|
{
|
||||||
|
if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
|
||||||
|
{
|
||||||
|
retval += "\\u00";
|
||||||
|
retval += char(48 + (c / 16));
|
||||||
|
retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
@@ -501,7 +559,21 @@ struct serializer
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {retval += *i; break;}
|
default :
|
||||||
|
{
|
||||||
|
const auto c = *i;
|
||||||
|
if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
|
||||||
|
{
|
||||||
|
retval += "\\u00";
|
||||||
|
retval += char(48 + (c / 16));
|
||||||
|
retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Only 1 or 2 consecutive `"`s are allowed in multiline basic string.
|
// Only 1 or 2 consecutive `"`s are allowed in multiline basic string.
|
||||||
@@ -557,8 +629,10 @@ struct serializer
|
|||||||
for(const auto& item : v)
|
for(const auto& item : v)
|
||||||
{
|
{
|
||||||
if(is_first) {is_first = false;} else {token += ',';}
|
if(is_first) {is_first = false;} else {token += ',';}
|
||||||
token += visit(serializer((std::numeric_limits<std::size_t>::max)(),
|
token += visit(serializer(
|
||||||
this->float_prec_, true), item);
|
(std::numeric_limits<std::size_t>::max)(), this->float_prec_,
|
||||||
|
/* inlined */ true, /*no comment*/ false, /*keys*/ {},
|
||||||
|
/*has_comment*/ !item.comments().empty()), item);
|
||||||
}
|
}
|
||||||
token += ']';
|
token += ']';
|
||||||
return token;
|
return token;
|
||||||
@@ -577,8 +651,10 @@ struct serializer
|
|||||||
if(is_first) {is_first = false;} else {token += ',';}
|
if(is_first) {is_first = false;} else {token += ',';}
|
||||||
token += format_key(kv.first);
|
token += format_key(kv.first);
|
||||||
token += '=';
|
token += '=';
|
||||||
token += visit(serializer((std::numeric_limits<std::size_t>::max)(),
|
token += visit(serializer(
|
||||||
this->float_prec_, true), kv.second);
|
(std::numeric_limits<std::size_t>::max)(), this->float_prec_,
|
||||||
|
/* inlined */ true, /*no comment*/ false, /*keys*/ {},
|
||||||
|
/*has_comment*/ !kv.second.comments().empty()), kv.second);
|
||||||
}
|
}
|
||||||
token += '}';
|
token += '}';
|
||||||
return token;
|
return token;
|
||||||
@@ -588,8 +664,16 @@ struct serializer
|
|||||||
{
|
{
|
||||||
std::string token;
|
std::string token;
|
||||||
|
|
||||||
// print non-table stuff first. because after printing [foo.bar], the
|
// print non-table elements first.
|
||||||
// remaining non-table values will be assigned into [foo.bar], not [foo]
|
// ```toml
|
||||||
|
// [foo] # a table we're writing now here
|
||||||
|
// key = "value" # <- non-table element, "key"
|
||||||
|
// # ...
|
||||||
|
// [foo.bar] # <- table element, "bar"
|
||||||
|
// ```
|
||||||
|
// because after printing [foo.bar], the remaining non-table values will
|
||||||
|
// be assigned into [foo.bar], not [foo]. Those values should be printed
|
||||||
|
// earlier.
|
||||||
for(const auto& kv : v)
|
for(const auto& kv : v)
|
||||||
{
|
{
|
||||||
if(kv.second.is_table() || is_array_of_tables(kv.second))
|
if(kv.second.is_table() || is_array_of_tables(kv.second))
|
||||||
@@ -597,21 +681,16 @@ struct serializer
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!kv.second.comments().empty() && !no_comment_)
|
token += write_comments(kv.second);
|
||||||
{
|
|
||||||
for(const auto& c : kv.second.comments())
|
|
||||||
{
|
|
||||||
token += '#';
|
|
||||||
token += c;
|
|
||||||
token += '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto key_and_sep = format_key(kv.first) + " = ";
|
const auto key_and_sep = format_key(kv.first) + " = ";
|
||||||
const auto residual_width = (this->width_ > key_and_sep.size()) ?
|
const auto residual_width = (this->width_ > key_and_sep.size()) ?
|
||||||
this->width_ - key_and_sep.size() : 0;
|
this->width_ - key_and_sep.size() : 0;
|
||||||
token += key_and_sep;
|
token += key_and_sep;
|
||||||
token += visit(serializer(residual_width, this->float_prec_, true),
|
token += visit(serializer(residual_width, this->float_prec_,
|
||||||
kv.second);
|
/*can be inlined*/ true, /*no comment*/ false, /*keys*/ {},
|
||||||
|
/*has_comment*/ !kv.second.comments().empty()), kv.second);
|
||||||
|
|
||||||
if(token.back() != '\n')
|
if(token.back() != '\n')
|
||||||
{
|
{
|
||||||
token += '\n';
|
token += '\n';
|
||||||
@@ -637,45 +716,172 @@ struct serializer
|
|||||||
ks.push_back(kv.first);
|
ks.push_back(kv.first);
|
||||||
|
|
||||||
auto tmp = visit(serializer(this->width_, this->float_prec_,
|
auto tmp = visit(serializer(this->width_, this->float_prec_,
|
||||||
!multiline_table_printed, this->no_comment_, ks),
|
!multiline_table_printed, this->no_comment_, ks,
|
||||||
kv.second);
|
/*has_comment*/ !kv.second.comments().empty()), kv.second);
|
||||||
|
|
||||||
|
// If it is the first time to print a multi-line table, it would be
|
||||||
|
// helpful to separate normal key-value pair and subtables by a
|
||||||
|
// newline.
|
||||||
|
// (this checks if the current key-value pair contains newlines.
|
||||||
|
// but it is not perfect because multi-line string can also contain
|
||||||
|
// a newline. in such a case, an empty line will be written) TODO
|
||||||
if((!multiline_table_printed) &&
|
if((!multiline_table_printed) &&
|
||||||
std::find(tmp.cbegin(), tmp.cend(), '\n') != tmp.cend())
|
std::find(tmp.cbegin(), tmp.cend(), '\n') != tmp.cend())
|
||||||
{
|
{
|
||||||
multiline_table_printed = true;
|
multiline_table_printed = true;
|
||||||
}
|
token += '\n'; // separate key-value pairs and subtables
|
||||||
else
|
|
||||||
{
|
|
||||||
// still inline tables only.
|
|
||||||
tmp += '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!kv.second.comments().empty() && !no_comment_)
|
token += write_comments(kv.second);
|
||||||
{
|
token += tmp;
|
||||||
for(const auto& c : kv.second.comments())
|
|
||||||
|
// care about recursive tables (all tables in each level prints
|
||||||
|
// newline and there will be a full of newlines)
|
||||||
|
if(tmp.substr(tmp.size() - 2, 2) != "\n\n" &&
|
||||||
|
tmp.substr(tmp.size() - 4, 4) != "\r\n\r\n" )
|
||||||
{
|
{
|
||||||
token += '#';
|
|
||||||
token += c;
|
|
||||||
token += '\n';
|
token += '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
token += tmp;
|
else
|
||||||
|
{
|
||||||
|
token += write_comments(kv.second);
|
||||||
|
token += tmp;
|
||||||
|
token += '\n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string make_array_of_tables(const array_type& v) const
|
||||||
|
{
|
||||||
|
// if it's not inlined, we need to add `[[table.key]]`.
|
||||||
|
// but if it can be inlined, we can format it as the following.
|
||||||
|
// ```
|
||||||
|
// table.key = [
|
||||||
|
// {...},
|
||||||
|
// # comment
|
||||||
|
// {...},
|
||||||
|
// ]
|
||||||
|
// ```
|
||||||
|
// This function checks if inlinization is possible or not, and then
|
||||||
|
// format the array-of-tables in a proper way.
|
||||||
|
//
|
||||||
|
// Note about comments:
|
||||||
|
//
|
||||||
|
// If the array itself has a comment (value_has_comment_ == true), we
|
||||||
|
// should try to make it inline.
|
||||||
|
// ```toml
|
||||||
|
// # comment about array
|
||||||
|
// array = [
|
||||||
|
// # comment about table element
|
||||||
|
// {of = "table"}
|
||||||
|
// ]
|
||||||
|
// ```
|
||||||
|
// If it is formatted as a multiline table, the two comments becomes
|
||||||
|
// indistinguishable.
|
||||||
|
// ```toml
|
||||||
|
// # comment about array
|
||||||
|
// # comment about table element
|
||||||
|
// [[array]]
|
||||||
|
// of = "table"
|
||||||
|
// ```
|
||||||
|
// So we need to try to make it inline, and it force-inlines regardless
|
||||||
|
// of the line width limit.
|
||||||
|
// It may fail if the element of a table has comment. In that case,
|
||||||
|
// the array-of-tables will be formatted as a multiline table.
|
||||||
|
if(this->can_be_inlined_ || this->value_has_comment_)
|
||||||
|
{
|
||||||
|
std::string token;
|
||||||
|
if(!keys_.empty())
|
||||||
|
{
|
||||||
|
token += format_key(keys_.back());
|
||||||
|
token += " = ";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool failed = false;
|
||||||
|
token += "[\n";
|
||||||
|
for(const auto& item : v)
|
||||||
|
{
|
||||||
|
// if an element of the table has a comment, the table
|
||||||
|
// cannot be inlined.
|
||||||
|
if(this->has_comment_inside(item.as_table()))
|
||||||
|
{
|
||||||
|
failed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// write comments for the table itself
|
||||||
|
token += write_comments(item);
|
||||||
|
|
||||||
|
const auto t = this->make_inline_table(item.as_table());
|
||||||
|
|
||||||
|
if(t.size() + 1 > width_ || // +1 for the last comma {...},
|
||||||
|
std::find(t.cbegin(), t.cend(), '\n') != t.cend())
|
||||||
|
{
|
||||||
|
// if the value itself has a comment, ignore the line width limit
|
||||||
|
if( ! this->value_has_comment_)
|
||||||
|
{
|
||||||
|
failed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
token += t;
|
||||||
|
token += ",\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ! failed)
|
||||||
|
{
|
||||||
|
token += "]\n";
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
// if failed, serialize them as [[array.of.tables]].
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string token;
|
||||||
|
for(const auto& item : v)
|
||||||
|
{
|
||||||
|
token += write_comments(item);
|
||||||
|
token += "[[";
|
||||||
|
token += format_keys(keys_);
|
||||||
|
token += "]]\n";
|
||||||
|
token += this->make_multiline_table(item.as_table());
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string write_comments(const value_type& v) const
|
||||||
|
{
|
||||||
|
std::string retval;
|
||||||
|
if(this->no_comment_) {return retval;}
|
||||||
|
|
||||||
|
for(const auto& c : v.comments())
|
||||||
|
{
|
||||||
|
retval += '#';
|
||||||
|
retval += c;
|
||||||
|
retval += '\n';
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_array_of_tables(const value_type& v) const
|
bool is_array_of_tables(const value_type& v) const
|
||||||
{
|
{
|
||||||
if(!v.is_array()) {return false;}
|
if(!v.is_array() || v.as_array().empty()) {return false;}
|
||||||
const auto& a = v.as_array();
|
return is_array_of_tables(v.as_array());
|
||||||
return !a.empty() && a.front().is_table();
|
}
|
||||||
|
bool is_array_of_tables(const array_type& v) const
|
||||||
|
{
|
||||||
|
// Since TOML v0.5.0, heterogeneous arrays are allowed. So we need to
|
||||||
|
// check all the element in an array to check if the array is an array
|
||||||
|
// of tables.
|
||||||
|
return std::all_of(v.begin(), v.end(), [](const value_type& elem) {
|
||||||
|
return elem.is_table();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool can_be_inlined_;
|
bool can_be_inlined_;
|
||||||
bool no_comment_;
|
bool no_comment_;
|
||||||
|
bool value_has_comment_;
|
||||||
int float_prec_;
|
int float_prec_;
|
||||||
std::size_t width_;
|
std::size_t width_;
|
||||||
std::vector<toml::key> keys_;
|
std::vector<toml::key> keys_;
|
||||||
@@ -699,7 +905,7 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
|
|||||||
oss << v.comments();
|
oss << v.comments();
|
||||||
oss << '\n'; // to split the file comment from the first element
|
oss << '\n'; // to split the file comment from the first element
|
||||||
}
|
}
|
||||||
const auto serialized = visit(serializer<value_type>(w, fprec, no_comment, false), v);
|
const auto serialized = visit(serializer<value_type>(w, fprec, false, no_comment), v);
|
||||||
oss << serialized;
|
oss << serialized;
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
@@ -720,7 +926,7 @@ template<typename charT, typename traits>
|
|||||||
std::basic_ostream<charT, traits>&
|
std::basic_ostream<charT, traits>&
|
||||||
nocomment(std::basic_ostream<charT, traits>& os)
|
nocomment(std::basic_ostream<charT, traits>& os)
|
||||||
{
|
{
|
||||||
// by default, it is zero. and by defalut, it shows comments.
|
// by default, it is zero. and by default, it shows comments.
|
||||||
os.iword(detail::comment_index(os)) = 1;
|
os.iword(detail::comment_index(os)) = 1;
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
@@ -729,7 +935,7 @@ template<typename charT, typename traits>
|
|||||||
std::basic_ostream<charT, traits>&
|
std::basic_ostream<charT, traits>&
|
||||||
showcomment(std::basic_ostream<charT, traits>& os)
|
showcomment(std::basic_ostream<charT, traits>& os)
|
||||||
{
|
{
|
||||||
// by default, it is zero. and by defalut, it shows comments.
|
// by default, it is zero. and by default, it shows comments.
|
||||||
os.iword(detail::comment_index(os)) = 0;
|
os.iword(detail::comment_index(os)) = 0;
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
@@ -746,7 +952,7 @@ operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
|
|||||||
const int fprec = static_cast<int>(os.precision());
|
const int fprec = static_cast<int>(os.precision());
|
||||||
os.width(0);
|
os.width(0);
|
||||||
|
|
||||||
// by defualt, iword is initialized byl 0. And by default, toml11 outputs
|
// by default, iword is initialized by 0. And by default, toml11 outputs
|
||||||
// comments. So `0` means showcomment. 1 means nocommnet.
|
// comments. So `0` means showcomment. 1 means nocommnet.
|
||||||
const bool no_comment = (1 == os.iword(detail::comment_index(os)));
|
const bool no_comment = (1 == os.iword(detail::comment_index(os)));
|
||||||
|
|
||||||
+10
-3
@@ -3,6 +3,7 @@
|
|||||||
#ifndef TOML11_SOURCE_LOCATION_HPP
|
#ifndef TOML11_SOURCE_LOCATION_HPP
|
||||||
#define TOML11_SOURCE_LOCATION_HPP
|
#define TOML11_SOURCE_LOCATION_HPP
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
@@ -124,7 +125,7 @@ inline std::string format_underline(const std::string& message,
|
|||||||
|
|
||||||
std::ostringstream retval;
|
std::ostringstream retval;
|
||||||
|
|
||||||
if(colorize)
|
if(color::should_color() || colorize)
|
||||||
{
|
{
|
||||||
retval << color::colorize; // turn on ANSI color
|
retval << color::colorize; // turn on ANSI color
|
||||||
}
|
}
|
||||||
@@ -136,12 +137,18 @@ inline std::string format_underline(const std::string& message,
|
|||||||
// if it is "[error]", it removes that part from the message shown.
|
// if it is "[error]", it removes that part from the message shown.
|
||||||
if(message.size() > 7 && message.substr(0, 7) == "[error]")
|
if(message.size() > 7 && message.substr(0, 7) == "[error]")
|
||||||
{
|
{
|
||||||
retval << color::bold << color::red << "[error]" << color::reset
|
retval
|
||||||
|
#ifndef TOML11_NO_ERROR_PREFIX
|
||||||
|
<< color::bold << color::red << "[error]" << color::reset
|
||||||
|
#endif
|
||||||
<< color::bold << message.substr(7) << color::reset << '\n';
|
<< color::bold << message.substr(7) << color::reset << '\n';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
retval << color::bold << color::red << "[error] " << color::reset
|
retval
|
||||||
|
#ifndef TOML11_NO_ERROR_PREFIX
|
||||||
|
<< color::bold << color::red << "[error] " << color::reset
|
||||||
|
#endif
|
||||||
<< color::bold << message << color::reset << '\n';
|
<< color::bold << message << color::reset << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
+6
-2
@@ -2,13 +2,17 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_STRING_HPP
|
#ifndef TOML11_STRING_HPP
|
||||||
#define TOML11_STRING_HPP
|
#define TOML11_STRING_HPP
|
||||||
|
|
||||||
|
#include "version.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||||
#if __has_include(<string_view>)
|
#if __has_include(<string_view>)
|
||||||
|
#define TOML11_USING_STRING_VIEW 1
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -53,7 +57,7 @@ struct string
|
|||||||
string& operator+=(const std::string& rhs) {str += rhs; return *this;}
|
string& operator+=(const std::string& rhs) {str += rhs; return *this;}
|
||||||
string& operator+=(const string& rhs) {str += rhs.str; return *this;}
|
string& operator+=(const string& rhs) {str += rhs.str; return *this;}
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
|
||||||
explicit string(std::string_view s): kind(string_t::basic), str(s){}
|
explicit string(std::string_view s): kind(string_t::basic), str(s){}
|
||||||
string(std::string_view s, string_t k): kind(k), str(s){}
|
string(std::string_view s, string_t k): kind(k), str(s){}
|
||||||
|
|
||||||
+36
-8
@@ -2,6 +2,11 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_TRAITS_HPP
|
#ifndef TOML11_TRAITS_HPP
|
||||||
#define TOML11_TRAITS_HPP
|
#define TOML11_TRAITS_HPP
|
||||||
|
|
||||||
|
#include "from.hpp"
|
||||||
|
#include "into.hpp"
|
||||||
|
#include "version.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -9,7 +14,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||||
#if __has_include(<string_view>)
|
#if __has_include(<string_view>)
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#endif // has_include(<string_view>)
|
#endif // has_include(<string_view>)
|
||||||
@@ -84,6 +89,22 @@ struct has_into_toml_method_impl
|
|||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct has_specialized_from_impl
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
static std::false_type check(...);
|
||||||
|
template<typename T, std::size_t S = sizeof(::toml::from<T>)>
|
||||||
|
static std::true_type check(::toml::from<T>*);
|
||||||
|
};
|
||||||
|
struct has_specialized_into_impl
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
static std::false_type check(...);
|
||||||
|
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
|
||||||
|
static std::true_type check(::toml::from<T>*);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Intel C++ compiler can not use decltype in parent class declaration, here
|
/// Intel C++ compiler can not use decltype in parent class declaration, here
|
||||||
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
|
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
|
||||||
#ifdef __INTEL_COMPILER
|
#ifdef __INTEL_COMPILER
|
||||||
@@ -114,6 +135,11 @@ template<typename T>
|
|||||||
struct has_into_toml_method
|
struct has_into_toml_method
|
||||||
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
|
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct has_specialized_from : decltype(has_specialized_from_impl::check<T>(nullptr)){};
|
||||||
|
template<typename T>
|
||||||
|
struct has_specialized_into : decltype(has_specialized_into_impl::check<T>(nullptr)){};
|
||||||
|
|
||||||
#ifdef __INTEL_COMPILER
|
#ifdef __INTEL_COMPILER
|
||||||
#undef decltype
|
#undef decltype
|
||||||
#endif
|
#endif
|
||||||
@@ -121,7 +147,7 @@ struct has_into_toml_method
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// C++17 and/or/not
|
// C++17 and/or/not
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||||
|
|
||||||
using std::conjunction;
|
using std::conjunction;
|
||||||
using std::disjunction;
|
using std::disjunction;
|
||||||
@@ -183,8 +209,10 @@ template<typename T>
|
|||||||
struct is_container : conjunction<
|
struct is_container : conjunction<
|
||||||
negation<is_map<T>>, // not a map
|
negation<is_map<T>>, // not a map
|
||||||
negation<std::is_same<T, std::string>>, // not a std::string
|
negation<std::is_same<T, std::string>>, // not a std::string
|
||||||
#if __cplusplus >= 201703L
|
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||||
|
#if __has_include(<string_view>)
|
||||||
negation<std::is_same<T, std::string_view>>, // not a std::string_view
|
negation<std::is_same<T, std::string_view>>, // not a std::string_view
|
||||||
|
#endif // has_include(<string_view>)
|
||||||
#endif
|
#endif
|
||||||
has_iterator<T>, // has T::iterator
|
has_iterator<T>, // has T::iterator
|
||||||
has_value_type<T> // has T::value_type
|
has_value_type<T> // has T::value_type
|
||||||
@@ -206,7 +234,7 @@ struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// C++14 index_sequence
|
// C++14 index_sequence
|
||||||
|
|
||||||
#if __cplusplus >= 201402L
|
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||||
|
|
||||||
using std::index_sequence;
|
using std::index_sequence;
|
||||||
using std::make_index_sequence;
|
using std::make_index_sequence;
|
||||||
@@ -236,12 +264,12 @@ struct index_sequence_maker<0>
|
|||||||
template<std::size_t N>
|
template<std::size_t N>
|
||||||
using make_index_sequence = typename index_sequence_maker<N-1>::type;
|
using make_index_sequence = typename index_sequence_maker<N-1>::type;
|
||||||
|
|
||||||
#endif // __cplusplus >= 2014
|
#endif // cplusplus >= 2014
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// C++14 enable_if_t
|
// C++14 enable_if_t
|
||||||
|
|
||||||
#if __cplusplus >= 201402L
|
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||||
|
|
||||||
using std::enable_if_t;
|
using std::enable_if_t;
|
||||||
|
|
||||||
@@ -250,12 +278,12 @@ using std::enable_if_t;
|
|||||||
template<bool B, typename T>
|
template<bool B, typename T>
|
||||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||||
|
|
||||||
#endif // __cplusplus >= 2014
|
#endif // cplusplus >= 2014
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// return_type_of_t
|
// return_type_of_t
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L && defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable>=201703
|
||||||
|
|
||||||
template<typename F, typename ... Args>
|
template<typename F, typename ... Args>
|
||||||
using return_type_of_t = std::invoke_result_t<F, Args...>;
|
using return_type_of_t = std::invoke_result_t<F, Args...>;
|
||||||
+24
-1
@@ -21,9 +21,14 @@ class basic_value;
|
|||||||
using character = char;
|
using character = char;
|
||||||
using key = std::string;
|
using key = std::string;
|
||||||
|
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ <= 4
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wshadow"
|
||||||
|
#endif
|
||||||
|
|
||||||
using boolean = bool;
|
using boolean = bool;
|
||||||
using integer = std::int64_t;
|
using integer = std::int64_t;
|
||||||
using floating = double; // "float" is a keyward, cannot use it here.
|
using floating = double; // "float" is a keyword, cannot use it here.
|
||||||
// the following stuffs are structs defined here, so aliases are not needed.
|
// the following stuffs are structs defined here, so aliases are not needed.
|
||||||
// - string
|
// - string
|
||||||
// - offset_datetime
|
// - offset_datetime
|
||||||
@@ -32,12 +37,26 @@ using floating = double; // "float" is a keyward, cannot use it here.
|
|||||||
// - local_date
|
// - local_date
|
||||||
// - local_time
|
// - local_time
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
// default toml::value and default array/table. these are defined after defining
|
// default toml::value and default array/table. these are defined after defining
|
||||||
// basic_value itself.
|
// basic_value itself.
|
||||||
// using value = basic_value<discard_comments, std::unordered_map, std::vector>;
|
// using value = basic_value<discard_comments, std::unordered_map, std::vector>;
|
||||||
// using array = typename value::array_type;
|
// using array = typename value::array_type;
|
||||||
// using table = typename value::table_type;
|
// using table = typename value::table_type;
|
||||||
|
|
||||||
|
// to avoid warnings about `value_t::integer` is "shadowing" toml::integer in
|
||||||
|
// GCC -Wshadow=global.
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# if 7 <= __GNUC__
|
||||||
|
# pragma GCC diagnostic ignored "-Wshadow=global"
|
||||||
|
# else // gcc-6 or older
|
||||||
|
# pragma GCC diagnostic ignored "-Wshadow"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
enum class value_t : std::uint8_t
|
enum class value_t : std::uint8_t
|
||||||
{
|
{
|
||||||
empty = 0,
|
empty = 0,
|
||||||
@@ -52,6 +71,9 @@ enum class value_t : std::uint8_t
|
|||||||
array = 9,
|
array = 9,
|
||||||
table = 10,
|
table = 10,
|
||||||
};
|
};
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename charT, typename traits>
|
template<typename charT, typename traits>
|
||||||
inline std::basic_ostream<charT, traits>&
|
inline std::basic_ostream<charT, traits>&
|
||||||
@@ -147,4 +169,5 @@ template<typename T, typename V> struct is_exact_toml_type<T const volatile&, V>
|
|||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
} // toml
|
} // toml
|
||||||
|
|
||||||
#endif// TOML11_TYPES_H
|
#endif// TOML11_TYPES_H
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user