Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/descriptor-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ For descriptor templates see [package-types.md](package-types.md).
| Native module library (Form A) | [`mcpplibs.xpkg`](../pkgs/x/xpkg.lua) · [`mcpplibs.tinyhttps`](../pkgs/t/tinyhttps.lua) · [`tensorvia-cpu`](../pkgs/t/tensorvia-cpu.lua) · [`ffmpeg`](../pkgs/f/ffmpeg.lua) (module layer; sources compiled directly through `compat.ffmpeg`) · [`opencv`](../pkgs/o/opencv.opencv.lua) (single repository: the module layer and the full OpenCV 5 source build both live in the package, and only this descriptor stays on the index side) · [`mcpplibs.grpc`](../pkgs/g/grpc.lua) (gRPC 1.83.0 — the one library here that CANNOT be a compat descriptor: upstream publishes no self-contained source artifact, its tag archive carrying abseil/protobuf/re2/boringssl/zlib as empty submodule placeholders, so [grpc-m](https://github.com/mcpplibs/grpc-m)'s release tarball IS that artifact. It vendors only gRPC's own source and takes the five dependencies from this index, so a consumer that also uses protobuf links one copy rather than two) |
| Form A whose consumer deps must be written by hand | [`huxerui.huxerui`](../pkgs/h/huxerui.huxerui.lua) (HuxerUI declares its GTK4 stack on the TARGET axis, which is the form mcpp recommends and which a descriptor structurally cannot carry — three platform blocks, and a cfg selector is not a platform. `mcpp emit xpkg` says so and emits empty `deps`, so the 36-entry closure is transcribed into `xpm.linux.deps` at PLATFORM level (a per-version `deps` is inert). Its `licenses`/`repo` also deliberately disagree with what emit produces) |
| Native multi-module library with feature-scoped sources | [`gzj-creator.galay`](../pkgs/g/gzj-creator.galay.lua) (Galay 5.0.2 — the upstream Form-A manifest exposes `galay.utils` and `galay.kernel` by default, while SSL, HTTP, database, RPC, MCP, and tracing modules stay behind named features and their corresponding dependencies. The index keeps the upstream manifest intact and tests the default module surface on Unix.) |
| C-source compat (with `features`) | [`compat.cjson`](../pkgs/c/compat.cjson.lua) · [`compat.zlib`](../pkgs/c/compat.zlib.lua) · [`compat.hiredis`](../pkgs/c/compat.hiredis.lua) (the classic 1.2.0 — a 7-TU C build whose flat tarball headers get `hiredis/`-prefixed wrapper headers via `generated_files`, so consumers write `#include <hiredis/hiredis.h>` exactly like upstream's install layout) · [`compat.sqlite3`](../pkgs/c/compat.sqlite3.lua) (plain C-source, no features: the single `sqlite3.c` amalgamation; 3.45.3, the final maintenance release of the most widely deployed 3.45.x line) · [`compat.libuv`](../pkgs/c/compat.libuv.lua) (libuv 1.48.0 — the per-OS source sets transcribed from upstream's CMakeLists, because a `src/unix/*.c` glob would compile every OS's backend at once; linux/macos get explicit unix subsets, windows globs `src/win/*.c`) · [`compat.xxhash`](../pkgs/c/compat.xxhash.lua) (one TU, one header, no features at all — the interesting decision is what is NOT compiled: `xxh_x86dispatch.c` selects an AVX2/AVX512 path at RUNTIME and needs per-file `-mavx2` plus `XXH_X86DISPATCH` at every call site, so the package ships the flagless SSE2 baseline instead. Nor is the header-only `XXH_INLINE_ALL` mode chosen: it re-emits the implementation in every TU that hashes anything, which is the right trade only when there is exactly one such TU — something a package cannot know) · [`compat.quickjs-ng`](../pkgs/c/compat.quickjs-ng.lua) (QuickJS-ng 0.17.0 — upstream's four engine TUs and nothing else. `quickjs-libc.c`, the optional standard library that gives scripts files, the environment, timers and child processes, is NOT compiled, so an embedder gets an engine with no host access unless it adds its own. The tarball keeps `quickjs.h` beside private headers with generic names (`list.h`, `cutils.h`), so a `generated_files` forwarder is the only include directory, as in compat.libaio) |
| C-source compat (with `features`) | [`compat.cjson`](../pkgs/c/compat.cjson.lua) · [`compat.zlib`](../pkgs/c/compat.zlib.lua) · [`compat.zlib-ng`](../pkgs/c/compat.zlib-ng.lua) (zlib-ng 2.3.3 in its zlib-compatible form — CMake's `WITH_RUNTIME_CPU_DETECTION=OFF` build, so each function binds at compile time to the best path the architecture's baseline guarantees: NEON on aarch64, SSE2 on x86_64, which an ok image needs because openkal names no processor feature. The architecture sources gate themselves and a generated header sets the gate from the compiler's own macro; the one source without a gate is compiled through a generated forwarder. install() derives `zlib.h`, `zconf.h`, `zlib_name_mangling.h` and `gzread_mangle.h` from the tarball's templates, writing zconf.h's `HAVE_UNISTD_H` line as `#if !defined(_WIN32)` so the library and every consumer read one text. The test reads a stream madler's zlib wrote) · [`compat.hiredis`](../pkgs/c/compat.hiredis.lua) (the classic 1.2.0 — a 7-TU C build whose flat tarball headers get `hiredis/`-prefixed wrapper headers via `generated_files`, so consumers write `#include <hiredis/hiredis.h>` exactly like upstream's install layout) · [`compat.sqlite3`](../pkgs/c/compat.sqlite3.lua) (plain C-source, no features: the single `sqlite3.c` amalgamation; 3.45.3, the final maintenance release of the most widely deployed 3.45.x line) · [`compat.libuv`](../pkgs/c/compat.libuv.lua) (libuv 1.48.0 — the per-OS source sets transcribed from upstream's CMakeLists, because a `src/unix/*.c` glob would compile every OS's backend at once; linux/macos get explicit unix subsets, windows globs `src/win/*.c`) · [`compat.xxhash`](../pkgs/c/compat.xxhash.lua) (one TU, one header, no features at all — the interesting decision is what is NOT compiled: `xxh_x86dispatch.c` selects an AVX2/AVX512 path at RUNTIME and needs per-file `-mavx2` plus `XXH_X86DISPATCH` at every call site, so the package ships the flagless SSE2 baseline instead. Nor is the header-only `XXH_INLINE_ALL` mode chosen: it re-emits the implementation in every TU that hashes anything, which is the right trade only when there is exactly one such TU — something a package cannot know) · [`compat.quickjs-ng`](../pkgs/c/compat.quickjs-ng.lua) (QuickJS-ng 0.17.0 — upstream's four engine TUs and nothing else. `quickjs-libc.c`, the optional standard library that gives scripts files, the environment, timers and child processes, is NOT compiled, so an embedder gets an engine with no host access unless it adds its own. The tarball keeps `quickjs.h` beside private headers with generic names (`list.h`, `cutils.h`), so a `generated_files` forwarder is the only include directory, as in compat.libaio) |
| C-source compat whose sources are chosen by ARCHITECTURE | [`compat.wamr`](../pkgs/c/compat.wamr.lua) (WAMR 2.4.5 — the descriptor schema varies `sources` and `cflags` per OS but has no per-architecture hook, and `archs` is package metadata rather than a selector. WAMR needs both: one of `BUILD_TARGET_X86_64`/`BUILD_TARGET_AARCH64` must be defined or `wasm_runtime_common.c` compiles its whole invoke-native section away and the link fails on `invokeNative`, and the implementation of that symbol is a hand-written assembly file per architecture. Both halves are handed to the preprocessor instead: a `generated_files` config header maps `__x86_64__`/`__aarch64__` to the matching `BUILD_TARGET_*` and reaches every TU through `-include`, and a generated `.S` — `.S`, because upstream's `arch/invokeNative_*.s` are lowercase and clang assembles those WITHOUT the preprocessor, so unlike libffi's `.S` files they cannot guard themselves — `#include`s the chosen one as text. Two further notes worth copying: `-std=gnu11` arrives through `cflags` because `c_standard = "c11"` defines `__STRICT_ANSI__`, under which the bare `asm` in `platform_internal.h` is not a keyword; and the POSIX files upstream drops when WASI is off are carried unconditionally rather than `!`-excluded and re-added by the `libc-wasi` feature, because an exclusion glob is global and wins over the feature's own entry for the same file) |
| C-source compat where the library IS a kernel ABI | [`compat.libaio`](../pkgs/c/compat.libaio.lua) (libaio 0.3.113 — twelve syscall-wrapper TUs, and the only `xpm` section is `linux`, because there is no port to declare: `struct iocb` is the kernel's and every TU is `syscall(__NR_io_*, …)`. Consumers gate it with `[target.'cfg(linux)'.dependencies]`, the mirror image of compat.wil. Three things it teaches. **One public header out of a source dir**: upstream installs exactly one, `libaio.h`, but the tarball keeps it in `src/` beside the private headers — one of which is named `syscall.h` and would SHADOW glibc's for every consumer TU — so `include_dirs` names a `generated_files` forwarder and nothing else; the package's own sources reach the real header through it while their quote-form `#include "syscall.h"` still resolves next to the including `.c`, so no `-I` into `src/` is needed at all. **A `c_standard` that is a trap**: `-std=c11` sets `__STRICT_ANSI__`, which hides `syscall()` and `sigset_t`, and the public header then fails to parse at `io_pgetevents`; declaring `c_standard = "gnu11"` LOOKS like the fix but mcpp 2026.8.27.2 accepts the string and still emits `-std=c11` (visible in the emitted `compile_commands.json`), so `-D_GNU_SOURCE` in `cflags` is the spelling that takes effect. **Symbol versioning in a static package**: `io_getevents` and `io_cancel` have no ordinary definitions upstream — the functions are `io_getevents_0_4` etc. publishing short names through `.symver … @@LIBAIO_0.4` — which resolves for an executable under both ld.bfd and lld, but not when a consumer builds a `.so` straight out of these objects; that needs upstream's `src/libaio.map`, exactly as upstream's own `libaio.a` does) |
| C++-source compat, Linux-only POSIX API + consumer-visible header fixes | [`compat.libserial`](../pkgs/c/compat.libserial.lua) (LibSerial 1.0.0 — `SerialPort`/`SerialStream`, three TUs from upstream's `LIBSERIAL_SOURCES`, and the only `xpm` section is `linux`: the headers open with `<termios.h>` and every TU reaches `<linux/serial.h>`, so it is gated like compat.libaio. **A header that only compiles by accident gets a shim**: `src/libserial/SerialPortConstants.h` uses `uint8_t` but includes neither `<cstdint>` nor `<stdint.h>`, so a consumer TU that opens a libserial header first fails with an undeclared-type error; a `generated_files` shim placed ahead of `*/src` includes `<cstdint>` and `#include_next`s upstream's header (the compat.yaml-cpp / compat.cpptrace pattern). The test proves it by including the libserial header first of all and asserts the rest over a real openpty() pair. **A header a shim cannot fix is patched in `install()`**: `SerialPort.h`'s public template `call_with_retry` is spelled with `std::result_of`, removed in C++20 — libstdc++ still ships it, libc++ does not, so on an llvm toolchain the library and every consumer TU fail to compile. A shim cannot reach a template inside the header, and libc++'s `_LIBCPP_ENABLE_CXX20_REMOVED_TYPE_TRAITS` only works when defined before every TU's first libc++ header, so the hook rewrites both spellings to the equivalent `std::invoke_result_t<Fn, Args...>` and asserts the match counts) |
Expand Down
Loading
Loading