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 CHANGED
@@ -4,7 +4,7 @@ A simple, private C++ package manager that works with any static file hosting pr
4
4
 
5
5
  There is no central registry. You control where packages are hosted.
6
6
 
7
- > **README version: 2.0.1** — Last updated to reflect the v2 build-profile system.
7
+ > **README version: 2.1.0** — Adds CMake toolchain generation, the `wyvrnpm build` command, declarative compatibility, and `--build=missing` source-build.
8
8
 
9
9
  ---
10
10
 
@@ -40,10 +40,13 @@ wyvrnpm configure profile detect
40
40
  # 4. Install dependencies (resolved against your build profile)
41
41
  wyvrnpm install
42
42
 
43
- # 5. Publish your package (uses the active profile automatically)
43
+ # 5. Configure and build via the generated CMake preset
44
+ wyvrnpm build
45
+
46
+ # 6. Publish your package (uses the active profile automatically)
44
47
  wyvrnpm publish
45
48
 
46
- # 6. (Optional) Link local packages for development
49
+ # 7. (Optional) Link local packages for development
47
50
  cd ../my-local-lib && wyvrnpm link
48
51
  cd ../my-app && wyvrnpm link my-local-lib
49
52
  ```
@@ -112,7 +115,14 @@ Resolves the full dependency graph and downloads all packages.
112
115
 
113
116
  **Source priority:** CLI `--source` values are used if provided. If omitted, sources are loaded from the [configuration file](#configuration-file).
114
117
 
115
- **Profile resolution:** `--profile` selects the named build profile. If omitted, `config.defaultProfile` is used, falling back to `"default"`. v2 binaries are matched first by exact profile hash; if no exact match is found, the tool looks for a compatible build (same OS + arch, any compiler), then falls back to the v1 legacy path.
118
+ **Profile resolution:** `--profile` selects the named build profile. If omitted, `config.defaultProfile` is used, falling back to `"default"`. v2 binaries are resolved in this order:
119
+
120
+ 1. **Exact profile-hash match** — the preferred path.
121
+ 2. **Declarative compatibility** — each published build may advertise a `compatibility` block (e.g. "compatible with any `msvc.version ≥ 193` on `Windows/x86_64`"). The best compatible candidate is picked deterministically.
122
+ 3. **Source build** (with `--build=missing`) — clones the package's source at the published `gitSha`, resolves its own dependencies, invokes CMake through the shared toolchain generator, and caches the result under `%LOCALAPPDATA%\wyvrnpm\bc\`. On Windows/MSVC with a Ninja or Make generator, `vcvarsall.bat` is auto-activated.
123
+ 4. **v1 legacy path** — only when no v2 entry exists for the package at all.
124
+
125
+ The pre-2.1 "same OS + arch, any compiler" loose fallback is removed from the default path. It remains reachable for one release cycle via `WYVRNPM_ALLOW_LOOSE_COMPAT=1` and prints a deprecation warning.
116
126
 
117
127
  ```bash
118
128
  # Use configured sources and the default build profile
@@ -128,6 +138,9 @@ wyvrnpm install --source https://pkg.example.com/cpp
128
138
  wyvrnpm install \
129
139
  --source https://primary.example.com/cpp \
130
140
  --source https://mirror.example.com/cpp
141
+
142
+ # Build any missing binary from source
143
+ wyvrnpm install --build=missing
131
144
  ```
132
145
 
133
146
  **Options**
@@ -136,6 +149,7 @@ wyvrnpm install \
136
149
  |---|---|---|
137
150
  | `--source` / `-s` | *(config)* | Base URL of a package source. Repeat for multiple. Overrides config when provided. |
138
151
  | `--profile` / `-p` | *(config / "default")* | Named build profile to use for v2 binary resolution. |
152
+ | `--build` | `never` | Resolution mode when no exact or compatible profile match exists: `never` fails; `missing` clones and builds the package from its published `gitRepo@gitSha`; `always` rebuilds even when a binary exists. |
139
153
  | `--platform` | `win_x64` | v1 legacy platform sub-path (used as a fallback when no v2 binary is found). |
140
154
  | `--timeout` | `300` | HTTP request timeout in seconds. |
141
155
  | `--manifest` | `./wyvrn.json` | Path to the manifest file. |
@@ -143,6 +157,66 @@ wyvrnpm install \
143
157
 
144
158
  Packages are extracted to `wyvrn_internal/{name}/`. A `wyvrn.lock` file is written alongside the manifest recording the exact resolved versions, profile, and per-package SHA256. On subsequent installs the lock file pins all previously resolved versions — only newly added dependencies are resolved fresh.
145
159
 
160
+ After download, `install` also generates:
161
+
162
+ - `wyvrn_internal/wyvrn_toolchain.cmake` — CMake toolchain pointing at the resolved packages.
163
+ - `wyvrn_internal/wyvrn_deps.cmake` — post-`project()` include for `find_package()` wiring and runtime DLL copy.
164
+ - `wyvrn_internal/wyvrn_profile.json` — snapshot of the active build profile.
165
+ - `CMakePresets.json` (or `CMakeUserPresets.json` if the project root file is user-owned) with a `wyvrn-<profile>` configure preset. Presets for other profiles are preserved so multiple profiles coexist.
166
+
167
+ ---
168
+
169
+ ### `wyvrnpm build`
170
+
171
+ Configures and builds the project through the wyvrnpm-generated CMake preset. Auto-runs `install` first if `wyvrn_toolchain.cmake` is missing or `wyvrn.lock` is newer than it.
172
+
173
+ ```bash
174
+ # Configure + build with the default profile's preset (wyvrn-default)
175
+ wyvrnpm build
176
+
177
+ # Build Debug, verbose compiler output
178
+ wyvrnpm build --config Debug --verbose
179
+
180
+ # Use a specific profile's preset
181
+ wyvrnpm build --profile release
182
+
183
+ # Explicit preset name (overrides profile-derived default)
184
+ wyvrnpm build --preset wyvrn-release
185
+
186
+ # Build a single target
187
+ wyvrnpm build --target my-lib
188
+
189
+ # Wipe the build directory first
190
+ wyvrnpm build --clean
191
+
192
+ # Build, then install to the CMake install prefix
193
+ wyvrnpm build --install
194
+ wyvrnpm build --install --install-prefix C:\out\stage
195
+
196
+ # Skip the auto-install step
197
+ wyvrnpm build --no-auto-install
198
+
199
+ # Pass extra args through to cmake --build
200
+ wyvrnpm build -- -j 8
201
+ ```
202
+
203
+ **Options**
204
+
205
+ | Option | Default | Description |
206
+ |---|---|---|
207
+ | `--preset` / `-P` | `wyvrn-<profile>` | CMake configure preset name. |
208
+ | `--profile` / `-p` | *(config / "default")* | Build profile — determines the default preset name. |
209
+ | `--config` / `-c` | `Release` | Build configuration (`Debug` \| `Release` \| `RelWithDebInfo` \| `MinSizeRel`). |
210
+ | `--target` / `-t` | *(all)* | Specific CMake target to build. |
211
+ | `--verbose` / `-v` | `false` | Pass `--verbose` to `cmake --build`. |
212
+ | `--clean` | `false` | Remove the build directory before configuring. |
213
+ | `--install` | `false` | Run `cmake --install` after a successful build. |
214
+ | `--install-prefix` | *(baked in)* | Override `CMAKE_INSTALL_PREFIX` for `--install` without reconfiguring. |
215
+ | `--auto-install` | `true` | Auto-run `wyvrnpm install` when the toolchain is stale. Disable with `--no-auto-install`. |
216
+ | `--source` / `-s` | *(config)* | Package sources — passed through to `install` when auto-installing. |
217
+
218
+ Everything after `--` is forwarded verbatim to `cmake --build` (e.g. `-j 8`).
219
+
146
220
  ---
147
221
 
148
222
  ### `wyvrnpm publish`
@@ -221,9 +295,19 @@ build/
221
295
  Removes the `wyvrn_internal/` package cache and `wyvrn.lock`.
222
296
 
223
297
  ```bash
298
+ # Project-local cleanup
224
299
  wyvrnpm clean
300
+
301
+ # Also wipe the machine-wide source-build cache used by --build=missing
302
+ wyvrnpm clean --build-cache
225
303
  ```
226
304
 
305
+ **Options**
306
+
307
+ | Option | Default | Description |
308
+ |---|---|---|
309
+ | `--build-cache` | `false` | Also remove the source-build cache under `%LOCALAPPDATA%\wyvrnpm\bc\` (Unix: `~/.cache/wyvrnpm/bc/`). |
310
+
227
311
  ---
228
312
 
229
313
  ### `wyvrnpm link`
@@ -651,6 +735,203 @@ Fields use PascalCase. `Dependencies` is an array — transitive dependencies ar
651
735
 
652
736
  **`dependencies`** can be either a plain version string (`"major.minor.patch.build"`) or an object with `version` and an optional `settings` map. The `settings` map overrides individual build profile fields for that specific dependency — useful when a dependency must be consumed with a different runtime linkage or C++ standard than your default profile.
653
737
 
738
+ ### Source-build recipe (`build`)
739
+
740
+ A library package may include an optional `build` section that tells `wyvrnpm install --build=missing` how to rebuild it from source. Only `system: "cmake"` is supported today.
741
+
742
+ ```json
743
+ {
744
+ "name": "zlib",
745
+ "version": "1.3.0.0",
746
+ "kind": "StaticLib",
747
+ "build": {
748
+ "system": "cmake",
749
+ "generator": ["Ninja", "Visual Studio 17 2022"],
750
+ "configs": ["Release", "Debug"],
751
+ "configure": ["-DZLIB_BUILD_EXAMPLES=OFF"],
752
+ "buildArgs": ["--parallel"],
753
+ "installDir": "install",
754
+ "sourceSubdir": "."
755
+ }
756
+ }
757
+ ```
758
+
759
+ | Field | Default | Description |
760
+ |---|---|---|
761
+ | `system` | `cmake` | Build system. Only `cmake` is supported. |
762
+ | `generator` | *(CMake default)* | Single generator (`"Ninja"`) or an array tried in order — first available wins. |
763
+ | `configs` | `["Debug","Release","RelWithDebInfo","MinSizeRel"]` | CMake configurations to build and install. |
764
+ | `configure` | `[]` | Extra args appended to `cmake` at configure time. |
765
+ | `buildArgs` | `[]` | Extra args appended to `cmake --build`. |
766
+ | `installDir` | `install` | Install prefix relative to the binary dir. |
767
+ | `sourceSubdir` | `.` | Where `CMakeLists.txt` lives relative to the clone root. |
768
+ | `requiredTools` | `[]` | Tools that must be on `PATH` before the build starts (fail-fast check). |
769
+
770
+ On Windows with MSVC and a non-Visual-Studio generator (Ninja, Make), `vcvarsall.bat` is auto-activated for the spawned CMake process — no need to launch from a Developer Prompt.
771
+
772
+ ---
773
+
774
+ ## Compatibility Rules
775
+
776
+ Publishers declare an optional `compatibility` block in a package's `wyvrn.json`. It tells wyvrnpm which profile fields must match the consumer's profile exactly, and which may legitimately differ without breaking ABI. When no exact `profileHash` match exists on the registry, `install` evaluates this block against every published build for the requested `(name, version)` and picks the best compatible candidate.
777
+
778
+ ### Block format
779
+
780
+ Each field maps to a mode — either as a string shorthand or an object:
781
+
782
+ ```json
783
+ {
784
+ "name": "zlib",
785
+ "version": "1.3.0.0",
786
+ "compatibility": {
787
+ "compiler.cppstd": "lte",
788
+ "compiler.runtime": "exact",
789
+ "compiler.version": "exact-or-newer"
790
+ }
791
+ }
792
+ ```
793
+
794
+ Object form is accepted too (`{ "mode": "lte" }`) and leaves room for future per-field options.
795
+
796
+ ### Supported modes
797
+
798
+ | Mode | Meaning |
799
+ |---|---|
800
+ | `exact` | Package and consumer values must be equal. |
801
+ | `any` | Field is ignored for compatibility purposes. |
802
+ | `lte` | Package value ≤ consumer value — e.g. a `cppstd=20` package is usable by a `cppstd=23` consumer. |
803
+ | `gte` | Package value ≥ consumer value (symmetry; rarely useful). |
804
+ | `exact-or-newer` | Same as `lte` at MVP — kept as a distinct name because it reads naturally for compiler-version fields. |
805
+
806
+ **Defaults:**
807
+
808
+ - Any field not listed is treated as `exact`.
809
+ - `os` and `arch` are **always `exact`** regardless of what the block says. Cross-OS / cross-arch binaries are never ABI-compatible.
810
+
811
+ ### Where to author it
812
+
813
+ The block lives in the **source** `wyvrn.json` (the one you commit). It is read at publish time and written into the uploaded manifest. If the source `wyvrn.json` has no `compatibility` block, `wyvrnpm publish` injects a conservative default (all fields `exact`) so existing packages behave strict-by-default.
814
+
815
+ Consumers never author compatibility — it is a property of the published package.
816
+
817
+ ### Tiebreaker
818
+
819
+ When multiple published builds satisfy the consumer's profile, the winner is picked deterministically:
820
+
821
+ 1. Prefer the candidate whose `compiler` matches the consumer's.
822
+ 2. Prefer the highest numeric `compiler.version`.
823
+ 3. Prefer the candidate whose `compiler.runtime` matches the consumer's.
824
+ 4. Fall back to the lexicographically earliest `profileHash`.
825
+
826
+ The chosen candidate is logged along with a per-field summary (e.g. `compiler.cppstd 20→23 (lte), compiler.runtime=dynamic`).
827
+
828
+ ### Legacy loose fallback
829
+
830
+ The pre-2.1 "same OS + arch, any compiler" fallback is removed from the default resolution path. For one release cycle it remains reachable via an env var:
831
+
832
+ ```bash
833
+ WYVRNPM_ALLOW_LOOSE_COMPAT=1 wyvrnpm install
834
+ ```
835
+
836
+ This prints a deprecation warning every time it fires and will be removed in the next minor release. Prefer adding a real `compatibility` block to affected packages, or rebuilding with `--build=missing`.
837
+
838
+ ---
839
+
840
+ ## Source Builds
841
+
842
+ `wyvrnpm install --build=missing` clones a package's source at its published `gitSha` and builds it locally when no prebuilt binary matches (exact or compatible) the consumer's profile. This is the Conan-2.0 `--build=missing` parity feature.
843
+
844
+ ### When it fires
845
+
846
+ 1. You run `wyvrnpm install --build=missing`.
847
+ 2. For each dependency, wyvrnpm tries `v2 exact → v2 compat` first.
848
+ 3. If neither hits, it looks up `gitRepo` + `gitSha` from **any** existing build of the same `(name, version)` on the registry (they are equal across profiles for a given version).
849
+ 4. It clones, resolves the package's own transitive deps, invokes CMake through the shared toolchain generator, zips the install dir, and treats the result as a v2 download.
850
+
851
+ If the package has no prior publish on the registry at all, there is no `gitSha` to clone — source-build fails fast with a clear error. Source-builds cascade transitively: if package A needs source-build and depends on package B which also needs source-build, both are built.
852
+
853
+ ### Authoring the `build` recipe
854
+
855
+ Libraries that want to be source-buildable declare a `build` section in their own `wyvrn.json`. See [Project Manifest §Source-build recipe](#source-build-recipe-build) for the field list. Only `system: "cmake"` is supported today.
856
+
857
+ ### Generator fallback
858
+
859
+ `build.generator` accepts either a string or an array:
860
+
861
+ | Form | Behaviour |
862
+ |---|---|
863
+ | `"Ninja"` | Strict — fails if Ninja is not available. |
864
+ | `["Ninja", "Visual Studio 17 2022"]` | Tried in order — first available wins. Unknown entries are trusted (CMake decides at configure time). |
865
+ | *(omitted)* | Uses CMake's platform default. |
866
+
867
+ ### MSVC environment auto-activation (Windows)
868
+
869
+ On Windows, when **all** of the following hold:
870
+
871
+ - `profile.compiler === "msvc"`
872
+ - The chosen generator is **not** a Visual Studio generator (e.g. Ninja, Make)
873
+ - `cl.exe` is not on `PATH`
874
+
875
+ …wyvrnpm locates Visual Studio via `vswhere.exe`, runs `vcvarsall.bat <arch>` in a sub-shell, captures the resulting environment, and uses it for the CMake spawn. You do not need to launch from a Developer Prompt.
876
+
877
+ Arch mapping follows the active profile:
878
+
879
+ | `profile.arch` | `vcvarsall` arg |
880
+ |---|---|
881
+ | `x86_64` | `x64` |
882
+ | `x86` | `x86` |
883
+ | `armv8` | `arm64` |
884
+ | `armv7` | `arm` |
885
+
886
+ VS generators skip this path entirely — MSBuild resolves MSVC itself.
887
+
888
+ ### Cache
889
+
890
+ Source builds are cached machine-wide, keyed by `(name, version, profileHash)`:
891
+
892
+ | Platform | Path |
893
+ |---|---|
894
+ | Windows | `%LOCALAPPDATA%\wyvrnpm\bc\{name}-{version}-{profileHash}\` |
895
+ | Linux / macOS | `~/.cache/wyvrnpm/bc/{name}-{version}-{profileHash}/` |
896
+
897
+ Re-running `install --build=missing` with the same inputs short-circuits to the cached artefact. The cache root is deliberately shallow (`bc/`, not `build-cache/`) to keep nested CMake paths under Windows' 260-char limit.
898
+
899
+ Clone behaviour is tri-tier:
900
+
901
+ 1. **Shallow-SHA fetch** (`git fetch origin <sha> --depth=1`) — fastest; works when the git server allows it.
902
+ 2. **Full fetch** — falls back to a full `git clone --tags` when the server rejects shallow-SHA (older Bitbucket installs disable `uploadpack.allowReachableSHA1InWant`).
903
+ 3. **Rebuild from scratch** — if the cached clone is broken, wipes and retries.
904
+
905
+ After every clone/fetch, wyvrnpm runs `git cat-file -e <sha>^{commit}` to verify the SHA is actually reachable. If it is not, the error points at the likely cause: the publisher forgot to push before running `wyvrnpm publish`.
906
+
907
+ ### Publish-time guard
908
+
909
+ To catch the unpushed-commit case before consumers hit it, `wyvrnpm publish` checks whether the current `HEAD` is reachable from any remote branch or tag and warns if it is not:
910
+
911
+ ```
912
+ [wyvrn] warn: git SHA abc1234 is not on origin — source-build consumers will fail until pushed
913
+ ```
914
+
915
+ The warning does **not** block publishing.
916
+
917
+ ### Header-only libraries
918
+
919
+ `kind: "HeaderOnlyLib"` packages still need a `build` section and a CMake `install()` rule that copies headers. There is no fast-path that zips the source tree directly — consumers get exactly what the `install()` step produces, same as any other kind.
920
+
921
+ ### Clearing the cache
922
+
923
+ ```bash
924
+ # Remove the project-local cache (wyvrn_internal/ + wyvrn.lock)
925
+ wyvrnpm clean
926
+
927
+ # Also wipe the machine-wide source-build cache
928
+ wyvrnpm clean --build-cache
929
+ ```
930
+
931
+ ### Credentials for private repos
932
+
933
+ wyvrnpm uses your ambient git configuration (SSH keys, credential helpers, Windows Credential Manager). It does not manage git credentials itself. If `git clone <gitRepo>` works from your shell, source-build works.
934
+
654
935
  ---
655
936
 
656
937
  ## Lock File (wyvrn.lock)
@@ -687,6 +968,103 @@ Locked versions always take priority over transitive requests. A warning is prin
687
968
 
688
969
  ---
689
970
 
971
+ ## CMake Integration
972
+
973
+ `wyvrnpm install` emits a ready-to-use CMake toolchain alongside the downloaded packages. Most projects only need to run:
974
+
975
+ ```bash
976
+ wyvrnpm install
977
+ wyvrnpm build
978
+ ```
979
+
980
+ …which is equivalent to:
981
+
982
+ ```bash
983
+ cmake --preset wyvrn-default
984
+ cmake --build build/wyvrn-default --config Release
985
+ ```
986
+
987
+ **Generated files (inside the project)**
988
+
989
+ | Path | Purpose |
990
+ |---|---|
991
+ | `wyvrn_internal/wyvrn_toolchain.cmake` | Toolchain file — sets `CMAKE_PREFIX_PATH`, compiler/runtime, and standards from the active profile. Include via the preset or `-DCMAKE_TOOLCHAIN_FILE=…`. |
992
+ | `wyvrn_internal/wyvrn_deps.cmake` | Include **after** `project()` (e.g. `include(${CMAKE_BINARY_DIR}/../wyvrn_internal/wyvrn_deps.cmake)`). Wires `find_package()` calls and defines `wyvrnpm_finalize_targets(<tgt>…)` for runtime DLL copy next to your executable. |
993
+ | `wyvrn_internal/wyvrn_profile.json` | Snapshot of the profile the toolchain was generated against. |
994
+ | `CMakePresets.json` / `CMakeUserPresets.json` | `wyvrn-<profile>` configure preset. Regenerating preserves other profiles' presets. |
995
+
996
+ **Bundled CMake utilities** (shipped in the npm tarball under `cmake/`) are auto-included by `wyvrn_toolchain.cmake`:
997
+
998
+ | File | Provides |
999
+ |---|---|
1000
+ | `cpp.cmake` | C++ standard defaults (guarded — toolchain wins). |
1001
+ | `variables.cmake` | Platform detection (`WYVRN_PLATFORM_WIN`, …) and compiler flags. |
1002
+ | `options.cmake` | Feature toggles (`WYVRN_ENABLE_LOG`, …). |
1003
+ | `functions.cmake` | `SETUP_LIBRARY` / `SETUP_EXE` plus HAL source-collection helpers. |
1004
+ | `macros.cmake` | `WYVRN_INSTALL_MODULE`, `WYVRN_CONFIGURE_VERSION_HEADER`. |
1005
+
1006
+ **Minimal `CMakeLists.txt`:**
1007
+
1008
+ ```cmake
1009
+ cmake_minimum_required(VERSION 3.21)
1010
+ project(my-app CXX)
1011
+
1012
+ include(${CMAKE_SOURCE_DIR}/wyvrn_internal/wyvrn_deps.cmake)
1013
+
1014
+ add_executable(my-app src/main.cpp)
1015
+ target_link_libraries(my-app PRIVATE OpenSSL::SSL zlib::zlib)
1016
+
1017
+ wyvrnpm_finalize_targets(my-app) # copies runtime DLLs next to the .exe
1018
+ ```
1019
+
1020
+ ---
1021
+
1022
+ ## Installing Build Artifacts (`wyvrnpm build --install`)
1023
+
1024
+ `wyvrnpm build --install` runs `cmake --install <binaryDir>` after a successful build, invoking every `install()` rule in your `CMakeLists.txt`. This is the step that produces a redistributable layout (headers + libs + runtime files in a tidy tree) rather than the raw CMake build directory.
1025
+
1026
+ ### Typical use
1027
+
1028
+ ```bash
1029
+ # Configure, build, and install to the default prefix (baked in at configure time)
1030
+ wyvrnpm build --install
1031
+
1032
+ # Override the install prefix without reconfiguring
1033
+ wyvrnpm build --install --install-prefix C:\out\stage
1034
+
1035
+ # Install a specific config
1036
+ wyvrnpm build --install --config Debug
1037
+ ```
1038
+
1039
+ ### What it does, in order
1040
+
1041
+ 1. **Staleness check** — if `wyvrn_internal/wyvrn_toolchain.cmake` is missing or `wyvrn.lock` is newer than it, auto-runs `wyvrnpm install` first. Disable with `--no-auto-install`.
1042
+ 2. **Optional clean** — `--clean` wipes the build directory before configuring.
1043
+ 3. **Configure** — `cmake --preset wyvrn-<profile>` (or the value of `--preset`).
1044
+ 4. **Build** — `cmake --build <binaryDir> --config <config>`.
1045
+ 5. **Install** — `cmake --install <binaryDir> --config <config> [--prefix <install-prefix>]`.
1046
+
1047
+ ### `--auto-install` vs `--install`
1048
+
1049
+ These two flags are easy to confuse — they control unrelated things:
1050
+
1051
+ | Flag | What it does | When it runs |
1052
+ |---|---|---|
1053
+ | `--auto-install` *(default: on)* | Runs `wyvrnpm install` if the toolchain is stale. Disable with `--no-auto-install`. | **Before** configure. |
1054
+ | `--install` *(default: off)* | Runs `cmake --install` after a successful build. | **After** build. |
1055
+
1056
+ ### `--install-prefix`
1057
+
1058
+ CMake bakes `CMAKE_INSTALL_PREFIX` into the build cache at configure time. Passing `--install-prefix` at install time uses `cmake --install --prefix <path>` to override the baked value **without** re-running configure — cheaper than a full reconfigure when you only want to stage to a different location.
1059
+
1060
+ If you omit `--install-prefix`, the baked default is used. The baked default comes from the generated preset, typically under `build/wyvrn-<profile>/install`.
1061
+
1062
+ ### Permissions
1063
+
1064
+ Installing to a system path (`/usr/local`, `C:\Program Files`) requires the usual elevated permissions — wyvrnpm does not auto-elevate. For staging or packaging, point `--install-prefix` at a writable user directory instead.
1065
+
1066
+ ---
1067
+
690
1068
  ## Version Conflict Resolution
691
1069
 
692
1070
  When the dependency graph requires the same package at multiple versions, the highest version wins. If a `wyvrn.lock` exists, locked versions always take priority over any conflicting transitive request. A warning is printed for every conflict detected.
package/bin/wyvrn.js CHANGED
@@ -9,9 +9,11 @@ const clean = require('../src/commands/clean');
9
9
  const publish = require('../src/commands/publish');
10
10
  const configure = require('../src/commands/configure');
11
11
  const profile = require('../src/commands/profile');
12
+ const build = require('../src/commands/build');
12
13
  const { link, unlink } = require('../src/commands/link');
13
14
 
14
15
  yargs
16
+ .parserConfiguration({ 'populate--': true })
15
17
  .option('manifest', {
16
18
  type: 'string',
17
19
  description: 'Path to manifest file',
@@ -48,6 +50,14 @@ yargs
48
50
  type: 'string',
49
51
  description: 'Build profile name to use (default: config.defaultProfile → "default")',
50
52
  })
53
+ .option('build', {
54
+ type: 'string',
55
+ choices: ['never', 'missing', 'always'],
56
+ default: 'never',
57
+ description:
58
+ 'Resolution mode when no exact profile match exists. ' +
59
+ 'never=fail; missing=build from source (pending phase 3); always=rebuild (pending phase 3)',
60
+ })
51
61
  .option('platform', {
52
62
  type: 'string',
53
63
  description: 'v1 legacy platform path (used as fallback if v2 not found)',
@@ -63,12 +73,95 @@ yargs
63
73
  (argv) => install(argv),
64
74
  )
65
75
 
76
+ // ── build ─────────────────────────────────────────────────────────────────
77
+ .command(
78
+ 'build',
79
+ 'Configure and build the project via the wyvrnpm-generated CMake preset. ' +
80
+ 'Auto-runs `install` if the toolchain is missing or stale.',
81
+ (y) => {
82
+ y
83
+ .option('preset', {
84
+ alias: 'P',
85
+ type: 'string',
86
+ description: 'CMake configure preset name (default: wyvrn-<profile>)',
87
+ })
88
+ .option('profile', {
89
+ alias: 'p',
90
+ type: 'string',
91
+ description: 'Build profile name — determines the default preset',
92
+ })
93
+ .option('config', {
94
+ alias: 'c',
95
+ type: 'string',
96
+ choices: ['Debug', 'Release', 'RelWithDebInfo', 'MinSizeRel'],
97
+ default: 'Release',
98
+ description: 'Build configuration',
99
+ })
100
+ .option('target', {
101
+ alias: 't',
102
+ type: 'string',
103
+ description: 'CMake target to build (default: all)',
104
+ })
105
+ .option('verbose', {
106
+ alias: 'v',
107
+ type: 'boolean',
108
+ default: false,
109
+ description: 'Pass --verbose to cmake --build (detailed compiler output)',
110
+ })
111
+ .option('clean', {
112
+ type: 'boolean',
113
+ default: false,
114
+ description: 'Remove the build directory before configuring',
115
+ })
116
+ .option('install', {
117
+ type: 'boolean',
118
+ default: false,
119
+ description: 'Run `cmake --install` after the build (installs to the prefix baked at configure time, or --install-prefix)',
120
+ })
121
+ .option('install-prefix', {
122
+ type: 'string',
123
+ description: 'Override CMAKE_INSTALL_PREFIX for `--install` without reconfiguring',
124
+ })
125
+ .option('auto-install', {
126
+ type: 'boolean',
127
+ default: true,
128
+ description: 'Auto-run `wyvrnpm install` when the toolchain is stale. Disable with --no-auto-install.',
129
+ })
130
+ .option('source', {
131
+ alias: 's',
132
+ type: 'string',
133
+ array: true,
134
+ description: 'Package source(s) — passed through to `install` when auto-installing',
135
+ })
136
+ .option('platform', {
137
+ type: 'string',
138
+ choices: ['win_x64', 'win_x86', 'linux_x64', 'linux_x86', 'osx_x64', 'osx_arm64'],
139
+ default: 'win_x64',
140
+ })
141
+ .option('timeout', {
142
+ type: 'number',
143
+ default: 300,
144
+ });
145
+ },
146
+ (argv) => build({
147
+ ...argv,
148
+ autoInstall: argv['auto-install'],
149
+ installPrefix: argv['install-prefix'],
150
+ }),
151
+ )
152
+
66
153
  // ── clean ─────────────────────────────────────────────────────────────────
67
154
  .command(
68
155
  'clean',
69
- 'Remove downloaded packages and lock file',
70
- () => {},
71
- (argv) => clean(argv),
156
+ 'Remove downloaded packages and lock file. --build-cache also wipes the machine-wide source-build cache.',
157
+ (y) => {
158
+ y.option('build-cache', {
159
+ type: 'boolean',
160
+ default: false,
161
+ description: 'Also remove the source-build cache under %LOCALAPPDATA%\\wyvrnpm\\bc\\',
162
+ });
163
+ },
164
+ (argv) => clean({ ...argv, buildCache: argv['build-cache'] }),
72
165
  )
73
166
 
74
167
  // ── publish ───────────────────────────────────────────────────────────────
@@ -0,0 +1,9 @@
1
+ # Define the cpp information ( version, compilation type, thread type, exception handling )
2
+ # Set a C++20 default only if the consumer (or wyvrnpm's toolchain) has not
3
+ # already chosen a standard — the toolchain sets CMAKE_CXX_STANDARD from the
4
+ # active build profile before project(), and that explicit choice must win.
5
+ if(NOT DEFINED CMAKE_CXX_STANDARD)
6
+ set(CMAKE_CXX_STANDARD 20)
7
+ set(CMAKE_CXX_STANDARD_REQUIRED True)
8
+ endif()
9
+ set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API OFF)