mirror of
https://github.com/build-cpp/cmkr
synced 2026-06-08 13:22:55 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 153bdbe591 | |||
| 97f1c5c1cc | |||
| 5b6d9c3826 | |||
| a90988b81a | |||
| 3a1298f4e8 | |||
| 534f955827 | |||
| ef537ce084 | |||
| 9cdd0f7344 | |||
| e69cf4d2b9 | |||
| e98a906231 | |||
| 9a82f8c796 | |||
| 13255c68cf | |||
| 5768460827 | |||
| 50d4a905b6 | |||
| f957cec2dc | |||
| 232e49e087 | |||
| 7408d42160 | |||
| 1596a8143d | |||
| 9b0f18ee94 | |||
| 887086dc05 |
+1
-1
@@ -10,7 +10,7 @@ AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
|
||||
Generated
+1
-1
@@ -25,7 +25,7 @@ project(cmkr
|
||||
LANGUAGES
|
||||
CXX
|
||||
VERSION
|
||||
0.2.11
|
||||
0.2.14
|
||||
DESCRIPTION
|
||||
"CMakeLists generator from TOML"
|
||||
)
|
||||
|
||||
@@ -69,3 +69,5 @@ arguments:
|
||||
- https://github.com/ToruNiina/toml11
|
||||
- https://github.com/mpark/variant
|
||||
- https://www.svgrepo.com/svg/192268/hammer
|
||||
- https://github.com/can1357 for buying `cmkr.build` ❤️
|
||||
- https://github.com/JustasMasiulis for fixing the dark theme ❤️
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ cmkr-include = false
|
||||
|
||||
[project]
|
||||
name = "cmkr"
|
||||
version = "0.2.11"
|
||||
version = "0.2.14"
|
||||
description = "CMakeLists generator from TOML"
|
||||
languages = ["CXX"]
|
||||
subdirs = ["third_party", "tests"]
|
||||
|
||||
@@ -46,7 +46,7 @@ endif()
|
||||
|
||||
message(STATUS "Version ${OLDVERSION} -> ${NEWVERSION}")
|
||||
|
||||
find_program(CMKR_EXECUTABLE "cmkr" PATHS "${CMAKE_SOURCE_DIR}/build" 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}")
|
||||
|
||||
# Replace version in cmake.toml
|
||||
|
||||
+22
-5
@@ -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.11" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
set(CMKR_TAG "v0.2.14" 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
|
||||
@@ -58,7 +58,7 @@ else()
|
||||
endif()
|
||||
|
||||
# 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}")
|
||||
string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
|
||||
if(NOT CMKR_DIRECTORY_PREFIX MATCHES "\\/$")
|
||||
@@ -72,10 +72,27 @@ endif()
|
||||
set(CMKR_DIRECTORY "${CMKR_DIRECTORY_PREFIX}${CMKR_TAG}")
|
||||
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
|
||||
if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE)
|
||||
if(CMKR_EXECUTABLE MATCHES "^${CMAKE_CURRENT_BINARY_DIR}/_cmkr")
|
||||
if(DEFINED ENV{CMKR_CACHE} AND EXISTS "$ENV{CMKR_CACHE}")
|
||||
cmkr_startswith("${CMKR_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/_cmkr" CMKR_STARTSWITH_BUILD)
|
||||
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}'")
|
||||
if(EXISTS "${CMKR_CACHED_EXECUTABLE}")
|
||||
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
|
||||
@@ -86,7 +103,7 @@ if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE)
|
||||
message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
||||
unset(CMKR_EXECUTABLE CACHE)
|
||||
endif()
|
||||
elseif(DEFINED ENV{CMKR_CACHE} AND EXISTS "$ENV{CMKR_CACHE}" AND CMKR_EXECUTABLE MATCHES "^${CMKR_DIRECTORY_PREFIX}")
|
||||
elseif(DEFINED ENV{CMKR_CACHE} AND CMKR_STARTSWITH_CACHE)
|
||||
message(AUTHOR_WARNING "[cmkr] Upgrading cached '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
||||
unset(CMKR_EXECUTABLE CACHE)
|
||||
endif()
|
||||
|
||||
+4
-2
@@ -200,7 +200,9 @@ working-directory = "mytest-dir"
|
||||
condition = "mycondition"
|
||||
targets = ["mytarget", "mytest"]
|
||||
destination = ["bin"]
|
||||
component = "mycomponent"
|
||||
files = ["content/my.png"]
|
||||
dirs = [""]
|
||||
configs = [""]
|
||||
dirs = ["include"]
|
||||
configs = ["Release", "Debug"]
|
||||
optional = false
|
||||
```
|
||||
@@ -128,6 +128,7 @@ struct Install {
|
||||
std::vector<std::string> configs;
|
||||
std::string destination;
|
||||
std::string component;
|
||||
bool optional = false;
|
||||
};
|
||||
|
||||
struct Subdir {
|
||||
|
||||
+44
-18
@@ -89,8 +89,24 @@ static void create_file(const fs::path &path, const std::string &contents) {
|
||||
ofs << contents;
|
||||
}
|
||||
|
||||
// CMake target name rules: https://cmake.org/cmake/help/latest/policy/CMP0037.html [A-Za-z0-9_.+\-]
|
||||
// TOML bare keys: non-empty strings composed only of [A-Za-z0-9_-]
|
||||
// We replace all non-TOML bare key characters with _
|
||||
static std::string escape_project_name(const std::string &name) {
|
||||
std::string escaped;
|
||||
escaped.reserve(name.length());
|
||||
for (auto ch : name) {
|
||||
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '-') {
|
||||
escaped += ch;
|
||||
} else {
|
||||
escaped += '_';
|
||||
}
|
||||
}
|
||||
return escaped;
|
||||
}
|
||||
|
||||
void generate_project(const std::string &type) {
|
||||
const auto name = fs::current_path().stem().string();
|
||||
const auto name = escape_project_name(fs::current_path().stem().string());
|
||||
if (fs::exists(fs::current_path() / "cmake.toml")) {
|
||||
throw std::runtime_error("Cannot initialize a project when cmake.toml already exists!");
|
||||
}
|
||||
@@ -126,13 +142,17 @@ void generate_project(const std::string &type) {
|
||||
|
||||
struct CommandEndl {
|
||||
std::stringstream &ss;
|
||||
CommandEndl(std::stringstream &ss) : ss(ss) {}
|
||||
void endl() { ss << '\n'; }
|
||||
CommandEndl(std::stringstream &ss) : ss(ss) {
|
||||
}
|
||||
void endl() {
|
||||
ss << '\n';
|
||||
}
|
||||
};
|
||||
|
||||
struct RawArg {
|
||||
RawArg() = default;
|
||||
RawArg(std::string arg) : arg(std::move(arg)) {}
|
||||
RawArg(std::string arg) : arg(std::move(arg)) {
|
||||
}
|
||||
|
||||
std::string arg;
|
||||
};
|
||||
@@ -148,7 +168,8 @@ struct Command {
|
||||
std::string post_comment;
|
||||
|
||||
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)) {}
|
||||
: ss(ss), depth(depth), command(std::move(command)), post_comment(std::move(post_comment)) {
|
||||
}
|
||||
|
||||
~Command() noexcept(false) {
|
||||
if (!generated) {
|
||||
@@ -162,10 +183,11 @@ struct Command {
|
||||
return "\"\"";
|
||||
}
|
||||
// Don't quote arguments that don't need quoting
|
||||
if (str.find(' ') == std::string::npos && str.find('\"') == std::string::npos && str.find('/') == std::string::npos &&
|
||||
str.find(';') == std::string::npos) {
|
||||
// https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#unquoted-argument
|
||||
// NOTE: Normally '/' does not require quoting according to the documentation but this has been the case here
|
||||
// previously, so for backwards compatibility its still here.
|
||||
if (str.find_first_of("()#\"\\'> |/;") == str.npos)
|
||||
return str;
|
||||
}
|
||||
std::string result;
|
||||
result += "\"";
|
||||
for (char ch : str) {
|
||||
@@ -316,7 +338,8 @@ static std::string tolf(const std::string &str) {
|
||||
};
|
||||
|
||||
struct Generator {
|
||||
Generator(const parser::Project &project) : project(project) {}
|
||||
Generator(const parser::Project &project) : project(project) {
|
||||
}
|
||||
Generator(const Generator &) = delete;
|
||||
|
||||
const parser::Project &project;
|
||||
@@ -342,7 +365,9 @@ struct Generator {
|
||||
return CommandEndl(ss);
|
||||
}
|
||||
|
||||
void endl() { ss << '\n'; }
|
||||
void endl() {
|
||||
ss << '\n';
|
||||
}
|
||||
|
||||
void inject_includes(const std::vector<std::string> &includes) {
|
||||
if (!includes.empty()) {
|
||||
@@ -633,8 +658,12 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
cmd("include")("FetchContent");
|
||||
cmd("message")("STATUS", "Fetching vcpkg (" + version_name + ")...");
|
||||
cmd("FetchContent_Declare")("vcpkg", "URL", url);
|
||||
cmd("FetchContent_MakeAvailable")("vcpkg");
|
||||
cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
|
||||
// Not using FetchContent_MakeAvailable here in case vcpkg adds CMakeLists.txt
|
||||
cmd("FetchContent_GetProperties")("vcpkg");
|
||||
cmd("if")("NOT", "vcpkg_POPULATED");
|
||||
cmd("FetchContent_Populate")("vcpkg");
|
||||
cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
|
||||
cmd("endif")();
|
||||
cmd("endif")();
|
||||
endl();
|
||||
// clang-format on
|
||||
@@ -718,11 +747,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
version_info = " (" + content.arguments.at("SVN_REVISION") + ")";
|
||||
}
|
||||
cmd("message")("STATUS", "Fetching " + content.name + version_info + "...");
|
||||
ss << "FetchContent_Declare(\n\t" << content.name << "\n";
|
||||
for (const auto &arg : content.arguments) {
|
||||
ss << "\t" << arg.first << "\n\t\t" << arg.second << "\n";
|
||||
}
|
||||
ss << ")\n";
|
||||
cmd("FetchContent_Declare")(content.name, content.arguments);
|
||||
cmd("FetchContent_MakeAvailable")(content.name).endl();
|
||||
|
||||
gen.conditional_includes(content.include_after);
|
||||
@@ -1044,8 +1069,9 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
component_name = inst.targets.front();
|
||||
}
|
||||
auto component = std::make_pair("COMPONENT", component_name);
|
||||
auto optional = inst.optional ? "OPTIONAL" : "";
|
||||
ConditionScope cs(gen, inst.condition);
|
||||
cmd("install")(targets, dirs, files, configs, destination, component);
|
||||
cmd("install")(targets, dirs, files, configs, destination, component, optional);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-4
@@ -1,15 +1,21 @@
|
||||
#include "error.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
namespace cmkr {
|
||||
namespace error {
|
||||
|
||||
Status::Status(Code ec) noexcept : ec_(ec) {}
|
||||
Status::Status(Code ec) noexcept : ec_(ec) {
|
||||
}
|
||||
|
||||
Status::operator int() const noexcept { return static_cast<int>(ec_); }
|
||||
Status::operator int() const noexcept {
|
||||
return static_cast<int>(ec_);
|
||||
}
|
||||
|
||||
Status::Code Status::code() const noexcept { return ec_; }
|
||||
Status::Code Status::code() const noexcept {
|
||||
return ec_;
|
||||
}
|
||||
|
||||
} // namespace error
|
||||
} // namespace cmkr
|
||||
@@ -20,6 +26,6 @@ static const char *err_string[] = {
|
||||
};
|
||||
|
||||
const char *cmkr_error_status(int i) {
|
||||
assert(i >= 0 && i < (sizeof(err_string) / sizeof(*(err_string))));
|
||||
assert(i >= 0 && static_cast<size_t>(i) < (sizeof(err_string) / sizeof(*(err_string))));
|
||||
return err_string[i];
|
||||
}
|
||||
|
||||
+9
-3
@@ -4,7 +4,9 @@
|
||||
namespace cmkr {
|
||||
namespace help {
|
||||
|
||||
const char *version() noexcept { return "cmkr version " CMKR_VERSION; }
|
||||
const char *version() noexcept {
|
||||
return "cmkr version " CMKR_VERSION;
|
||||
}
|
||||
|
||||
const char *message() noexcept {
|
||||
return R"lit(
|
||||
@@ -22,6 +24,10 @@ arguments:
|
||||
} // namespace help
|
||||
} // namespace cmkr
|
||||
|
||||
const char *cmkr_help_version(void) { return cmkr::help::version(); }
|
||||
const char *cmkr_help_version(void) {
|
||||
return cmkr::help::version();
|
||||
}
|
||||
|
||||
const char *cmkr_help_message(void) { return cmkr::help::message(); }
|
||||
const char *cmkr_help_message(void) {
|
||||
return cmkr::help::message();
|
||||
}
|
||||
+19
-7
@@ -54,8 +54,10 @@ class TomlChecker {
|
||||
tsl::ordered_set<toml::key> m_conditionVisited;
|
||||
|
||||
public:
|
||||
TomlChecker(const TomlBasicValue &v, const toml::key &ky) : m_v(toml::find(v, ky)) {}
|
||||
TomlChecker(const TomlBasicValue &v) : m_v(v) {}
|
||||
TomlChecker(const TomlBasicValue &v, const toml::key &ky) : m_v(toml::find(v, ky)) {
|
||||
}
|
||||
TomlChecker(const TomlBasicValue &v) : m_v(v) {
|
||||
}
|
||||
TomlChecker(const TomlChecker &) = delete;
|
||||
TomlChecker(TomlChecker &&) = delete;
|
||||
|
||||
@@ -109,9 +111,13 @@ class TomlChecker {
|
||||
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 {
|
||||
for (const auto &itr : m_v.as_table()) {
|
||||
@@ -152,7 +158,8 @@ class TomlCheckerRoot {
|
||||
bool m_checked = false;
|
||||
|
||||
public:
|
||||
TomlCheckerRoot(const TomlBasicValue &root) : m_root(root) {}
|
||||
TomlCheckerRoot(const TomlBasicValue &root) : m_root(root) {
|
||||
}
|
||||
TomlCheckerRoot(const TomlCheckerRoot &) = delete;
|
||||
TomlCheckerRoot(TomlCheckerRoot &&) = delete;
|
||||
|
||||
@@ -426,9 +433,12 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
||||
throw std::runtime_error(format_key_error("Unknown key '" + argItr.first + "'", argItr.first, argItr.second));
|
||||
}
|
||||
|
||||
c.visit(argItr.first);
|
||||
// Make sure not to emit keys like "condition" in the FetchContent call
|
||||
if (!c.visisted(key)) {
|
||||
content.arguments.emplace(key, value);
|
||||
}
|
||||
|
||||
content.arguments.emplace(key, value);
|
||||
c.visit(argItr.first);
|
||||
}
|
||||
contents.emplace_back(std::move(content));
|
||||
}
|
||||
@@ -616,6 +626,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
||||
i.optional("configs", inst.configs);
|
||||
i.required("destination", inst.destination);
|
||||
i.optional("component", inst.component);
|
||||
i.optional("optional", inst.optional);
|
||||
installs.push_back(inst);
|
||||
}
|
||||
}
|
||||
@@ -624,6 +635,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
||||
auto &v = checker.create(toml, "vcpkg");
|
||||
v.optional("url", vcpkg.url);
|
||||
v.optional("version", vcpkg.version);
|
||||
|
||||
for (const auto &p : v.find("packages").as_array()) {
|
||||
Vcpkg::Package package;
|
||||
const auto &package_str = p.as_string().str;
|
||||
|
||||
Generated
+8
-8
@@ -14,7 +14,7 @@ add_test(
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/basic"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ add_test(
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/interface"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
@@ -34,7 +34,7 @@ add_test(
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/fetch-content"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
@@ -44,7 +44,7 @@ add_test(
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/conditions"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ add_test(
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/vcpkg"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
@@ -64,7 +64,7 @@ add_test(
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/cxx-standard"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
@@ -74,7 +74,7 @@ add_test(
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/globbing"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
@@ -84,7 +84,7 @@ add_test(
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/templates"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user