Compare commits

...

30 Commits

Author SHA1 Message Date
Duncan Ogilvie 8f4b376e42 Bump to 0.2.45 2025-08-26 17:16:10 +02:00
Duncan Ogilvie fcbf937c49 Merge pull request #189 from iamtimmy/main
template add-function arguments
2025-08-26 17:00:55 +02:00
iamtimmy e609c8a48f template add-function arguments
add arguments support to add-function functionality in templates
2025-08-26 16:46:32 +02:00
Duncan Ogilvie 735898dbac Update basics.md 2025-08-11 03:37:01 +02:00
Duncan Ogilvie f7126b0158 Update basics.md 2025-08-11 03:35:53 +02:00
Duncan Ogilvie b6702714eb Fix info 2025-08-11 03:31:57 +02:00
Duncan Ogilvie efa4f716c2 Add CMake phases to basics 2025-08-11 03:30:28 +02:00
Duncan Ogilvie 76b7b8e778 Clarify basics documentation page 2025-08-11 03:05:37 +02:00
Duncan Ogilvie 501b26ced5 Update fetch-content documentation 2025-06-25 01:50:29 +02:00
Duncan Ogilvie 5bc36275ad Merge pull request #185 from build-cpp/gh-actions-bump
Bump github actions
2025-05-30 01:16:56 +02:00
Duncan Ogilvie 35c837a181 Bump github actions 2025-05-30 00:24:22 +02:00
Duncan Ogilvie 710dfa4963 Merge pull request #182 from evanwporter/patch-1
bumped up upload version
2025-05-30 00:15:38 +02:00
Duncan Ogilvie c49ee6bafe Update README.md 2025-05-29 23:21:04 +02:00
Evan 368273bab2 bumped up upload version 2025-04-19 15:49:15 -07:00
Duncan Ogilvie b1249af365 Bump to 0.2.44 2025-01-19 15:12:34 +01:00
Duncan Ogilvie ea2ff31b5a Merge pull request #173 from build-cpp/fix-empty-properties
Make sure empty target properties are emitted correctly
2025-01-19 15:10:06 +01:00
Duncan Ogilvie a32eb66df4 Make sure empty target properties are emitted correctly 2025-01-19 14:53:50 +01:00
Duncan Ogilvie 9b85833240 Add link to example vcpkg repository 2024-12-06 18:19:35 +01:00
Duncan Ogilvie ccb3d0b9ef Bump to 0.2.43 2024-12-04 13:00:03 +01:00
Duncan Ogilvie 49cdab39bd Merge pull request #169 from build-cpp/namespace-targets
Support `::mylib` which that target that exists at configure-time
2024-12-04 12:55:57 +01:00
Duncan Ogilvie e318139314 Add documentation for ::mylib 2024-12-04 12:15:51 +01:00
Duncan Ogilvie 0f2a9a55fb Support link-libraries = ["::mylib"] which checks the if target exists
https://gitlab.kitware.com/cmake/cmake/-/issues/26497
2024-12-04 12:15:49 +01:00
Duncan Ogilvie 38cec2d5d1 Do not allow lambdas on a single line 2024-12-04 11:55:13 +01:00
Duncan Ogilvie 3caf593438 Bump to 0.2.42 2024-12-03 15:35:05 +01:00
Duncan Ogilvie c94dbd6416 Merge pull request #168 from build-cpp/target-directory-bug
Fix linking against a target that's also a directory
2024-12-03 13:41:16 +01:00
Duncan Ogilvie a1eaf601c6 Fix linking against a target that's also a directory
Closes #166
2024-12-03 13:39:32 +01:00
Duncan Ogilvie 10320c8e55 Bump to 0.2.41 2024-12-02 15:56:02 +01:00
Duncan Ogilvie 45e12c8d98 Merge pull request #165 from build-cpp/cmake-support
Fix vcpkg support for CMake 3.30
2024-12-02 15:55:43 +01:00
Duncan Ogilvie e12ebc060d Use FetchContent_MakeAvailable for vcpkg 2024-12-02 15:54:19 +01:00
Duncan Ogilvie c6e3fc159f Suppress deprecation warning for CMake <3.10 2024-12-02 15:50:22 +01:00
14 changed files with 194 additions and 79 deletions
+1
View File
@@ -13,6 +13,7 @@ AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortLambdasOnASingleLine: None
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
+7 -10
View File
@@ -10,19 +10,16 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [windows-2022, macos-latest, ubuntu-20.04]
os: [windows-2022, macos-latest, ubuntu-22.04]
env:
BUILD_TYPE: 'Release'
CMAKE_GENERATOR: 'Ninja'
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Ninja
uses: seanmiddleditch/gha-setup-ninja@6263846cf3c17009dfc81604efabae16044fc074 # master
uses: actions/checkout@v4
- name: Visual Studio Development Environment
uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.1
- name: Tag cmkr.cmake
if: ${{ startsWith(github.ref, 'refs/tags/') }}
@@ -45,27 +42,27 @@ jobs:
ctest -C ${{ env.BUILD_TYPE }} --verbose
- name: Upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ github.event.repository.name }}-${{ matrix.os }}
path: install/bin/*
- name: Get lowercase OS name
id: osname
uses: ASzc/change-string-case-action@07c1e24a97f0951e13f88870b99c058fcf0b14cf # v5
uses: ASzc/change-string-case-action@ccb130a4e483d3e86287289183704dc9bf53e77e # master 2024-04-05
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
string: ${{ runner.os }}
- name: Compress artifacts
uses: vimtor/action-zip@26a249fb00d43ca98dad77a4b3838025fc226aa1 # v1.1
uses: vimtor/action-zip@1379ea20d4c5705669ba81fd626dd01b1c738f26 # v1.2
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
files: install/bin/
dest: ${{ github.event.repository.name }}-${{ steps.osname.outputs.lowercase }}.zip
- name: Release
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') || contains(github.ref, '-pre') }}
+3 -3
View File
@@ -10,7 +10,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: clang-format
id: clang-format
@@ -35,7 +35,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Run editorconfig-checker
uses: editorconfig-checker/action-editorconfig-checker@d4fca16fc71adef10fbe101903b654449fa9570c # master 2022-03-15
uses: editorconfig-checker/action-editorconfig-checker@27dd658c2b1282c7f1f4dc242cdf0f6d8af728ab # master 2025-05-30
+2 -2
View File
@@ -1,7 +1,7 @@
# This file is automatically generated from cmake.toml - DO NOT EDIT
# See https://github.com/build-cpp/cmkr for more information
cmake_minimum_required(VERSION 2.8...3.8)
cmake_minimum_required(VERSION 2.8...3.31)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build")
@@ -22,7 +22,7 @@ project(cmkr
LANGUAGES
CXX
VERSION
0.2.40
0.2.45
DESCRIPTION
"CMakeLists generator from TOML"
)
+2
View File
@@ -1,5 +1,7 @@
# cmkr
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/build-cpp/cmkr)
`cmkr`, pronounced "cmaker", is a modern build system based on [CMake](https://cmake.org/) and [TOML](https://toml.io).
`cmkr` parses `cmake.toml` files and generates a modern, idiomatic `CMakeLists.txt` for you. A minimal example:
+2 -2
View File
@@ -1,10 +1,10 @@
[cmake]
version = "2.8...3.8"
version = "2.8...3.31"
cmkr-include = false
[project]
name = "cmkr"
version = "0.2.40"
version = "0.2.45"
description = "CMakeLists generator from TOML"
languages = ["CXX"]
include-after = [
+1 -1
View File
@@ -2,7 +2,7 @@ include_guard()
# Change these defaults to point to your infrastructure if desired
set(CMKR_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE)
set(CMKR_TAG "v0.2.40" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
set(CMKR_TAG "v0.2.45" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE)
# To bootstrap/generate a cmkr project: cmake -P cmkr.cmake
+80 -13
View File
@@ -6,7 +6,7 @@ nav_order: 1
# Basics
To effectively use cmkr it helps to understand the basic concepts of CMake.
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
@@ -16,25 +16,41 @@ A CMake **project** is a collection of targets. In the context of libraries the
## 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 library you can build. There are also [pseudo targets](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#pseudo-targets), but we ignore them for now.
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 to build them.
Targets have a collection of **properties** that describe how the compiler builds them.
Examples of properties:
The most commonly-used properties:
- _Sources_: the `*.cpp` files used to build the target.
- _Compile options_: Command line flags for the compiler.
- _Link libraries_: The **dependencies** required to build this target.
- [_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 of the linker, CMake also propagates properties of the target you link to.
**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_.
<sub>You can think of **linking** as _depending on_.</sub>
You should think of **linking** in CMake as _depending on_.
{:.info}
The propagation of properties depends on their **visibility**:
@@ -44,7 +60,7 @@ The propagation of properties depends on their **visibility**:
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
## Example
The most intuitive example is with _include directories_. Imagine there are two targets:
@@ -67,10 +83,61 @@ name = "DataProcessor"
type = "static"
sources = ["StringUtils/src/stringutils.cpp"]
headers = ["StringUtils/include/stringutils.hpp"]
include-directories = ["StringUtils/include"]
include-directories = ["StringUtils/include"] # public (default for libraries)
[target.DataProcessor]
type = "executable"
sources = ["DataProcessor/src/main.cpp"]
link-libraries = ["StringUtils"]
```
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.
+18 -12
View File
@@ -171,7 +171,9 @@ The vcpkg `version` will automatically generate the `url` from the [official rep
To specify package features you can use the following syntax: `imgui[docking-experimental,freetype,sdl2-binding,opengl3-binding]`. To disable the [default features](https://learn.microsoft.com/en-us/vcpkg/concepts/default-features) you can do: `cpp-httplib[core,openssl]`
The `overlay-ports` feature allows you to embed vcpkg ports inside your project, without having to fork the main vcpkg registry or creating a custom registry. You can find more information in the relevant [documentation](https://learn.microsoft.com/en-us/vcpkg/concepts/overlay-ports). The `overlay-triplets` feature allows you to customize triplets and change the default behavior (for example always preferring static libraries on Windows). To specify both in one go you can do `[vcpkg].overlay = "my-overlay"`.
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
@@ -189,26 +191,28 @@ components = ["mycomponent"]
**Note**: The `[fetch-content]` feature is unpolished and will likely change in a future release.
```toml
# Include CMake project from git
[fetch-content.gitcontent]
condition = "mycondition"
git = "https://github.com/myuser/gitcontent"
tag = "v0.1"
shallow = false
shallow = false # shallow clone (--depth 1)
system = false
subdir = ""
subdir = "" # folder containing CMakeLists.txt
# Include a CMake project from a URL
[fetch-content.urlcontent]
condition = "mycondition"
url = "https://content-host.com/urlcontent.zip"
# Other supported algorithms:
# md5, sha1, sha224, sha256, sha384, sha512, sha3_224, sha3_256, sha3_384, sha3_512
hash = "SHA1 502a4e25b8b209889c99c7fa0732102682c2e4ff"
sha1 = "502a4e25b8b209889c99c7fa0732102682c2e4ff"
[fetch-content.svncontent]
condition = "mycondition"
svn = "https://svn-host.com/url"
rev = "svn_rev"
[fetch-content.urlcontent]
condition = "mycondition"
url = "https://content-host.com/urlcontent.zip"
# These are equivalent, supported algorithms:
# md5, sha1, sha224, sha256, sha384, sha512, sha3_224, sha3_256, sha3_384, sha3_512
hash = "SHA1 502a4e25b8b209889c99c7fa0732102682c2e4ff"
sha1 = "502a4e25b8b209889c99c7fa0732102682c2e4ff"
```
Table keys that match CMake variable names (`[A-Z_]+`) will be passed to the [`FetchContent_Declare`](https://cmake.org/cmake/help/latest/module/FetchContent.html#command:fetchcontent_declare) command.
@@ -272,7 +276,7 @@ A table mapping the cmkr features to the relevant CMake construct and the releva
| `compile-options` | [`target_compile_options`](https://cmake.org/cmake/help/latest/command/target_compile_options.html) | Adds compiler flags. |
| `include-directories` | [`target_include_directories`](https://cmake.org/cmake/help/latest/command/target_include_directories.html) | Adds include directories. |
| `link-directories` | [`target_link_directories`](https://cmake.org/cmake/help/latest/command/target_link_directories.html) | Adds library directories. |
| `link-libraries` | [`target_link_libraries`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) | Adds library dependencies. |
| `link-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. |
@@ -298,6 +302,7 @@ 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
@@ -309,6 +314,7 @@ 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)
+3 -2
View File
@@ -16,8 +16,9 @@ Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) from [GitHub](https://github.com)
name = "fetch-content"
description = "Fetching from git"
[fetch-content]
fmt = { git = "https://github.com/fmtlib/fmt", tag = "7.1.3" }
[fetch-content.fmt]
git = "https://github.com/fmtlib/fmt"
tag = "7.1.3"
[target.example]
type = "executable"
+1
View File
@@ -118,6 +118,7 @@ struct Target {
struct Template {
Target outline;
std::string add_function;
std::vector<std::string> add_arguments;
bool pass_sources_to_add_function = false;
};
+58 -23
View File
@@ -289,6 +289,10 @@ struct RawArg {
}
std::string arg;
bool empty() const {
return arg.empty();
}
};
// Credit: JustMagic
@@ -406,7 +410,7 @@ struct Command {
}
bool print_arg(const RawArg &arg) {
if (arg.arg.empty()) {
if (arg.empty()) {
return true;
}
@@ -558,11 +562,15 @@ struct Generator {
}
void conditional_includes(const parser::ConditionVector &include) {
handle_condition(include, [this](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
handle_condition(include, [this](const std::string &, const std::vector<std::string> &includes) {
inject_includes(includes);
});
}
void conditional_cmake(const parser::Condition<std::string> &cmake) {
handle_condition(cmake, [this](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
handle_condition(cmake, [this](const std::string &, const std::string &cmake) {
inject_cmake(cmake);
});
}
bool if_condition(const std::string &condition) {
@@ -719,9 +727,15 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
// Helper lambdas for more convenient CMake generation
auto &ss = gen.ss;
auto cmd = [&gen](const std::string &command) { return gen.cmd(command); };
auto comment = [&gen](const std::string &comment) { return gen.comment(comment); };
auto endl = [&gen]() { gen.endl(); };
auto cmd = [&gen](const std::string &command) {
return gen.cmd(command);
};
auto comment = [&gen](const std::string &comment) {
return gen.comment(comment);
};
auto endl = [&gen]() {
gen.endl();
};
std::string cmkr_url = "https://github.com/build-cpp/cmkr";
comment("This file is automatically generated from cmake.toml - DO NOT EDIT");
@@ -943,15 +957,11 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
cmd("endif")();
cmd("message")("STATUS", "Fetching vcpkg (" + version_name + ")...");
cmd("FetchContent_Declare")("vcpkg", vcpkg_args);
// Not using FetchContent_MakeAvailable here in case vcpkg adds CMakeLists.txt
cmd("FetchContent_GetProperties")("vcpkg");
cmd("if")("NOT", "vcpkg_POPULATED");
cmd("FetchContent_Populate")("vcpkg");
cmd("if")("CMAKE_HOST_SYSTEM_NAME", "STREQUAL", "Darwin", "AND", "CMAKE_OSX_ARCHITECTURES", "STREQUAL", RawArg("\"\""));
cmd("set")("CMAKE_OSX_ARCHITECTURES", "${CMAKE_HOST_SYSTEM_PROCESSOR}", "CACHE", "STRING", RawArg("\"\""), "FORCE");
cmd("endif")();
cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
cmd("FetchContent_MakeAvailable")("vcpkg").endl();
cmd("if")("CMAKE_HOST_SYSTEM_NAME", "STREQUAL", "Darwin", "AND", "CMAKE_OSX_ARCHITECTURES", "STREQUAL", RawArg("\"\""));
cmd("set")("CMAKE_OSX_ARCHITECTURES", "${CMAKE_HOST_SYSTEM_PROCESSOR}", "CACHE", "STRING", RawArg("\"\""), "FORCE");
cmd("endif")();
cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
cmd("endif")();
endl();
// clang-format on
@@ -1149,7 +1159,9 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
for (size_t i = 0; i < project.targets.size(); i++) {
const auto &target = project.targets[i];
auto throw_target_error = [&target](const std::string &message) { throw std::runtime_error("[target." + target.name + "] " + message); };
auto throw_target_error = [&target](const std::string &message) {
throw std::runtime_error("[target." + target.name + "] " + message);
};
const parser::Template *tmplate = nullptr;
std::unique_ptr<ConditionScope> tmplate_cs{};
@@ -1360,12 +1372,11 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
// Handle custom add commands from templates.
if (tmplate != nullptr && !tmplate->add_function.empty()) {
add_command = tmplate->add_function;
target_type_string = ""; // TODO: let templates supply options to the add_command here?
if (tmplate->pass_sources_to_add_function) {
cmd(add_command)(target.name, target_type_string, "${" + sources_var + "}");
cmd(add_command)(target.name, tmplate->add_arguments, "${" + sources_var + "}");
} else {
cmd(add_command)(target.name, target_type_string).endl();
cmd(add_command)(target.name, tmplate->add_arguments).endl();
if (has_sources) {
cmd("target_sources")(target.name, target_type == parser::target_interface ? "INTERFACE" : "PRIVATE",
"${" + sources_var + "}");
@@ -1388,8 +1399,29 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
}
auto target_cmd = [&](const char *command, const parser::ConditionVector &cargs, const std::string &scope) {
gen.handle_condition(cargs,
[&](const std::string &, const std::vector<std::string> &args) { cmd(command)(target.name, scope, args); });
gen.handle_condition(cargs, [&](const std::string &, const std::vector<std::string> &args) {
cmd(command)(target.name, scope, args);
});
};
auto link_libraries = [&](const parser::ConditionVector &cargs, const std::string &scope) {
gen.handle_condition(cargs, [&](const std::string &, const std::vector<std::string> &args) {
std::vector<std::string> targs;
for (const std::string &arg : args) {
if (arg.find("::") == 0) {
auto library = arg.substr(2);
// clang-format off
cmd("if")("NOT", "TARGET", library);
cmd("message")("FATAL_ERROR", "Target \"" + library + "\" referenced by \"" + target.name + "\" does not exist!");
cmd("endif")().endl();
// clang-format on
targs.push_back(std::move(library));
} else {
targs.push_back(arg);
}
}
cmd("target_link_libraries")(target.name, scope, targs);
});
};
auto gen_target_cmds = [&](const parser::Target &t) {
@@ -1408,8 +1440,8 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
target_cmd("target_link_directories", t.link_directories, target_scope);
target_cmd("target_link_directories", t.private_link_directories, "PRIVATE");
target_cmd("target_link_libraries", t.link_libraries, target_scope);
target_cmd("target_link_libraries", t.private_link_libraries, "PRIVATE");
link_libraries(t.link_libraries, target_scope);
link_libraries(t.private_link_libraries, "PRIVATE");
target_cmd("target_link_options", t.link_options, target_scope);
target_cmd("target_link_options", t.private_link_options, "PRIVATE");
@@ -1432,14 +1464,17 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
}
gen.handle_condition(props, [&](const std::string &, const tsl::ordered_map<std::string, std::string> &properties) {
tsl::ordered_map<std::string, RawArg> raw_properties;
for (const auto &propItr : properties) {
if (propItr.first == "MSVC_RUNTIME_LIBRARY") {
if (project_root->project_msvc_runtime == parser::msvc_last) {
throw_target_error("You cannot set msvc-runtime without setting the root [project].msvc-runtime");
}
}
// NOTE: We need to make sure that empty strings do not get omitted
raw_properties.emplace(propItr.first, Command::quote(propItr.second));
}
cmd("set_target_properties")(target.name, "PROPERTIES", properties);
cmd("set_target_properties")(target.name, "PROPERTIES", raw_properties);
});
}
+13 -9
View File
@@ -656,22 +656,25 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
// 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_path : libraries[library_entries.first]) {
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_path.find("${") != std::string::npos || library_path.find("$ENV{") != std::string::npos ||
library_path.find("$CACHE{") != std::string::npos) &&
library_path.find('}') != std::string::npos) {
if ((library.find("${") != std::string::npos || library.find("$ENV{") != std::string::npos ||
library.find("$CACHE{") != std::string::npos) &&
library.find('}') != std::string::npos) {
continue;
}
if (fs::exists(fs::path(path) / library_path)) {
// If the file path is relative, prepend ${CMAKE_CURRENT_SOURCE_DIR}
library_path.insert(0, "${CMAKE_CURRENT_SOURCE_DIR}/");
} else if (library_path.find_first_of(R"(\/)") != std::string::npos) {
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_path);
key + "\": " + library);
} else {
// NOTE: We cannot check if system libraries exist, so we leave them as-is
}
@@ -782,6 +785,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
tmplate.outline = parse_target(name, t, true);
t.optional("add-function", tmplate.add_function);
t.optional("add-arguments", tmplate.add_arguments);
t.optional("pass-sources-to-add-function", tmplate.pass_sources_to_add_function);
t.optional("pass-sources", tmplate.pass_sources_to_add_function);
+3 -2
View File
@@ -4,8 +4,9 @@
name = "fetch-content"
description = "Fetching from git"
[fetch-content]
fmt = { git = "https://github.com/fmtlib/fmt", tag = "7.1.3" }
[fetch-content.fmt]
git = "https://github.com/fmtlib/fmt"
tag = "7.1.3"
[target.example]
type = "executable"