Skip to content

Commit 7b20d8c

Browse files
committed
Restore [vcpkg].version functionality and add a test + documentation
1 parent ffdedbd commit 7b20d8c

File tree

9 files changed

+150
-22
lines changed

9 files changed

+150
-22
lines changed

docs/examples/vcpkg.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
# Automatically generated from tests/vcpkg/cmake.toml - DO NOT EDIT
3+
layout: default
4+
title: Dependencies from vcpkg
5+
permalink: /examples/vcpkg
6+
parent: Examples
7+
nav_order: 4
8+
---
9+
10+
# Dependencies from vcpkg
11+
12+
Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) using [vcpkg](https://vcpkg.io/) and links an `example` target to it:
13+
14+
```toml
15+
[project]
16+
name = "vcpkg"
17+
description = "Dependencies from vcpkg"
18+
19+
# See https://github.com/microsoft/vcpkg/releases for vcpkg versions
20+
# See https://vcpkg.io/en/packages.html for available packages
21+
[vcpkg]
22+
version = "2021.05.12"
23+
packages = ["fmt"]
24+
25+
[find-package]
26+
fmt = {}
27+
28+
[target.example]
29+
type = "executable"
30+
sources = ["src/main.cpp"]
31+
link-libraries = ["fmt::fmt"]
32+
```
33+
34+
The bootstrapping of vcpkg is fully automated and no user interaction is necessary. You can disable vcpkg by setting `CMKR_DISABLE_VCPKG=ON`.
35+
36+
<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>

include/cmake.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct Package {
3333
};
3434

3535
struct Vcpkg {
36+
std::string version;
3637
std::string url;
3738
std::vector<std::string> packages;
3839
};

src/cmake.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ CMake::CMake(const std::string &path, bool build) {
257257

258258
if (toml.contains("vcpkg")) {
259259
const auto &v = toml::find(toml, "vcpkg");
260-
vcpkg.url = toml::find(v, "url").as_string();
260+
get_optional(v, "url", vcpkg.url);
261+
get_optional(v, "version", vcpkg.version);
261262
vcpkg.packages = toml::find<decltype(vcpkg.packages)>(v, "packages");
262263
}
263264

src/gen.cpp

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ struct Command {
163163

164164
~Command() {
165165
if (!generated) {
166-
assert(false && "Incorrect usage of cmd()");
166+
assert(false && "Incorrect usage of cmd(), you probably forgot ()");
167167
}
168168
}
169169

@@ -297,7 +297,7 @@ struct Command {
297297
}
298298

299299
template <class... Ts>
300-
CommandEndl operator()(Ts &&... values) {
300+
CommandEndl operator()(Ts &&...values) {
301301
generated = true;
302302
ss << indent(depth) << command << '(';
303303
(void)std::initializer_list<bool>{print_arg(values)...};
@@ -406,6 +406,31 @@ struct Generator {
406406
}
407407
};
408408

409+
static std::string vcpkg_escape_identifier(const std::string &name) {
410+
// Do a reasonable effort to escape the project name for use with vcpkg
411+
std::string escaped;
412+
for (char ch : name) {
413+
if ((ch & 0x80) != 0) {
414+
throw std::runtime_error("Non-ASCII characters are not allowed in [project].name when using [vcpkg]");
415+
}
416+
417+
if (ch == '_' || ch == ' ') {
418+
ch = '-';
419+
}
420+
421+
escaped += std::tolower(ch);
422+
}
423+
424+
const std::regex reserved("prn|aux|nul|con|lpt[1-9]|com[1-9]|core|default");
425+
const std::regex ok("[a-z0-9]+(-[a-z0-9]+)*");
426+
std::cmatch m;
427+
if (!std::regex_match(escaped.c_str(), m, reserved) && std::regex_match(escaped.c_str(), m, ok)) {
428+
return escaped;
429+
} else {
430+
throw std::runtime_error("The escaped project name '" + escaped + "' is not usable with [vcpkg]");
431+
}
432+
}
433+
409434
int generate_cmake(const char *path, bool root) {
410435
if (!fs::exists(fs::path(path) / "cmake.toml")) {
411436
throw std::runtime_error("No cmake.toml found!");
@@ -422,8 +447,9 @@ int generate_cmake(const char *path, bool root) {
422447
auto inject_includes = [&gen](const std::vector<std::string> &includes) { gen.inject_includes(includes); };
423448
auto inject_cmake = [&gen](const std::string &cmake) { gen.inject_cmake(cmake); };
424449

450+
std::string cmkr_url = "https://github.com/build-cpp/cmkr";
425451
comment("This file is automatically generated from cmake.toml - DO NOT EDIT");
426-
comment("See https://github.com/build-cpp/cmkr for more information");
452+
comment("See " + cmkr_url + " for more information");
427453
endl();
428454

429455
if (root) {
@@ -523,30 +549,40 @@ int generate_cmake(const char *path, bool root) {
523549
}
524550
}
525551

526-
if (!cmake.vcpkg.packages.empty() && !cmake.vcpkg.url.empty()) {
527-
auto vcpkg_escape_identifier = [](const std::string &name) -> std::string {
528-
const std::regex ok("[a-z0-9]+(-[a-z0-9]+)*");
529-
const std::regex reserved("prn|aux|nul|con|lpt[1-9]|com[1-9]|core|default");
530-
std::cmatch m;
531-
if (!std::regex_match(name.c_str(), m, reserved) && std::regex_match(name.c_str(), m, ok)) {
532-
return name;
533-
} else {
534-
// should probably throw!
535-
return "project-name";
552+
if (!cmake.vcpkg.packages.empty()) {
553+
// Allow the user to specify a url or derive it from the version
554+
auto url = cmake.vcpkg.url;
555+
if (url.empty()) {
556+
if (cmake.vcpkg.version.empty()) {
557+
throw std::runtime_error("You need either [vcpkg].version or [vcpkg].url");
536558
}
537-
};
559+
url = "https://github.com/microsoft/vcpkg/archive/refs/tags/" + cmake.vcpkg.version + ".tar.gz";
560+
}
561+
562+
// CMake to bootstrap vcpkg and download the packages
563+
// clang-format off
564+
cmd("if")("CMKR_ROOT_PROJECT", "AND", "NOT", "CMKR_DISABLE_VCPKG");
565+
cmd("include")("FetchContent");
566+
cmd("message")("STATUS", "Fetching vcpkg...");
567+
cmd("FetchContent_Declare")("vcpkg", "URL", url);
568+
cmd("FetchContent_MakeAvailable")("vcpkg");
569+
cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
570+
cmd("endif")();
571+
// clang-format on
572+
573+
// Generate vcpkg.json
538574
using namespace nlohmann;
539575
json j;
576+
j["$cmkr"] = "This file is automatically generated from cmake.toml - DO NOT EDIT";
577+
j["$cmkr-url"] = cmkr_url;
540578
j["$schema"] = "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json";
541579
j["name"] = vcpkg_escape_identifier(cmake.project_name);
542-
if (!cmake.project_version.empty())
543-
j["version"] = cmake.project_version;
580+
j["version-string"] = cmake.project_version;
544581
j["dependencies"] = cmake.vcpkg.packages;
545-
cmd("include")("FetchContent");
546-
cmd("message")("STATUS", "Fetching vcpkg...");
547-
cmd("FetchContent_Declare")("vcpkg", "URL", cmake.vcpkg.url);
548-
cmd("FetchContent_MakeAvailable")("vcpkg");
549-
cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake");
582+
if (!cmake.project_description.empty()) {
583+
j["description"] = cmake.project_description;
584+
}
585+
550586
std::ofstream ofs("vcpkg.json");
551587
if (!ofs) {
552588
throw std::runtime_error("Failed to create a vcpkg.json manifest file!");

tests/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/cmake.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,10 @@ arguments = ["build"]
2020
name = "conditions"
2121
command = "$<TARGET_FILE:cmkr>"
2222
working-directory = "conditions"
23+
arguments = ["build"]
24+
25+
[[test]]
26+
name = "vcpkg"
27+
command = "$<TARGET_FILE:cmkr>"
28+
working-directory = "vcpkg"
2329
arguments = ["build"]

tests/vcpkg/cmake.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) using [vcpkg](https://vcpkg.io/) and links an `example` target to it:
2+
3+
[project]
4+
name = "vcpkg"
5+
description = "Dependencies from vcpkg"
6+
7+
# See https://github.com/microsoft/vcpkg/releases for vcpkg versions
8+
# See https://vcpkg.io/en/packages.html for available packages
9+
[vcpkg]
10+
version = "2021.05.12"
11+
packages = ["fmt"]
12+
13+
[find-package]
14+
fmt = {}
15+
16+
[target.example]
17+
type = "executable"
18+
sources = ["src/main.cpp"]
19+
link-libraries = ["fmt::fmt"]
20+
21+
# The bootstrapping of vcpkg is fully automated and no user interaction is necessary. You can disable vcpkg by setting `CMKR_DISABLE_VCPKG=ON`.

tests/vcpkg/src/main.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <fmt/core.h>
2+
3+
int main()
4+
{
5+
fmt::print("Hello, world!\n");
6+
}

tests/vcpkg/vcpkg.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$cmkr": "This file is automatically generated from cmake.toml - DO NOT EDIT",
3+
"$cmkr-url": "https://github.com/build-cpp/cmkr",
4+
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
5+
"dependencies": [
6+
"fmt"
7+
],
8+
"description": "Example of using vcpkg",
9+
"name": "vcpkg",
10+
"version-string": ""
11+
}

0 commit comments

Comments
 (0)