wyvrnpm 2.0.2 → 2.1.0
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 +382 -4
- package/bin/wyvrn.js +96 -3
- package/cmake/cpp.cmake +9 -0
- package/cmake/functions.cmake +224 -0
- package/cmake/macros.cmake +233 -0
- package/cmake/options.cmake +23 -0
- package/cmake/variables.cmake +171 -0
- package/package.json +2 -1
- package/src/build/cache.js +101 -0
- package/src/build/clone.js +170 -0
- package/src/build/cmake.js +342 -0
- package/src/build/index.js +244 -0
- package/src/build/msvc-env.js +217 -0
- package/src/build/recipe.js +129 -0
- package/src/commands/build.js +242 -0
- package/src/commands/clean.js +25 -9
- package/src/commands/configure.js +6 -5
- package/src/commands/init.js +3 -2
- package/src/commands/install.js +61 -14
- package/src/commands/link.js +18 -15
- package/src/commands/profile.js +15 -12
- package/src/commands/publish.js +67 -31
- package/src/compat.js +232 -0
- package/src/config.js +3 -1
- package/src/download.js +369 -87
- package/src/logger.js +78 -0
- package/src/profile.js +28 -0
- package/src/providers/file.js +4 -3
- package/src/providers/http.js +3 -2
- package/src/providers/s3.js +3 -2
- package/src/resolve.js +33 -7
- package/src/toolchain/deps.js +164 -0
- package/src/toolchain/index.js +141 -0
- package/src/toolchain/presets.js +191 -0
- package/src/toolchain/template.cmake +66 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const VENDOR_KEY = 'wyvrnpm/generated';
|
|
7
|
+
const SCHEMA_VERSION = 3; // requires CMake ≥ 3.21
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Safely parse a JSON file; returns null on any error (missing, malformed, …).
|
|
11
|
+
* @param {string} p
|
|
12
|
+
* @returns {object|null}
|
|
13
|
+
*/
|
|
14
|
+
function safeReadJson(p) {
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* True if the parsed presets object was produced by wyvrnpm (i.e. carries our
|
|
24
|
+
* vendor marker). Hand-edited or user-owned files return false.
|
|
25
|
+
*
|
|
26
|
+
* @param {object|null} presets
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
*/
|
|
29
|
+
function isWyvrnGenerated(presets) {
|
|
30
|
+
return !!presets && typeof presets.vendor === 'object' && !!presets.vendor[VENDOR_KEY];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build the configure preset object for the active profile.
|
|
35
|
+
*
|
|
36
|
+
* @param {object} args
|
|
37
|
+
* @param {string} args.profileName
|
|
38
|
+
* @param {string} args.profileHash
|
|
39
|
+
* @param {string} args.toolchainRelPath Relative from project root, CMake-style
|
|
40
|
+
* forward slashes.
|
|
41
|
+
*/
|
|
42
|
+
function buildConfigurePreset({ profileName, profileHash, toolchainRelPath }) {
|
|
43
|
+
return {
|
|
44
|
+
name: `wyvrn-${profileName}`,
|
|
45
|
+
displayName: `wyvrnpm (${profileName})`,
|
|
46
|
+
description: `Generated by wyvrnpm install — profile hash ${profileHash}`,
|
|
47
|
+
binaryDir: `\${sourceDir}/build/wyvrn-${profileName}`,
|
|
48
|
+
cacheVariables: {
|
|
49
|
+
CMAKE_TOOLCHAIN_FILE: `\${sourceDir}/${toolchainRelPath}`,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Two build presets per configure preset: Debug and Release.
|
|
56
|
+
*
|
|
57
|
+
* @param {string} profileName
|
|
58
|
+
* @returns {Array<object>}
|
|
59
|
+
*/
|
|
60
|
+
function buildBuildPresets(profileName) {
|
|
61
|
+
const config = `wyvrn-${profileName}`;
|
|
62
|
+
return [
|
|
63
|
+
{
|
|
64
|
+
name: `${config}-debug`,
|
|
65
|
+
displayName: `wyvrn ${profileName} (Debug)`,
|
|
66
|
+
configurePreset: config,
|
|
67
|
+
configuration: 'Debug',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: `${config}-release`,
|
|
71
|
+
displayName: `wyvrn ${profileName} (Release)`,
|
|
72
|
+
configurePreset: config,
|
|
73
|
+
configuration: 'Release',
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Build a fresh presets file from scratch (no prior content to merge).
|
|
80
|
+
*/
|
|
81
|
+
function buildFreshPresetsFile({ profileName, profileHash, toolchainRelPath }) {
|
|
82
|
+
return {
|
|
83
|
+
version: SCHEMA_VERSION,
|
|
84
|
+
vendor: {
|
|
85
|
+
[VENDOR_KEY]: {
|
|
86
|
+
profileName,
|
|
87
|
+
profileHash,
|
|
88
|
+
generatedAt: new Date().toISOString(),
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
configurePresets: [buildConfigurePreset({ profileName, profileHash, toolchainRelPath })],
|
|
92
|
+
buildPresets: buildBuildPresets(profileName),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Merge the current profile's presets into an existing wyvrnpm-generated
|
|
98
|
+
* file. Presets with matching `name` are replaced; others are preserved so
|
|
99
|
+
* `wyvrnpm install --profile release` followed by `wyvrnpm install --profile
|
|
100
|
+
* debug` leaves both profiles available in the file.
|
|
101
|
+
*
|
|
102
|
+
* @param {object} existing
|
|
103
|
+
* @param {object} args forwarded to the preset builders
|
|
104
|
+
* @returns {object}
|
|
105
|
+
*/
|
|
106
|
+
function mergeIntoExisting(existing, { profileName, profileHash, toolchainRelPath }) {
|
|
107
|
+
const newConfigure = buildConfigurePreset({ profileName, profileHash, toolchainRelPath });
|
|
108
|
+
const newBuilds = buildBuildPresets(profileName);
|
|
109
|
+
const newConfigureNames = new Set([newConfigure.name]);
|
|
110
|
+
const newBuildNames = new Set(newBuilds.map((b) => b.name));
|
|
111
|
+
|
|
112
|
+
const configurePresets = (existing.configurePresets ?? []).filter((p) => !newConfigureNames.has(p.name));
|
|
113
|
+
configurePresets.push(newConfigure);
|
|
114
|
+
|
|
115
|
+
const buildPresets = (existing.buildPresets ?? []).filter((p) => !newBuildNames.has(p.name));
|
|
116
|
+
buildPresets.push(...newBuilds);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
...existing,
|
|
120
|
+
version: existing.version ?? SCHEMA_VERSION,
|
|
121
|
+
vendor: {
|
|
122
|
+
...(existing.vendor ?? {}),
|
|
123
|
+
[VENDOR_KEY]: {
|
|
124
|
+
profileName,
|
|
125
|
+
profileHash,
|
|
126
|
+
generatedAt: new Date().toISOString(),
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
configurePresets,
|
|
130
|
+
buildPresets,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Write a CMakePresets.json (or CMakeUserPresets.json, as fallback) under
|
|
136
|
+
* `projectRoot`. Never overwrites a user-owned file.
|
|
137
|
+
*
|
|
138
|
+
* Resolution order:
|
|
139
|
+
* 1. CMakePresets.json
|
|
140
|
+
* - Does not exist → create it.
|
|
141
|
+
* - Exists, wyvrn-gen → merge into it.
|
|
142
|
+
* - Exists, user-owned → leave alone, fall through.
|
|
143
|
+
* 2. CMakeUserPresets.json
|
|
144
|
+
* - Does not exist → create it.
|
|
145
|
+
* - Exists, wyvrn-gen → merge into it.
|
|
146
|
+
* - Exists, user-owned → skip (action: "skipped").
|
|
147
|
+
*
|
|
148
|
+
* @param {object} args
|
|
149
|
+
* @param {string} args.projectRoot Directory containing top-level CMakeLists.txt.
|
|
150
|
+
* @param {string} args.profileName
|
|
151
|
+
* @param {string} args.profileHash
|
|
152
|
+
* @param {string} args.toolchainRelPath CMake-style forward slashes, relative to projectRoot.
|
|
153
|
+
* @returns {{ path: string|null, action: 'created'|'updated'|'skipped', isUser: boolean }}
|
|
154
|
+
*/
|
|
155
|
+
function generateCMakePresets({ projectRoot, profileName, profileHash, toolchainRelPath }) {
|
|
156
|
+
const candidates = [
|
|
157
|
+
{ filePath: path.join(projectRoot, 'CMakePresets.json'), isUser: false },
|
|
158
|
+
{ filePath: path.join(projectRoot, 'CMakeUserPresets.json'), isUser: true },
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
for (const { filePath, isUser } of candidates) {
|
|
162
|
+
if (!fs.existsSync(filePath)) {
|
|
163
|
+
const content = buildFreshPresetsFile({ profileName, profileHash, toolchainRelPath });
|
|
164
|
+
fs.writeFileSync(filePath, JSON.stringify(content, null, 2) + '\n', 'utf8');
|
|
165
|
+
return { path: filePath, action: 'created', isUser };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const existing = safeReadJson(filePath);
|
|
169
|
+
if (isWyvrnGenerated(existing)) {
|
|
170
|
+
const merged = mergeIntoExisting(existing, { profileName, profileHash, toolchainRelPath });
|
|
171
|
+
fs.writeFileSync(filePath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
172
|
+
return { path: filePath, action: 'updated', isUser };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// User-owned — do not touch, try next candidate.
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return { path: null, action: 'skipped', isUser: false };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports = {
|
|
182
|
+
generateCMakePresets,
|
|
183
|
+
// Exported for tests
|
|
184
|
+
isWyvrnGenerated,
|
|
185
|
+
buildConfigurePreset,
|
|
186
|
+
buildBuildPresets,
|
|
187
|
+
buildFreshPresetsFile,
|
|
188
|
+
mergeIntoExisting,
|
|
189
|
+
VENDOR_KEY,
|
|
190
|
+
SCHEMA_VERSION,
|
|
191
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Generated by wyvrnpm — do not edit.
|
|
2
|
+
# Regenerated on every `wyvrnpm install`.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=wyvrn_internal/wyvrn_toolchain.cmake
|
|
6
|
+
#
|
|
7
|
+
# Profile : {{PROFILE_NAME}} [{{PROFILE_HASH}}]
|
|
8
|
+
# Generated: {{GENERATED_AT}}
|
|
9
|
+
|
|
10
|
+
if(WYVRNPM_TOOLCHAIN_INCLUDED)
|
|
11
|
+
return()
|
|
12
|
+
endif()
|
|
13
|
+
set(WYVRNPM_TOOLCHAIN_INCLUDED TRUE)
|
|
14
|
+
|
|
15
|
+
# ── Active build profile (copied verbatim from wyvrn_profile.json) ────────────
|
|
16
|
+
set(WYVRN_PROFILE_NAME "{{PROFILE_NAME}}")
|
|
17
|
+
set(WYVRN_PROFILE_HASH "{{PROFILE_HASH}}")
|
|
18
|
+
set(WYVRN_PROFILE_OS "{{PROFILE_OS}}")
|
|
19
|
+
set(WYVRN_PROFILE_ARCH "{{PROFILE_ARCH}}")
|
|
20
|
+
set(WYVRN_PROFILE_COMPILER "{{PROFILE_COMPILER}}")
|
|
21
|
+
set(WYVRN_PROFILE_COMPILER_VERSION "{{PROFILE_COMPILER_VERSION}}")
|
|
22
|
+
set(WYVRN_PROFILE_CPPSTD "{{PROFILE_CPPSTD}}")
|
|
23
|
+
set(WYVRN_PROFILE_RUNTIME "{{PROFILE_RUNTIME}}")
|
|
24
|
+
|
|
25
|
+
# ── Path to wyvrnpm's bundled CMake utilities (variables.cmake, etc.) ─────────
|
|
26
|
+
# Resolved at generation time so the toolchain works regardless of whether
|
|
27
|
+
# wyvrnpm was installed globally, locally, or via npx.
|
|
28
|
+
set(WYVRNPM_CMAKE_DIR "{{WYVRNPM_CMAKE_DIR}}")
|
|
29
|
+
|
|
30
|
+
# ── C++ standard ──────────────────────────────────────────────────────────────
|
|
31
|
+
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
|
32
|
+
set(CMAKE_CXX_STANDARD {{PROFILE_CPPSTD}})
|
|
33
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
34
|
+
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
35
|
+
endif()
|
|
36
|
+
|
|
37
|
+
# ── MSVC runtime library ──────────────────────────────────────────────────────
|
|
38
|
+
# Only meaningful when the actual compiler is MSVC. CMake ignores this on other
|
|
39
|
+
# compilers, so setting it unconditionally is safe.
|
|
40
|
+
if("${WYVRN_PROFILE_RUNTIME}" STREQUAL "dynamic")
|
|
41
|
+
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
|
42
|
+
elseif("${WYVRN_PROFILE_RUNTIME}" STREQUAL "static")
|
|
43
|
+
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
|
44
|
+
endif()
|
|
45
|
+
|
|
46
|
+
# ── Position-independent code (sensible default for mixed static/shared) ──────
|
|
47
|
+
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
|
48
|
+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|
49
|
+
endif()
|
|
50
|
+
|
|
51
|
+
# ── CMAKE_PREFIX_PATH: so find_package(<dep> CONFIG) finds installed deps ─────
|
|
52
|
+
list(PREPEND CMAKE_PREFIX_PATH
|
|
53
|
+
{{PREFIX_PATH_ENTRIES}}
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# ── CMAKE_MODULE_PATH: so include(<script>) finds bundled *.cmake files ───────
|
|
57
|
+
list(PREPEND CMAKE_MODULE_PATH
|
|
58
|
+
"${WYVRNPM_CMAKE_DIR}"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# ── Post-project() hook ───────────────────────────────────────────────────────
|
|
62
|
+
# CMAKE_PROJECT_INCLUDE runs after the first project() call, which is when
|
|
63
|
+
# CMAKE_SYSTEM_NAME / CMAKE_CXX_COMPILER_ID / CMAKE_SIZEOF_VOID_P become valid.
|
|
64
|
+
# The bundled utilities (variables.cmake etc.) rely on those — so they must be
|
|
65
|
+
# included from here, not from the toolchain body above.
|
|
66
|
+
set(CMAKE_PROJECT_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/wyvrn_deps.cmake")
|