Documentation: http://www.highscore.de/boost/process0.5/
borisschaeling / boost-process Goto Github PK
View Code? Open in Web Editor NEWBoost.Process is a library to manage system processes
License: Boost Software License 1.0
Boost.Process is a library to manage system processes
License: Boost Software License 1.0
Documentation: http://www.highscore.de/boost/process0.5/
In boost-process/libs/process/example/wait.cpp:52 , the class boost::asio::windows::object_handle is used with the child process handle.
I think CloseHandle() will be called twice with the same process handle in the destructors of boost::process::child and boost::asio::windows::object_handle.
DuplicateHandle() can be used to avoid the problem:
#if defined(BOOST_WINDOWS_API)
DWORD exit_code;
HANDLE dupHandle;
DuplicateHandle(GetCurrentProcess(),c.process_handle(),GetCurrentProcess(),&dupHandle,
0,false,DUPLICATE_SAME_ACCESS));
boost::asio::windows::object_handle handle(io_service, dupHandle);
handle.async_wait(
[&handle, &exit_code](const boost::system::error_code&)
{ ::GetExitCodeProcess(handle.native(), &exit_code); }
);
#endif
The way char
vs wchar_t
strings are handled on Windows makes hard to write portable code. Currently, if UNICODE
is defined the API is wide and if not it is narrow. On POSIX it is always narrow.
The only way to write portable code with this API is to use the preprocessor to select completely separate implementations based on #ifdef UNICODE
.
Instead both narrow and wide versions should always be defined and it is up to the caller which they use.
The problem did not exist in previous versions of Boost.Process.
Briefly looking through the source code I've noticed that at least one its header file includes windows.h
. This file has always been a nightmare as it spoils global namespace with lots of macro definitions with unprefixed names which are likely to clash. It's not the the way like modern C++ deals with things.
The only one way windows.h
could be reliably hidden is putting it in a source file, not a header. I know that after this you cannot call the library header only, but to me this really makes sense for code sanity.
The docs for set_args
say 'The first argument specifies the executable to start unless run_exe is used'. It's not clear from this if the first argument you pass is argv[0] or argv[1] when also using run_exe.
It turns out on Windows that the first argument in argv[0], rather than what you passed to run_exe. It looks like this is different from the POSIX behaviour:
explicit run_exe_(const std::string &s) : s_(s), cmd_line_(new char*[2])
{
cmd_line_[0] = const_cast<char*>(s_.c_str());
cmd_line_[1] = 0;
}
Hey Boris,
I was trying to trace the status of the project and couldn't really figure out where things stand. What are the open issues that need to be resolved before another boost review can be done?
Hi,
To compile with Solaris, the following patch would be needed:
Index: boost/process/posix/initializers/inherit_env.hpp
===================================================================
--- boost/process/posix/initializers/inherit_env.hpp (revision 262831)
+++ boost/process/posix/initializers/inherit_env.hpp (working copy)
@@ -17,6 +17,10 @@
# define environ (*_NSGetEnviron())
#else
# include <unistd.h>
+extern "C"
+{
+ extern char **environ;
+}
#endif
namespace boost { namespace process { namespace posix { namespace initializers {
Regards,
Daniel.
Hi,
it would be nice to have the license information mentioned in the README file.
Linking to http://www.highscore.de/boost/process/index.html would probably also be a good idea..
Currently, license information can only be obtained by looking at the header files which mention a LICENSE_1_0.txt
file or a link to the boost website.
When arguments contain quotes on Windows, they are not passed to the program correctly because the argument handling in Boost.Process 0.5 is naive. Currently, it just checks to see if an argument has a space in it and, if so, surround the argument with quotations. This breaks if the argument itself contains quotations.
The previous version of Boost.Process did not have this problem.
Howdy. I am using Boost Process to run a child process (command called DreamDaemon, game server) from a parent C++ application, obviously. I was wondering if there was a way to keep the child DreamDaemon process when my C++ application closes.
e.g. I run the following code:
child child = execute(set_args(argsChild), close_stdin());
With argsChild as my command line arguments
DreamDaemon will start up, and the game will start. However, if I terminate my own application (control+c), it kills the DreamDaemon instance with it. Not entirely sure if this is making sense, so if you can't follow, I'll try to explain it another way.
Is it possible to keep the DreamDaemon process running even when my parent app is closed? I would have thought that since I just execute the command, it is hands off? Does this have something to do with the child object being killed when my application is terminated? Any info you can give would be appreciated, thanks!
First of all, thanks for the good work here, the API is very clean, and yet extensible and practical, which is a good thing when trying to abstract something so different across OSes.
However, I don't fully understand why the code is so much static. Why did you choose to use compile time polymorphism (i.e. templates) instead of runtime polymorphism (i.e. vtables) ? IMHO the overhead of spawning a process makes the cost of a vtable access ridiculous.
My problem, somewhat related to the previous question, is how to create a set of initializers, and then spawn a process. I would like to do something like:
std::vector<Initializer> initializers;
if (some_condition)
initializers.push_back(some_initializer);
auto child = boost::process::executor()(args, initializers);
In order to create the type Initializer
, I would have to do complicated things:
template<typename Executor>
struct InitializerBase
{
virtual void on_fork_setup(Executor& e) = 0;
// ... other methods here
};
template<typename Executor, typename ConcreteInitializer>
struct InitializerWrapper : InitializerBase<Executor>
{
ConcreteInitializer _initializer;
template<typename... Args
explicit InitializerWrapper(Args&&... args)
: _initializer(std::forward<Args>(args)...)
{}
void on_fork_setup(Executor& e) override { _initializer.on_fork_setup(e); }
// ... other methods here
};
template<typename Executor>
struct _Initializer
{
typedef Executor executor_type;
std::unique_ptr<InitializerBase> _initializer;
void on_fork_setup(Executor& e) { _initializer.on_fork_setup(e); }
// ... other methods here
}
#ifdef POSIX_SOMETHING
typedef _Initializer<PosixExecutor> Initializer;
#else
// something else
#endif
template<typename ConcreteInitializer, typename... Args>
Initializer make_initializer(Args&&... args)
{
return Initializer(new InitializerWrapper<typename Initializer::executor_type, ConcreteInitializer>(
std::forward<Args>(args)...);
}
(I omitted the boilerplate code for constructors and destructors)
That's pretty much re-virtualizing your code ... Do you know a better way ?
I want to call the executable svn
which is defined in my PATH environment variable with some arguments. I've used set_args
instead of run_exe
. The execute call fails, boost-process creates a wrong CreateProcess call.
std::vector<std::string> const args = { "svn", "propget", "-R", "svn:externals"};
using namespace boost;
system::error_code ec;
process::execute(process::set_args(args), process::set_on_error(ec));
See CreateProcess
If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:
The directory from which the application loaded.
The current directory for the parent process.
The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The directories that are listed in the PATH environment variable. Note that this function does not search the per-application path specified by the App Paths registry key. To include this per-application path in the search sequence, use the ShellExecute function.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.