Skip to content

Commit 52d2d31

Browse files
committed
Handling boost process v2 in Process
* changed process implementation for boost > 1.85 (references #1328)
1 parent 82ade01 commit 52d2d31

File tree

4 files changed

+171
-16
lines changed

4 files changed

+171
-16
lines changed

.github/workflows/CI-windows.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
release: false
2626
install: >-
2727
mingw-w64-x86_64-toolchain mingw-w64-x86_64-gcc mingw-w64-x86_64-gcc-fortran
28-
mingw-w64-x86_64-cmake mingw-w64-x86_64-doxygen
28+
mingw-w64-x86_64-cmake mingw-w64-x86_64-doxygen make
2929
mingw-w64-x86_64-boost mingw-w64-x86_64-gdal mingw-w64-x86_64-curl-winssl
3030
mingw-w64-x86_64-qt5 mingw-w64-x86_64-openssl
3131
git p7zip mingw-w64-x86_64-gnuplot mingw-w64-x86_64-graphviz

CMake.in.cmake

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#
22
# Configuration file for CMakeLists.txt files
33
#
4-
# Author : Jean-Christophe FABRE <[email protected]>
4+
# Authors : Jean-Christophe FABRE <[email protected]>
5+
# Armel THÖNI <[email protected]>
56
#
67
# This file is included by the main CMakeLists.txt file, and defines variables
78
# to configure the build and install
@@ -23,7 +24,7 @@ SET(OFBUILD_CUSTOM_CMAKE_VERSION "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.
2324
SET(OPENFLUID_VERSION_MAJOR 2)
2425
SET(OPENFLUID_VERSION_MINOR 2)
2526
SET(OPENFLUID_VERSION_PATCH 1)
26-
SET(OPENFLUID_VERSION_STATUS "alpha5") # example: SET(OPENFLUID_VERSION_STATUS "rc1")
27+
SET(OPENFLUID_VERSION_STATUS "alpha6") # example: SET(OPENFLUID_VERSION_STATUS "rc1")
2728

2829
SET(OPENFLUID_VERSION_FULL "${OPENFLUID_VERSION_MAJOR}.${OPENFLUID_VERSION_MINOR}.${OPENFLUID_VERSION_PATCH}")
2930

src/openfluid/utils/CMakeLists.txt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
11

22
INCLUDE_DIRECTORIES(${GDAL_INCLUDE_DIR} ${CURL_INCLUDE_DIRS})
33

4-
# Hack for boost::process on Windows/MinGW only
4+
SET(BOOST_COMPONENTS )
5+
SET(BOOST_LINK_LIBRARIES Boost::boost)
6+
IF(Boost_VERSION_MINOR GREATER 85)
7+
SET(BOOST_COMPONENTS ${BOOST_COMPONENTS} process)
8+
SET(BOOST_LINK_LIBRARIES ${BOOST_LINK_LIBRARIES} Boost::process)
9+
ENDIF()
10+
11+
512
IF(MINGW)
6-
FIND_PACKAGE(Boost REQUIRED filesystem)
13+
SET(BOOST_COMPONENTS ${BOOST_COMPONENTS} filesystem system thread)
14+
# Hack for boost::process on Windows/MinGW only
715
IF(Boost_VERSION GREATER 107000)
816
ADD_DEFINITIONS(-DBOOST_USE_WINDOWS_H -DWIN32_LEAN_AND_MEAN)
917
ENDIF()
18+
IF(Boost_VERSION_MINOR GREATER 85)
19+
SET(BOOST_LINK_LIBRARIES ${BOOST_LINK_LIBRARIES} bcrypt)
20+
ENDIF()
1021
ENDIF()
11-
22+
FIND_PACKAGE(Boost REQUIRED ${BOOST_COMPONENTS})
23+
ADD_COMPILE_DEFINITIONS(Boost_VERSION_MINOR=${Boost_VERSION_MINOR})
1224

1325
SET(OPENFLUID_UTILS_CPP GDALHelpers.cpp
1426
Process.cpp
@@ -46,12 +58,11 @@ TARGET_LINK_LIBRARIES(openfluid-utils
4658
openfluid-tools
4759
${GDAL_LIBRARIES}
4860
${CURL_LIBRARIES}
49-
Boost::boost
61+
${BOOST_LINK_LIBRARIES}
5062
$<$<BOOL:${MINGW}>:Boost::filesystem> $<$<BOOL:${MINGW}>:ws2_32> # MinGW hack
5163
)
5264

5365

54-
5566
INSTALL(TARGETS openfluid-utils
5667
RUNTIME DESTINATION ${OFBUILD_BIN_INSTALL_PATH}
5768
LIBRARY DESTINATION ${OFBUILD_LIB_INSTALL_PATH}

src/openfluid/utils/Process.cpp

Lines changed: 151 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,21 @@
4242
#include <sstream>
4343
#include <iterator>
4444

45+
#if (Boost_VERSION_MINOR > 85) && defined(OPENFLUID_OS_WINDOWS)
46+
#include <winsock2.h> // FIXME check if useful or necessary, theorically useful to respect include order
47+
#endif
48+
#if (Boost_VERSION_MINOR > 85)
49+
#include <unordered_map>
50+
#include <boost/asio/io_context.hpp>
51+
#include <boost/asio/readable_pipe.hpp>
52+
#include <boost/asio/read.hpp>
53+
#include <boost/process/v2/process.hpp>
54+
#include <boost/process/v2/environment.hpp>
55+
#include <boost/process/v2/stdio.hpp>
56+
#include <boost/process/v2/start_dir.hpp>
57+
#else
4558
#include <boost/process.hpp>
59+
#endif
4660

4761
#include <openfluid/tools/FilesystemPath.hpp>
4862
#include <openfluid/tools/StringHelpers.hpp>
@@ -136,6 +150,107 @@ bool Process::run()
136150

137151
try
138152
{
153+
#if (Boost_VERSION_MINOR > 85)
154+
std::ofstream StdOutFile;
155+
std::ofstream StdErrFile;
156+
std::string LineOut;
157+
std::string LineErr;
158+
std::unordered_map<std::string, std::string> ProcessEnv;
159+
boost::asio::io_context Ctx;
160+
boost::asio::readable_pipe PipeOut{Ctx};
161+
boost::asio::readable_pipe PipeErr{Ctx};
162+
163+
bool SinkOutToFile = !m_Cmd.OutFile.empty();
164+
bool SinkErrToFile = !m_Cmd.ErrFile.empty();
165+
166+
// prepare environment
167+
if (m_Env.Inherits)
168+
{
169+
for(const auto& InheritedVar : boost::process::v2::environment::current())
170+
{
171+
ProcessEnv[InheritedVar.key().string()] = InheritedVar.value().string();
172+
}
173+
}
174+
175+
for (const auto& Var : m_Env.Vars)
176+
{
177+
ProcessEnv[Var.first] = Var.second;
178+
}
179+
// Hotfix for windows bug when work dir is empty
180+
std::string WorkDir;
181+
if (m_Cmd.WorkDir.empty())
182+
{
183+
WorkDir = "."; // warning boost : If your path is relative, it may fail on posix,
184+
//because the directory is changed before a call to execve.
185+
}
186+
else
187+
{
188+
WorkDir = m_Cmd.WorkDir;
189+
}
190+
191+
// boost::process::shell, <- not relevant in new system?
192+
boost::process::v2::process Proc(Ctx, m_Cmd.Program, m_Cmd.Args,
193+
boost::process::v2::process_stdio{nullptr, PipeOut, PipeErr},
194+
boost::process::v2::process_start_dir(WorkDir),
195+
boost::process::v2::process_environment(ProcessEnv));
196+
197+
// if out is redirected, create out file
198+
if (SinkOutToFile)
199+
{
200+
openfluid::tools::Path(openfluid::tools::Path(m_Cmd.OutFile).dirname()).makeDirectory();
201+
StdOutFile.open(m_Cmd.OutFile,std::ios::out);
202+
}
203+
204+
// if error is redirected, create error file
205+
if (SinkErrToFile)
206+
{
207+
openfluid::tools::Path(openfluid::tools::Path(m_Cmd.ErrFile).dirname()).makeDirectory();
208+
StdErrFile.open(m_Cmd.ErrFile,std::ios::out);
209+
}
210+
211+
boost::system::error_code Ec;
212+
boost::asio::read(PipeOut, boost::asio::dynamic_buffer(LineOut), Ec);
213+
if (!Ec || (Ec == boost::asio::error::eof))
214+
{
215+
std::cout << "Boost process reading error in out stream: " << Ec.message() << std::endl;
216+
openfluid::utils::log::error("Process", "Boost process reading error in out stream");
217+
}
218+
boost::asio::read(PipeErr, boost::asio::dynamic_buffer(LineErr), Ec);
219+
if (!Ec || (Ec == boost::asio::error::eof))
220+
{
221+
std::cout << "Boost process reading error in err stream: " << Ec.message() << std::endl;
222+
openfluid::utils::log::error("Process", "Boost process reading error in err stream");
223+
}
224+
225+
Proc.wait();
226+
for (const auto& L : openfluid::tools::split(LineOut, "\n"))
227+
{
228+
if (SinkOutToFile)
229+
{
230+
// if out is redirected, sink out lines in file
231+
StdOutFile << L << "\n";
232+
}
233+
else
234+
{
235+
m_OutLines.push_back(L);
236+
}
237+
}
238+
239+
for (const auto& L : openfluid::tools::split(LineErr, "\n"))
240+
{
241+
if (SinkErrToFile)
242+
{
243+
// if out is redirected, sink out lines in file
244+
StdErrFile << L << "\n";
245+
}
246+
else
247+
{
248+
m_ErrLines.push_back(L);
249+
}
250+
}
251+
252+
m_ExitCode = Proc.exit_code();
253+
#else
139254
boost::process::environment ProcessEnv;
140255
boost::process::ipstream StdOutStr;
141256
boost::process::ipstream StdErrStr;
@@ -229,17 +344,12 @@ bool Process::run()
229344

230345
BPC.wait();
231346
m_ExitCode = BPC.exit_code();
347+
#endif
232348
}
233-
catch(const boost::process::process_error& E)
349+
catch(const std::exception& E)
234350
{
235351
m_ErrorMsg = std::string(E.what());
236-
openfluid::utils::log::error("Process", std::string("Boost process error: ")+E.what());
237-
return false;
238-
}
239-
catch(...)
240-
{
241-
// TODO for logging purposes
242-
openfluid::utils::log::error("Process", "Boost process error");
352+
openfluid::utils::log::error("Process", std::string("Boost process error: ")+m_ErrorMsg);
243353
return false;
244354
}
245355

@@ -291,6 +401,38 @@ int Process::system(const std::string& Program, const std::vector<std::string>&
291401

292402
int Process::system(const Command& Cmd, const Environment& Env)
293403
{
404+
#if (Boost_VERSION_MINOR > 85)
405+
boost::asio::io_context Ctx;
406+
std::unordered_map<std::string, std::string> ProcessEnv;
407+
// prepare environment
408+
if (Env.Inherits)
409+
{
410+
for(const auto& InheritedVar : boost::process::v2::environment::current())
411+
{
412+
ProcessEnv[InheritedVar.key().string()] = InheritedVar.value().string();
413+
}
414+
}
415+
416+
for (const auto& Var : Env.Vars)
417+
{
418+
ProcessEnv[Var.first] = Var.second;
419+
}
420+
// Hotfix for windows bug when work dir is empty
421+
std::string WorkDir;
422+
if (Cmd.WorkDir.empty())
423+
{
424+
WorkDir = "."; // warning boost : If your path is relative, it may fail on posix,
425+
//because the directory is changed before a call to execve.
426+
}
427+
else
428+
{
429+
WorkDir = Cmd.WorkDir;
430+
}
431+
boost::process::v2::process Proc(Ctx, Cmd.Program, Cmd.Args,
432+
boost::process::v2::process_start_dir(WorkDir),
433+
boost::process::v2::process_environment(ProcessEnv));
434+
return Proc.wait();
435+
#else
294436
boost::process::environment ProcessEnv;
295437

296438
// prepare environment
@@ -321,6 +463,7 @@ int Process::system(const Command& Cmd, const Environment& Env)
321463
boost::process::args = Cmd.Args,
322464
boost::process::start_dir = WorkDir,
323465
ProcessEnv);
466+
#endif
324467
}
325468

326469

0 commit comments

Comments
 (0)