diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9275318..a2663fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ env: # through the runner named after its format, which is how `mcpp run --format # app` reaches `macapp-run`. An engine below it stages no `needs` lines, and # `dist-apk` refuses its tree naming this release. - MCPP_VERSION: 2026.9.14.2 + MCPP_VERSION: 2026.9.16.1 # AN ENGINE BUILT FROM SOURCE, WHEN A DISPATCH NAMES ONE. # # Empty on every push and pull request, so the steps run the release above. @@ -1249,11 +1249,12 @@ jobs: # does; `dist-apk` provisions the four payloads on its own # `feature-xlings.dist-apk` table (`xim:android-build-tools`, `xim: # android-platform`, `xim:jdk-temurin`, `xim:android-debug-keystore`). - # NOT YET GREEN under this job's pinned `MCPP_VERSION`: `kind = "app"` - # and `mcpp::min_platform_version()` are #622 engine additions, and - # this step needs the release that carries them (see this repository's - # README, `dist-apk`'s own row) -- raising the pin is P5's own change, - # together with the rest of this collection's release. + # `kind = "app"` and `mcpp::min_platform_version()` are #622 engine + # additions, and this step needed the release that carries them; the pin + # has been above it since 2026.9.14.2 and the step is green. From + # 2026.9.16.1 the pin also carries the engine's strip decision + # (`MCPP_PACK_STRIP`, `MCPP_PACK_DEBUG_SYMBOLS_DIR`), which is what lets + # legs (m) and (n) below run rather than report themselves skipped. # # THIS STEP ASSERTS PACKAGING ONLY, DELIBERATELY, NOT `mcpp run # --format apk`. This fixture's own `main.cpp` and `mcpp.toml` DO wire @@ -1352,6 +1353,19 @@ jobs: working-directory: tests/apk-consumer-libraries run: MCPP="$MCPP" ./check-apk-libraries.sh + # LIBRARIES THE GRAPH CONTRIBUTES (0.12.0). `tests/apk-consumer-graph/lib` + # states `[package.metadata.dist-apk]`, and the application names it only + # as a dependency. Under an engine that gives the root build program the + # resolved graph (mcpp 2026.9.16.1+) the library's resource is in the APK, + # `graph_libraries = false` reads none, the application's own library wins + # a resource both define, and a malformed contribution is refused naming + # the package and the key; under an older engine the pack succeeds without + # the contribution. The script chooses its legs from `mcpp --version`. + - name: dist-apk collects the libraries the resolved graph contributes + timeout-minutes: 30 + working-directory: tests/apk-consumer-graph + run: MCPP="$MCPP" ./check-apk-graph.sh + # Compiles the device unit on a machine with no GPU: the clang route # produces sm_89 code from the payload toolkit. Running it needs a # device, so the run is of the CPU variant, which the same seam serves. @@ -2046,6 +2060,18 @@ jobs: working-directory: tests/metal-consumer run: MCPP="$MCPP" ./check-metal.sh + # rules-swift (mcpp#647 E2): a C++ program calling a Swift function, which + # calls back into C through the bridging header, printing a line from each + # side; the generated header declares the exported function; the fixture + # links for the iOS simulator when the runner has that SDK. On a runner + # without swiftc the script asserts the rule's refusal and annotates the + # run instead. + - name: rules-swift compiles a package's Swift sources, or records that this runner has no swiftc + if: ${{ !cancelled() && runner.os == 'macOS' }} + timeout-minutes: 20 + working-directory: tests/swift-consumer + run: MCPP="$MCPP" ./check-swift.sh + # THE iOS ROW, FOR REAL (#622 B1's other half). `tests/ios-app-consumer` # is the same fixture the Linux `consumers` job checks at the plan # level (see that fixture's own header); here it is built, packed and diff --git a/README.md b/README.md index b14580f..d71756f 100644 --- a/README.md +++ b/README.md @@ -69,14 +69,15 @@ engine's own module family and is not used here. | `rules-metal` | `mcpp.rules.metal` | 2026.9.8.1 | the Metal toolchain of the macOS host's Xcode, located rather than installed: Xcode is not redistributable, so no payload is declared. `.metal` sources the project names on a macOS or iOS row become one `xcrun --sdk metal` action per shader (`-MMD`, so an edited `#include` recompiles the shaders that include it) and one `xcrun --sdk metallib` action per library, placed beside the program with `mcpp::deploy` under `metallib/`, which `dist-apple` maps into the bundle's resources. `compile(shaders)` compiles one source several times with definitions of its own, one library per `shader`; `options::library` links every shader into one library (`default` is the one `newDefaultLibrary` finds). Before planning anything the rule asks `xcrun --sdk --show-sdk-path` and `--find metal` / `--find metallib`, and refuses naming the command that answered nothing, because a missing SDK and a missing compiler have different remedies (Xcode 26 installs the Metal toolchain as a separate component). A shader on any other row is refused naming the row. CI compiles the fixture on `macos-15` and checks each library's magic, and that a header edit recompiles only the shaders that include it | | `rules-slang` | `mcpp.rules.slang` | 2026.9.7.1 | `[build] accel = "vulkan1.2"`, a constrained glob for `*.slang`. Slang is a different language from GLSL rather than a second driver for it -- its own module system, generics, and targets beyond SPIR-V -- so it is a rule of its own. `.slang` is **not** in the engine's device-source table: this feature declares `device_extensions = [".slang"]` and `rule_module = "mcpp.rules.slang"`, and the engine routes it from there. That is the criterion for the whole arrangement -- a new device language costs no engine release. Since 0.7.0 it has the same `options::storage` axis as `rules-spirv` (header / object / sidecar), `options::extra_args` for the arguments the rule has no field for, and `options::per_file` for what one shader gets that the others do not -- a project with a `-fvk-use-gl-layout` and one shader needing `-emit-spirv-via-glsl` writes both without leaving one `compile()` call | | `rules-spirv` | `mcpp.rules.spirv` | 2026.9.6.6 | `[build] accel = "vulkan1.2"`, a constrained glob for the shader stages; compiles each shader through a `role = "source"` action and states which of the two compilers produced it | +| `rules-swift` | `mcpp.rules.swift` | 2026.9.8.1 | the Swift compiler of the macOS host's Xcode or Command Line Tools, located rather than installed, as `rules-metal` locates its toolchain. From 0.12.0. The `.swift` sources a project names on a macOS or iOS row compile as one module named after the package: one whole-module `xcrun --sdk swiftc -wmo -emit-object -target ` action whose role is `object`, so the object joins every image of the package, and one `swiftc -typecheck -emit-objc-header-path` action whose role is `source`, whose directory `mcpp::include_dir` adds, so the package's C and C++ sources include `-Swift.h`. `options::bridging_header` names a C header Swift sees without an import. The link receives the toolchain's `usr/lib/swift/` and the SDK's `usr/lib/swift` as search directories and `/usr/lib/swift` as a run path through `mcpp::link_flag`. Before planning anything the rule asks `xcrun --sdk --show-sdk-path` and `--find swiftc`, and refuses naming the command that answered nothing; a Swift source on any other row is refused naming the row. Not supported: a Swift `import` of another package's module, and another package's C++ including this package's generated header, which both need an engine channel that publishes a package's interface directory to its dependents; and SwiftPM dependencies. CI builds `tests/swift-consumer` on `macos-15` -- a C++ program calling a `@_cdecl` Swift function that calls back into C -- and runs it | | `rules-sycl` | `mcpp.rules.sycl` | 2026.9.6.6 | `[build] accel = "sycl"` or `"sycl, cuda12.9+{sm_89}"`, a constrained glob for `*.sycl`, and `compat:sycl-runtime` so the artifact can reach `libsycl.so.9` at run time. Its own engine need is `.sycl` in the device-source table, 2026.9.6.1 | | `tools-embed` | `mcpp.tools.embed` | 2026.9.5.4 | nothing beyond mcpp: it reads a file and writes a header while the build program runs. The floor is the release whose fast path compares a declared file input, without which an edit to the data does not reach the binary | | `tools-island` | `mcpp.tools.island` | 2026.9.7.1 | nothing beyond mcpp: it reads marked entry points out of an island's own source and writes the `extern "C"` boundary header its compiler reads and the module the C++ side imports. Not a device rule -- it claims no extension, and a project calls it from its own `build.mcpp` | | `dist-appimage` | `mcpp.dist.appimage` | 2026.9.11.1 | `xim:appimagetool`, which this feature declares on the `cfg(linux)` axis. Linux only. Turns the tree `mcpp pack` staged into one AppImage: the staged bundle is already an AppDir bar three files, so the member writes an `AppRun`, a `.desktop` entry and an icon into it and invokes one tool -- it never copies or re-lays-out a tree that can be hundreds of megabytes. From 0.11.1 `options::icon` may be an SVG as well as a PNG: the image carries `.svg`, because the desktop entry names the icon without an extension and a reader finds it by the file's, and any other format is refused by name | | `dist-wix` | `mcpp.dist.wix` | 2026.9.11.1 | `xim:wix` 5.0.2-1, which this feature declares on the Windows target axis; the .NET 6 runtime the tool needs is a Windows component the payload does not carry, and `wix --version` names it when it is missing. Windows only. `--format msi` renders a `.wxs` and passes the program in as a preprocessor variable, because a bind path that resolves to nothing is silent. From 0.10.0 `--format setup` is a Burn bundle chaining that MSI, with WiX's stock bootstrapper application (`bal:WixStandardBootstrapperApplication`, theme `hyperlinkLicense`, `options::license_url` its link) loaded through the `WixToolset.BootstrapperApplications.wixext` extension the 5.0.2-1 payload carries (`options::extension` names another). The bundle is written as `-.exe` beside the MSI, with an UpgradeCode of its own, and `options::bundle_output` naming `setup.exe` is refused before `wix` runs, because `wix` refuses that name (WIX0388). A project with its own bootstrapper application supplies `options::bundle_wxs`, which receives the MSI as `$(Msi)`. From 0.10.1 the MSI installs the staged tree, not the program alone: every file `mcpp pack` stages beside the program (a deployed file, a resolved DLL) is named file by file in a `StagedFiles` component group written beside the definition -- enumerated while the tree exists, never harvested from a directory -- placed at its staged path under `INSTALLFOLDER`, and declared an input of the action; the generated definition references the group, and a project's own `options::wxs` installs it with ``. `options::inputs` and `options::bundle_inputs` declare the files a project's own definitions name beyond that (an icon, a bootstrapper application and its payloads). CI builds the bundle on `windows-2022` and compares the MSI `wix burn extract` takes out of it with the one the first action wrote, and installs the MSI administratively and compares both the program and a deployed file | -| `dist-apple` | `mcpp.dist.apple` | 2026.9.14.2 (0.10.0); 2026.9.11.2 (macOS) and 2026.9.12.3 (iOS) before it | the base macOS install (`ditto`, `codesign`, `hdiutil`), and `xim:macapp-run` for `mcpp run` on macOS, which this feature declares with `when = "run"`. macOS: `Contents/`-shaped, as always. iOS (`aarch64-ios-sim`, `aarch64-ios`): a flat bundle at the same call site -- no separate feature, no separate module -- with `MinimumOSVersion` from `mcpp::min_platform_version()` (#622 A11), `CFBundleSupportedPlatforms` read from `env == "sim"`, `UIDeviceFamily`, `LSRequiresIPhoneOS`, and a directory of flat PNGs listed under `CFBundleIcons` in place of macOS's single `.icns` file. Signing is skipped on the simulator row (`options::identity` is ignored, with a `mcpp::warning` naming why), and the device row signs only with an identity. The iOS row is measured end to end on `macos-15`: a real `mcpp build`, `mcpp pack --format app` and `mcpp run` against `aarch64-ios-sim`, through `xim:apple-simulator-tools`' `simctl-run`. **The macOS floor is one release higher than its siblings** and the reason is not this member: under 2026.9.11.1 `mcpp pack` staged before dispatching and let a staging failure fail the command, so on a Mach-O program -- which the built-in closure walk refuses, because it uses `LD_TRACE_LOADED_OBJECTS` and dyld answers that by running the program -- every dispatched format was unreachable, including one that reads no staged tree. 2026.9.11.2 makes staging a service to the provider. From 0.9.2 the staged tree's deployed files (`bin//...`, which the engine stages for a Mach-O program before the closure walk since the release for mcpp#630) land at the bundle's resource destination -- `Contents/Resources//...` on macOS, the bundle root on iOS -- and the launcher alone goes to the executable directory, so `CFBundleExecutable` names a file that is where it says. The iOS fixture declares `llvm.libcxx` and `llvm.compiler-rt-builtins` under `cfg(os = "ios")`, which is what an application that imports `std` on those rows declares. From 0.10.0, with mcpp 2026.9.14.2: the dylibs the engine stages beside a Mach-O program, which the stage manifest's `needs` lines name, go to `Contents/Frameworks/` (`Frameworks/` on iOS) and not to the resources; the program is linked with the rpath that finds them there (`@executable_path/../Frameworks`, `@executable_path/Frameworks` on iOS) through `mcpp::link_flag`, so no file is edited after the link; a macOS bundle without `options::identity` is signed ad hoc, frameworks first and the bundle second, which `codesign --verify --deep --strict` requires of a bundle that carries a framework; an incomplete closure is a `mcpp::warning` naming the unresolved libraries; every refusal is a `mcpp::warning` as well, because the engine discards a build program's output when it exits 0. On macOS the member supplies the runner named `app` (`macapp-run`), so `mcpp run --format app` runs the bundle's executable in the foreground and returns its status with no runner in the manifest; a manifest runner of that name wins. `--format dmg` stages the bundle beside an `Applications` link and writes a UDZO image with `hdiutil create` (`options::volume_name`, `options::dmg`); it is refused on iOS. An engine below 2026.9.14.2 stages no `needs` lines, so the bundle carries no framework, anchors the rpath to the package directory, and hands the bundle directory to the kernel under `mcpp run --format app` unless `--runner app` is typed. CI measures the bundle on `macos-15`: the load command, the signature, the program with and without its framework (exit 7, then "Library not loaded"), `mcpp run --format app` with and without `--runner app`, and `hdiutil verify` and an attached image. From 0.11.0: a project's own Info.plist entries (`options::info_plist`), an iOS device bundle's provisioning profile (`options::provisioning_profile`), and `devicectl-run` (`xim:apple-device-tools`) as the device row's runner named `app` -- see [`dist-apple`: a project's Info.plist, and an iOS device](#dist-apple-a-projects-infoplist-and-an-ios-device) | -| `dist-web` | `mcpp.dist.web` | 2026.9.13.1, the release that carries `${mcpp.self}` and `mcpp stage`'s argument shape as an engine contract (`stage --verify content --output `) -- what lets this member's copy run on every host mcpp does, Windows included, in place of the `cp` this member used through 0.8.0 | nothing beyond mcpp: `wasm32-emscripten` only. Copies `${mcpp.stage_dir}/bin/` -- the `.js` launcher, the implicit `.wasm`, the `.data` when present, and every `mcpp::deploy`'d file, all of which #622 A5 and A4 already stage there -- to `/web/`, dropping the `bin/` prefix a browser has no use for, and writes an `index.html` rendered from a project template or a built-in default that loads the script with a plain `