Skip to content

Commit 283b076

Browse files
committed
Hand the contract a launcher it can execute
The Intel macOS host built its whole SDK, validated it, and then died with no such file or directory naming nothing. The Rosetta gate passes `arch -x86_64` as the launcher that lets an arm64 machine run what it cross-built, and that arrives as one string. Interpolated into a VERBATIM COMMAND, a string with a space in it is one argv[0], so what was looked up on disk was a program called "arch -x86_64": $ cmake -E env FOO=1 "arch -x86_64" cmake -E echo ran no such file or directory $ cmake -E env FOO=1 arch -x86_64 cmake -E echo ran ran The Intel host is cross-built, so the contract is the only thing that executes what it produced: without it the host publishes unverified, which is the situation the gate was written to end. Second defect of the same commit, and it was hidden behind the first -- the build never reached the contract while the smoke test was killing the arm64 leg it cross-builds from. tests/cmake/host-runner-command.cmake runs the shape the target uses, with a two-word launcher that exists wherever the test runs; against a runner that is not split it fails three ways, one of them by not running the command at all.
1 parent d831fe3 commit 283b076

3 files changed

Lines changed: 64 additions & 1 deletion

File tree

cmake/HostRunner.cmake

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
include_guard(GLOBAL)
2+
3+
# A launcher prefix arrives as one string -- "arch -x86_64" -- and has to
4+
# reach COMMAND as separate arguments. Under VERBATIM a string with a space
5+
# in it is one argv[0], so the run dies with "no such file or directory"
6+
# naming nothing, after the whole SDK has been built.
7+
function(vitasdk_host_runner_command output runner)
8+
separate_arguments(parts NATIVE_COMMAND "${runner}")
9+
set(${output} ${parts} PARENT_SCOPE)
10+
endfunction()

cmake/recipes/FinalizeSdk.cmake

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,16 @@ add_custom_target(finalize-sdk
130130
# this machine can still execute -- x86_64 macOS on arm64, through Rosetta --
131131
# sets it to the launcher that makes that true, so the contract runs against
132132
# the SDK that was actually built rather than being skipped.
133+
include(${CMAKE_CURRENT_LIST_DIR}/../HostRunner.cmake)
134+
133135
set(VITASDK_HOST_RUNNER "" CACHE STRING
134136
"Launcher prefix for running this host's binaries, if one is needed")
137+
vitasdk_host_runner_command(vitasdk_host_runner_argv "${VITASDK_HOST_RUNNER}")
135138

136139
add_custom_target(check-toolchain-contract
137140
COMMAND ${CMAKE_COMMAND} -E env
138141
VITASDK=${CMAKE_INSTALL_PREFIX}
139-
${VITASDK_HOST_RUNNER}
142+
${vitasdk_host_runner_argv}
140143
${CMAKE_SOURCE_DIR}/tests/toolchain-contract/run.sh
141144
DEPENDS finalize-sdk
142145
VERBATIM
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# A launcher with arguments has to reach the command as arguments.
2+
#
3+
# The Rosetta gate runs the Intel macOS contract through `arch -x86_64`, and
4+
# that arrives from the shell as one string. Interpolated into a VERBATIM
5+
# COMMAND it became a single argv[0] with a space in it, so the run died with
6+
#
7+
# no such file or directory
8+
#
9+
# naming nothing, after the whole SDK had been built and validated. The Intel
10+
# host is cross-built, so this is the only thing that executes what it made.
11+
12+
cmake_minimum_required(VERSION 3.20)
13+
14+
include(${CMAKE_CURRENT_LIST_DIR}/../../cmake/HostRunner.cmake)
15+
16+
function(check_length description runner expected)
17+
vitasdk_host_runner_command(parts "${runner}")
18+
list(LENGTH parts length)
19+
if(NOT length EQUAL expected)
20+
message(SEND_ERROR "${description}: expected ${expected} argument(s), got ${length}: ${parts}")
21+
endif()
22+
endfunction()
23+
24+
check_length("a host that runs its own binaries needs no launcher" "" 0)
25+
check_length("a launcher with an argument stays two arguments" "arch -x86_64" 2)
26+
check_length("a launcher with several arguments keeps them all" "qemu-aarch64 -L /sysroot" 3)
27+
28+
vitasdk_host_runner_command(runner_argv "arch -x86_64")
29+
list(GET runner_argv 0 first)
30+
if(NOT first STREQUAL "arch")
31+
message(SEND_ERROR "the launcher itself is not the first argument: ${first}")
32+
endif()
33+
34+
# The shape the target uses, run for real: a two-word launcher, an
35+
# environment, and a command behind it. cmake -E env is the launcher here
36+
# because it exists wherever this test runs.
37+
vitasdk_host_runner_command(launcher "${CMAKE_COMMAND} -E env")
38+
execute_process(
39+
COMMAND ${CMAKE_COMMAND} -E env VITASDK=irrelevant
40+
${launcher}
41+
${CMAKE_COMMAND} -E echo the-contract-ran
42+
OUTPUT_VARIABLE output
43+
RESULT_VARIABLE status
44+
ERROR_VARIABLE errors)
45+
string(STRIP "${output}" output)
46+
if(NOT status EQUAL 0 OR NOT output STREQUAL "the-contract-ran")
47+
message(SEND_ERROR "a launcher with arguments did not reach the command: status ${status}, output '${output}', errors '${errors}'")
48+
endif()
49+
50+
message(STATUS "host runner command: all checks passed")

0 commit comments

Comments
 (0)