mirror of
https://github.com/build-cpp/cmkr
synced 2026-06-08 13:22:55 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3cd84a9708 | |||
| 9932e501ce | |||
| 1b37dd76a5 | |||
| 82f2a11311 | |||
| eaf03eb785 | |||
| 8ea5b77ba5 | |||
| a12b3ae021 | |||
| 2450cfb2c9 | |||
| 8d024556e3 | |||
| af3807ca2b | |||
| 17f085c66d | |||
| 5ad6134e07 | |||
| 7b20d8c54c | |||
| ffdedbdace | |||
| bb7a0bc0ed | |||
| dd0003f8fe | |||
| a32caca8f0 | |||
| f565ad2af0 | |||
| dc4b59f05d | |||
| 4988f141e4 |
Generated
+9
-6
@@ -71,27 +71,28 @@ generate_documentation()
|
||||
|
||||
unset(CMKR_TARGET)
|
||||
unset(CMKR_SOURCES)
|
||||
|
||||
# Target cmkr
|
||||
set(CMKR_TARGET cmkr)
|
||||
set(cmkr_SOURCES "")
|
||||
|
||||
list(APPEND cmkr_SOURCES
|
||||
"src/args.cpp"
|
||||
"src/arguments.cpp"
|
||||
"src/build.cpp"
|
||||
"src/cmake.cpp"
|
||||
"src/cmake_generator.cpp"
|
||||
"src/error.cpp"
|
||||
"src/gen.cpp"
|
||||
"src/help.cpp"
|
||||
"src/main.cpp"
|
||||
"include/args.hpp"
|
||||
"src/project_parser.cpp"
|
||||
"include/arguments.hpp"
|
||||
"include/build.hpp"
|
||||
"include/cmake.hpp"
|
||||
"include/cmake_generator.hpp"
|
||||
"include/enum_helper.hpp"
|
||||
"include/error.hpp"
|
||||
"include/fs.hpp"
|
||||
"include/gen.hpp"
|
||||
"include/help.hpp"
|
||||
"include/literals.hpp"
|
||||
"include/project_parser.hpp"
|
||||
)
|
||||
|
||||
list(APPEND cmkr_SOURCES
|
||||
@@ -125,10 +126,12 @@ target_link_libraries(cmkr PRIVATE
|
||||
ghc_filesystem
|
||||
mpark_variant
|
||||
ordered_map
|
||||
nlohmann_json
|
||||
)
|
||||
|
||||
unset(CMKR_TARGET)
|
||||
unset(CMKR_SOURCES)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
cmkr
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ type = "executable"
|
||||
sources = ["src/*.cpp", "include/*.hpp"]
|
||||
include-directories = ["include"]
|
||||
compile-features = ["cxx_std_11"]
|
||||
link-libraries = ["toml11", "ghc_filesystem", "mpark_variant", "ordered_map"]
|
||||
link-libraries = ["toml11", "ghc_filesystem", "mpark_variant", "ordered_map", "nlohmann_json"]
|
||||
|
||||
[[install]]
|
||||
targets = ["cmkr"]
|
||||
|
||||
+8
-3
@@ -2,14 +2,14 @@ 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 "archive_7cdf36f3" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
set(CMKR_TAG "archive_eaf03eb7" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
|
||||
# Set these from the command line to customize for development/debugging purposes
|
||||
set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable")
|
||||
set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation")
|
||||
|
||||
# Disable cmkr if generation is disabled
|
||||
if(CMKR_SKIP_GENERATION)
|
||||
if(DEFINED ENV{CI} OR CMKR_SKIP_GENERATION)
|
||||
message(STATUS "[cmkr] Skipping automatic cmkr generation")
|
||||
macro(cmkr)
|
||||
endmacro()
|
||||
@@ -132,10 +132,15 @@ macro(cmkr)
|
||||
|
||||
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST)
|
||||
|
||||
# Delete the temporary file if it was left for some reason
|
||||
set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt")
|
||||
if(EXISTS "${CMKR_TEMP_FILE}")
|
||||
file(REMOVE "${CMKR_TEMP_FILE}")
|
||||
endif()
|
||||
|
||||
if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST)
|
||||
# Copy the now-generated CMakeLists.txt to CMakerLists.txt
|
||||
# This is done because you cannot include() a file you are currently in
|
||||
set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt")
|
||||
configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY)
|
||||
|
||||
# Add the macro required for the hack at the start of the cmkr macro
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
# Automatically generated from tests/vcpkg/cmake.toml - DO NOT EDIT
|
||||
layout: default
|
||||
title: Dependencies from vcpkg
|
||||
permalink: /examples/vcpkg
|
||||
parent: Examples
|
||||
nav_order: 4
|
||||
---
|
||||
|
||||
# Dependencies from vcpkg
|
||||
|
||||
Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) using [vcpkg](https://vcpkg.io/) and links an `example` target to it:
|
||||
|
||||
```toml
|
||||
[project]
|
||||
name = "vcpkg"
|
||||
description = "Dependencies from vcpkg"
|
||||
|
||||
# See https://github.com/microsoft/vcpkg/releases for vcpkg versions
|
||||
# See https://vcpkg.io/en/packages.html for available packages
|
||||
[vcpkg]
|
||||
version = "2021.05.12"
|
||||
packages = ["fmt"]
|
||||
|
||||
[find-package]
|
||||
fmt = {}
|
||||
|
||||
[target.example]
|
||||
type = "executable"
|
||||
sources = ["src/main.cpp"]
|
||||
link-libraries = ["fmt::fmt"]
|
||||
```
|
||||
|
||||
The bootstrapping of vcpkg is fully automated and no user interaction is necessary. You can disable vcpkg by setting `CMKR_DISABLE_VCPKG=ON`.
|
||||
|
||||
<sup><sub>This page was automatically generated from [tests/vcpkg/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/vcpkg/cmake.toml).</sub></sup>
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <vector>
|
||||
|
||||
namespace cmkr {
|
||||
namespace cmake {
|
||||
namespace parser {
|
||||
|
||||
struct Setting {
|
||||
std::string name;
|
||||
@@ -34,6 +34,7 @@ struct Package {
|
||||
|
||||
struct Vcpkg {
|
||||
std::string version;
|
||||
std::string url;
|
||||
std::vector<std::string> packages;
|
||||
};
|
||||
|
||||
@@ -55,19 +56,37 @@ struct Target {
|
||||
std::string name;
|
||||
TargetType type = {};
|
||||
|
||||
// https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#project-commands
|
||||
ConditionVector compile_definitions;
|
||||
ConditionVector compile_features;
|
||||
ConditionVector compile_options;
|
||||
ConditionVector include_directories;
|
||||
ConditionVector link_directories;
|
||||
ConditionVector link_libraries;
|
||||
ConditionVector link_options;
|
||||
ConditionVector precompile_headers;
|
||||
ConditionVector headers;
|
||||
ConditionVector sources;
|
||||
|
||||
// https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#project-commands
|
||||
ConditionVector compile_definitions;
|
||||
ConditionVector private_compile_definitions;
|
||||
|
||||
ConditionVector compile_features;
|
||||
ConditionVector private_compile_features;
|
||||
|
||||
ConditionVector compile_options;
|
||||
ConditionVector private_compile_options;
|
||||
|
||||
ConditionVector include_directories;
|
||||
ConditionVector private_include_directories;
|
||||
|
||||
ConditionVector link_directories;
|
||||
ConditionVector private_link_directories;
|
||||
|
||||
ConditionVector link_libraries;
|
||||
ConditionVector private_link_libraries;
|
||||
|
||||
ConditionVector link_options;
|
||||
ConditionVector private_link_options;
|
||||
|
||||
ConditionVector precompile_headers;
|
||||
ConditionVector private_precompile_headers;
|
||||
|
||||
std::string condition;
|
||||
std::string alias;
|
||||
tsl::ordered_map<std::string, std::string> properties;
|
||||
Condition<tsl::ordered_map<std::string, std::string>> properties;
|
||||
|
||||
Condition<std::string> cmake_before;
|
||||
Condition<std::string> cmake_after;
|
||||
@@ -91,14 +110,23 @@ struct Install {
|
||||
std::string destination;
|
||||
};
|
||||
|
||||
struct CMake {
|
||||
struct Subdir {
|
||||
std::string name;
|
||||
std::string condition;
|
||||
Condition<std::string> cmake_before;
|
||||
Condition<std::string> cmake_after;
|
||||
ConditionVector include_before;
|
||||
ConditionVector include_after;
|
||||
};
|
||||
|
||||
struct Project {
|
||||
// This is the CMake version required to use all cmkr versions.
|
||||
std::string cmake_version = "3.15";
|
||||
std::string cmkr_include = "cmkr.cmake";
|
||||
std::string build_dir = "build";
|
||||
std::string generator;
|
||||
std::string config;
|
||||
Condition<std::vector<std::string>> subdirs;
|
||||
Condition<std::vector<std::string>> project_subdirs;
|
||||
std::vector<std::string> cppflags;
|
||||
std::vector<std::string> cflags;
|
||||
std::vector<std::string> linkflags;
|
||||
@@ -121,9 +149,12 @@ struct CMake {
|
||||
std::vector<Test> tests;
|
||||
std::vector<Install> installs;
|
||||
tsl::ordered_map<std::string, std::string> conditions;
|
||||
std::vector<Subdir> subdirs;
|
||||
|
||||
CMake(const std::string &path, bool build);
|
||||
Project(const std::string &path, bool build);
|
||||
};
|
||||
|
||||
} // namespace cmake
|
||||
bool is_root_path(const std::string &path);
|
||||
|
||||
} // namespace parser
|
||||
} // namespace cmkr
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "args.hpp"
|
||||
#include "arguments.hpp"
|
||||
#include "build.hpp"
|
||||
#include "gen.hpp"
|
||||
#include "cmake_generator.hpp"
|
||||
#include "help.hpp"
|
||||
|
||||
#include "fs.hpp"
|
||||
+19
-19
@@ -1,7 +1,7 @@
|
||||
#include "build.hpp"
|
||||
#include "cmake.hpp"
|
||||
#include "project_parser.hpp"
|
||||
#include "error.hpp"
|
||||
#include "gen.hpp"
|
||||
#include "cmake_generator.hpp"
|
||||
|
||||
#include "fs.hpp"
|
||||
#include <sstream>
|
||||
@@ -14,10 +14,10 @@ namespace cmkr {
|
||||
namespace build {
|
||||
|
||||
int run(int argc, char **argv) {
|
||||
cmake::CMake cmake(".", true);
|
||||
parser::Project project(".", true);
|
||||
if (argc > 2) {
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
cmake.build_args.push_back(argv[i]);
|
||||
project.build_args.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
std::stringstream ss;
|
||||
@@ -25,22 +25,22 @@ int run(int argc, char **argv) {
|
||||
if (gen::generate_cmake(fs::current_path().string().c_str()))
|
||||
throw std::runtime_error("CMake generation failure!");
|
||||
|
||||
ss << "cmake -S. -B" << cmake.build_dir << " ";
|
||||
ss << "cmake -S. -B" << project.build_dir << " ";
|
||||
|
||||
if (!cmake.generator.empty()) {
|
||||
ss << "-G \"" << cmake.generator << "\" ";
|
||||
if (!project.generator.empty()) {
|
||||
ss << "-G \"" << project.generator << "\" ";
|
||||
}
|
||||
if (!cmake.config.empty()) {
|
||||
ss << "-DCMAKE_BUILD_TYPE=" << cmake.config << " ";
|
||||
if (!project.config.empty()) {
|
||||
ss << "-DCMAKE_BUILD_TYPE=" << project.config << " ";
|
||||
}
|
||||
if (!cmake.gen_args.empty()) {
|
||||
for (const auto &arg : cmake.gen_args) {
|
||||
if (!project.gen_args.empty()) {
|
||||
for (const auto &arg : project.gen_args) {
|
||||
ss << "-D" << arg << " ";
|
||||
}
|
||||
}
|
||||
ss << "&& cmake --build " << cmake.build_dir << " --parallel";
|
||||
ss << "&& cmake --build " << project.build_dir << " --parallel";
|
||||
if (argc > 2) {
|
||||
for (const auto &arg : cmake.build_args) {
|
||||
for (const auto &arg : project.build_args) {
|
||||
ss << " " << arg;
|
||||
}
|
||||
}
|
||||
@@ -50,17 +50,17 @@ int run(int argc, char **argv) {
|
||||
|
||||
int clean() {
|
||||
bool ret = false;
|
||||
cmake::CMake cmake(".", true);
|
||||
if (fs::exists(cmake.build_dir)) {
|
||||
ret = fs::remove_all(cmake.build_dir);
|
||||
fs::create_directory(cmake.build_dir);
|
||||
parser::Project project(".", true);
|
||||
if (fs::exists(project.build_dir)) {
|
||||
ret = fs::remove_all(project.build_dir);
|
||||
fs::create_directory(project.build_dir);
|
||||
}
|
||||
return !ret;
|
||||
}
|
||||
|
||||
int install() {
|
||||
cmake::CMake cmake(".", false);
|
||||
auto cmd = "cmake --install " + cmake.build_dir;
|
||||
parser::Project project(".", false);
|
||||
auto cmd = "cmake --install " + project.build_dir;
|
||||
return ::system(cmd.c_str());
|
||||
}
|
||||
} // namespace build
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#include "gen.hpp"
|
||||
#include "cmake.hpp"
|
||||
#include "cmake_generator.hpp"
|
||||
#include "error.hpp"
|
||||
#include "literals.hpp"
|
||||
#include "project_parser.hpp"
|
||||
|
||||
#include "fs.hpp"
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <new>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -155,12 +158,14 @@ struct Command {
|
||||
bool first_arg = true;
|
||||
bool had_newline = false;
|
||||
bool generated = false;
|
||||
std::string post_comment;
|
||||
|
||||
Command(std::stringstream &ss, int depth, const std::string &command) : ss(ss), depth(depth), command(command) {}
|
||||
Command(std::stringstream &ss, int depth, std::string command, std::string post_comment)
|
||||
: ss(ss), depth(depth), command(std::move(command)), post_comment(std::move(post_comment)) {}
|
||||
|
||||
~Command() {
|
||||
if (!generated) {
|
||||
assert(false && "Incorrect usage of cmd()");
|
||||
assert(false && "Incorrect usage of cmd(), you probably forgot ()");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +305,11 @@ struct Command {
|
||||
(void)std::initializer_list<bool>{print_arg(values)...};
|
||||
if (had_newline)
|
||||
ss << '\n' << indent(depth);
|
||||
ss << ")\n";
|
||||
ss << ")";
|
||||
if (!post_comment.empty()) {
|
||||
ss << " # " << post_comment;
|
||||
}
|
||||
ss << "\n";
|
||||
return CommandEndl(ss);
|
||||
}
|
||||
};
|
||||
@@ -316,25 +325,25 @@ static std::string tolf(const std::string &str) {
|
||||
};
|
||||
|
||||
struct Generator {
|
||||
Generator(cmake::CMake &cmake) : cmake(cmake) {}
|
||||
Generator(parser::Project &project) : project(project) {}
|
||||
Generator(const Generator &) = delete;
|
||||
|
||||
cmake::CMake &cmake;
|
||||
parser::Project &project;
|
||||
std::stringstream ss;
|
||||
int indent = 0;
|
||||
|
||||
Command cmd(const std::string &command) {
|
||||
Command cmd(const std::string &command, const std::string &post_comment = "") {
|
||||
if (command.empty())
|
||||
throw std::invalid_argument("command cannot be empty");
|
||||
if (command == "if") {
|
||||
indent++;
|
||||
return Command(ss, indent - 1, command);
|
||||
return Command(ss, indent - 1, command, post_comment);
|
||||
} else if (command == "else" || command == "elseif") {
|
||||
return Command(ss, indent - 1, command);
|
||||
return Command(ss, indent - 1, command, post_comment);
|
||||
} else if (command == "endif") {
|
||||
indent--;
|
||||
}
|
||||
return Command(ss, indent, command);
|
||||
return Command(ss, indent, command, post_comment);
|
||||
}
|
||||
|
||||
CommandEndl comment(const std::string &comment) {
|
||||
@@ -378,16 +387,16 @@ struct Generator {
|
||||
}
|
||||
|
||||
template <typename T, typename Lambda>
|
||||
void handle_condition(const cmake::Condition<T> &value, const Lambda &fn) {
|
||||
void handle_condition(const parser::Condition<T> &value, const Lambda &fn) {
|
||||
if (!value.empty()) {
|
||||
for (const auto &itr : value) {
|
||||
const auto &condition = itr.first;
|
||||
if (!condition.empty()) {
|
||||
if (cmake.conditions.count(condition) == 0) {
|
||||
if (project.conditions.count(condition) == 0) {
|
||||
// TODO: somehow print line number information here?
|
||||
throw std::runtime_error("Unknown condition '" + condition + "'");
|
||||
}
|
||||
cmd("if")(RawArg(cmake.conditions[condition]));
|
||||
cmd("if", condition)(RawArg(project.conditions[condition]));
|
||||
}
|
||||
|
||||
if (!itr.second.empty()) {
|
||||
@@ -403,28 +412,54 @@ struct Generator {
|
||||
}
|
||||
};
|
||||
|
||||
static std::string vcpkg_escape_identifier(const std::string &name) {
|
||||
// Do a reasonable effort to escape the project name for use with vcpkg
|
||||
std::string escaped;
|
||||
for (char ch : name) {
|
||||
if ((ch & 0x80) != 0) {
|
||||
throw std::runtime_error("Non-ASCII characters are not allowed in [project].name when using [vcpkg]");
|
||||
}
|
||||
|
||||
if (ch == '_' || ch == ' ') {
|
||||
ch = '-';
|
||||
}
|
||||
|
||||
escaped += std::tolower(ch);
|
||||
}
|
||||
|
||||
const std::regex reserved("prn|aux|nul|con|lpt[1-9]|com[1-9]|core|default");
|
||||
const std::regex ok("[a-z0-9]+(-[a-z0-9]+)*");
|
||||
std::cmatch m;
|
||||
if (!std::regex_match(escaped.c_str(), m, reserved) && std::regex_match(escaped.c_str(), m, ok)) {
|
||||
return escaped;
|
||||
} else {
|
||||
throw std::runtime_error("The escaped project name '" + escaped + "' is not usable with [vcpkg]");
|
||||
}
|
||||
}
|
||||
|
||||
int generate_cmake(const char *path, bool root) {
|
||||
if (!fs::exists(fs::path(path) / "cmake.toml")) {
|
||||
throw std::runtime_error("No cmake.toml found!");
|
||||
}
|
||||
|
||||
cmake::CMake cmake(path, false);
|
||||
Generator gen(cmake);
|
||||
parser::Project project(path, false);
|
||||
Generator gen(project);
|
||||
|
||||
// Helper lambdas for more convenient CMake generation
|
||||
auto &ss = gen.ss;
|
||||
auto cmd = [&gen](const std::string &comment) { return gen.cmd(comment); };
|
||||
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 inject_includes = [&gen](const std::vector<std::string> &includes) { gen.inject_includes(includes); };
|
||||
auto inject_cmake = [&gen](const std::string &cmake) { gen.inject_cmake(cmake); };
|
||||
|
||||
std::string cmkr_url = "https://github.com/build-cpp/cmkr";
|
||||
comment("This file is automatically generated from cmake.toml - DO NOT EDIT");
|
||||
comment("See https://github.com/build-cpp/cmkr for more information");
|
||||
comment("See " + cmkr_url + " for more information");
|
||||
endl();
|
||||
|
||||
if (root) {
|
||||
cmd("cmake_minimum_required")("VERSION", cmake.cmake_version).endl();
|
||||
cmd("cmake_minimum_required")("VERSION", project.cmake_version).endl();
|
||||
|
||||
comment("Regenerate CMakeLists.txt automatically in the root project");
|
||||
cmd("set")("CMKR_ROOT_PROJECT", "OFF");
|
||||
@@ -433,7 +468,7 @@ int generate_cmake(const char *path, bool root) {
|
||||
cmd("set")("CMKR_ROOT_PROJECT", "ON").endl();
|
||||
|
||||
comment("Bootstrap cmkr");
|
||||
cmd("include")(cmake.cmkr_include, "OPTIONAL", "RESULT_VARIABLE", "CMKR_INCLUDE_RESULT");
|
||||
cmd("include")(project.cmkr_include, "OPTIONAL", "RESULT_VARIABLE", "CMKR_INCLUDE_RESULT");
|
||||
cmd("if")("CMKR_INCLUDE_RESULT");
|
||||
cmd("cmkr")();
|
||||
cmd("endif")().endl();
|
||||
@@ -452,48 +487,48 @@ int generate_cmake(const char *path, bool root) {
|
||||
// clang-format on
|
||||
|
||||
// TODO: remove support and replace with global compile-features
|
||||
if (!cmake.cppflags.empty()) {
|
||||
if (!project.cppflags.empty()) {
|
||||
ss << "set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} \"";
|
||||
for (const auto &flag : cmake.cppflags) {
|
||||
for (const auto &flag : project.cppflags) {
|
||||
ss << flag << " ";
|
||||
}
|
||||
ss << "\")\n\n";
|
||||
}
|
||||
|
||||
// TODO: remove support and replace with global compile-features
|
||||
if (!cmake.cflags.empty()) {
|
||||
if (!project.cflags.empty()) {
|
||||
ss << "set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} \"";
|
||||
for (const auto &flag : cmake.cflags) {
|
||||
for (const auto &flag : project.cflags) {
|
||||
ss << flag << " ";
|
||||
}
|
||||
ss << "\")\n\n";
|
||||
}
|
||||
|
||||
// TODO: remove support and replace with global linker-flags
|
||||
if (!cmake.linkflags.empty()) {
|
||||
if (!project.linkflags.empty()) {
|
||||
ss << "set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} \"";
|
||||
for (const auto &flag : cmake.linkflags) {
|
||||
for (const auto &flag : project.linkflags) {
|
||||
ss << flag << " ";
|
||||
}
|
||||
ss << "\")\n\n";
|
||||
}
|
||||
|
||||
gen.handle_condition(cmake.include_before, [&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
||||
gen.handle_condition(cmake.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
||||
gen.handle_condition(project.include_before, [&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
||||
gen.handle_condition(project.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
||||
|
||||
if (!cmake.project_name.empty()) {
|
||||
auto languages = std::make_pair("LANGUAGES", cmake.project_languages);
|
||||
auto version = std::make_pair("VERSION", cmake.project_version);
|
||||
auto description = std::make_pair("DESCRIPTION", cmake.project_description);
|
||||
cmd("project")(cmake.project_name, languages, version, description).endl();
|
||||
if (!project.project_name.empty()) {
|
||||
auto languages = std::make_pair("LANGUAGES", project.project_languages);
|
||||
auto version = std::make_pair("VERSION", project.project_version);
|
||||
auto description = std::make_pair("DESCRIPTION", project.project_description);
|
||||
cmd("project")(project.project_name, languages, version, description).endl();
|
||||
}
|
||||
|
||||
gen.handle_condition(cmake.include_after, [&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
||||
gen.handle_condition(cmake.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
||||
gen.handle_condition(project.include_after, [&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
||||
gen.handle_condition(project.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
||||
|
||||
if (!cmake.contents.empty()) {
|
||||
if (!project.contents.empty()) {
|
||||
cmd("include")("FetchContent").endl();
|
||||
for (const auto &dep : cmake.contents) {
|
||||
for (const auto &dep : project.contents) {
|
||||
cmd("message")("STATUS", "Fetching " + dep.first + "...");
|
||||
ss << "FetchContent_Declare(\n\t" << dep.first << "\n";
|
||||
for (const auto &arg : dep.second) {
|
||||
@@ -520,20 +555,51 @@ int generate_cmake(const char *path, bool root) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmake.vcpkg.version.empty()) {
|
||||
assert("pmm is required in fetch-content for vcpkg to work" && cmake.contents.count("pmm") != 0);
|
||||
comment("Bootstrap vcpkg");
|
||||
cmd("include")("${pmm_SOURCE_DIR}/pmm.cmake");
|
||||
tsl::ordered_map<std::string, std::vector<std::string>> vcpkg_args;
|
||||
vcpkg_args["REVISION"] = {cmake.vcpkg.version};
|
||||
vcpkg_args["REQUIRES"] = cmake.vcpkg.packages;
|
||||
auto vcpkg = std::make_pair("VCPKG", vcpkg_args);
|
||||
cmd("pmm")(vcpkg).endl();
|
||||
if (!project.vcpkg.packages.empty()) {
|
||||
// Allow the user to specify a url or derive it from the version
|
||||
auto url = project.vcpkg.url;
|
||||
if (url.empty()) {
|
||||
if (project.vcpkg.version.empty()) {
|
||||
throw std::runtime_error("You need either [vcpkg].version or [vcpkg].url");
|
||||
}
|
||||
url = "https://github.com/microsoft/vcpkg/archive/refs/tags/" + project.vcpkg.version + ".tar.gz";
|
||||
}
|
||||
|
||||
// CMake to bootstrap vcpkg and download the packages
|
||||
// clang-format off
|
||||
cmd("if")("CMKR_ROOT_PROJECT", "AND", "NOT", "CMKR_DISABLE_VCPKG");
|
||||
cmd("include")("FetchContent");
|
||||
cmd("message")("STATUS", "Fetching vcpkg...");
|
||||
cmd("FetchContent_Declare")("vcpkg", "URL", url);
|
||||
cmd("FetchContent_MakeAvailable")("vcpkg");
|
||||
cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
|
||||
cmd("endif")();
|
||||
endl();
|
||||
// clang-format on
|
||||
|
||||
// Generate vcpkg.json
|
||||
using namespace nlohmann;
|
||||
json j;
|
||||
j["$cmkr"] = "This file is automatically generated from cmake.toml - DO NOT EDIT";
|
||||
j["$cmkr-url"] = cmkr_url;
|
||||
j["$schema"] = "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json";
|
||||
j["name"] = vcpkg_escape_identifier(project.project_name);
|
||||
j["version-string"] = project.project_version;
|
||||
j["dependencies"] = project.vcpkg.packages;
|
||||
if (!project.project_description.empty()) {
|
||||
j["description"] = project.project_description;
|
||||
}
|
||||
|
||||
std::ofstream ofs("vcpkg.json");
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("Failed to create a vcpkg.json manifest file!");
|
||||
}
|
||||
ofs << std::setw(2) << j << std::endl;
|
||||
}
|
||||
|
||||
if (!cmake.packages.empty()) {
|
||||
if (!project.packages.empty()) {
|
||||
comment("Packages");
|
||||
for (const auto &dep : cmake.packages) {
|
||||
for (const auto &dep : project.packages) {
|
||||
auto version = dep.version;
|
||||
if (version == "*")
|
||||
version.clear();
|
||||
@@ -544,17 +610,17 @@ int generate_cmake(const char *path, bool root) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmake.options.empty()) {
|
||||
if (!project.options.empty()) {
|
||||
comment("Options");
|
||||
for (const auto &opt : cmake.options) {
|
||||
for (const auto &opt : project.options) {
|
||||
cmd("option")(opt.name, opt.comment, opt.val ? "ON" : "OFF");
|
||||
}
|
||||
endl();
|
||||
}
|
||||
|
||||
if (!cmake.settings.empty()) {
|
||||
if (!project.settings.empty()) {
|
||||
comment("Settings");
|
||||
for (const auto &set : cmake.settings) {
|
||||
for (const auto &set : project.settings) {
|
||||
std::string set_val;
|
||||
if (set.val.index() == 1) {
|
||||
set_val = mpark::get<1>(set.val);
|
||||
@@ -573,30 +639,65 @@ int generate_cmake(const char *path, bool root) {
|
||||
endl();
|
||||
}
|
||||
|
||||
// generate_cmake is called on the subdirectories recursively later
|
||||
if (!cmake.subdirs.empty()) {
|
||||
gen.handle_condition(cmake.subdirs, [&](const std::string &, const std::vector<std::string> &subdirs) {
|
||||
for (const auto &dir : subdirs) {
|
||||
// clang-format off
|
||||
comment(dir);
|
||||
cmd("set")("CMKR_CMAKE_FOLDER", "${CMAKE_FOLDER}");
|
||||
cmd("if")("CMAKE_FOLDER");
|
||||
cmd("set")("CMAKE_FOLDER", "${CMAKE_FOLDER}/" + dir);
|
||||
cmd("else")();
|
||||
cmd("set")("CMAKE_FOLDER", dir);
|
||||
cmd("endif")();
|
||||
// clang-format on
|
||||
auto add_subdir = [&](const std::string &dir) {
|
||||
// clang-format off
|
||||
comment(dir);
|
||||
cmd("set")("CMKR_CMAKE_FOLDER", "${CMAKE_FOLDER}");
|
||||
cmd("if")("CMAKE_FOLDER");
|
||||
cmd("set")("CMAKE_FOLDER", "${CMAKE_FOLDER}/" + dir);
|
||||
cmd("else")();
|
||||
cmd("set")("CMAKE_FOLDER", dir);
|
||||
cmd("endif")();
|
||||
// clang-format on
|
||||
|
||||
cmd("add_subdirectory")(dir);
|
||||
cmd("set")("CMAKE_FOLDER", "${CMKR_CMAKE_FOLDER}").endl();
|
||||
cmd("add_subdirectory")(dir);
|
||||
cmd("set")("CMAKE_FOLDER", "${CMKR_CMAKE_FOLDER}").endl();
|
||||
};
|
||||
|
||||
// generate_cmake is called on the subdirectories recursively later
|
||||
if (!project.project_subdirs.empty()) {
|
||||
gen.handle_condition(project.project_subdirs, [&](const std::string &, const std::vector<std::string> &subdirs) {
|
||||
for (const auto &dir : subdirs) {
|
||||
add_subdir(dir);
|
||||
}
|
||||
});
|
||||
endl();
|
||||
}
|
||||
for (const auto &subdir : project.subdirs) {
|
||||
if (!subdir.condition.empty()) {
|
||||
const auto &condition = subdir.condition;
|
||||
if (project.conditions.count(condition) == 0) {
|
||||
throw std::runtime_error("Unknown condition '" + condition + "' for [subdir." + subdir.name + "]");
|
||||
}
|
||||
gen.cmd("if", condition)(RawArg(project.conditions[condition]));
|
||||
}
|
||||
|
||||
if (!cmake.targets.empty()) {
|
||||
for (const auto &target : cmake.targets) {
|
||||
gen.handle_condition(subdir.include_before,
|
||||
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
||||
gen.handle_condition(subdir.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
||||
|
||||
add_subdir(subdir.name);
|
||||
|
||||
gen.handle_condition(subdir.include_after, [&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
||||
gen.handle_condition(subdir.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
||||
|
||||
if (!subdir.condition.empty()) {
|
||||
cmd("endif")();
|
||||
}
|
||||
}
|
||||
|
||||
if (!project.targets.empty()) {
|
||||
for (const auto &target : project.targets) {
|
||||
comment("Target " + target.name);
|
||||
|
||||
if (!target.condition.empty()) {
|
||||
const auto &condition = target.condition;
|
||||
if (project.conditions.count(condition) == 0) {
|
||||
throw std::runtime_error("Unknown condition '" + condition + "' for [target." + target.name + "]");
|
||||
}
|
||||
gen.cmd("if", condition)(RawArg(project.conditions[condition]));
|
||||
}
|
||||
|
||||
cmd("set")("CMKR_TARGET", target.name);
|
||||
|
||||
gen.handle_condition(target.include_before,
|
||||
@@ -620,7 +721,7 @@ int generate_cmake(const char *path, bool root) {
|
||||
cmd("list")("APPEND", sources_var, sources);
|
||||
});
|
||||
|
||||
if (!added_toml && target.type != cmake::target_interface) {
|
||||
if (!added_toml && target.type != parser::target_interface) {
|
||||
cmd("list")("APPEND", sources_var, std::vector<std::string>{"cmake.toml"}).endl();
|
||||
}
|
||||
cmd("set")("CMKR_SOURCES", "${" + sources_var + "}");
|
||||
@@ -629,32 +730,32 @@ int generate_cmake(const char *path, bool root) {
|
||||
std::string target_type;
|
||||
std::string target_scope;
|
||||
switch (target.type) {
|
||||
case cmake::target_executable:
|
||||
case parser::target_executable:
|
||||
add_command = "add_executable";
|
||||
target_type = "";
|
||||
target_scope = "PRIVATE";
|
||||
break;
|
||||
case cmake::target_library:
|
||||
case parser::target_library:
|
||||
add_command = "add_library";
|
||||
target_type = "";
|
||||
target_scope = "PUBLIC";
|
||||
break;
|
||||
case cmake::target_shared:
|
||||
case parser::target_shared:
|
||||
add_command = "add_library";
|
||||
target_type = "SHARED";
|
||||
target_scope = "PUBLIC";
|
||||
break;
|
||||
case cmake::target_static:
|
||||
case parser::target_static:
|
||||
add_command = "add_library";
|
||||
target_type = "STATIC";
|
||||
target_scope = "PUBLIC";
|
||||
break;
|
||||
case cmake::target_interface:
|
||||
case parser::target_interface:
|
||||
add_command = "add_library";
|
||||
target_type = "INTERFACE";
|
||||
target_scope = "INTERFACE";
|
||||
break;
|
||||
case cmake::target_custom:
|
||||
case parser::target_custom:
|
||||
// TODO: add proper support, this is hacky
|
||||
add_command = "add_custom_target";
|
||||
target_type = "SOURCES";
|
||||
@@ -668,12 +769,12 @@ int generate_cmake(const char *path, bool root) {
|
||||
|
||||
// clang-format off
|
||||
cmd("if")(sources_var);
|
||||
cmd("target_sources")(target.name, target.type == cmake::target_interface ? "INTERFACE" : "PRIVATE", "${" + sources_var + "}");
|
||||
cmd("target_sources")(target.name, target.type == parser::target_interface ? "INTERFACE" : "PRIVATE", "${" + sources_var + "}");
|
||||
cmd("endif")().endl();
|
||||
// clang-format on
|
||||
|
||||
// The first executable target will become the Visual Studio startup project
|
||||
if (target.type == cmake::target_executable) {
|
||||
if (target.type == parser::target_executable) {
|
||||
cmd("get_directory_property")("CMKR_VS_STARTUP_PROJECT", "DIRECTORY", "${PROJECT_SOURCE_DIR}", "DEFINITION", "VS_STARTUP_PROJECT");
|
||||
// clang-format off
|
||||
cmd("if")("NOT", "CMKR_VS_STARTUP_PROJECT");
|
||||
@@ -683,29 +784,46 @@ int generate_cmake(const char *path, bool root) {
|
||||
}
|
||||
|
||||
if (!target.sources.empty()) {
|
||||
cmd("source_group")("TREE", "${CMAKE_CURRENT_SOURCE_DIR}", "FILES", "${" + target.name + "_SOURCES}").endl();
|
||||
cmd("source_group")("TREE", "${CMAKE_CURRENT_SOURCE_DIR}", "FILES", "${" + sources_var + "}").endl();
|
||||
}
|
||||
|
||||
if (!target.alias.empty()) {
|
||||
cmd("add_library")(target.alias, "ALIAS", target.name);
|
||||
}
|
||||
|
||||
auto target_cmd = [&](const char *command, const cmake::ConditionVector &cargs) {
|
||||
gen.handle_condition(
|
||||
cargs, [&](const std::string &, const std::vector<std::string> &args) { cmd(command)(target.name, target_scope, args); });
|
||||
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); });
|
||||
};
|
||||
|
||||
target_cmd("target_compile_definitions", target.compile_definitions);
|
||||
target_cmd("target_compile_features", target.compile_features);
|
||||
target_cmd("target_compile_options", target.compile_options);
|
||||
target_cmd("target_include_directories", target.include_directories);
|
||||
target_cmd("target_link_directories", target.link_directories);
|
||||
target_cmd("target_link_libraries", target.link_libraries);
|
||||
target_cmd("target_link_options", target.link_options);
|
||||
target_cmd("target_precompile_headers", target.precompile_headers);
|
||||
target_cmd("target_compile_definitions", target.compile_definitions, target_scope);
|
||||
target_cmd("target_compile_definitions", target.private_compile_definitions, "PRIVATE");
|
||||
|
||||
target_cmd("target_compile_features", target.compile_features, target_scope);
|
||||
target_cmd("target_compile_features", target.private_compile_features, "PRIVATE");
|
||||
|
||||
target_cmd("target_compile_options", target.compile_options, target_scope);
|
||||
target_cmd("target_compile_options", target.private_compile_options, "PRIVATE");
|
||||
|
||||
target_cmd("target_include_directories", target.include_directories, target_scope);
|
||||
target_cmd("target_include_directories", target.private_include_directories, "PRIVATE");
|
||||
|
||||
target_cmd("target_link_directories", target.link_directories, target_scope);
|
||||
target_cmd("target_link_directories", target.private_link_directories, "PRIVATE");
|
||||
|
||||
target_cmd("target_link_libraries", target.link_libraries, target_scope);
|
||||
target_cmd("target_link_libraries", target.private_link_libraries, "PRIVATE");
|
||||
|
||||
target_cmd("target_link_options", target.link_options, target_scope);
|
||||
target_cmd("target_link_options", target.private_link_options, "PRIVATE");
|
||||
|
||||
target_cmd("target_precompile_headers", target.precompile_headers, target_scope);
|
||||
target_cmd("target_precompile_headers", target.private_precompile_headers, "PRIVATE");
|
||||
|
||||
if (!target.properties.empty()) {
|
||||
cmd("set_target_properties")(target.name, "PROPERTIES", target.properties).endl();
|
||||
gen.handle_condition(target.properties, [&](const std::string &, const tsl::ordered_map<std::string, std::string> &properties) {
|
||||
cmd("set_target_properties")(target.name, "PROPERTIES", properties);
|
||||
});
|
||||
}
|
||||
|
||||
gen.handle_condition(target.include_after,
|
||||
@@ -714,12 +832,18 @@ int generate_cmake(const char *path, bool root) {
|
||||
|
||||
cmd("unset")("CMKR_TARGET");
|
||||
cmd("unset")("CMKR_SOURCES");
|
||||
|
||||
if (!target.condition.empty()) {
|
||||
cmd("endif")();
|
||||
}
|
||||
|
||||
endl();
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmake.tests.empty()) {
|
||||
if (!project.tests.empty()) {
|
||||
cmd("enable_testing")().endl();
|
||||
for (const auto &test : cmake.tests) {
|
||||
for (const auto &test : project.tests) {
|
||||
auto name = std::make_pair("NAME", test.name);
|
||||
auto configurations = std::make_pair("CONFIGURATIONS", test.configurations);
|
||||
auto dir = test.working_directory;
|
||||
@@ -733,8 +857,8 @@ int generate_cmake(const char *path, bool root) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmake.installs.empty()) {
|
||||
for (const auto &inst : cmake.installs) {
|
||||
if (!project.installs.empty()) {
|
||||
for (const auto &inst : project.installs) {
|
||||
auto targets = std::make_pair("TARGETS", inst.targets);
|
||||
auto dirs = std::make_pair("DIRS", inst.dirs);
|
||||
std::vector<std::string> files_data;
|
||||
@@ -777,12 +901,28 @@ int generate_cmake(const char *path, bool root) {
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &itr : cmake.subdirs) {
|
||||
for (const auto &sub : itr.second) {
|
||||
auto subpath = fs::path(path) / fs::path(sub);
|
||||
if (fs::exists(subpath / "cmake.toml"))
|
||||
generate_cmake(subpath.string().c_str(), false);
|
||||
auto generate_subdir = [path](const fs::path &sub) {
|
||||
// Skip generating for subdirectories that have a cmake.toml with a [project] in it
|
||||
fs::path subpath;
|
||||
for (const auto &p : sub) {
|
||||
subpath /= p;
|
||||
if (parser::is_root_path(subpath.string())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
subpath = path / sub;
|
||||
if (fs::exists(subpath / "cmake.toml")) {
|
||||
generate_cmake(subpath.string().c_str(), false);
|
||||
}
|
||||
};
|
||||
for (const auto &itr : project.project_subdirs) {
|
||||
for (const auto &sub : itr.second) {
|
||||
generate_subdir(sub);
|
||||
}
|
||||
}
|
||||
for (const auto &subdir : project.subdirs) {
|
||||
generate_subdir(subdir.name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#include "args.hpp"
|
||||
#include "arguments.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "cmake.hpp"
|
||||
#include "project_parser.hpp"
|
||||
|
||||
#include "enum_helper.hpp"
|
||||
#include "fs.hpp"
|
||||
@@ -7,10 +7,10 @@
|
||||
#include <tsl/ordered_map.h>
|
||||
|
||||
template <>
|
||||
const char *enumStrings<cmkr::cmake::TargetType>::data[] = {"executable", "library", "shared", "static", "interface", "custom"};
|
||||
const char *enumStrings<cmkr::parser::TargetType>::data[] = {"executable", "library", "shared", "static", "interface", "custom"};
|
||||
|
||||
namespace cmkr {
|
||||
namespace cmake {
|
||||
namespace parser {
|
||||
|
||||
using TomlBasicValue = toml::basic_value<toml::preserve_comments, tsl::ordered_map, std::vector>;
|
||||
|
||||
@@ -61,11 +61,12 @@ static void get_optional(const TomlBasicValue &v, const toml::key &ky, T &destin
|
||||
}
|
||||
}
|
||||
|
||||
CMake::CMake(const std::string &path, bool build) {
|
||||
if (!fs::exists(fs::path(path) / "cmake.toml")) {
|
||||
Project::Project(const std::string &path, bool build) {
|
||||
const auto toml_path = fs::path(path) / "cmake.toml";
|
||||
if (!fs::exists(toml_path)) {
|
||||
throw std::runtime_error("No cmake.toml was found!");
|
||||
}
|
||||
const auto toml = toml::parse<toml::preserve_comments, tsl::ordered_map, std::vector>((fs::path(path) / "cmake.toml").string());
|
||||
const auto toml = toml::parse<toml::preserve_comments, tsl::ordered_map, std::vector>(toml_path.string());
|
||||
if (build) {
|
||||
if (toml.contains("cmake")) {
|
||||
const auto &cmake = toml::find(toml, "cmake");
|
||||
@@ -99,7 +100,21 @@ CMake::CMake(const std::string &path, bool build) {
|
||||
get_optional(project, "cmake-after", cmake_after);
|
||||
get_optional(project, "include-before", include_before);
|
||||
get_optional(project, "include-after", include_after);
|
||||
get_optional(project, "subdirs", subdirs);
|
||||
get_optional(project, "subdirs", project_subdirs);
|
||||
}
|
||||
|
||||
if (toml.contains("subdir")) {
|
||||
const auto &subs = toml::find(toml, "subdir").as_table();
|
||||
for (const auto &sub : subs) {
|
||||
Subdir subdir;
|
||||
subdir.name = sub.first;
|
||||
get_optional(sub.second, "condition", subdir.condition);
|
||||
get_optional(sub.second, "cmake-before", subdir.cmake_before);
|
||||
get_optional(sub.second, "cmake-after", subdir.cmake_after);
|
||||
get_optional(sub.second, "include-before", subdir.include_before);
|
||||
get_optional(sub.second, "include-after", subdir.include_after);
|
||||
subdirs.push_back(subdir);
|
||||
}
|
||||
}
|
||||
|
||||
if (toml.contains("settings")) {
|
||||
@@ -181,34 +196,75 @@ CMake::CMake(const std::string &path, bool build) {
|
||||
target.name = itr.first;
|
||||
target.type = to_enum<TargetType>(toml::find(t, "type").as_string(), "target type");
|
||||
|
||||
get_optional(t, "headers", target.headers);
|
||||
get_optional(t, "sources", target.sources);
|
||||
|
||||
get_optional(t, "compile-definitions", target.compile_definitions);
|
||||
get_optional(t, "private-compile-definitions", target.private_compile_definitions);
|
||||
|
||||
get_optional(t, "compile-features", target.compile_features);
|
||||
get_optional(t, "private-compile-features", target.private_compile_features);
|
||||
|
||||
get_optional(t, "compile-options", target.compile_options);
|
||||
get_optional(t, "private-compile-options", target.private_compile_options);
|
||||
|
||||
get_optional(t, "include-directories", target.include_directories);
|
||||
get_optional(t, "private-include-directories", target.private_include_directories);
|
||||
|
||||
get_optional(t, "link-directories", target.link_directories);
|
||||
get_optional(t, "private-link-directories", target.private_link_directories);
|
||||
|
||||
get_optional(t, "link-libraries", target.link_libraries);
|
||||
get_optional(t, "private-link-libraries", target.private_link_libraries);
|
||||
|
||||
get_optional(t, "link-options", target.link_options);
|
||||
get_optional(t, "private-link-options", target.private_link_options);
|
||||
|
||||
get_optional(t, "precompile-headers", target.precompile_headers);
|
||||
get_optional(t, "private-precompile-headers", target.private_precompile_headers);
|
||||
|
||||
if (!target.headers.empty()) {
|
||||
auto &sources = target.sources.nth(0).value();
|
||||
const auto &headers = target.headers.nth(0)->second;
|
||||
sources.insert(sources.end(), headers.begin(), headers.end());
|
||||
}
|
||||
|
||||
if (t.contains("condition")) {
|
||||
target.condition = toml::find(t, "condition").as_string();
|
||||
}
|
||||
|
||||
if (t.contains("alias")) {
|
||||
target.alias = toml::find(t, "alias").as_string();
|
||||
}
|
||||
|
||||
if (t.contains("properties")) {
|
||||
const auto &props = toml::find(t, "properties").as_table();
|
||||
for (const auto &propKv : props) {
|
||||
if (propKv.second.is_array()) {
|
||||
auto store_property = [&target](const toml::key &k, const TomlBasicValue &v, const std::string &condition) {
|
||||
if (v.is_array()) {
|
||||
std::string property_list;
|
||||
for (const auto &list_val : propKv.second.as_array()) {
|
||||
for (const auto &list_val : v.as_array()) {
|
||||
if (!property_list.empty()) {
|
||||
property_list += ';';
|
||||
}
|
||||
property_list += list_val.as_string();
|
||||
}
|
||||
target.properties[propKv.first] = property_list;
|
||||
target.properties[condition][k] = property_list;
|
||||
} else if (v.is_boolean()) {
|
||||
target.properties[condition][k] = v.as_boolean() ? "ON" : "OFF";
|
||||
} else {
|
||||
target.properties[propKv.first] = propKv.second.as_string();
|
||||
target.properties[condition][k] = v.as_string();
|
||||
}
|
||||
};
|
||||
|
||||
const auto &props = toml::find(t, "properties").as_table();
|
||||
for (const auto &propKv : props) {
|
||||
const auto &k = propKv.first;
|
||||
const auto &v = propKv.second;
|
||||
if (v.is_table()) {
|
||||
for (const auto &condKv : v.as_table()) {
|
||||
store_property(condKv.first, condKv.second, k);
|
||||
}
|
||||
} else {
|
||||
store_property(k, v, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -250,15 +306,9 @@ CMake::CMake(const std::string &path, bool build) {
|
||||
|
||||
if (toml.contains("vcpkg")) {
|
||||
const auto &v = toml::find(toml, "vcpkg");
|
||||
vcpkg.version = toml::find(v, "version").as_string();
|
||||
get_optional(v, "url", vcpkg.url);
|
||||
get_optional(v, "version", vcpkg.version);
|
||||
vcpkg.packages = toml::find<decltype(vcpkg.packages)>(v, "packages");
|
||||
|
||||
// This allows the user to use a custom pmm version if desired
|
||||
if (contents.count("pmm") == 0) {
|
||||
contents["pmm"]["url"] = "https://github.com/vector-of-bool/pmm/archive/refs/tags/1.5.1.tar.gz";
|
||||
// Hack to not execute pmm's example CMakeLists.txt
|
||||
contents["pmm"]["SOURCE_SUBDIR"] = "pmm";
|
||||
}
|
||||
}
|
||||
|
||||
// Reasonable default conditions (you can override these if you desire)
|
||||
@@ -276,5 +326,15 @@ CMake::CMake(const std::string &path, bool build) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace cmake
|
||||
|
||||
bool is_root_path(const std::string &path) {
|
||||
const auto toml_path = fs::path(path) / "cmake.toml";
|
||||
if (!fs::exists(toml_path)) {
|
||||
return false;
|
||||
}
|
||||
const auto toml = toml::parse<toml::preserve_comments, tsl::ordered_map, std::vector>(toml_path.string());
|
||||
return toml.contains("project");
|
||||
}
|
||||
|
||||
} // namespace parser
|
||||
} // namespace cmkr
|
||||
Generated
+10
@@ -48,3 +48,13 @@ add_test(
|
||||
build
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME
|
||||
vcpkg
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/vcpkg"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
build
|
||||
)
|
||||
|
||||
|
||||
@@ -20,4 +20,10 @@ arguments = ["build"]
|
||||
name = "conditions"
|
||||
command = "$<TARGET_FILE:cmkr>"
|
||||
working-directory = "conditions"
|
||||
arguments = ["build"]
|
||||
|
||||
[[test]]
|
||||
name = "vcpkg"
|
||||
command = "$<TARGET_FILE:cmkr>"
|
||||
working-directory = "vcpkg"
|
||||
arguments = ["build"]
|
||||
@@ -14,4 +14,10 @@ windows.cmake-after = "message(STATUS win32-after)"
|
||||
macos.cmake-after = "message(STATUS macos-after)"
|
||||
linux.cmake-after = "message(STATUS linux-after)"
|
||||
unix.cmake-after = "message(STATUS unix-after)"
|
||||
custom.cmake-after = "message(STATUS custom-after)"
|
||||
custom.cmake-after = "message(STATUS custom-after)"
|
||||
|
||||
[target.example.properties]
|
||||
AUTOMOC = false
|
||||
custom.OUTPUT_NAME = "example2"
|
||||
custom.AUTORCC = true
|
||||
AUTOGEN = "ON"
|
||||
@@ -0,0 +1,21 @@
|
||||
# Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) using [vcpkg](https://vcpkg.io/) and links an `example` target to it:
|
||||
|
||||
[project]
|
||||
name = "vcpkg"
|
||||
description = "Dependencies from vcpkg"
|
||||
|
||||
# See https://github.com/microsoft/vcpkg/releases for vcpkg versions
|
||||
# See https://vcpkg.io/en/packages.html for available packages
|
||||
[vcpkg]
|
||||
version = "2021.05.12"
|
||||
packages = ["fmt"]
|
||||
|
||||
[find-package]
|
||||
fmt = {}
|
||||
|
||||
[target.example]
|
||||
type = "executable"
|
||||
sources = ["src/main.cpp"]
|
||||
link-libraries = ["fmt::fmt"]
|
||||
|
||||
# The bootstrapping of vcpkg is fully automated and no user interaction is necessary. You can disable vcpkg by setting `CMKR_DISABLE_VCPKG=ON`.
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <fmt/core.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
fmt::print("Hello, world!\n");
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$cmkr": "This file is automatically generated from cmake.toml - DO NOT EDIT",
|
||||
"$cmkr-url": "https://github.com/build-cpp/cmkr",
|
||||
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
|
||||
"dependencies": [
|
||||
"fmt"
|
||||
],
|
||||
"description": "Example of using vcpkg",
|
||||
"name": "vcpkg",
|
||||
"version-string": ""
|
||||
}
|
||||
+4
@@ -16,3 +16,7 @@ target_include_directories(toml11 INTERFACE toml11-3.6.0)
|
||||
# https://github.com/mpark/variant (BSL-1.0)
|
||||
add_library(mpark_variant INTERFACE)
|
||||
target_include_directories(mpark_variant INTERFACE variant-1.4.0/include)
|
||||
|
||||
# https://github.com/nlohmann/json (MIT)
|
||||
add_library(nlohmann_json INTERFACE)
|
||||
target_include_directories(nlohmann_json INTERFACE nlohmann-3.9.1/include)
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2021 Niels Lohmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+25447
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user