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 .github/workflows/openkal-compat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ env:
# run if this drifts from pins.toml. See the comment beside `mcpp` in
# pins.toml for why this pin, not just validate.yml's, is gated by the
# index floor.
MCPP_VERSION: "2026.10.24.1"
MCPP_VERSION: "2026.10.26.1"
# CROSS-VALIDATION BEFORE A RELEASE, NOT AFTER IT.
#
# Empty in an ordinary run, so this measurement keeps using the RELEASED
Expand Down
14 changes: 9 additions & 5 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,11 @@ env:
# one module map of what it reaches; every unit of an ELF target is compiled
# position-independent; `mcpp pack` states its build; `[build] jobs` bounds
# `test` and `pack` (#751, #753).
MCPP_VERSION: "2026.10.24.1"
#
# 2026.10.26.1 (mcpp-community/mcpp#841): a graph-supplied libstdc++ under
# clang (gcc.libstdcxx, the libstdcxx-llvm member), `requires` as a table,
# and one C++ runtime per process -- compat.sycl-runtime's requirement.
MCPP_VERSION: "2026.10.26.1"

jobs:
lint:
Expand Down Expand Up @@ -1476,15 +1480,15 @@ jobs:
fi

# `mp-units-module`: the reverse case. `mpusz.mp-units` requires
# libc++ on linux because GCC 16.1 cannot import its modules
# (`recursive lazy load`, mpusz/mp-units#717), so the gcc leg would
# only reach that refusal. Lift once xim ships a GCC that works.
# the llvm compiler on linux because GCC 16.1 cannot import its
# modules (`recursive lazy load`, mpusz/mp-units#717), so the gcc leg
# would only reach that refusal. Lift once xim ships a GCC that works.
if [ "${{ matrix.platform }}" = "linux" ] && [ "${{ matrix.toolchain }}" = "default" ]; then
kept=""
for m in $mine; do
case "$m" in
mp-units-module)
echo "skipping '$m' on the gcc leg: the package requires libc++" ;;
echo "skipping '$m' on the gcc leg: the package requires the llvm compiler" ;;
*) kept="$kept $m" ;;
esac
done
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/xpkgindex-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ concurrency:

env:
PYTHONUTF8: '1'
MCPP_VERSION: '2026.10.24.1'
MCPP_VERSION: '2026.10.26.1'
MCPP_INDEX_MIRROR: GLOBAL

jobs:
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@

### Added

- **`gcc.libstdcxx` 16.1.0.1。** 向 llvm 构建提供 `mcpp:c++-abi=libstdc++`:安装时链接
`xim:gcc` 16.1.0 载荷的头文件与运行库目录并写出自身清单(`std-module` 为 `bits/std.cc`),
clang 据此以 libstdc++ 编译、`import std` 与链接(需要 mcpp 2026.10.26.1,SPEC-002 §7)。
新增测试成员 `tests/examples/libstdcxx-llvm`。

### Changed

- **`compat.sycl-runtime` 在 Linux 上要求 `mcpp:c++-abi=libstdc++`。** `libsycl.so` 在 libstdc++
上抛出 `sycl::exception`,而一个进程中的两套 C++ 运行时之间带类型的 `catch` 不会匹配
(mcpp-community/mcpp#838)。gcc 工具链,或 llvm 加 `gcc.libstdcxx`,满足该要求;其他构建
在编译前被拒绝。测试成员 `sycl-runtime` 在 Linux 上陈述 gcc。
- **`mpusz.mp-units` 要求 `mcpp:compiler=llvm`**(原为 `mcpp:c++-abi=libc++`):约束来自 GCC 16.1
的模块缺陷,是编译器而不是 C++ 库。**`compat.glfw`** 以 `requires = { "mcpp:c-abi=glibc" }`
取代能力 `abi:glibc`。

- **`openkal-macos` 0.14.1、`openkal-musl` 0.21.1、`openkal-llvm-runtime` 0.15.6。** macOS 上
经 `fork` 复制的程序此前不能启动线程(`pthread_create` 返回 `EAGAIN`,
mcpplibs/openkal-musl#55):`kal_space_start` 只调用复制原语,而该系统的 `fork` 在原语前后
Expand Down
1 change: 1 addition & 0 deletions mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ members = [
"tests/examples/imgui-module",
"tests/examples/imgui-window",
"tests/examples/jwt-cpp",
"tests/examples/libstdcxx-llvm",
"tests/examples/marzer.tomlplusplus",
"tests/examples/marzer.tomlplusplus-build-mcpp",
"tests/examples/mcpp-plugins",
Expand Down
7 changes: 6 additions & 1 deletion pkgs/c/compat.glfw.lua
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,15 @@ package = {
["compat.opengl"] = "2026.05.31",
},
linux = {
-- The C library this package's X11 and GLX code is written for,
-- as a requirement on the target side (mcpp SPEC-002 §2.2). It
-- was the capability `abi:glibc`, which mcpp 2026.10.26.1 reads
-- as this same requirement and reports as a compatibility reading.
requires = { "mcpp:c-abi=glibc" },
cflags = { "-D_DEFAULT_SOURCE", "-D_GLFW_X11" },
runtime = {
dlopen_libs = { "libGLX.so.0", "libGL.so.1", "libGL.so" },
capabilities = { "x11.display", "opengl.glx.driver", "abi:glibc" },
capabilities = { "x11.display", "opengl.glx.driver" },
},
sources = {
"src/x11_init.c",
Expand Down
11 changes: 11 additions & 0 deletions pkgs/c/compat.sycl-runtime.lua
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,17 @@ package = {
-- adapter for is not something a runtime adapter should leave
-- unreachable.
deps = { ["compat.opencl"] = "2026.09.11" },
-- ONE C++ RUNTIME PER PROCESS, AND HERE IT IS libstdc++ (mcpp SPEC-002
-- §7). `libsycl.so` is built on libstdc++ and throws `sycl::exception`
-- on it; a program whose own C++ library is libc++ catches that only
-- as `catch (...)` (mcpp-community/mcpp#838), because the two runtimes
-- share the ABI names. So the consumer's build takes libstdc++: a gcc
-- toolchain, or llvm with `gcc.libstdcxx` in the graph (mcpp
-- 2026.10.26.1). Any other build is refused before it compiles, naming
-- both C++ libraries.
linux = {
requires = { "mcpp:c++-abi=libstdc++" },
},
runtime = {
library_dirs = { "mcpp_generated/sycl_runtime/lib" },
capabilities = { "sycl.runtime" },
Expand Down
158 changes: 158 additions & 0 deletions pkgs/g/gcc.libstdcxx.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
-- libstdc++ as the C++ layer of an llvm build: `provides mcpp:c++-abi=libstdc++`.
--
-- WHY IT EXISTS. One process holds one C++ runtime (mcpp SPEC-002 §7). A
-- component built on libstdc++ -- `libsycl.so`, whose `sycl::exception` a SYCL
-- program catches by type -- cannot share a process with the libc++ an llvm
-- build links: the two runtimes define the same ABI names, an exception thrown
-- by one is caught by the other's personality only as `catch (...)`
-- (mcpp-community/mcpp#838), and `std::runtime_error` has a different layout
-- in each. The build therefore takes libstdc++ as its own C++ library, and the
-- compiler stays clang:
--
-- [dependencies]
-- gcc.libstdcxx = "16.1.0.1"
--
-- [toolchain]
-- default = "[email protected]"
--
-- THE MECHANISM IS THE ONE `llvm.libcxx` AND `openkal-llvm-runtime` USE, ONE
-- LIBRARY OVER: `provides` names the layer, the engine compiles with
-- `-nostdinc++` and these headers, precompiles `std` from `bits/std.cc`, and
-- links with `-stdlib=libstdc++`. Nothing is downloaded or compiled: install()
-- links the `xim:gcc` payload's headers and runtime directory into this
-- package's tree and writes its manifest, so the headers a unit is compiled
-- against, the `std` module it imports and the library it loads are one
-- release of GCC.
--
-- THE VERSION IS GCC'S, and the fourth segment is the packaging revision, as
-- `llvm.libcxx` established. A descriptor's dependency edge is per platform,
-- not per version, so one descriptor follows one GCC release: the one mcpp's
-- default gcc toolchain uses.
--
-- REQUIRES mcpp 2026.10.26.1: an earlier engine has no wiring for a
-- graph-supplied libstdc++ under clang and refuses the build at the target
-- side, naming the c++-abi layer.
package = {
spec = "1",
namespace = "gcc",
name = "libstdcxx",
description = "libstdc++ from the GCC payload as the C++ standard library of an llvm build (provides mcpp:c++-abi=libstdc++)",
licenses = {"GPL-3.0-or-later WITH GCC-exception-3.1"},
repo = "https://gcc.gnu.org/git/gcc.git",
type = "package",

xpm = {
linux = {
-- The install-time edge: the payload whose headers and runtime
-- this package links. Materialised when THIS package installs.
deps = { "xim:[email protected]" },
["16.1.0.1"] = {
-- Nothing downloaded matters: the content is the tree
-- install() links. A stable, tiny anchor keeps the entry
-- well-formed, as compat.sycl-runtime does.
url = "https://raw.githubusercontent.com/gcc-mirror/gcc/releases/gcc-16.1.0/COPYING.RUNTIME",
sha256 = "9d6b43ce4d8de0c878bf16b54d8e7a10d9bd42b75178153e3af6a815bdc90f74",
},
["latest"] = { ref = "16.1.0.1" },
},
},

-- Written by install(), because the target directory under the headers
-- (`x86_64-linux-gnu`, `aarch64-linux-gnu`) is the payload's to say.
mcpp = "mcpp.toml",
}

import("xim.libxpkg.pkginfo")
import("xim.libxpkg.log")

local GCC_VERSION = "16.1.0"

-- The payload's install directory: the dependency edge's own answer first,
-- then the stores a shared registry keeps it in (the fallback
-- compat.sycl-runtime records the reason for).
local function gcc_dir()
local dir = pkginfo.install_dir("xim:gcc", GCC_VERSION)
if dir then return dir end
local roots = {}
local pfx = pkginfo.install_dir()
if pfx then roots[#roots + 1] = path.directory(path.directory(pfx)) end
local home = (os.getenv and os.getenv("XLINGS_HOME")) or ""
if home == "" then home = ((os.getenv and os.getenv("HOME")) or "") .. "/.xlings" end
roots[#roots + 1] = path.join(home, "data/xpkgs")
roots[#roots + 1] = path.join((os.getenv and os.getenv("HOME")) or "",
".mcpp/registry/data/xpkgs")
for _, root in ipairs(roots) do
local cand = path.join(root, "xim-x-gcc", GCC_VERSION)
if os.isdir(cand) then return cand end
end
return nil
end

-- The target directory under include/c++/<version>: the one whose name ends
-- in `-linux-gnu`. `io.popen` rather than `os.files`, which the recipe sandbox
-- does not provide.
local function target_dir(cxx)
local p = io.popen(string.format([[ls -1 "%s" 2>/dev/null]], cxx))
if not p then return nil end
local found
for line in p:lines() do
local name = line:gsub("[\r\n]+$", "")
if name:match("%-linux%-gnu$") and os.isdir(path.join(cxx, name)) then
found = name
break
end
end
p:close()
return found
end

function install()
os.tryrm(pkginfo.install_dir())
os.mkdir(pkginfo.install_dir())
local root = pkginfo.install_dir()

local gcc = gcc_dir()
if not gcc then
log.error("gcc.libstdcxx: the xim:gcc %s payload was not found", GCC_VERSION)
return false
end
local cxx = path.join(gcc, "include", "c++", GCC_VERSION)
local triple = target_dir(cxx)
if not os.isfile(path.join(cxx, "bits", "std.cc")) or not triple then
log.error("gcc.libstdcxx: %s has no bits/std.cc or no target directory", cxx)
return false
end
os.exec(string.format([[ln -sfn "%s" "%s"]], cxx, path.join(root, "cxx")))

-- The runtime: the C++ library and the unwinder it needs, by the names a
-- link asks for and the sonames the loader asks for.
local lib = path.join(root, "lib")
os.mkdir(lib)
for _, name in ipairs({ "libstdc++.so", "libstdc++.so.6", "libstdc++.a",
"libgcc_s.so", "libgcc_s.so.1" }) do
local f = path.join(gcc, "lib64", name)
if os.isfile(f) or os.islink(f) then
os.exec(string.format([[ln -sfn "%s" "%s"]], f, path.join(lib, name)))
end
end

io.writefile(path.join(root, "mcpp.toml"), string.format([[
[package]
namespace = "gcc"
name = "libstdcxx"
version = "%s"
mcpp = ">=2026.10.26.1"
provides = ["mcpp:c++-abi=libstdc++"]
requires = ["mcpp:compiler=llvm", "mcpp:c-abi=glibc"]

[build]
sources = []
include_dirs = ["cxx", "cxx/%s", "cxx/backward"]
std-module = "cxx/bits/std.cc"
std-compat-module = "cxx/bits/std.compat.cc"

[runtime]
library_dirs = ["lib"]
]], pkginfo.version(), triple))
return true
end
6 changes: 4 additions & 2 deletions pkgs/m/mpusz.mp-units.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ package = {
targets = { ["mp-units"] = { kind = "lib" } },
deps = {},
linux = {
-- 暂不支持 GCC:GCC 16.1 导入该模块时报 recursive lazy load(mpusz/mp-units#717)
requires = { "mcpp:c++-abi=libc++" },
-- 暂不支持 GCC:GCC 16.1 导入该模块时报 recursive lazy load(mpusz/mp-units#717)。
-- 约束的是编译器而不是 C++ 库:c++-abi 可以独立选择后(mcpp 2026.10.26.1,
-- llvm 加 gcc.libstdcxx),按编译器陈述。
requires = { "mcpp:compiler=llvm" },
},
},
}
Expand Down
18 changes: 18 additions & 0 deletions tests/examples/libstdcxx-llvm/mcpp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# gcc.libstdcxx: libstdc++ as the C++ library of an llvm build (mcpp SPEC-002
# §7, mcpp 2026.10.26.1). The compiler is clang; the headers, the `std` module
# and the library come from the GCC payload the package links. Linux only, as
# the package is; elsewhere the member builds with the leg's own toolchain and
# its test asserts nothing about the C++ library.
[package]
name = "libstdcxx-llvm-tests"
version = "0.1.0"
mcpp = ">=2026.10.26.1"

[toolchain]
linux = "[email protected]"

[indices]
gcc = { path = "../../.." }

[target.'cfg(linux)'.dependencies.gcc]
libstdcxx = "16.1.0.1"
26 changes: 26 additions & 0 deletions tests/examples/libstdcxx-llvm/tests/libstdcxx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// The C++ library under clang is libstdc++ (gcc.libstdcxx): `import std` comes
// from its `bits/std.cc`, a typed catch matches what its runtime threw, and the
// program carries no libc++. `<version>` is included for the one macro a
// module does not export: the library's own name.
#include <version>
import std;

int main() {
#if defined(__linux__)
# if !defined(__GLIBCXX__) || !defined(__clang__)
std::println("expected clang over libstdc++");
return 1;
# endif
#endif
std::vector<int> v{3, 1, 2};
std::ranges::sort(v);
try {
throw std::runtime_error(std::format("{}", v));
} catch (const std::exception& e) {
if (std::string_view(e.what()) != "[1, 2, 3]") return 2;
} catch (...) {
return 3;
}
std::println("ok");
return 0;
}
6 changes: 6 additions & 0 deletions tests/examples/sycl-runtime/mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,11 @@
name = "sycl-runtime-tests"
version = "0.1.0"

# ONE C++ RUNTIME PER PROCESS: the adapter requires the build's C++ library to
# be libstdc++ (libsycl.so throws on it), so on Linux the member states gcc,
# whichever leg runs it. llvm over libstdc++ is the libstdcxx-llvm member's.
[toolchain]
linux = "[email protected]"

[target.'cfg(linux)'.dependencies.compat]
sycl-runtime = "2026.09.10"
Loading