mirror of
https://github.com/arun11299/cpp-subprocess.git
synced 2025-08-05 04:46:21 -04:00
Enable basic windows support (#33)
* windows: fix implementation error - repair configure_pipe - allow vector initialization - add draft destructor - close pipes correctly * windows: add some test compatibility * windows: update readme * windows: add vector args to check_output
This commit is contained in:
parent
126ee2978f
commit
9c624ce4e3
@ -13,8 +13,10 @@ This library had these design goals:
|
||||
|
||||
|
||||
## Supported Platforms
|
||||
Unlike python2.7 subprocess module, this library currently only supports MAC OS and Linux.
|
||||
It has no support for Windows in its current state.
|
||||
This library supports MAC OS and Linux.
|
||||
|
||||
Support for Windows is limited at this time. Please report any specific use-cases that fail,
|
||||
and they will be fixed as they are reported.
|
||||
|
||||
## Integration
|
||||
Subprocess library has just a single source `subprocess.hpp` present at the top directory of this repository. All you need to do is add
|
||||
@ -34,6 +36,7 @@ Checkout http://templated-thoughts.blogspot.in/2016/03/sub-processing-with-moder
|
||||
## Compiler Support
|
||||
Linux - g++ 4.8 and above
|
||||
Mac OS - Clang 3.4 and later
|
||||
Windows - MSVC 2015 and above
|
||||
|
||||
## Examples
|
||||
Here are few examples to show how to get started:
|
||||
|
@ -272,11 +272,11 @@ namespace util
|
||||
|
||||
// Create a pipe for the child process's STDIN.
|
||||
if (!CreatePipe(read_handle, write_handle, &saAttr,0))
|
||||
throw OSError("Stdin CreatePipe", 0);
|
||||
throw OSError("CreatePipe", 0);
|
||||
|
||||
// Ensure the write handle to the pipe for STDIN is not inherited.
|
||||
if (!SetHandleInformation(child_handle, HANDLE_FLAG_INHERIT, 0))
|
||||
throw OSError("Stdin SetHandleInformation", 0);
|
||||
if (!SetHandleInformation(*child_handle, HANDLE_FLAG_INHERIT, 0))
|
||||
throw OSError("SetHandleInformation", 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1131,6 +1131,26 @@ public:
|
||||
if (!defer_process_start_) execute_process();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Popen(std::vector<std::string> vargs_, Args &&... args) : vargs_(vargs_)
|
||||
{
|
||||
init_args(std::forward<Args>(args)...);
|
||||
|
||||
// Setup the communication channels of the Popen class
|
||||
stream_.setup_comm_channels();
|
||||
|
||||
if (!defer_process_start_) execute_process();
|
||||
}
|
||||
|
||||
/*
|
||||
~Popen()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
CloseHandle(this->process_handle_);
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
void start_process() noexcept(false);
|
||||
|
||||
int pid() const noexcept { return child_pid_; }
|
||||
@ -1409,43 +1429,21 @@ inline void Popen::execute_process() noexcept(false)
|
||||
|
||||
this->process_handle_ = piProcInfo.hProcess;
|
||||
|
||||
try {
|
||||
char err_buf[SP_MAX_ERR_BUF_SIZ] = {0,};
|
||||
|
||||
int read_bytes = util::read_atmost_n(
|
||||
this->error(),
|
||||
err_buf,
|
||||
SP_MAX_ERR_BUF_SIZ);
|
||||
fclose(this->error());
|
||||
|
||||
if (read_bytes || strlen(err_buf)) {
|
||||
// Throw whatever information we have about child failure
|
||||
throw CalledProcessError(err_buf);
|
||||
}
|
||||
} catch (std::exception& exp) {
|
||||
stream_.cleanup_fds();
|
||||
throw;
|
||||
}
|
||||
|
||||
/*
|
||||
this->hExited_ =
|
||||
std::shared_future<int>(std::async(std::launch::async, [this] {
|
||||
WaitForSingleObject(this->hProcess_, INFINITE);
|
||||
std::async(std::launch::async, [this] {
|
||||
WaitForSingleObject(this->process_handle_, INFINITE);
|
||||
|
||||
CloseHandle(this->stream_.g_hChildStd_ERR_Wr);
|
||||
CloseHandle(this->stream_.g_hChildStd_OUT_Wr);
|
||||
CloseHandle(this->stream_.g_hChildStd_IN_Rd);
|
||||
});
|
||||
|
||||
DWORD exit_code;
|
||||
if (FALSE == GetExitCodeProcess(this->hProcess_, &exit_code))
|
||||
throw OSError("GetExitCodeProcess", 0);
|
||||
|
||||
CloseHandle(this->hProcess_);
|
||||
|
||||
return (int)exit_code;
|
||||
}));
|
||||
/*
|
||||
NOTE: In the linux version, there is a check to make sure that the process
|
||||
has been started. Here, we do nothing because CreateProcess will throw
|
||||
if we fail to create the process.
|
||||
*/
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int err_rd_pipe, err_wr_pipe;
|
||||
@ -1683,7 +1681,7 @@ namespace detail {
|
||||
inline void Streams::setup_comm_channels()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
util::configure_pipe(this->g_hChildStd_IN_Rd, &this->g_hChildStd_IN_Wr, &this->g_hChildStd_IN_Wr);
|
||||
util::configure_pipe(&this->g_hChildStd_IN_Rd, &this->g_hChildStd_IN_Wr, &this->g_hChildStd_IN_Wr);
|
||||
this->input(util::file_from_handle(this->g_hChildStd_IN_Wr, "w"));
|
||||
this->write_to_child_ = _fileno(this->input());
|
||||
|
||||
@ -1935,6 +1933,12 @@ OutBuffer check_output(const std::string& arg, Args&&... args)
|
||||
return (detail::check_output_impl(arg, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
OutBuffer check_output(std::vector<std::string> plist, Args &&... args)
|
||||
{
|
||||
return (detail::check_output_impl(plist, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* An easy way to pipeline easy commands.
|
||||
|
@ -8,7 +8,9 @@ void test_ret_code()
|
||||
std::cout << "Test::test_poll_ret_code" << std::endl;
|
||||
auto p = sp::Popen({"/usr/bin/false"});
|
||||
while (p.poll() == -1) {
|
||||
#ifndef _MSC_VER
|
||||
usleep(1000 * 100);
|
||||
#endif
|
||||
}
|
||||
assert (p.retcode() == 1);
|
||||
}
|
||||
|
@ -5,7 +5,11 @@ using namespace subprocess;
|
||||
|
||||
void test_exename()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
auto ret = call({"--version"}, executable{"cmake"}, shell{false});
|
||||
#else
|
||||
auto ret = call({"-l"}, executable{"ls"}, shell{false});
|
||||
#endif
|
||||
std::cout << ret << std::endl;
|
||||
}
|
||||
|
||||
@ -35,7 +39,11 @@ void test_easy_piping()
|
||||
|
||||
void test_shell()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
auto obuf = check_output({"cmake", "--version"}, shell{false});
|
||||
#else
|
||||
auto obuf = check_output({"ls", "-l"}, shell{false});
|
||||
#endif
|
||||
std::cout << obuf.buf.data() << std::endl;
|
||||
}
|
||||
|
||||
@ -43,9 +51,13 @@ void test_sleep()
|
||||
{
|
||||
auto p = Popen({"sleep", "30"}, shell{true});
|
||||
|
||||
while (p.poll() == -1) {
|
||||
while (p.poll() == -1)
|
||||
{
|
||||
std::cout << "Waiting..." << std::endl;
|
||||
#ifdef _MSC_VER
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::cout << "Sleep ended: ret code = " << p.retcode() << std::endl;
|
||||
|
Loading…
x
Reference in New Issue
Block a user