From ad112ada2b54846c25cd97e642eaf40b0a76e04d Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Fri, 13 Sep 2024 12:47:55 +0900 Subject: [PATCH] GH-44096: [C++] Don't use Boost.Process with Emscripten Because Boost.Process doesn't work with Emscripten. --- cpp/src/arrow/testing/process.cc | 169 +++++++++++++++++++------------ 1 file changed, 105 insertions(+), 64 deletions(-) diff --git a/cpp/src/arrow/testing/process.cc b/cpp/src/arrow/testing/process.cc index 941ddd9a6b603..133768ff015e6 100644 --- a/cpp/src/arrow/testing/process.cc +++ b/cpp/src/arrow/testing/process.cc @@ -18,39 +18,45 @@ #include "arrow/testing/process.h" #include "arrow/result.h" +#define BOOST_PROCESS_AVAILABLE +#ifdef __EMSCRIPTEN__ +# undef BOOST_PROCESS_AVAILABLE +#endif + +#ifdef BOOST_PROCESS_AVAILABLE // This boost/asio/io_context.hpp include is needless for no MinGW // build. // // This is for including boost/asio/detail/socket_types.hpp before any // "#include ". boost/asio/detail/socket_types.hpp doesn't // work if windows.h is already included. -#include +# include -#ifdef BOOST_PROCESS_HAVE_V2 +# ifdef BOOST_PROCESS_HAVE_V2 // We can't use v2 API on Windows because v2 API doesn't support // process group [1] and GCS testbench uses multiple processes [2]. // // [1] https://github.com/boostorg/process/issues/259 // [2] https://github.com/googleapis/storage-testbench/issues/669 -# ifndef _WIN32 -# define BOOST_PROCESS_USE_V2 +# ifndef _WIN32 +# define BOOST_PROCESS_USE_V2 +# endif # endif -#endif -#ifdef BOOST_PROCESS_USE_V2 -# ifdef BOOST_PROCESS_NEED_SOURCE +# ifdef BOOST_PROCESS_USE_V2 +# ifdef BOOST_PROCESS_NEED_SOURCE // Workaround for https://github.com/boostorg/process/issues/312 -# define BOOST_PROCESS_V2_SEPARATE_COMPILATION -# ifdef __APPLE__ -# include +# define BOOST_PROCESS_V2_SEPARATE_COMPILATION +# ifdef __APPLE__ +# include +# endif +# include +# include +# else +# include # endif -# include -# include +# include # else -# include -# endif -# include -#else // We need BOOST_USE_WINDOWS_H definition with MinGW when we use // boost/process.hpp. boost/process/detail/windows/handle_workaround.hpp // doesn't work without BOOST_USE_WINDOWS_H with MinGW because MinGW @@ -58,36 +64,37 @@ // // See also: // https://github.com/boostorg/process/blob/develop/include/boost/process/detail/windows/handle_workaround.hpp -# ifdef __MINGW32__ -# define BOOST_USE_WINDOWS_H = 1 -# endif -# ifdef BOOST_PROCESS_HAVE_V1 -# include -# else -# include +# ifdef __MINGW32__ +# define BOOST_USE_WINDOWS_H = 1 +# endif +# ifdef BOOST_PROCESS_HAVE_V1 +# include +# else +# include +# endif # endif -#endif -#ifdef __APPLE__ -# include -# include -#endif +# ifdef __APPLE__ +# include +# include +# endif -#include -#include -#include -#include +# include +# include +# include +# include -#ifdef BOOST_PROCESS_USE_V2 +# ifdef BOOST_PROCESS_USE_V2 namespace asio = BOOST_PROCESS_V2_ASIO_NAMESPACE; namespace process = BOOST_PROCESS_V2_NAMESPACE; namespace filesystem = process::filesystem; -#elif defined(BOOST_PROCESS_HAVE_V1) +# elif defined(BOOST_PROCESS_HAVE_V1) namespace process = boost::process::v1; namespace filesystem = boost::process::v1::filesystem; -#else +# else namespace process = boost::process; namespace filesystem = boost::filesystem; +# endif #endif namespace arrow::util { @@ -96,17 +103,20 @@ class Process::Impl { public: Impl() { // Get a copy of the current environment. -#ifdef BOOST_PROCESS_USE_V2 +#ifdef BOOST_PROCESS_AVAILABLE +# ifdef BOOST_PROCESS_USE_V2 for (const auto& kv : process::environment::current()) { env_[kv.key()] = process::environment::value(kv.value()); } -#else +# else env_ = process::environment(boost::this_process::environment()); +# endif #endif } ~Impl() { -#ifdef BOOST_PROCESS_USE_V2 +#ifdef BOOST_PROCESS_AVAILABLE +# ifdef BOOST_PROCESS_USE_V2 // V2 doesn't provide process group support yet: // https://github.com/boostorg/process/issues/259 // @@ -126,94 +136,124 @@ class Process::Impl { } } } -#else +# else process_group_ = nullptr; -#endif +# endif process_ = nullptr; +#endif } Status SetExecutable(const std::string& name) { -#ifdef BOOST_PROCESS_USE_V2 +#ifdef BOOST_PROCESS_AVAILABLE +# ifdef BOOST_PROCESS_USE_V2 executable_ = process::environment::find_executable(name); -#else +# else executable_ = process::search_path(name); -#endif +# endif if (executable_.empty()) { // Search the current executable directory as fallback. ARROW_ASSIGN_OR_RAISE(auto current_exe, ResolveCurrentExecutable()); -#ifdef BOOST_PROCESS_USE_V2 +# ifdef BOOST_PROCESS_USE_V2 std::unordered_map env; for (const auto& kv : process::environment::current()) { env[kv.key()] = process::environment::value(kv.value()); } env["PATH"] = process::environment::value(current_exe.parent_path()); executable_ = process::environment::find_executable(name, env); -#else +# else executable_ = process::search_path(name, {current_exe.parent_path()}); -#endif +# endif } if (executable_.empty()) { return Status::IOError("Failed to find '", name, "' in PATH"); } return Status::OK(); +#else + return Status::NotImplemented("Boost.Process isn't available on this system"); +#endif } - void SetArgs(const std::vector& args) { args_ = args; } + void SetArgs(const std::vector& args) { +#ifdef BOOST_PROCESS_AVAILABLE + args_ = args; +#endif + } void SetEnv(const std::string& name, const std::string& value) { -#ifdef BOOST_PROCESS_USE_V2 +#ifdef BOOST_PROCESS_AVAILABLE +# ifdef BOOST_PROCESS_USE_V2 env_[name] = process::environment::value(value); -#else +# else env_[name] = value; +# endif #endif } - void IgnoreStderr() { keep_stderr_ = false; } + void IgnoreStderr() { +#ifdef BOOST_PROCESS_AVAILABLE + keep_stderr_ = false; +#endif + } Status Execute() { +#ifdef BOOST_PROCESS_AVAILABLE try { -#ifdef BOOST_PROCESS_USE_V2 +# ifdef BOOST_PROCESS_USE_V2 return ExecuteV2(); -#else +# else return ExecuteV1(); -#endif +# endif } catch (const std::exception& e) { return Status::IOError("Failed to launch '", executable_, "': ", e.what()); } +#else + return Status::NotImplemented("Boost.Process isn't available on this system"); +#endif } bool IsRunning() { -#ifdef BOOST_PROCESS_USE_V2 +#ifdef BOOST_PROCESS_AVAILABLE +# ifdef BOOST_PROCESS_USE_V2 boost::system::error_code error_code; return process_ && process_->running(error_code); -#else +# else return process_ && process_->running(); +# endif +#else + return false; #endif } uint64_t pid() { +#ifdef BOOST_PROCESS_AVAILABLE if (!process_) { return 0; } return process_->id(); +#else + return 0; +#endif } private: +#ifdef BOOST_PROCESS_AVAILABLE filesystem::path executable_; std::vector args_; bool keep_stderr_ = true; -#ifdef BOOST_PROCESS_USE_V2 +# ifdef BOOST_PROCESS_USE_V2 std::unordered_map env_; std::unique_ptr process_; asio::io_context ctx_; // boost/process/v2/ doesn't support process group yet: // https://github.com/boostorg/process/issues/259 -#else +# else process::environment env_; std::unique_ptr process_; std::unique_ptr process_group_; +# endif #endif +#ifdef BOOST_PROCESS_AVAILABLE Result ResolveCurrentExecutable() { // See https://stackoverflow.com/a/1024937/10194 for various // platform-specific recipes. @@ -221,25 +261,25 @@ class Process::Impl { filesystem::path path; boost::system::error_code error_code; -#if defined(__linux__) +# if defined(__linux__) path = filesystem::canonical("/proc/self/exe", error_code); -#elif defined(__APPLE__) +# elif defined(__APPLE__) char buf[PATH_MAX + 1]; uint32_t bufsize = sizeof(buf); if (_NSGetExecutablePath(buf, &bufsize) < 0) { return Status::Invalid("Can't resolve current exe: path too large"); } path = filesystem::canonical(buf, error_code); -#elif defined(_WIN32) +# elif defined(_WIN32) char buf[MAX_PATH + 1]; if (!GetModuleFileNameA(NULL, buf, sizeof(buf))) { return Status::Invalid("Can't get executable file path"); } path = filesystem::canonical(buf, error_code); -#else +# else ARROW_UNUSED(error_code); return Status::NotImplemented("Not available on this system"); -#endif +# endif if (error_code) { // XXX fold this into the Status class? return Status::IOError("Can't resolve current exe: ", error_code.message()); @@ -248,7 +288,7 @@ class Process::Impl { } } -#ifdef BOOST_PROCESS_USE_V2 +# ifdef BOOST_PROCESS_USE_V2 Status ExecuteV2() { process::process_environment env(env_); // We can't use std::make_unique. @@ -258,7 +298,7 @@ class Process::Impl { : process::process_stdio{{}, {}, nullptr})); return Status::OK(); } -#else +# else Status ExecuteV1() { process_group_ = std::make_unique(); if (keep_stderr_) { @@ -271,6 +311,7 @@ class Process::Impl { } return Status::OK(); } +# endif #endif };