Skip to content

Commit 6447292

Browse files
committed
fix(bench): three CI-only failures — PIE, the pre-project payload, and an unpacked dependency
**我先前说「CI 通过」是错的。** 当时还有 10 个 job 在跑,我看到「20 绿 0 红」就 下了结论,而那 10 个里就有这些格子。拿部分数据当结论,在这个整场都在讲「失败看 起来像成功」的分支上尤其不该发生。 三个都只在 CI 上出现,本地一直绿 —— 原因各不相同: **1. fixture 的 xmake 臂:PIE 没有说出口。** relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a PIE object; recompile with -fPIE ld: failed to set dynamic section sizes: bad value 载荷 gcc 在 CI runner 上默认 PIE 链接、在开发机上不是,所以编译不带 `-fPIE` 的 对象只在 CI 被拒。12 个格子红。mcpp 与 cmake 在这里都产出 PIE(bazel 适配器为此 传 `--force_pic`),所以把它显式写出来,四条臂产出同一种可执行文件。 **2. cmake 的载荷 flags 到得太晚。** `bench_hermetic_payload()` 依赖 `CMAKE_CXX_COMPILER_ID`,而它要 `project()` 之后才有 —— 但失败的正是 `project()` 里的那次探测: /usr/bin/ld: cannot find crt1.o: No such file or directory CMake 把它报成「编译器无法编译一个简单程序」,既不提 sysroot 也不提载荷。开发机 上因为宿主有 crt1.o 而通过。新增 `bench_hermetic_payload_preproject()`,按编译器 **路径**判断(调用方本来就用 `-DCMAKE_CXX_COMPILER` 给了它),在 project() 之前 补上 `-B`/`--sysroot`。 **3. 依赖根本没被解包。** mcpp 从全局构建缓存取 `mcpplibs.cmdline`,**缓存命中 不解包源码**,于是新 runner 上两条外部臂都拿不到那三个单元。xmake 臂的守卫如实 报了出来;cmake 臂当时只 warning、然后静默地少编三个单元 —— 已改成 FATAL_ERROR, 和 xmake 那条对齐。bench.yml 在矩阵开始前丢掉该包的缓存,让下一次 mcpp 构建从源码 编一次(三个翻译单元,发生在任何测量之前)。
1 parent fa9d685 commit 6447292

5 files changed

Lines changed: 93 additions & 3 deletions

File tree

.github/workflows/bench.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,20 @@ jobs:
299299
# and say nothing.
300300
BIN=$(bash .github/tools/newest_artifact.sh target 'mcpp')
301301
echo "MCPP_UNDER_TEST=$BIN" >> "$GITHUB_ENV"
302+
303+
# THE FOREIGN ARMS NEED THE DEPENDENCY'S SOURCES, and a cache hit never
304+
# unpacks them. mcpp serves `mcpplibs.cmdline` from its global build
305+
# cache, so on a fresh runner nothing is unpacked under
306+
# registry/data/xpkgs — and the cmake and xmake arms, which compile
307+
# those units from source to match what mcpp linked, then fail:
308+
# bench: mcpplibs.cmdline 0.0.1 is not unpacked under .../xpkgs
309+
# (that message is the xmake arm's guard doing its job — the cmake arm
310+
# used to warn and silently build without the units instead).
311+
#
312+
# Dropping the cached package makes the next mcpp build compile it from
313+
# source, which unpacks it. Cheap — three translation units — and it
314+
# happens before any measurement starts.
315+
rm -rf "$HOME"/.mcpp/build-cache/v1/pkg/mcpplibs/*cmdline* || true
302316
echo "under test : $("$BIN" --version)"
303317
echo "reference : $(command -v mcpp && mcpp --version || echo 'not installed')"
304318

bench/projects/common/cmake/hermetic_payload.cmake

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,53 @@ function(bench_add_source_dep target name version)
220220
target_sources(${target} PRIVATE ${impls})
221221
endif()
222222
endfunction()
223+
224+
# ── The half that must run BEFORE project() ─────────────────────────────────
225+
#
226+
# `bench_hermetic_payload()` above keys off CMAKE_CXX_COMPILER_ID, which does
227+
# not exist until project() has probed the compiler — and that probe is exactly
228+
# what fails without these flags:
229+
#
230+
# [2/2] .../xim-x-gcc/16.1.0/bin/g++ ... -o cmTC_c87ee
231+
# /usr/bin/ld: cannot find crt1.o: No such file or directory
232+
# /usr/bin/ld: cannot find crti.o: No such file or directory
233+
#
234+
# CMake reports that as "The C++ compiler is not able to compile a simple test
235+
# program", naming neither the sysroot nor the payload. It passed on developer
236+
# boxes because a host crt1.o was findable there and did not on CI.
237+
#
238+
# So this one keys off the compiler PATH, which the caller already has from
239+
# -DCMAKE_CXX_COMPILER. Same flags, same reasoning as the GNU branch above;
240+
# a compiler outside the registry is left alone, exactly as there.
241+
function(bench_hermetic_payload_preproject)
242+
if(NOT CMAKE_CXX_COMPILER OR WIN32)
243+
return()
244+
endif()
245+
get_filename_component(_real "${CMAKE_CXX_COMPILER}" REALPATH)
246+
string(FIND "${_real}" "xpkgs" _pos)
247+
if(_pos EQUAL -1)
248+
return()
249+
endif()
250+
# clang carries its own include chain (see the Clang branch above) and does
251+
# not need -B/--sysroot to link a test program; only the gcc payload does.
252+
if(NOT _real MATCHES "g\\+\\+$" AND NOT _real MATCHES "gcc$")
253+
return()
254+
endif()
255+
bench_registry_xpkgs(_xpkgs)
256+
bench_newest_package("${_xpkgs}" "xim-x-binutils" _binutils)
257+
set(_sysroot "${_xpkgs}/../subos/default")
258+
set(_add "")
259+
if(_binutils)
260+
string(APPEND _add " -B${_binutils}/bin")
261+
endif()
262+
if(IS_DIRECTORY "${_sysroot}")
263+
string(APPEND _add " --sysroot=${_sysroot}")
264+
endif()
265+
if(_add STREQUAL "")
266+
return()
267+
endif()
268+
foreach(_v CMAKE_CXX_FLAGS CMAKE_C_FLAGS CMAKE_EXE_LINKER_FLAGS)
269+
set(${_v} "${${_v}}${_add}" PARENT_SCOPE)
270+
endforeach()
271+
message(STATUS "bench: hermetic payload applied before project()${_add}")
272+
endfunction()

bench/projects/mcpp/CMakeLists.txt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ set(CMAKE_CXX_STANDARD 23)
5151
set(CMAKE_CXX_STANDARD_REQUIRED ON)
5252
set(CMAKE_CXX_EXTENSIONS OFF)
5353

54+
include(${CMAKE_CURRENT_LIST_DIR}/../common/cmake/hermetic_payload.cmake)
55+
bench_hermetic_payload_preproject()
56+
5457
project(mcpp CXX)
5558
# Every mcpp module says `import std;`. This asks CMake to build the standard
5659
# library module from the compiler's own libstdc++.modules.json, which the
@@ -140,9 +143,16 @@ set(MCPP_CMDLINE_SRC
140143
if(IS_DIRECTORY "${MCPP_CMDLINE_SRC}")
141144
file(GLOB MCPP_CMDLINE_MODULES CONFIGURE_DEPENDS "${MCPP_CMDLINE_SRC}/*.cppm")
142145
else()
143-
message(WARNING "mcpplibs.cmdline ${MCPP_CMDLINE_VERSION} not unpacked at "
144-
"${MCPP_CMDLINE_SRC}; this build will not match mcpp's own")
145-
set(MCPP_CMDLINE_MODULES "")
146+
# FATAL, not a warning. Warning here builds mcpp WITHOUT three of its units
147+
# and the failure lands at the link as `undefined reference to ...cmdline...`,
148+
# naming a consumer rather than the missing package — and on CI it did exactly
149+
# that. A description that cannot name the same sources mcpp compiled is not a
150+
# comparison arm. (The xmake arm beside this one raises for the same reason.)
151+
message(FATAL_ERROR
152+
"mcpplibs.cmdline ${MCPP_CMDLINE_VERSION} is not unpacked at "
153+
"${MCPP_CMDLINE_SRC} — build the tree with mcpp once first, so both "
154+
"arms compile the same dependency sources. A cache hit does NOT unpack "
155+
"them; bench.yml drops the cached package before the matrix for this.")
146156
endif()
147157

148158
add_executable(mcpp ${MCPP_SOURCES})

bench/projects/xlings/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ if(NOT CMAKE_C_COMPILER AND CMAKE_CXX_COMPILER)
8484
endif()
8585
endif()
8686

87+
include(${CMAKE_CURRENT_LIST_DIR}/../common/cmake/hermetic_payload.cmake)
88+
bench_hermetic_payload_preproject()
89+
8790
project(xlings C CXX)
8891
set(CMAKE_CXX_MODULE_STD 1)
8992

bench/src/fixture/buildfiles.cppm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,19 @@ inline void emit_xmake(const std::filesystem::path& root, Variant variant, const
173173
// cost none of the others do.
174174
lua += " set_policy(\"build.c++.modules.std\", false)\n";
175175
}
176+
// ⚠️ PIE MUST BE EXPLICIT ON BOTH SIDES. The payload gcc defaults to a PIE
177+
// link on the CI runners and to a non-PIE link on some developer boxes, so
178+
// compiling without `-fPIE` produced objects the linker then refused:
179+
// relocation R_X86_64_32 against `.rodata.str1.1' can not be used
180+
// when making a PIE object; recompile with -fPIE
181+
// ld: failed to set dynamic section sizes: bad value
182+
// Twelve fixture cells red on CI, green locally — the difference was the
183+
// driver's default, not the engine. mcpp and cmake produce PIE here (the
184+
// bazel adapter passes --force_pic for the same reason), so saying it out
185+
// loud keeps all four arms producing the same kind of executable.
186+
lua += " add_cxflags(\"-fPIE\", {force = true})\n";
187+
lua += " add_ldflags(\"-pie\", {force = true})\n";
188+
176189
// Same payload flags as the cmake arm: xmake is handed the driver through
177190
// CXX, and a registry gcc without -B/--sysroot cannot link.
178191
if (!pf.compile.empty())

0 commit comments

Comments
 (0)