From 1cf95bffb64726acbe0e0505c923ad1f2fa803e2 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Tue, 8 Sep 2026 11:19:05 +0000 Subject: [PATCH] [build] Add CPPJIT_EXTRA_INTERPRETER_ARGS for packagers The embedded clang probes well-known prefixes for the host toolchain's headers. Where a distribution does not lay its toolchain out that way -- Nix, Guix, any relocatable prefix -- the probe comes up empty and the interpreter fails at its first #include, with no recourse short of patching the wrapper. Bake the search paths in at configure time instead. CppInterOp still appends CPPINTEROP_EXTRA_INTERPRETER_ARGS after them, so the runtime can add to the baked arguments. The value is escaped for the string literal it lands in, so a Windows include path survives the preprocessor, and a ';' is rejected as CMake's list separator. Report a failed interpreter creation while here: a rejected argument left CreateInterpreter returning nullptr while LoadCppInterOp reported success, and the first code to assume an interpreter segfaulted. --- CMakeLists.txt | 16 ++++++++++++++++ src/interop/interop_wrapper.cxx | 19 ++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3f8ed8..543c035 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,8 @@ set(CPPINTEROP_GIT_REPOSITORY "https://github.com/compiler-research/CppInterOp.g set(CPPINTEROP_GIT_TAG "9802d61921ad5688ae42e4e628d754fc1192244d" CACHE STRING "") set(CPPINTEROP_SOURCE_DIR "" CACHE PATH "Override default CppInterOp built by ExternalProject_Add, with a path to local CppInterOp source") +set(CPPJIT_EXTRA_INTERPRETER_ARGS "" CACHE STRING + "Space-separated arguments passed at interpreter creation") # The full Development component requires libpython, which manylinux # images do not ship and extension modules do not need. @@ -78,6 +80,20 @@ target_compile_definitions(cppjit PRIVATE CPPJIT_CLANG_INCLUDE_DIR="${CPPJIT_INTEROP_CLANG_DIR}" ) +# The value lands in a string literal, so backslashes and quotes must survive +# the preprocessor; a ";" cannot be carried through CMake at all. +if(CPPJIT_EXTRA_INTERPRETER_ARGS) + if("${CPPJIT_EXTRA_INTERPRETER_ARGS}" MATCHES ";") + message(FATAL_ERROR + "CPPJIT_EXTRA_INTERPRETER_ARGS must not contain ';', CMake's list separator") + endif() + string(REPLACE "\\" "\\\\" _cppjit_extra_args "${CPPJIT_EXTRA_INTERPRETER_ARGS}") + string(REPLACE "\"" "\\\"" _cppjit_extra_args "${_cppjit_extra_args}") + target_compile_definitions(cppjit PRIVATE + CPPJIT_EXTRA_INTERPRETER_ARGS="${_cppjit_extra_args}" + ) +endif() + target_include_directories(cppjit PRIVATE # src/ itself resolves the public "cpyrt/*.h" spellings against the # flattened src/cpyrt/ directory diff --git a/src/interop/interop_wrapper.cxx b/src/interop/interop_wrapper.cxx index d29dada..765f1a0 100644 --- a/src/interop/interop_wrapper.cxx +++ b/src/interop/interop_wrapper.cxx @@ -131,8 +131,8 @@ static bool loadDispatchAPI(const InterOpPaths& Paths) { return true; } -// CppInterOp itself appends CPPINTEROP_EXTRA_INTERPRETER_ARGS inside -// CreateInterpreter, so nothing needs to be forwarded from here. +// CppInterOp appends the CPPINTEROP_EXTRA_INTERPRETER_ARGS environment +// variable itself, so only build-time arguments are forwarded from here. static interop::TInterp_t acquireOrCreateInterpreter(const InterOpPaths& Paths) { if (auto existingInterp = Cpp::GetInterpreter()) @@ -154,6 +154,16 @@ acquireOrCreateInterpreter(const InterOpPaths& Paths) { args.push_back("-resource-dir"); args.push_back(resourceDir.c_str()); } +#ifdef CPPJIT_EXTRA_INTERPRETER_ARGS + // Space-split like CppInterOp's CPPINTEROP_EXTRA_INTERPRETER_ARGS, which + // CreateInterpreter appends after these. + std::vector bakedArgs; + std::istringstream bakedStream(CPPJIT_EXTRA_INTERPRETER_ARGS); + for (std::string arg; bakedStream >> arg;) + bakedArgs.push_back(arg); + for (const std::string& arg : bakedArgs) + args.push_back(arg.c_str()); +#endif return Cpp::CreateInterpreter(args, /*GpuArgs=*/{}); } @@ -246,7 +256,10 @@ extern "C" int LoadCppInterOp() { if (!loadDispatchAPI(Paths)) return; - acquireOrCreateInterpreter(Paths); + if (!acquireOrCreateInterpreter(Paths)) { + std::cerr << "[cppjit] Failed to create interpreter" << std::endl; + return; + } configureInterpreter(Paths); preloadHeaders(); defineRuntimeHelpers();