|
|
|
@ -13,15 +13,6 @@
|
|
|
|
|
namespace cmkr {
|
|
|
|
|
namespace gen {
|
|
|
|
|
|
|
|
|
|
static std::string to_upper(const std::string &str) {
|
|
|
|
|
std::string temp;
|
|
|
|
|
temp.reserve(str.size());
|
|
|
|
|
for (auto c : str) {
|
|
|
|
|
temp.push_back(::toupper(c));
|
|
|
|
|
}
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string format(const char *format, tsl::ordered_map<std::string, std::string> variables) {
|
|
|
|
|
std::string s = format;
|
|
|
|
|
for (const auto &itr : variables) {
|
|
|
|
@ -34,7 +25,7 @@ static std::string format(const char *format, tsl::ordered_map<std::string, std:
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs::path &toml_dir) {
|
|
|
|
|
static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs::path &toml_dir, bool root_project) {
|
|
|
|
|
std::vector<std::string> temp;
|
|
|
|
|
|
|
|
|
|
auto extract_suffix = [](const fs::path &base, const fs::path &full) {
|
|
|
|
@ -47,6 +38,10 @@ static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs
|
|
|
|
|
auto stem = name.filename().stem().string();
|
|
|
|
|
auto ext = name.extension();
|
|
|
|
|
|
|
|
|
|
if (root_project && stem == "**" && name == name.filename()) {
|
|
|
|
|
throw std::runtime_error("Recursive globbing not allowed in project root: " + name.string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stem == "*") {
|
|
|
|
|
for (const auto &f : fs::directory_iterator(toml_dir / name.parent_path(), fs::directory_options::follow_directory_symlink)) {
|
|
|
|
|
if (!f.is_directory() && f.path().extension() == ext) {
|
|
|
|
@ -71,11 +66,11 @@ static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::vector<std::string> expand_cmake_paths(const std::vector<std::string> &sources, const fs::path &toml_dir) {
|
|
|
|
|
static std::vector<std::string> expand_cmake_paths(const std::vector<std::string> &sources, const fs::path &toml_dir, bool root_project) {
|
|
|
|
|
// TODO: add duplicate checking
|
|
|
|
|
std::vector<std::string> result;
|
|
|
|
|
for (const auto &src : sources) {
|
|
|
|
|
auto expanded = expand_cmake_path(src, toml_dir);
|
|
|
|
|
auto expanded = expand_cmake_path(src, toml_dir, root_project);
|
|
|
|
|
for (const auto &f : expanded) {
|
|
|
|
|
result.push_back(f);
|
|
|
|
|
}
|
|
|
|
@ -94,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!");
|
|
|
|
|
}
|
|
|
|
@ -131,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;
|
|
|
|
|
};
|
|
|
|
@ -153,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,11 +178,16 @@ struct Command {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string quote(const std::string &str) {
|
|
|
|
|
// Quote an empty string
|
|
|
|
|
if (str.empty()) {
|
|
|
|
|
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) {
|
|
|
|
@ -317,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;
|
|
|
|
@ -343,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()) {
|
|
|
|
@ -398,6 +422,14 @@ 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); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void conditional_cmake(const parser::Condition<std::string> &cmake) {
|
|
|
|
|
handle_condition(cmake, [this](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ConditionScope {
|
|
|
|
@ -472,6 +504,9 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
throw std::runtime_error("No cmake.toml found!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Root project doesn't have a parent
|
|
|
|
|
auto root_project = parent_project == nullptr;
|
|
|
|
|
|
|
|
|
|
parser::Project project(parent_project, path, false);
|
|
|
|
|
Generator gen(project);
|
|
|
|
|
|
|
|
|
@ -480,16 +515,13 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
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 " + cmkr_url + " for more information");
|
|
|
|
|
endl();
|
|
|
|
|
|
|
|
|
|
// Root project doesn't have a parent
|
|
|
|
|
if (parent_project == nullptr) {
|
|
|
|
|
if (root_project) {
|
|
|
|
|
cmd("cmake_minimum_required")("VERSION", project.cmake_version).endl();
|
|
|
|
|
|
|
|
|
|
if (!project.allow_in_tree) {
|
|
|
|
@ -562,7 +594,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
if (!project.options.empty()) {
|
|
|
|
|
comment("Options");
|
|
|
|
|
for (const auto &opt : project.options) {
|
|
|
|
|
cmd("option")(opt.name, opt.comment, opt.val ? "ON" : "OFF");
|
|
|
|
|
cmd("option")(opt.name, RawArg(Command::quote(opt.comment)), opt.val ? "ON" : "OFF");
|
|
|
|
|
}
|
|
|
|
|
endl();
|
|
|
|
|
}
|
|
|
|
@ -588,8 +620,8 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
endl();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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); });
|
|
|
|
|
gen.conditional_includes(project.include_before);
|
|
|
|
|
gen.conditional_cmake(project.cmake_before);
|
|
|
|
|
|
|
|
|
|
if (!project.project_name.empty()) {
|
|
|
|
|
auto languages = std::make_pair("LANGUAGES", project.project_languages);
|
|
|
|
@ -598,17 +630,19 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
cmd("project")(project.project_name, languages, version, description).endl();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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); });
|
|
|
|
|
gen.conditional_includes(project.include_after);
|
|
|
|
|
gen.conditional_cmake(project.cmake_after);
|
|
|
|
|
|
|
|
|
|
if (!project.vcpkg.packages.empty()) {
|
|
|
|
|
// Allow the user to specify a url or derive it from the version
|
|
|
|
|
auto url = project.vcpkg.url;
|
|
|
|
|
auto version_name = 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";
|
|
|
|
|
version_name = project.vcpkg.version;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Show a nicer error than vcpkg when specifying an invalid package name
|
|
|
|
@ -622,10 +656,14 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
// clang-format off
|
|
|
|
|
cmd("if")("CMKR_ROOT_PROJECT", "AND", "NOT", "CMKR_DISABLE_VCPKG");
|
|
|
|
|
cmd("include")("FetchContent");
|
|
|
|
|
cmd("message")("STATUS", "Fetching vcpkg...");
|
|
|
|
|
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
|
|
|
|
@ -689,7 +727,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
|
|
|
|
|
ofs << " ],\n";
|
|
|
|
|
ofs << " \"description\": \"" << escape(project.project_description) << "\",\n";
|
|
|
|
|
ofs << " \"name\": \"" << escape(project.project_name) << "\",\n";
|
|
|
|
|
ofs << " \"name\": \"" << escape(vcpkg_escape_identifier(project.project_name)) << "\",\n";
|
|
|
|
|
ofs << R"( "version-string": "")" << '\n';
|
|
|
|
|
ofs << "}\n";
|
|
|
|
|
}
|
|
|
|
@ -698,6 +736,10 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
cmd("include")("FetchContent").endl();
|
|
|
|
|
for (const auto &content : project.contents) {
|
|
|
|
|
ConditionScope cs(gen, content.condition);
|
|
|
|
|
|
|
|
|
|
gen.conditional_includes(content.include_before);
|
|
|
|
|
gen.conditional_cmake(content.cmake_before);
|
|
|
|
|
|
|
|
|
|
std::string version_info = "";
|
|
|
|
|
if (content.arguments.contains("GIT_TAG")) {
|
|
|
|
|
version_info = " (" + content.arguments.at("GIT_TAG") + ")";
|
|
|
|
@ -705,12 +747,11 @@ 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);
|
|
|
|
|
gen.conditional_cmake(content.cmake_after);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -755,14 +796,13 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
for (const auto &subdir : project.subdirs) {
|
|
|
|
|
ConditionScope cs(gen, subdir.condition);
|
|
|
|
|
|
|
|
|
|
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); });
|
|
|
|
|
gen.conditional_includes(subdir.include_before);
|
|
|
|
|
gen.conditional_cmake(subdir.cmake_before);
|
|
|
|
|
|
|
|
|
|
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); });
|
|
|
|
|
gen.conditional_includes(subdir.include_after);
|
|
|
|
|
gen.conditional_cmake(subdir.cmake_after);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!project.targets.empty()) {
|
|
|
|
@ -792,14 +832,12 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
cmd("set")("CMKR_TARGET", target.name);
|
|
|
|
|
|
|
|
|
|
if (tmplate != nullptr) {
|
|
|
|
|
gen.handle_condition(tmplate->outline.include_before,
|
|
|
|
|
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
|
|
|
|
gen.handle_condition(tmplate->outline.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
|
|
|
|
gen.conditional_includes(tmplate->outline.include_before);
|
|
|
|
|
gen.conditional_cmake(tmplate->outline.cmake_before);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gen.handle_condition(target.include_before,
|
|
|
|
|
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
|
|
|
|
gen.handle_condition(target.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
|
|
|
|
gen.conditional_includes(target.include_before);
|
|
|
|
|
gen.conditional_cmake(target.cmake_before);
|
|
|
|
|
|
|
|
|
|
auto sources_var = target.name + "_SOURCES";
|
|
|
|
|
|
|
|
|
@ -808,7 +846,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
|
|
|
|
|
if (tmplate != nullptr) {
|
|
|
|
|
gen.handle_condition(tmplate->outline.sources, [&](const std::string &condition, const std::vector<std::string> &condition_sources) {
|
|
|
|
|
auto sources = expand_cmake_paths(condition_sources, path);
|
|
|
|
|
auto sources = expand_cmake_paths(condition_sources, path, root_project);
|
|
|
|
|
if (sources.empty()) {
|
|
|
|
|
auto source_key = condition.empty() ? "sources" : (condition + ".sources");
|
|
|
|
|
throw std::runtime_error(target.name + " " + source_key + " wildcard found 0 files");
|
|
|
|
@ -818,7 +856,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gen.handle_condition(target.sources, [&](const std::string &condition, const std::vector<std::string> &condition_sources) {
|
|
|
|
|
auto sources = expand_cmake_paths(condition_sources, path);
|
|
|
|
|
auto sources = expand_cmake_paths(condition_sources, path, root_project);
|
|
|
|
|
if (sources.empty()) {
|
|
|
|
|
auto source_key = condition.empty() ? "sources" : (condition + ".sources");
|
|
|
|
|
throw std::runtime_error(target.name + " " + source_key + " wildcard found 0 files");
|
|
|
|
@ -980,14 +1018,12 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gen.handle_condition(target.include_after,
|
|
|
|
|
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
|
|
|
|
gen.handle_condition(target.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
|
|
|
|
gen.conditional_includes(target.include_after);
|
|
|
|
|
gen.conditional_cmake(target.cmake_after);
|
|
|
|
|
|
|
|
|
|
if (tmplate != nullptr) {
|
|
|
|
|
gen.handle_condition(tmplate->outline.include_after,
|
|
|
|
|
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
|
|
|
|
|
gen.handle_condition(tmplate->outline.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
|
|
|
|
|
gen.conditional_includes(tmplate->outline.include_after);
|
|
|
|
|
gen.conditional_cmake(tmplate->outline.cmake_after);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd("unset")("CMKR_TARGET");
|
|
|
|
@ -1020,7 +1056,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
auto dirs = std::make_pair("DIRS", inst.dirs);
|
|
|
|
|
std::vector<std::string> files_data;
|
|
|
|
|
if (!inst.files.empty()) {
|
|
|
|
|
files_data = expand_cmake_paths(inst.files, path);
|
|
|
|
|
files_data = expand_cmake_paths(inst.files, path, root_project);
|
|
|
|
|
if (files_data.empty()) {
|
|
|
|
|
throw std::runtime_error("[[install]] files wildcard did not resolve to any files");
|
|
|
|
|
}
|
|
|
|
@ -1028,9 +1064,14 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
|
|
|
|
auto files = std::make_pair("FILES", inst.files);
|
|
|
|
|
auto configs = std::make_pair("CONFIGURATIONS", inst.configs);
|
|
|
|
|
auto destination = std::make_pair("DESTINATION", inst.destination);
|
|
|
|
|
auto component = std::make_pair("COMPONENT", inst.targets.empty() ? "" : inst.targets.front());
|
|
|
|
|
auto component_name = inst.component;
|
|
|
|
|
if (component_name.empty() && !inst.targets.empty()) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|