diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14776a89d..688abf222 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -199,52 +199,3 @@ jobs: run: | cd ../boost-root b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker - - posix-cmake-subdir: - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-18.04 - - os: ubuntu-20.04 - - os: ubuntu-22.04 - - os: macos-11 - - runs-on: ${{matrix.os}} - - steps: - - uses: actions/checkout@v2 - - - name: Install packages - if: matrix.install - run: sudo apt install ${{matrix.install}} - - - name: Setup Boost - run: | - echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY - LIBRARY=${GITHUB_REPOSITORY#*/} - echo LIBRARY: $LIBRARY - echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV - echo GITHUB_BASE_REF: $GITHUB_BASE_REF - echo GITHUB_REF: $GITHUB_REF - REF=${GITHUB_BASE_REF:-$GITHUB_REF} - REF=${REF#refs/heads/} - echo REF: $REF - BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true - echo BOOST_BRANCH: $BOOST_BRANCH - cd .. - git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root - cd boost-root - cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY - git submodule update --init tools/boostdep - python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY - - - name: Use library with add_subdirectory - run: | - cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test - mkdir __build__ && cd __build__ - cmake .. - cmake --build . - ctest --output-on-failure --no-tests=error - - diff --git a/doc/concepts.qbk b/doc/concepts.qbk index f9f27d493..3b028cddd 100644 --- a/doc/concepts.qbk +++ b/doc/concepts.qbk @@ -35,7 +35,7 @@ In this library the following functions are used for the creation of unnamed pip As the name suggests, named pipes have a string identifier. This means that a handle to them can be obtained with the identifier, too. -The implementation on posix uses [@(http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos], +The implementation on posix uses [@http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos], which means, that the named pipe behaves like a file. Windows does provide a facility called [@https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx named pipes], diff --git a/doc/v2/introduction.qbk b/doc/v2/introduction.qbk index e97f60b17..18029c3c0 100644 --- a/doc/v2/introduction.qbk +++ b/doc/v2/introduction.qbk @@ -57,7 +57,7 @@ file-handles for the subprocess. Certain parts of boost.process were not as reliable as they should've been. -This concerns especially the `wait_for`` and `wait_until` functions on the process. +This concerns especially the `wait_for` and `wait_until` functions on the process. The latter are easy to do on windows, but posix does not provide an API for this. Thus the wait_for used signals or fork, which was all but safe. Since process v2 is based on asio and thus supports cancellation, diff --git a/include/boost/process/detail/posix/basic_cmd.hpp b/include/boost/process/detail/posix/basic_cmd.hpp index d648e4909..f310f1276 100644 --- a/include/boost/process/detail/posix/basic_cmd.hpp +++ b/include/boost/process/detail/posix/basic_cmd.hpp @@ -112,7 +112,10 @@ struct exe_cmd_init : boost::process::detail::api::handler_base_ext { if (exe.empty()) //cmd style { - exec.exe = args.front().c_str(); + if (args.empty()) + exec.exe = ""; + else + exec.exe = args.front().c_str(); exec.cmd_style = true; } else diff --git a/include/boost/process/detail/posix/basic_pipe.hpp b/include/boost/process/detail/posix/basic_pipe.hpp index 965db6370..50fd4de39 100644 --- a/include/boost/process/detail/posix/basic_pipe.hpp +++ b/include/boost/process/detail/posix/basic_pipe.hpp @@ -77,12 +77,9 @@ class basic_pipe void assign_source(native_handle_type h) { _source = h;} void assign_sink (native_handle_type h) { _sink = h;} - - - int_type write(const char_type * data, int_type count) { - int_type write_len; + ssize_t write_len; while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1) { //Try again if interrupted @@ -90,19 +87,19 @@ class basic_pipe if (err != EINTR) ::boost::process::detail::throw_last_error(); } - return write_len; + return static_cast(write_len); } int_type read(char_type * data, int_type count) { - int_type read_len; - while ((read_len = static_cast(::read(_source, data, count * sizeof(char_type)))) == -1) + ssize_t read_len; + while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1) { //Try again if interrupted auto err = errno; if (err != EINTR) ::boost::process::detail::throw_last_error(); } - return read_len; + return static_cast(read_len); } bool is_open() const diff --git a/include/boost/process/detail/windows/basic_pipe.hpp b/include/boost/process/detail/windows/basic_pipe.hpp index 3cf904474..0fe524d21 100644 --- a/include/boost/process/detail/windows/basic_pipe.hpp +++ b/include/boost/process/detail/windows/basic_pipe.hpp @@ -158,7 +158,7 @@ basic_pipe::basic_pipe(const std::string & name) ::boost::process::detail::throw_last_error("create_named_pipe() failed"); ::boost::winapi::HANDLE_ sink = boost::winapi::create_file( - name.c_str(), + name_.c_str(), ::boost::winapi::GENERIC_WRITE_, 0, nullptr, OPEN_EXISTING_, FILE_FLAG_OVERLAPPED_, //to allow read diff --git a/include/boost/process/detail/windows/pipe_in.hpp b/include/boost/process/detail/windows/pipe_in.hpp index 39546eae6..1ef215279 100644 --- a/include/boost/process/detail/windows/pipe_in.hpp +++ b/include/boost/process/detail/windows/pipe_in.hpp @@ -14,6 +14,8 @@ #include #include #include +#include + namespace boost { namespace process { namespace detail { namespace windows { diff --git a/include/boost/process/detail/windows/pipe_out.hpp b/include/boost/process/detail/windows/pipe_out.hpp index 125a34862..24cd6a82a 100644 --- a/include/boost/process/detail/windows/pipe_out.hpp +++ b/include/boost/process/detail/windows/pipe_out.hpp @@ -15,10 +15,10 @@ #include #include #include - -namespace boost { namespace process { namespace detail { namespace windows { +#include +namespace boost { namespace process { namespace detail { namespace windows { template struct pipe_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles diff --git a/include/boost/process/environment.hpp b/include/boost/process/environment.hpp index 3aa4c9160..0d276cdac 100644 --- a/include/boost/process/environment.hpp +++ b/include/boost/process/environment.hpp @@ -263,7 +263,7 @@ class basic_environment_impl : public Implementation auto st1 = key + ::boost::process::detail::equal_sign(); while (*p != nullptr) { - const int len = std::char_traits::length(*p); + const std::size_t len = std::char_traits::length(*p); if ((std::distance(st1.begin(), st1.end()) < len) && std::equal(st1.begin(), st1.end(), *p)) break; @@ -277,7 +277,7 @@ class basic_environment_impl : public Implementation auto st1 = key + ::boost::process::detail::equal_sign(); while (*p != nullptr) { - const int len = std::char_traits::length(*p); + const std::size_t len = std::char_traits::length(*p); if ((std::distance(st1.begin(), st1.end()) < len) && std::equal(st1.begin(), st1.end(), *p)) break; @@ -292,8 +292,9 @@ class basic_environment_impl : public Implementation auto st1 = st + ::boost::process::detail::equal_sign(); while (*p != nullptr) { - const int len = std::char_traits::length(*p); - if ((std::distance(st1.begin(), st1.end()) < len) + const std::size_t len = std::char_traits::length(*p); + if ((std::distance(st1.begin(), st1.end()) < + static_cast(len)) && std::equal(st1.begin(), st1.end(), *p)) return 1u; p++; diff --git a/include/boost/process/pipe.hpp b/include/boost/process/pipe.hpp index 24b261514..11040717d 100644 --- a/include/boost/process/pipe.hpp +++ b/include/boost/process/pipe.hpp @@ -122,10 +122,14 @@ struct basic_pipebuf : std::basic_streambuf ///Destructor -> writes the frest of the data ~basic_pipebuf() + try { if (basic_pipebuf::is_open()) basic_pipebuf::overflow(Traits::eof()); } + catch (process_error & ) + { + } ///Move construct from a pipe. basic_pipebuf(pipe_type && p) : _pipe(std::move(p)), diff --git a/include/boost/process/v2/environment.hpp b/include/boost/process/v2/environment.hpp index ae081d162..69bacb663 100644 --- a/include/boost/process/v2/environment.hpp +++ b/include/boost/process/v2/environment.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/process/v2/exit_code.hpp b/include/boost/process/v2/exit_code.hpp index 3835d9f94..3ee580063 100644 --- a/include/boost/process/v2/exit_code.hpp +++ b/include/boost/process/v2/exit_code.hpp @@ -94,12 +94,19 @@ inline int evaluate_exit_code(int code) #endif - -/** Convert the exit-code in a completion into an error if the actual error isn't set. +/// @{ +/** Helper to subsume an exit-code into an error_code if there's no actual error isn't set. * @code {.cpp} * process proc{ctx, "exit", {"1"}}; * - * proc.async_wait(code_as_error( + * proc.async_wait( + * asio::deferred( + * [&proc](error_code ec, int) + * { + * return asio::deferred.values( + * check_exit_code(ec, proc.native_exit_code()) + * ); + * * [](error_code ec) * { * assert(ec.value() == 10); @@ -107,144 +114,19 @@ inline int evaluate_exit_code(int code) * })); * * @endcode - */ -template -struct code_as_error_t -{ - CompletionToken token_; - const error_category & category; - - template - code_as_error_t(Token_ && token, const error_category & category) - : token_(std::forward(token)), category(category) - { - } -}; - -/// Deduction function for code_as_error_t. -template -code_as_error_t code_as_error( - CompletionToken && token, - const error_category & category = error::get_exit_code_category()) -{ - return code_as_error_t::type>( - std::forward(token), category); -}; - -namespace detail -{ + */ -template -struct code_as_error_handler +inline error_code check_exit_code( + error_code &ec, native_exit_code_type native_code, + const error_category & category = error::get_exit_code_category()) { - typedef void result_type; - - template - code_as_error_handler(H && h, const error_category & category) - : handler_(std::forward(h)), category(category) - { - } - - void operator()(error_code ec, native_exit_code_type code) - { - if (!ec) - BOOST_PROCESS_V2_ASSIGN_EC(ec, code, category) - std::move(handler_)(ec); - } - - - Handler handler_; - const error_category & category; -}; - + if (!ec) + BOOST_PROCESS_V2_ASSIGN_EC(ec, native_code, category); + return ec; } +/// @} BOOST_PROCESS_V2_END_NAMESPACE - -#if !defined(BOOST_PROCESS_V2_STANDALONE) -namespace boost -{ -#endif -namespace asio -{ - -template -struct async_result< - BOOST_PROCESS_V2_NAMESPACE::code_as_error_t, - void(BOOST_PROCESS_V2_NAMESPACE::error_code, - BOOST_PROCESS_V2_NAMESPACE::native_exit_code_type)> -{ - using signature = void(BOOST_PROCESS_V2_NAMESPACE::error_code); - using return_type = typename async_result::return_type; - - - template - struct init_wrapper - { - init_wrapper(Initiation init) - : initiation_(std::move(init)) - { - } - - template - void operator()( - Handler && handler, - const BOOST_PROCESS_V2_NAMESPACE::error_category & cat, - Args && ... args) - { - std::move(initiation_)( - BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler::type>( - std::forward(handler), cat), - std::forward(args)...); - } - - Initiation initiation_; - - }; - - template - static BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, signature, - (async_initiate( - declval::type> >(), - declval(), - declval()...))) - initiate( - Initiation && initiation, - RawCompletionToken && token, - Args &&... args) - { - return async_initiate( - init_wrapper::type>( - std::forward(initiation)), - token.token_, - token.category, - std::forward(args)...); - } -}; - - - - -template