This is an automated email from the ASF dual-hosted git repository.
kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 62060ab55b GH-44096: [C++] Don't use Boost.Process with Emscripten
(#44097)
62060ab55b is described below
commit 62060ab55be2dc811e5abf0c5aba9834d3056ee1
Author: Sutou Kouhei <[email protected]>
AuthorDate: Sat Sep 14 07:45:36 2024 +0900
GH-44096: [C++] Don't use Boost.Process with Emscripten (#44097)
### Rationale for this change
Boost.Process doesn't work with Emscripten. So we can't build
`arrow::util::Process`.
### What changes are included in this PR?
Don't use Boost.Process with Emscripten. `arrow::util::Process` returns
`Status::NotImplemented` with Emscripten.
### Are these changes tested?
Yes.
### Are there any user-facing changes?
No.
* GitHub Issue: #44096
Authored-by: Sutou Kouhei <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
---
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 941ddd9a6b..133768ff01 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 <windows.h>". boost/asio/detail/socket_types.hpp doesn't
// work if windows.h is already included.
-#include <boost/asio/io_context.hpp>
+# include <boost/asio/io_context.hpp>
-#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 <sys/sysctl.h>
+# define BOOST_PROCESS_V2_SEPARATE_COMPILATION
+# ifdef __APPLE__
+# include <sys/sysctl.h>
+# endif
+# include <boost/process/v2.hpp>
+# include <boost/process/v2/src.hpp>
+# else
+# include <boost/process/v2.hpp>
# endif
-# include <boost/process/v2.hpp>
-# include <boost/process/v2/src.hpp>
+# include <unordered_map>
# else
-# include <boost/process/v2.hpp>
-# endif
-# include <unordered_map>
-#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 <boost/process/v1.hpp>
-# else
-# include <boost/process.hpp>
+# ifdef __MINGW32__
+# define BOOST_USE_WINDOWS_H = 1
+# endif
+# ifdef BOOST_PROCESS_HAVE_V1
+# include <boost/process/v1.hpp>
+# else
+# include <boost/process.hpp>
+# endif
# endif
-#endif
-#ifdef __APPLE__
-# include <limits.h>
-# include <mach-o/dyld.h>
-#endif
+# ifdef __APPLE__
+# include <limits.h>
+# include <mach-o/dyld.h>
+# endif
-#include <chrono>
-#include <iostream>
-#include <sstream>
-#include <thread>
+# include <chrono>
+# include <iostream>
+# include <sstream>
+# include <thread>
-#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<process::environment::key,
process::environment::value> 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<std::string>& args) { args_ = args; }
+ void SetArgs(const std::vector<std::string>& 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<std::string> args_;
bool keep_stderr_ = true;
-#ifdef BOOST_PROCESS_USE_V2
+# ifdef BOOST_PROCESS_USE_V2
std::unordered_map<process::environment::key, process::environment::value>
env_;
std::unique_ptr<process::process> 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::child> process_;
std::unique_ptr<process::group> process_group_;
+# endif
#endif
+#ifdef BOOST_PROCESS_AVAILABLE
Result<filesystem::path> 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<process::process>.
@@ -258,7 +298,7 @@ class Process::Impl {
: process::process_stdio{{}, {},
nullptr}));
return Status::OK();
}
-#else
+# else
Status ExecuteV1() {
process_group_ = std::make_unique<process::group>();
if (keep_stderr_) {
@@ -271,6 +311,7 @@ class Process::Impl {
}
return Status::OK();
}
+# endif
#endif
};