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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
> 本文件追踪 `mcpp-community/mcpp` 公开仓的版本演进。
> 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)。

## [0.0.107] — 2026-07-25

### 修复

- **`mcpp test` 不再漏建共享库的 SONAME 别名(0.0.104 起的回归)。** 声明了 `soname` 的共享库产物写作 `bin/libX11.so`,但记录的 SONAME 是 `libX11.so.6`,链接器解析传递 `NEEDED`、加载器启动程序时找的都是后者 —— 别名不是附属产物,而是**任何链接该库的目标的前置条件**。此前别名是一条无人依赖的独立 ninja 边,只能经 `default` 到达;0.0.104 的 test 能力批次([#274](https://github.com/mcpp-community/mcpp/pull/274))让 `mcpp test` 改为显式指定 ninja 目标以隔离逐测试编译,于是这条边被静默跳过。

症状离根因很远,这也是它潜伏三个版本的原因:消费者链接期报 `libX11.so: undefined reference to xcb_connect`(伴 `libxcb.so.1 ... not found`),或测试二进制以 `exit 127` 退出。`mcpp build` / `mcpp run` 走 `default`,一直正常,所以只有以 `mcpp test` 驱动的工程会中招 —— mcpp-index 的 CI 正是如此,`gui-stack` / `imgui-module` / `imgui-window` 三个成员自 0.0.104 起持续失败。

修法是把别名挂到消费者的隐式输入上(`plan.cppm` 的 `append_direct_shared_deps`),与被链接的 `.so` 并列。无论 ninja 的目标是 `default` 还是某个测试二进制都会生成,且不会多编译任何东西。e2e 64 补了 `mcpp test` 一段覆盖此路径 —— 它此前只覆盖 `build` + `run`,正是缺口所在。

## [0.0.106] — 2026-07-25

> 落地 **SPEC-001**(`docs/spec/package-identity.md`)—— 包身份的规范形态。0.0.105 为修 #278 引入的「`name` 必须写成完全限定名」是**编码约束而非设计规则**:它的唯一成因是 mcpp 构造安装目标时丢弃了已读到的字面 `name`、改用 `<ns>.<短名>` 重新渲染一遍。本版本改为直接使用字面值,规范形态回归 **`namespace` 承载层级、`name` 是单一原子段**。配套 xlings 0.4.69([#381](https://github.com/openxlings/xlings/issues/381),索引改按 `(namespace, name)` 建键)。
Expand Down
2 changes: 1 addition & 1 deletion mcpp.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mcpp"
version = "0.0.106"
version = "0.0.107"
description = "Modern C++ build & package management tool"
license = "Apache-2.0"
authors = ["mcpp-community"]
Expand Down
13 changes: 13 additions & 0 deletions src/build/plan.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,19 @@ make_plan(const mcpp::manifest::Manifest& manifest,
for (auto targetIndex : targetsIt->second) {
auto const& dep = sharedDepTargets[targetIndex];
lu.implicitInputs.push_back(dep.output);
// The SONAME alias is a prerequisite too, not a by-product: the
// library is written as bin/libX11.so but records SONAME
// libX11.so.6, so both the linker (resolving a transitive
// NEEDED) and the loader look for the alias, never for the
// plain name. Hanging it off the consumer keeps it correct
// under explicit ninja goals — `mcpp test` names the test
// binaries, and an alias edge that nothing depends on is
// reachable only through `default`, so it was silently skipped
// (0.0.104-0.0.106). The failure surfaced far away, as
// `libX11.so: undefined reference to xcb_connect` or a test
// exiting 127.
for (auto const& alias : runtime_aliases_for_target(dep.target))
lu.implicitInputs.push_back(alias);
auto flags = shared_library_link_flags(dep.target);
lu.linkFlags.insert(lu.linkFlags.end(), flags.begin(), flags.end());
}
Expand Down
2 changes: 1 addition & 1 deletion src/toolchain/fingerprint.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import mcpp.toolchain.detect;

export namespace mcpp::toolchain {

inline constexpr std::string_view MCPP_VERSION = "0.0.106";
inline constexpr std::string_view MCPP_VERSION = "0.0.107";

struct FingerprintInputs {
Toolchain toolchain;
Expand Down
30 changes: 30 additions & 0 deletions tests/e2e/64_shared_soname_runtime_alias.sh
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,34 @@ readelf -d "$so" | grep -q 'Library soname: \[libdepShared.so.1\]' || {
exit 1
}

# ── `mcpp test` must produce the alias too ──────────────────────────
# The alias edge is reachable through ninja's `default`, which is what build
# and run use. `mcpp test` names its goals explicitly (to isolate per-test
# compiles), and from 0.0.104 to 0.0.106 that skipped the alias: a test binary
# linked against libdepShared.so records NEEDED libdepShared.so.1 and then
# exits 127 because the loader cannot find it. Start from a clean target dir so
# only the test path can create it.
mkdir -p tests
cat > tests/linked_test.cpp <<'EOF'
extern "C" int dep_shared_answer();

int main() {
return dep_shared_answer() == 42 ? 0 : 1;
}
EOF

rm -rf target
"$MCPP" test > test.log 2>&1 || {
cat test.log
echo "mcpp test failed — the SONAME alias is a prerequisite of anything that links the library, not a by-product of the default target"
exit 1
}

alias_from_test="$(find target -name 'libdepShared.so.1' | head -1)"
[ -n "$alias_from_test" ] || {
cat test.log
echo "mcpp test did not produce the ABI soname alias"
exit 1
}

echo "OK"
Loading