Split subprocess launching into Linux and macOS implementations - #4972
copybara-service[bot] merged 4 commits into
Conversation
Move the Linux embedded helper and Darwin spawn code behind a common SpawnSubprocess interface selected by Bazel's target OS. Keep pipe capture, environment construction, timeouts, and waiting in subprocess.cc. The macOS target no longer depends on the embedded Linux helper. Search the child's PATH with posix_spawn on macOS to avoid the posix_spawnp/chdir failure with relative PATH entries. Preserve execvp's shell fallback and test relative and empty PATH entries, permission failures, slash-containing commands, and scripts without shebangs. Destroy spawn file actions on every return path without losing ownership of a live child when cleanup fails.
allight
left a comment
There was a problem hiding this comment.
Can you instead have the check be for _POSIX_VERSION >= 202409L instead of checking for macos version and name files subprocess_posix and subprocess_with_wrapper? It seems that new versions of glibc & linux have the same addchdir functionality so it would be nice to be able to swap everything over to that once we update our libc.
Otherwise this all looks fine (although merging it might take a while due to internal repo differences.
|
@allight Happy to use |
Rename the launchers to subprocess_posix and subprocess_with_wrapper. Let Linux toolchains opt into direct spawning with --//xls/common:use_posix_spawn_chdir, while retaining the wrapper default for older libc versions and omitting helper dependencies in direct builds. Use the POSIX.1-2024 addchdir API when _POSIX_VERSION is at least 202405L, and support glibc's extension from 2.29 onward. Keep Darwin's SDK and runtime availability adapter for older macOS deployment targets.
|
SGTM |
Move chdir API selection out of subprocess_posix.cc into separate POSIX, Darwin, and glibc adapters. The shared spawning algorithm has no platform conditionals; only the Darwin adapter retains SDK/runtime availability checks. Replace the boolean setting with subprocess_chdir=auto|posix|glibc so the build selects one API explicitly. Auto preserves the macOS native launcher and the older-libc Linux wrapper. The glibc adapter enables _GNU_SOURCE locally, and direct builds still omit the embedded helper dependency.
This PR builds on @ecpeterson's macOS subprocess support in #4951. I wanted to stack a launcher interface on top, with Bazel selecting the implementation, so the shared subprocess code needs fewer
#ifdefs.Why keep the wrapper?
XLS can be multithreaded. After
fork, the child inherits runtime state but only the calling thread survives; POSIX restricts it to async-signal-safe operations untilexecsucceeds. Usingposix_spawnlets libc handle that launch machinery without XLS running its own setup code in that interval. (POSIX fork specification)Older Linux libc cannot express a child working-directory change through a spawn action. The wrapper provides that capability:
posix_spawnstarts the helper, which changes directory and callsexecvpon the requested command. The helper runs in a fresh executable image, so it can use ordinary C++ diagnostics during setup. The target replaces the helper and keeps its PID. Embedding the helper and executing it from amemfdavoids a runtime dependency on a separately installed helper or Bazel output files.With a suitable libc and deployment target, the build can select the direct launcher, which records the chdir action and spawns the target immediately.
Implementation selection
subprocess_posix.cccontains the direct-spawn algorithm with no platform conditionals. Bazel selects a small chdir adapter through--//xls/common:subprocess_chdir:auto(default)subprocess_with_wrapper.ccon Linux for older-libc compatibility.posixglibcOnly the Darwin adapter contains SDK/runtime availability checks. The standard and glibc adapters each make one API call. The wrapper owns its embedded
memfdhelper withFileDescriptor; direct builds omit the helper dependency. Both launchers sit behindsubprocess_for_os.h, with pipe capture, environment construction, timeouts, and waiting in the shared caller.Darwin's
posix_spawnpcan returnENOENTafter launching a child when a chdir action is combined with a relative PATH. The direct implementation searches the child's PATH usingposix_spawnfor each candidate. It handles empty and relative PATH entries, permission errors, and the shell fallback for executable text without a shebang. Five launcher tests exercise these cases.Stack and related work
This branch contains #4951's commit (
d5cc747d4) plus the follow-up commits, and targetsmain.Related: #4864 implements non-Linux support by materializing the helper in a temporary file. This approach uses native Darwin spawning without a temporary helper.
Testing
With Bazel 8.7.0:
bazel test --config=ci -c opt --test_output=errors \ //xls/common:subprocess_test //xls/common:subprocess_for_os_testTo test direct spawning with the hermetic glibc 2.39 toolchain:
bazel test --config=ci -c opt --test_output=errors \ --platforms=@llvm//platforms:linux_x86_64_gnu.2.39 \ --//xls/common:subprocess_chdir=glibc \ //xls/common:subprocess_test //xls/common:subprocess_for_os_testThe resulting Linux binaries require a compatible runtime.
The macOS runs set matching
--macos_minimum_os,--host_macos_minimum_os, and--action_env=MACOSX_DEPLOYMENT_TARGETvalues. The standard adapter run also set--//xls/common:subprocess_chdir=posix. Bazel dependency checks confirmed the wrapper/helper in the Linux default and exactly the glibc adapter with no helper in the Linux direct build.Older macOS runtimes have not been exercised. Availability guards select the macOS 26 API when available and the older
_npAPI otherwise.