diff --git a/docs/examples/vcpkg.md b/docs/examples/vcpkg.md
new file mode 100644
index 0000000..237d397
--- /dev/null
+++ b/docs/examples/vcpkg.md
@@ -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`.
+
+This page was automatically generated from [tests/vcpkg/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/vcpkg/cmake.toml).
diff --git a/include/cmake.hpp b/include/cmake.hpp
index a4299ff..4de5984 100644
--- a/include/cmake.hpp
+++ b/include/cmake.hpp
@@ -33,6 +33,7 @@ struct Package {
};
struct Vcpkg {
+ std::string version;
std::string url;
std::vector packages;
};
diff --git a/src/cmake.cpp b/src/cmake.cpp
index aa7c0e0..6fe3b1c 100644
--- a/src/cmake.cpp
+++ b/src/cmake.cpp
@@ -257,7 +257,8 @@ CMake::CMake(const std::string &path, bool build) {
if (toml.contains("vcpkg")) {
const auto &v = toml::find(toml, "vcpkg");
- vcpkg.url = toml::find(v, "url").as_string();
+ get_optional(v, "url", vcpkg.url);
+ get_optional(v, "version", vcpkg.version);
vcpkg.packages = toml::find(v, "packages");
}
diff --git a/src/gen.cpp b/src/gen.cpp
index 911a460..cea8b84 100644
--- a/src/gen.cpp
+++ b/src/gen.cpp
@@ -163,7 +163,7 @@ struct Command {
~Command() {
if (!generated) {
- assert(false && "Incorrect usage of cmd()");
+ assert(false && "Incorrect usage of cmd(), you probably forgot ()");
}
}
@@ -297,7 +297,7 @@ struct Command {
}
template
- CommandEndl operator()(Ts &&... values) {
+ CommandEndl operator()(Ts &&...values) {
generated = true;
ss << indent(depth) << command << '(';
(void)std::initializer_list{print_arg(values)...};
@@ -406,6 +406,31 @@ 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!");
@@ -422,8 +447,9 @@ int generate_cmake(const char *path, bool root) {
auto inject_includes = [&gen](const std::vector &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) {
@@ -523,30 +549,40 @@ int generate_cmake(const char *path, bool root) {
}
}
- if (!cmake.vcpkg.packages.empty() && !cmake.vcpkg.url.empty()) {
- auto vcpkg_escape_identifier = [](const std::string &name) -> std::string {
- const std::regex ok("[a-z0-9]+(-[a-z0-9]+)*");
- const std::regex reserved("prn|aux|nul|con|lpt[1-9]|com[1-9]|core|default");
- std::cmatch m;
- if (!std::regex_match(name.c_str(), m, reserved) && std::regex_match(name.c_str(), m, ok)) {
- return name;
- } else {
- // should probably throw!
- return "project-name";
+ if (!cmake.vcpkg.packages.empty()) {
+ // Allow the user to specify a url or derive it from the version
+ auto url = cmake.vcpkg.url;
+ if (url.empty()) {
+ if (cmake.vcpkg.version.empty()) {
+ throw std::runtime_error("You need either [vcpkg].version or [vcpkg].url");
}
- };
+ url = "https://github.com/microsoft/vcpkg/archive/refs/tags/" + cmake.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")();
+ // 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(cmake.project_name);
- if (!cmake.project_version.empty())
- j["version"] = cmake.project_version;
+ j["version-string"] = cmake.project_version;
j["dependencies"] = cmake.vcpkg.packages;
- cmd("include")("FetchContent");
- cmd("message")("STATUS", "Fetching vcpkg...");
- cmd("FetchContent_Declare")("vcpkg", "URL", cmake.vcpkg.url);
- cmd("FetchContent_MakeAvailable")("vcpkg");
- cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
+ if (!cmake.project_description.empty()) {
+ j["description"] = cmake.project_description;
+ }
+
std::ofstream ofs("vcpkg.json");
if (!ofs) {
throw std::runtime_error("Failed to create a vcpkg.json manifest file!");
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 19efc1f..8565573 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -48,3 +48,13 @@ add_test(
build
)
+add_test(
+ NAME
+ vcpkg
+ WORKING_DIRECTORY
+ "${CMAKE_CURRENT_LIST_DIR}/vcpkg"
+ COMMAND
+ $
+ build
+)
+
diff --git a/tests/cmake.toml b/tests/cmake.toml
index b708184..ebc12b2 100644
--- a/tests/cmake.toml
+++ b/tests/cmake.toml
@@ -20,4 +20,10 @@ arguments = ["build"]
name = "conditions"
command = "$"
working-directory = "conditions"
+arguments = ["build"]
+
+[[test]]
+name = "vcpkg"
+command = "$"
+working-directory = "vcpkg"
arguments = ["build"]
\ No newline at end of file
diff --git a/tests/vcpkg/cmake.toml b/tests/vcpkg/cmake.toml
new file mode 100644
index 0000000..9ef39bf
--- /dev/null
+++ b/tests/vcpkg/cmake.toml
@@ -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`.
\ No newline at end of file
diff --git a/tests/vcpkg/src/main.cpp b/tests/vcpkg/src/main.cpp
new file mode 100644
index 0000000..4a2fe7e
--- /dev/null
+++ b/tests/vcpkg/src/main.cpp
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ fmt::print("Hello, world!\n");
+}
\ No newline at end of file
diff --git a/tests/vcpkg/vcpkg.json b/tests/vcpkg/vcpkg.json
new file mode 100644
index 0000000..2ed5f1a
--- /dev/null
+++ b/tests/vcpkg/vcpkg.json
@@ -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": ""
+}