wyvrnpm 2.10.2 → 2.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1914 -1860
- package/bin/{wyvrn.js → wyvrnpm.js} +66 -0
- package/cmake/cpp.cmake +9 -9
- package/cmake/functions.cmake +224 -224
- package/cmake/macros.cmake +284 -284
- package/package.json +3 -2
- package/src/auth.js +66 -66
- package/src/binary-dir.js +95 -0
- package/src/bootstrap/cookbook.js +196 -196
- package/src/bootstrap/detect.js +150 -150
- package/src/bootstrap/index.js +220 -220
- package/src/bootstrap/version.js +72 -72
- package/src/build/cache.js +344 -344
- package/src/build/clone.js +170 -170
- package/src/build/cmake.js +342 -342
- package/src/build/index.js +299 -297
- package/src/build/msvc-env.js +260 -260
- package/src/build/recipe.js +188 -188
- package/src/commands/add.js +141 -141
- package/src/commands/bootstrap.js +96 -96
- package/src/commands/build.js +482 -452
- package/src/commands/cache.js +189 -189
- package/src/commands/clean.js +80 -80
- package/src/commands/configure.js +92 -92
- package/src/commands/init.js +70 -70
- package/src/commands/install-skill.js +115 -115
- package/src/commands/install.js +730 -674
- package/src/commands/link.js +320 -320
- package/src/commands/profile.js +237 -237
- package/src/commands/publish.js +584 -555
- package/src/commands/show.js +252 -252
- package/src/commands/version.js +187 -0
- package/src/compat.js +273 -273
- package/src/conf/index.js +415 -391
- package/src/conf/namespaces.js +94 -94
- package/src/context.js +230 -230
- package/src/http-fetch.js +53 -53
- package/src/ignore.js +118 -118
- package/src/logger.js +122 -122
- package/src/options.js +303 -303
- package/src/settings-overrides.js +152 -152
- package/src/toolchain/deps.js +164 -164
- package/src/toolchain/index.js +212 -212
- package/src/toolchain/presets.js +356 -340
- package/src/toolchain/template.cmake +77 -77
- package/src/upload-built.js +265 -265
- package/src/version-range.js +301 -301
- package/src/zip-safe.js +52 -52
- package/src/zip-stream.js +126 -0
|
@@ -1,152 +1,152 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Pattern-based settings overrides (EVALUATION.md F11).
|
|
4
|
-
//
|
|
5
|
-
// `wyvrn.json` may declare a top-level `settingsOverrides` block whose
|
|
6
|
-
// keys are glob patterns over dependency names. Every matching pattern
|
|
7
|
-
// contributes to the resolved dep's `settings` merge; the per-dep
|
|
8
|
-
// literal settings (inside `dependencies`) still win over patterns.
|
|
9
|
-
//
|
|
10
|
-
// Conan users know this feature as profile-side `boost*:compiler.cppstd=17`.
|
|
11
|
-
// Ours lives in the manifest because that's where literal settings
|
|
12
|
-
// overrides already live — one fewer concept for recipe authors.
|
|
13
|
-
//
|
|
14
|
-
// Pure, no I/O. Exported helpers:
|
|
15
|
-
// - normalizeSettingsOverrides: validate + sort by specificity
|
|
16
|
-
// - resolveOverrideSettings: compute the merged settings for a dep name
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Valid profile field keys that settings overrides may target.
|
|
20
|
-
* Mirrors `HASHED_PROFILE_FIELDS` in src/profile.js, but as the allow-
|
|
21
|
-
* list for OVERRIDE values (os/arch/compiler/etc.). If a pattern
|
|
22
|
-
* override tries to set something else, reject at parse time rather
|
|
23
|
-
* than silently letting it through into mergeProfile.
|
|
24
|
-
*/
|
|
25
|
-
const ALLOWED_SETTINGS_KEYS = new Set([
|
|
26
|
-
'os', 'arch', 'compiler', 'compiler.version', 'compiler.cppstd', 'compiler.runtime',
|
|
27
|
-
]);
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Convert a glob pattern to a RegExp. Supports `*` (any chars),
|
|
31
|
-
* `?` (single char), literal everything else. No brace expansion,
|
|
32
|
-
* no negation — keep the mental model small.
|
|
33
|
-
*
|
|
34
|
-
* @param {string} glob
|
|
35
|
-
* @returns {RegExp}
|
|
36
|
-
*/
|
|
37
|
-
function globToRegExp(glob) {
|
|
38
|
-
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
39
|
-
const pattern = escaped.replace(/\*/g, '.*').replace(/\?/g, '.');
|
|
40
|
-
return new RegExp(`^${pattern}$`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Specificity heuristic: fewer wildcards = more specific. Ties broken
|
|
45
|
-
* by longer literal prefix, then lexical order for determinism. More
|
|
46
|
-
* specific patterns get applied LAST so they override less-specific
|
|
47
|
-
* ones in the merge.
|
|
48
|
-
*
|
|
49
|
-
* @param {string} glob
|
|
50
|
-
* @returns {[number, number, string]} sort key — lower = less specific
|
|
51
|
-
*/
|
|
52
|
-
function specificityKey(glob) {
|
|
53
|
-
const wildcards = (glob.match(/[*?]/g) ?? []).length;
|
|
54
|
-
const literalPrefix = glob.match(/^[^*?]*/)?.[0].length ?? 0;
|
|
55
|
-
// Invert sort order: more wildcards → lower score; more prefix → higher score.
|
|
56
|
-
return [-wildcards, literalPrefix, glob];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Validate + sort a raw `settingsOverrides` block. Returns an array of
|
|
61
|
-
* `{ pattern, regex, settings }` in application order (least-specific
|
|
62
|
-
* first). A string pattern alone (literal `"openssl"`) works too — it
|
|
63
|
-
* matches only that exact name.
|
|
64
|
-
*
|
|
65
|
-
* Throws on:
|
|
66
|
-
* - non-object block
|
|
67
|
-
* - non-string keys (JSON can't produce these but defensive)
|
|
68
|
-
* - non-object values
|
|
69
|
-
* - empty pattern strings
|
|
70
|
-
* - unknown settings keys in a value
|
|
71
|
-
* - non-string value leaves (settings values must be strings like
|
|
72
|
-
* the profile itself: "dynamic", "17", "gcc")
|
|
73
|
-
*
|
|
74
|
-
* @param {unknown} block
|
|
75
|
-
* @returns {Array<{ pattern: string, regex: RegExp, settings: Record<string, string> }>}
|
|
76
|
-
*/
|
|
77
|
-
function normalizeSettingsOverrides(block) {
|
|
78
|
-
if (block === undefined || block === null) return [];
|
|
79
|
-
if (typeof block !== 'object' || Array.isArray(block)) {
|
|
80
|
-
throw new Error('settingsOverrides must be an object mapping globs to settings');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const entries = [];
|
|
84
|
-
for (const [rawPattern, rawValue] of Object.entries(block)) {
|
|
85
|
-
if (typeof rawPattern !== 'string' || rawPattern.length === 0) {
|
|
86
|
-
throw new Error(`settingsOverrides: pattern must be a non-empty string, got ${JSON.stringify(rawPattern)}`);
|
|
87
|
-
}
|
|
88
|
-
if (!rawValue || typeof rawValue !== 'object' || Array.isArray(rawValue)) {
|
|
89
|
-
throw new Error(`settingsOverrides["${rawPattern}"]: value must be an object of settings`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const settings = {};
|
|
93
|
-
for (const [k, v] of Object.entries(rawValue)) {
|
|
94
|
-
if (!ALLOWED_SETTINGS_KEYS.has(k)) {
|
|
95
|
-
throw new Error(
|
|
96
|
-
`settingsOverrides["${rawPattern}"]: unknown key "${k}" — ` +
|
|
97
|
-
`allowed: ${[...ALLOWED_SETTINGS_KEYS].join(', ')}`,
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
if (typeof v !== 'string' || v.length === 0) {
|
|
101
|
-
throw new Error(
|
|
102
|
-
`settingsOverrides["${rawPattern}"].${k}: value must be a non-empty string, ` +
|
|
103
|
-
`got ${JSON.stringify(v)}`,
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
settings[k] = v;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
entries.push({ pattern: rawPattern, regex: globToRegExp(rawPattern), settings });
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Sort by specificity ascending so more-specific patterns apply LAST
|
|
113
|
-
// (their settings therefore win on per-key merge).
|
|
114
|
-
entries.sort((a, b) => {
|
|
115
|
-
const ka = specificityKey(a.pattern);
|
|
116
|
-
const kb = specificityKey(b.pattern);
|
|
117
|
-
for (let i = 0; i < ka.length; i++) {
|
|
118
|
-
if (ka[i] < kb[i]) return -1;
|
|
119
|
-
if (ka[i] > kb[i]) return 1;
|
|
120
|
-
}
|
|
121
|
-
return 0;
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
return entries;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Merge all matching pattern overrides for `depName` into a flat
|
|
129
|
-
* settings object. Less-specific patterns apply first; more-specific
|
|
130
|
-
* patterns overlay on top. Does NOT include the literal per-dep
|
|
131
|
-
* `settings` (caller layers that on after — literal always wins).
|
|
132
|
-
*
|
|
133
|
-
* @param {string} depName
|
|
134
|
-
* @param {ReturnType<typeof normalizeSettingsOverrides>} normalized
|
|
135
|
-
* @returns {Record<string, string>}
|
|
136
|
-
*/
|
|
137
|
-
function resolveOverrideSettings(depName, normalized) {
|
|
138
|
-
const out = {};
|
|
139
|
-
for (const entry of normalized) {
|
|
140
|
-
if (entry.regex.test(depName)) {
|
|
141
|
-
Object.assign(out, entry.settings);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return out;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
module.exports = {
|
|
148
|
-
ALLOWED_SETTINGS_KEYS,
|
|
149
|
-
globToRegExp,
|
|
150
|
-
normalizeSettingsOverrides,
|
|
151
|
-
resolveOverrideSettings,
|
|
152
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Pattern-based settings overrides (EVALUATION.md F11).
|
|
4
|
+
//
|
|
5
|
+
// `wyvrn.json` may declare a top-level `settingsOverrides` block whose
|
|
6
|
+
// keys are glob patterns over dependency names. Every matching pattern
|
|
7
|
+
// contributes to the resolved dep's `settings` merge; the per-dep
|
|
8
|
+
// literal settings (inside `dependencies`) still win over patterns.
|
|
9
|
+
//
|
|
10
|
+
// Conan users know this feature as profile-side `boost*:compiler.cppstd=17`.
|
|
11
|
+
// Ours lives in the manifest because that's where literal settings
|
|
12
|
+
// overrides already live — one fewer concept for recipe authors.
|
|
13
|
+
//
|
|
14
|
+
// Pure, no I/O. Exported helpers:
|
|
15
|
+
// - normalizeSettingsOverrides: validate + sort by specificity
|
|
16
|
+
// - resolveOverrideSettings: compute the merged settings for a dep name
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Valid profile field keys that settings overrides may target.
|
|
20
|
+
* Mirrors `HASHED_PROFILE_FIELDS` in src/profile.js, but as the allow-
|
|
21
|
+
* list for OVERRIDE values (os/arch/compiler/etc.). If a pattern
|
|
22
|
+
* override tries to set something else, reject at parse time rather
|
|
23
|
+
* than silently letting it through into mergeProfile.
|
|
24
|
+
*/
|
|
25
|
+
const ALLOWED_SETTINGS_KEYS = new Set([
|
|
26
|
+
'os', 'arch', 'compiler', 'compiler.version', 'compiler.cppstd', 'compiler.runtime',
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Convert a glob pattern to a RegExp. Supports `*` (any chars),
|
|
31
|
+
* `?` (single char), literal everything else. No brace expansion,
|
|
32
|
+
* no negation — keep the mental model small.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} glob
|
|
35
|
+
* @returns {RegExp}
|
|
36
|
+
*/
|
|
37
|
+
function globToRegExp(glob) {
|
|
38
|
+
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
39
|
+
const pattern = escaped.replace(/\*/g, '.*').replace(/\?/g, '.');
|
|
40
|
+
return new RegExp(`^${pattern}$`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Specificity heuristic: fewer wildcards = more specific. Ties broken
|
|
45
|
+
* by longer literal prefix, then lexical order for determinism. More
|
|
46
|
+
* specific patterns get applied LAST so they override less-specific
|
|
47
|
+
* ones in the merge.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} glob
|
|
50
|
+
* @returns {[number, number, string]} sort key — lower = less specific
|
|
51
|
+
*/
|
|
52
|
+
function specificityKey(glob) {
|
|
53
|
+
const wildcards = (glob.match(/[*?]/g) ?? []).length;
|
|
54
|
+
const literalPrefix = glob.match(/^[^*?]*/)?.[0].length ?? 0;
|
|
55
|
+
// Invert sort order: more wildcards → lower score; more prefix → higher score.
|
|
56
|
+
return [-wildcards, literalPrefix, glob];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Validate + sort a raw `settingsOverrides` block. Returns an array of
|
|
61
|
+
* `{ pattern, regex, settings }` in application order (least-specific
|
|
62
|
+
* first). A string pattern alone (literal `"openssl"`) works too — it
|
|
63
|
+
* matches only that exact name.
|
|
64
|
+
*
|
|
65
|
+
* Throws on:
|
|
66
|
+
* - non-object block
|
|
67
|
+
* - non-string keys (JSON can't produce these but defensive)
|
|
68
|
+
* - non-object values
|
|
69
|
+
* - empty pattern strings
|
|
70
|
+
* - unknown settings keys in a value
|
|
71
|
+
* - non-string value leaves (settings values must be strings like
|
|
72
|
+
* the profile itself: "dynamic", "17", "gcc")
|
|
73
|
+
*
|
|
74
|
+
* @param {unknown} block
|
|
75
|
+
* @returns {Array<{ pattern: string, regex: RegExp, settings: Record<string, string> }>}
|
|
76
|
+
*/
|
|
77
|
+
function normalizeSettingsOverrides(block) {
|
|
78
|
+
if (block === undefined || block === null) return [];
|
|
79
|
+
if (typeof block !== 'object' || Array.isArray(block)) {
|
|
80
|
+
throw new Error('settingsOverrides must be an object mapping globs to settings');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const entries = [];
|
|
84
|
+
for (const [rawPattern, rawValue] of Object.entries(block)) {
|
|
85
|
+
if (typeof rawPattern !== 'string' || rawPattern.length === 0) {
|
|
86
|
+
throw new Error(`settingsOverrides: pattern must be a non-empty string, got ${JSON.stringify(rawPattern)}`);
|
|
87
|
+
}
|
|
88
|
+
if (!rawValue || typeof rawValue !== 'object' || Array.isArray(rawValue)) {
|
|
89
|
+
throw new Error(`settingsOverrides["${rawPattern}"]: value must be an object of settings`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const settings = {};
|
|
93
|
+
for (const [k, v] of Object.entries(rawValue)) {
|
|
94
|
+
if (!ALLOWED_SETTINGS_KEYS.has(k)) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`settingsOverrides["${rawPattern}"]: unknown key "${k}" — ` +
|
|
97
|
+
`allowed: ${[...ALLOWED_SETTINGS_KEYS].join(', ')}`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (typeof v !== 'string' || v.length === 0) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`settingsOverrides["${rawPattern}"].${k}: value must be a non-empty string, ` +
|
|
103
|
+
`got ${JSON.stringify(v)}`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
settings[k] = v;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
entries.push({ pattern: rawPattern, regex: globToRegExp(rawPattern), settings });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Sort by specificity ascending so more-specific patterns apply LAST
|
|
113
|
+
// (their settings therefore win on per-key merge).
|
|
114
|
+
entries.sort((a, b) => {
|
|
115
|
+
const ka = specificityKey(a.pattern);
|
|
116
|
+
const kb = specificityKey(b.pattern);
|
|
117
|
+
for (let i = 0; i < ka.length; i++) {
|
|
118
|
+
if (ka[i] < kb[i]) return -1;
|
|
119
|
+
if (ka[i] > kb[i]) return 1;
|
|
120
|
+
}
|
|
121
|
+
return 0;
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return entries;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Merge all matching pattern overrides for `depName` into a flat
|
|
129
|
+
* settings object. Less-specific patterns apply first; more-specific
|
|
130
|
+
* patterns overlay on top. Does NOT include the literal per-dep
|
|
131
|
+
* `settings` (caller layers that on after — literal always wins).
|
|
132
|
+
*
|
|
133
|
+
* @param {string} depName
|
|
134
|
+
* @param {ReturnType<typeof normalizeSettingsOverrides>} normalized
|
|
135
|
+
* @returns {Record<string, string>}
|
|
136
|
+
*/
|
|
137
|
+
function resolveOverrideSettings(depName, normalized) {
|
|
138
|
+
const out = {};
|
|
139
|
+
for (const entry of normalized) {
|
|
140
|
+
if (entry.regex.test(depName)) {
|
|
141
|
+
Object.assign(out, entry.settings);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = {
|
|
148
|
+
ALLOWED_SETTINGS_KEYS,
|
|
149
|
+
globToRegExp,
|
|
150
|
+
normalizeSettingsOverrides,
|
|
151
|
+
resolveOverrideSettings,
|
|
152
|
+
};
|
package/src/toolchain/deps.js
CHANGED
|
@@ -1,164 +1,164 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generate the contents of `wyvrn_deps.cmake`.
|
|
5
|
-
*
|
|
6
|
-
* This file is loaded via `CMAKE_PROJECT_INCLUDE` — it runs after the
|
|
7
|
-
* consumer's first `project()` call, which is when CMake variables like
|
|
8
|
-
* `CMAKE_CXX_COMPILER_ID`, `CMAKE_SIZEOF_VOID_P`, `CMAKE_SYSTEM_NAME`, and
|
|
9
|
-
* `WIN32` / `APPLE` / `UNIX` become valid. The bundled utility scripts
|
|
10
|
-
* (`variables.cmake` etc.) rely on those, so they cannot be included from
|
|
11
|
-
* the toolchain body.
|
|
12
|
-
*
|
|
13
|
-
* @param {object} args
|
|
14
|
-
* @param {string[]} args.packageNames Resolved dep names in topological order.
|
|
15
|
-
* @param {string} args.profileHash 16-char profile hash (for logging).
|
|
16
|
-
* @returns {string} CMake file content.
|
|
17
|
-
*/
|
|
18
|
-
function generateDepsCmake({ packageNames, profileHash }) {
|
|
19
|
-
const findPackageCalls = packageNames
|
|
20
|
-
.map((name) => ` find_package(${name} CONFIG QUIET)`)
|
|
21
|
-
.join('\n');
|
|
22
|
-
|
|
23
|
-
const resolvedList = packageNames.map((n) => ` ${n}`).join('\n');
|
|
24
|
-
|
|
25
|
-
return `# Generated by wyvrnpm — do not edit.
|
|
26
|
-
# Loaded after project() via CMAKE_PROJECT_INCLUDE.
|
|
27
|
-
# Profile hash: ${profileHash}
|
|
28
|
-
|
|
29
|
-
if(WYVRN_DEPS_INCLUDED)
|
|
30
|
-
return()
|
|
31
|
-
endif()
|
|
32
|
-
set(WYVRN_DEPS_INCLUDED TRUE)
|
|
33
|
-
|
|
34
|
-
# List of every package resolved by \`wyvrnpm install\`, in topological order.
|
|
35
|
-
set(WYVRN_RESOLVED_PACKAGES
|
|
36
|
-
${resolvedList || ' # (none)'}
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
# ── Bundled wyvrnpm CMake utilities ───────────────────────────────────────────
|
|
40
|
-
# Included in the order the utility scripts expect.
|
|
41
|
-
include("\${WYVRNPM_CMAKE_DIR}/variables.cmake")
|
|
42
|
-
include("\${WYVRNPM_CMAKE_DIR}/options.cmake")
|
|
43
|
-
include("\${WYVRNPM_CMAKE_DIR}/cpp.cmake")
|
|
44
|
-
include("\${WYVRNPM_CMAKE_DIR}/functions.cmake")
|
|
45
|
-
include("\${WYVRNPM_CMAKE_DIR}/macros.cmake")
|
|
46
|
-
|
|
47
|
-
# ── Sanity checks (warn only — do not override the consumer's environment) ───
|
|
48
|
-
if(DEFINED CMAKE_CXX_COMPILER_ID AND DEFINED WYVRN_PROFILE_COMPILER)
|
|
49
|
-
set(_wyvrn_expected_compiler_id "")
|
|
50
|
-
if(WYVRN_PROFILE_COMPILER STREQUAL "msvc")
|
|
51
|
-
set(_wyvrn_expected_compiler_id "MSVC")
|
|
52
|
-
elseif(WYVRN_PROFILE_COMPILER STREQUAL "gcc")
|
|
53
|
-
set(_wyvrn_expected_compiler_id "GNU")
|
|
54
|
-
elseif(WYVRN_PROFILE_COMPILER STREQUAL "clang")
|
|
55
|
-
set(_wyvrn_expected_compiler_id "Clang")
|
|
56
|
-
elseif(WYVRN_PROFILE_COMPILER STREQUAL "apple-clang")
|
|
57
|
-
set(_wyvrn_expected_compiler_id "AppleClang")
|
|
58
|
-
endif()
|
|
59
|
-
if(_wyvrn_expected_compiler_id AND NOT CMAKE_CXX_COMPILER_ID STREQUAL _wyvrn_expected_compiler_id)
|
|
60
|
-
message(WARNING
|
|
61
|
-
"wyvrnpm profile expects compiler '\${WYVRN_PROFILE_COMPILER}' "
|
|
62
|
-
"(CMake id '\${_wyvrn_expected_compiler_id}') but the active compiler "
|
|
63
|
-
"is '\${CMAKE_CXX_COMPILER_ID}'. Installed binaries may be ABI-incompatible."
|
|
64
|
-
)
|
|
65
|
-
endif()
|
|
66
|
-
endif()
|
|
67
|
-
|
|
68
|
-
if(DEFINED CMAKE_SIZEOF_VOID_P AND DEFINED WYVRN_PROFILE_ARCH)
|
|
69
|
-
if(WYVRN_PROFILE_ARCH STREQUAL "x86_64" OR WYVRN_PROFILE_ARCH STREQUAL "armv8")
|
|
70
|
-
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|
71
|
-
message(WARNING
|
|
72
|
-
"wyvrnpm profile expects 64-bit arch '\${WYVRN_PROFILE_ARCH}' "
|
|
73
|
-
"but CMake is configuring a 32-bit build (CMAKE_SIZEOF_VOID_P=\${CMAKE_SIZEOF_VOID_P})."
|
|
74
|
-
)
|
|
75
|
-
endif()
|
|
76
|
-
elseif(WYVRN_PROFILE_ARCH STREQUAL "x86")
|
|
77
|
-
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 4)
|
|
78
|
-
message(WARNING
|
|
79
|
-
"wyvrnpm profile expects 32-bit arch 'x86' "
|
|
80
|
-
"but CMake is configuring a 64-bit build (CMAKE_SIZEOF_VOID_P=\${CMAKE_SIZEOF_VOID_P})."
|
|
81
|
-
)
|
|
82
|
-
endif()
|
|
83
|
-
endif()
|
|
84
|
-
endif()
|
|
85
|
-
|
|
86
|
-
# ── wyvrnpm_find_dependencies() ───────────────────────────────────────────────
|
|
87
|
-
# One-shot helper: resolves every package that wyvrnpm installed.
|
|
88
|
-
# Packages that don't ship a CMake config are silently skipped (CONFIG QUIET).
|
|
89
|
-
function(wyvrnpm_find_dependencies)
|
|
90
|
-
${findPackageCalls || ' # (no dependencies)'}
|
|
91
|
-
|
|
92
|
-
# Post-find aliasing: ensure every resolved package has a wyvrn::<name>
|
|
93
|
-
# target, creating an INTERFACE alias when the package exports only
|
|
94
|
-
# <name>::<name>. Skipped when wyvrn::<name> already exists.
|
|
95
|
-
foreach(_wyvrn_pkg IN LISTS WYVRN_RESOLVED_PACKAGES)
|
|
96
|
-
if(TARGET wyvrn::\${_wyvrn_pkg})
|
|
97
|
-
# Already provided by the package's own CMake config.
|
|
98
|
-
elseif(TARGET \${_wyvrn_pkg}::\${_wyvrn_pkg})
|
|
99
|
-
add_library(wyvrn::\${_wyvrn_pkg} INTERFACE IMPORTED)
|
|
100
|
-
set_target_properties(wyvrn::\${_wyvrn_pkg} PROPERTIES
|
|
101
|
-
INTERFACE_LINK_LIBRARIES \${_wyvrn_pkg}::\${_wyvrn_pkg}
|
|
102
|
-
)
|
|
103
|
-
endif()
|
|
104
|
-
endforeach()
|
|
105
|
-
endfunction()
|
|
106
|
-
|
|
107
|
-
# ── wyvrnpm_enable_runtime_dll_copy(target) ───────────────────────────────────
|
|
108
|
-
# Adds a POST_BUILD command that copies every runtime DLL the target depends on
|
|
109
|
-
# (transitively, via \$<TARGET_RUNTIME_DLLS:...>) next to the target's own
|
|
110
|
-
# binary — so consumers can run the executable straight from the build dir
|
|
111
|
-
# without \`PATH\` tinkering. No-op on non-Windows platforms and on non-
|
|
112
|
-
# executable targets.
|
|
113
|
-
#
|
|
114
|
-
# Respects the per-target opt-out property WYVRN_COPY_RUNTIME_DLLS OFF.
|
|
115
|
-
# Requires CMake ≥ 3.21 (for TARGET_RUNTIME_DLLS).
|
|
116
|
-
function(wyvrnpm_enable_runtime_dll_copy target)
|
|
117
|
-
if(NOT WIN32)
|
|
118
|
-
return()
|
|
119
|
-
endif()
|
|
120
|
-
if(NOT TARGET \${target})
|
|
121
|
-
message(WARNING "wyvrnpm_enable_runtime_dll_copy: target '\${target}' does not exist")
|
|
122
|
-
return()
|
|
123
|
-
endif()
|
|
124
|
-
get_target_property(_wyvrn_type \${target} TYPE)
|
|
125
|
-
if(NOT _wyvrn_type STREQUAL "EXECUTABLE")
|
|
126
|
-
return()
|
|
127
|
-
endif()
|
|
128
|
-
get_target_property(_wyvrn_optout \${target} WYVRN_COPY_RUNTIME_DLLS)
|
|
129
|
-
if(_wyvrn_optout STREQUAL "OFF" OR _wyvrn_optout STREQUAL "FALSE")
|
|
130
|
-
return()
|
|
131
|
-
endif()
|
|
132
|
-
add_custom_command(TARGET \${target} POST_BUILD
|
|
133
|
-
COMMAND \${CMAKE_COMMAND} -E copy_if_different
|
|
134
|
-
"\$<TARGET_RUNTIME_DLLS:\${target}>"
|
|
135
|
-
"\$<TARGET_FILE_DIR:\${target}>"
|
|
136
|
-
COMMAND_EXPAND_LISTS
|
|
137
|
-
VERBATIM
|
|
138
|
-
)
|
|
139
|
-
endfunction()
|
|
140
|
-
|
|
141
|
-
# ── wyvrnpm_finalize_targets() ────────────────────────────────────────────────
|
|
142
|
-
# Discovers all executable targets in the calling directory (top-level only,
|
|
143
|
-
# not recursive) and wires each one up for runtime-DLL copy. Call this at the
|
|
144
|
-
# end of the consumer's top-level CMakeLists.txt, AFTER all add_executable()
|
|
145
|
-
# calls, so every target is visible.
|
|
146
|
-
#
|
|
147
|
-
# Scope: uses the BUILDSYSTEM_TARGETS directory property of the calling
|
|
148
|
-
# directory. For multi-subdirectory projects where executables are added from
|
|
149
|
-
# subdirectories, consumers should either:
|
|
150
|
-
# (a) call wyvrnpm_enable_runtime_dll_copy(<tgt>) explicitly for each exe, or
|
|
151
|
-
# (b) call wyvrnpm_finalize_targets() from each subdirectory.
|
|
152
|
-
function(wyvrnpm_finalize_targets)
|
|
153
|
-
get_property(_wyvrn_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
|
|
154
|
-
foreach(_wyvrn_t IN LISTS _wyvrn_targets)
|
|
155
|
-
get_target_property(_wyvrn_type \${_wyvrn_t} TYPE)
|
|
156
|
-
if(_wyvrn_type STREQUAL "EXECUTABLE")
|
|
157
|
-
wyvrnpm_enable_runtime_dll_copy(\${_wyvrn_t})
|
|
158
|
-
endif()
|
|
159
|
-
endforeach()
|
|
160
|
-
endfunction()
|
|
161
|
-
`;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
module.exports = { generateDepsCmake };
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate the contents of `wyvrn_deps.cmake`.
|
|
5
|
+
*
|
|
6
|
+
* This file is loaded via `CMAKE_PROJECT_INCLUDE` — it runs after the
|
|
7
|
+
* consumer's first `project()` call, which is when CMake variables like
|
|
8
|
+
* `CMAKE_CXX_COMPILER_ID`, `CMAKE_SIZEOF_VOID_P`, `CMAKE_SYSTEM_NAME`, and
|
|
9
|
+
* `WIN32` / `APPLE` / `UNIX` become valid. The bundled utility scripts
|
|
10
|
+
* (`variables.cmake` etc.) rely on those, so they cannot be included from
|
|
11
|
+
* the toolchain body.
|
|
12
|
+
*
|
|
13
|
+
* @param {object} args
|
|
14
|
+
* @param {string[]} args.packageNames Resolved dep names in topological order.
|
|
15
|
+
* @param {string} args.profileHash 16-char profile hash (for logging).
|
|
16
|
+
* @returns {string} CMake file content.
|
|
17
|
+
*/
|
|
18
|
+
function generateDepsCmake({ packageNames, profileHash }) {
|
|
19
|
+
const findPackageCalls = packageNames
|
|
20
|
+
.map((name) => ` find_package(${name} CONFIG QUIET)`)
|
|
21
|
+
.join('\n');
|
|
22
|
+
|
|
23
|
+
const resolvedList = packageNames.map((n) => ` ${n}`).join('\n');
|
|
24
|
+
|
|
25
|
+
return `# Generated by wyvrnpm — do not edit.
|
|
26
|
+
# Loaded after project() via CMAKE_PROJECT_INCLUDE.
|
|
27
|
+
# Profile hash: ${profileHash}
|
|
28
|
+
|
|
29
|
+
if(WYVRN_DEPS_INCLUDED)
|
|
30
|
+
return()
|
|
31
|
+
endif()
|
|
32
|
+
set(WYVRN_DEPS_INCLUDED TRUE)
|
|
33
|
+
|
|
34
|
+
# List of every package resolved by \`wyvrnpm install\`, in topological order.
|
|
35
|
+
set(WYVRN_RESOLVED_PACKAGES
|
|
36
|
+
${resolvedList || ' # (none)'}
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# ── Bundled wyvrnpm CMake utilities ───────────────────────────────────────────
|
|
40
|
+
# Included in the order the utility scripts expect.
|
|
41
|
+
include("\${WYVRNPM_CMAKE_DIR}/variables.cmake")
|
|
42
|
+
include("\${WYVRNPM_CMAKE_DIR}/options.cmake")
|
|
43
|
+
include("\${WYVRNPM_CMAKE_DIR}/cpp.cmake")
|
|
44
|
+
include("\${WYVRNPM_CMAKE_DIR}/functions.cmake")
|
|
45
|
+
include("\${WYVRNPM_CMAKE_DIR}/macros.cmake")
|
|
46
|
+
|
|
47
|
+
# ── Sanity checks (warn only — do not override the consumer's environment) ───
|
|
48
|
+
if(DEFINED CMAKE_CXX_COMPILER_ID AND DEFINED WYVRN_PROFILE_COMPILER)
|
|
49
|
+
set(_wyvrn_expected_compiler_id "")
|
|
50
|
+
if(WYVRN_PROFILE_COMPILER STREQUAL "msvc")
|
|
51
|
+
set(_wyvrn_expected_compiler_id "MSVC")
|
|
52
|
+
elseif(WYVRN_PROFILE_COMPILER STREQUAL "gcc")
|
|
53
|
+
set(_wyvrn_expected_compiler_id "GNU")
|
|
54
|
+
elseif(WYVRN_PROFILE_COMPILER STREQUAL "clang")
|
|
55
|
+
set(_wyvrn_expected_compiler_id "Clang")
|
|
56
|
+
elseif(WYVRN_PROFILE_COMPILER STREQUAL "apple-clang")
|
|
57
|
+
set(_wyvrn_expected_compiler_id "AppleClang")
|
|
58
|
+
endif()
|
|
59
|
+
if(_wyvrn_expected_compiler_id AND NOT CMAKE_CXX_COMPILER_ID STREQUAL _wyvrn_expected_compiler_id)
|
|
60
|
+
message(WARNING
|
|
61
|
+
"wyvrnpm profile expects compiler '\${WYVRN_PROFILE_COMPILER}' "
|
|
62
|
+
"(CMake id '\${_wyvrn_expected_compiler_id}') but the active compiler "
|
|
63
|
+
"is '\${CMAKE_CXX_COMPILER_ID}'. Installed binaries may be ABI-incompatible."
|
|
64
|
+
)
|
|
65
|
+
endif()
|
|
66
|
+
endif()
|
|
67
|
+
|
|
68
|
+
if(DEFINED CMAKE_SIZEOF_VOID_P AND DEFINED WYVRN_PROFILE_ARCH)
|
|
69
|
+
if(WYVRN_PROFILE_ARCH STREQUAL "x86_64" OR WYVRN_PROFILE_ARCH STREQUAL "armv8")
|
|
70
|
+
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|
71
|
+
message(WARNING
|
|
72
|
+
"wyvrnpm profile expects 64-bit arch '\${WYVRN_PROFILE_ARCH}' "
|
|
73
|
+
"but CMake is configuring a 32-bit build (CMAKE_SIZEOF_VOID_P=\${CMAKE_SIZEOF_VOID_P})."
|
|
74
|
+
)
|
|
75
|
+
endif()
|
|
76
|
+
elseif(WYVRN_PROFILE_ARCH STREQUAL "x86")
|
|
77
|
+
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 4)
|
|
78
|
+
message(WARNING
|
|
79
|
+
"wyvrnpm profile expects 32-bit arch 'x86' "
|
|
80
|
+
"but CMake is configuring a 64-bit build (CMAKE_SIZEOF_VOID_P=\${CMAKE_SIZEOF_VOID_P})."
|
|
81
|
+
)
|
|
82
|
+
endif()
|
|
83
|
+
endif()
|
|
84
|
+
endif()
|
|
85
|
+
|
|
86
|
+
# ── wyvrnpm_find_dependencies() ───────────────────────────────────────────────
|
|
87
|
+
# One-shot helper: resolves every package that wyvrnpm installed.
|
|
88
|
+
# Packages that don't ship a CMake config are silently skipped (CONFIG QUIET).
|
|
89
|
+
function(wyvrnpm_find_dependencies)
|
|
90
|
+
${findPackageCalls || ' # (no dependencies)'}
|
|
91
|
+
|
|
92
|
+
# Post-find aliasing: ensure every resolved package has a wyvrn::<name>
|
|
93
|
+
# target, creating an INTERFACE alias when the package exports only
|
|
94
|
+
# <name>::<name>. Skipped when wyvrn::<name> already exists.
|
|
95
|
+
foreach(_wyvrn_pkg IN LISTS WYVRN_RESOLVED_PACKAGES)
|
|
96
|
+
if(TARGET wyvrn::\${_wyvrn_pkg})
|
|
97
|
+
# Already provided by the package's own CMake config.
|
|
98
|
+
elseif(TARGET \${_wyvrn_pkg}::\${_wyvrn_pkg})
|
|
99
|
+
add_library(wyvrn::\${_wyvrn_pkg} INTERFACE IMPORTED)
|
|
100
|
+
set_target_properties(wyvrn::\${_wyvrn_pkg} PROPERTIES
|
|
101
|
+
INTERFACE_LINK_LIBRARIES \${_wyvrn_pkg}::\${_wyvrn_pkg}
|
|
102
|
+
)
|
|
103
|
+
endif()
|
|
104
|
+
endforeach()
|
|
105
|
+
endfunction()
|
|
106
|
+
|
|
107
|
+
# ── wyvrnpm_enable_runtime_dll_copy(target) ───────────────────────────────────
|
|
108
|
+
# Adds a POST_BUILD command that copies every runtime DLL the target depends on
|
|
109
|
+
# (transitively, via \$<TARGET_RUNTIME_DLLS:...>) next to the target's own
|
|
110
|
+
# binary — so consumers can run the executable straight from the build dir
|
|
111
|
+
# without \`PATH\` tinkering. No-op on non-Windows platforms and on non-
|
|
112
|
+
# executable targets.
|
|
113
|
+
#
|
|
114
|
+
# Respects the per-target opt-out property WYVRN_COPY_RUNTIME_DLLS OFF.
|
|
115
|
+
# Requires CMake ≥ 3.21 (for TARGET_RUNTIME_DLLS).
|
|
116
|
+
function(wyvrnpm_enable_runtime_dll_copy target)
|
|
117
|
+
if(NOT WIN32)
|
|
118
|
+
return()
|
|
119
|
+
endif()
|
|
120
|
+
if(NOT TARGET \${target})
|
|
121
|
+
message(WARNING "wyvrnpm_enable_runtime_dll_copy: target '\${target}' does not exist")
|
|
122
|
+
return()
|
|
123
|
+
endif()
|
|
124
|
+
get_target_property(_wyvrn_type \${target} TYPE)
|
|
125
|
+
if(NOT _wyvrn_type STREQUAL "EXECUTABLE")
|
|
126
|
+
return()
|
|
127
|
+
endif()
|
|
128
|
+
get_target_property(_wyvrn_optout \${target} WYVRN_COPY_RUNTIME_DLLS)
|
|
129
|
+
if(_wyvrn_optout STREQUAL "OFF" OR _wyvrn_optout STREQUAL "FALSE")
|
|
130
|
+
return()
|
|
131
|
+
endif()
|
|
132
|
+
add_custom_command(TARGET \${target} POST_BUILD
|
|
133
|
+
COMMAND \${CMAKE_COMMAND} -E copy_if_different
|
|
134
|
+
"\$<TARGET_RUNTIME_DLLS:\${target}>"
|
|
135
|
+
"\$<TARGET_FILE_DIR:\${target}>"
|
|
136
|
+
COMMAND_EXPAND_LISTS
|
|
137
|
+
VERBATIM
|
|
138
|
+
)
|
|
139
|
+
endfunction()
|
|
140
|
+
|
|
141
|
+
# ── wyvrnpm_finalize_targets() ────────────────────────────────────────────────
|
|
142
|
+
# Discovers all executable targets in the calling directory (top-level only,
|
|
143
|
+
# not recursive) and wires each one up for runtime-DLL copy. Call this at the
|
|
144
|
+
# end of the consumer's top-level CMakeLists.txt, AFTER all add_executable()
|
|
145
|
+
# calls, so every target is visible.
|
|
146
|
+
#
|
|
147
|
+
# Scope: uses the BUILDSYSTEM_TARGETS directory property of the calling
|
|
148
|
+
# directory. For multi-subdirectory projects where executables are added from
|
|
149
|
+
# subdirectories, consumers should either:
|
|
150
|
+
# (a) call wyvrnpm_enable_runtime_dll_copy(<tgt>) explicitly for each exe, or
|
|
151
|
+
# (b) call wyvrnpm_finalize_targets() from each subdirectory.
|
|
152
|
+
function(wyvrnpm_finalize_targets)
|
|
153
|
+
get_property(_wyvrn_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
|
|
154
|
+
foreach(_wyvrn_t IN LISTS _wyvrn_targets)
|
|
155
|
+
get_target_property(_wyvrn_type \${_wyvrn_t} TYPE)
|
|
156
|
+
if(_wyvrn_type STREQUAL "EXECUTABLE")
|
|
157
|
+
wyvrnpm_enable_runtime_dll_copy(\${_wyvrn_t})
|
|
158
|
+
endif()
|
|
159
|
+
endforeach()
|
|
160
|
+
endfunction()
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = { generateDepsCmake };
|