diff --git a/sfw/core/sub_process.cpp b/sfw/core/sub_process.cpp new file mode 100644 index 0000000..0687959 --- /dev/null +++ b/sfw/core/sub_process.cpp @@ -0,0 +1,705 @@ +/*************************************************************************/ +/* sub_process.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +//--STRIP +#include "sub_process.h" +//--STRIP + +#if defined(_WIN64) || defined(_WIN32) + +// TODO clean these up +#include +#include +#include +#include +#include +#include +#include + +Error SubProcess::start() { + if (_executable_path.empty()) { + return ERR_FILE_BAD_PATH; + } + + if (is_process_running()) { + return ERR_BUSY; + } + + String path = _executable_path.replace("/", "\\"); + + String cmdline = _quote_command_line_argument(path); + for (int i = 0; i < _arguments.size(); ++i) { + cmdline += " " + _quote_command_line_argument(_arguments[i]); + } + + ZeroMemory(&_process_info.si, sizeof(_process_info.si)); + _process_info.si.cb = sizeof(_process_info.si); + ZeroMemory(&_process_info.pi, sizeof(_process_info.pi)); + LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&_process_info.si; + + Char16String modstr = cmdline.utf16(); // Windows wants to change this no idea why. + + bool inherit_handles = false; + + if (_read_output) { + // Create pipe for StdOut and StdErr. + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = true; + sa.lpSecurityDescriptor = NULL; + + ERR_FAIL_COND_V(!CreatePipe(&_pipe_handles[0], &_pipe_handles[1], &sa, 0), ERR_CANT_FORK); + ERR_FAIL_COND_V(!SetHandleInformation(_pipe_handles[0], HANDLE_FLAG_INHERIT, 0), ERR_CANT_FORK); // Read handle is for host process only and should not be inherited. + + _process_info.si.dwFlags |= STARTF_USESTDHANDLES; + _process_info.si.hStdOutput = _pipe_handles[1]; + if (_read_std_err) { + _process_info.si.hStdError = _pipe_handles[1]; + } + inherit_handles = true; + } + + DWORD creaton_flags = NORMAL_PRIORITY_CLASS; + if (_open_console) { + creaton_flags |= CREATE_NEW_CONSOLE; + } else { + creaton_flags |= CREATE_NO_WINDOW; + } + + int ret = CreateProcessW(nullptr, (LPWSTR)(modstr.ptrw()), nullptr, nullptr, inherit_handles, creaton_flags, nullptr, nullptr, si_w, &_process_info.pi); + if (!ret && _read_output) { + CloseHandle(_pipe_handles[0]); // Cleanup pipe handles. + CloseHandle(_pipe_handles[1]); + + _pipe_handles[0] = NULL; + _pipe_handles[1] = NULL; + } + + ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK); + + if (_blocking) { + if (_read_output) { + CloseHandle(_pipe_handles[1]); // Close pipe write handle (only child process is writing). + + int bytes_in_buffer = 0; + + const int CHUNK_SIZE = 4096; + DWORD read = 0; + for (;;) { // Read StdOut and StdErr from pipe. + _bytes.resize(bytes_in_buffer + CHUNK_SIZE); + const bool success = ReadFile(_pipe_handles[0], _bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, NULL); + if (!success || read == 0) { + break; + } + // Assume that all possible encodings are ASCII-compatible. + // Break at newline to allow receiving long output in portions. + int newline_index = -1; + for (int i = read - 1; i >= 0; i--) { + if (_bytes[bytes_in_buffer + i] == '\n') { + newline_index = i; + break; + } + } + + if (newline_index == -1) { + bytes_in_buffer += read; + continue; + } + + const int bytes_to_convert = bytes_in_buffer + (newline_index + 1); + _append_to_pipe(_bytes.ptr(), bytes_to_convert); + + bytes_in_buffer = read - (newline_index + 1); + memmove(_bytes.ptr(), _bytes.ptr() + bytes_to_convert, bytes_in_buffer); + } + + if (bytes_in_buffer > 0) { + _append_to_pipe(_bytes.ptr(), bytes_in_buffer); + } + + CloseHandle(_pipe_handles[0]); // Close pipe read handle. + } + + WaitForSingleObject(_process_info.pi.hProcess, INFINITE); + + DWORD ret2; + GetExitCodeProcess(_process_info.pi.hProcess, &ret2); + _exitcode = ret2; + + CloseHandle(_process_info.pi.hProcess); + CloseHandle(_process_info.pi.hThread); + } else { + if (_read_output) { + //eventually we will need to keep this + CloseHandle(_pipe_handles[1]); // Close pipe write handle (only child process is writing). + _pipe_handles[1] = NULL; + } + + _process_started = true; + + ProcessID pid = _process_info.pi.dwProcessId; + _process_id = pid; + } + + return OK; +} + +Error SubProcess::stop() { + if (!_process_started) { + return OK; + } + + if (_pipe_handles[0]) { + CloseHandle(_pipe_handles[0]); // Cleanup pipe handles. + _pipe_handles[0] = NULL; + } + + if (_pipe_handles[1]) { + CloseHandle(_pipe_handles[1]); + _pipe_handles[1] = NULL; + } + + const int ret = TerminateProcess(_process_info.pi.hProcess, 0); + + CloseHandle(_process_info.pi.hProcess); + CloseHandle(_process_info.pi.hThread); + + ZeroMemory(&_process_info.si, sizeof(_process_info.si)); + _process_info.si.cb = sizeof(_process_info.si); + ZeroMemory(&_process_info.pi, sizeof(_process_info.pi)); + + _process_started = false; + + return ret != 0 ? OK : FAILED; +} + +Error SubProcess::poll() { + if (!_process_started) { + return FAILED; + } + + if (!_pipe_handles[0]) { + return FAILED; + } + + _pipe.clear(); + + int bytes_in_buffer = 0; + + const int CHUNK_SIZE = 4096; + DWORD read = 0; + + _bytes.resize(bytes_in_buffer + CHUNK_SIZE); + const bool success = ReadFile(_pipe_handles[0], _bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, NULL); + + if (!success) { + stop(); + return ERR_FILE_EOF; + } + + if (read == 0) { + return OK; + } + + // Assume that all possible encodings are ASCII-compatible. + // Break at newline to allow receiving long output in portions. + int newline_index = -1; + for (int i = read - 1; i >= 0; i--) { + if (_bytes[bytes_in_buffer + i] == '\n') { + newline_index = i; + break; + } + } + + if (newline_index == -1) { + bytes_in_buffer += read; + return OK; + } + + const int bytes_to_convert = bytes_in_buffer + (newline_index + 1); + _append_to_pipe(_bytes.ptr(), bytes_to_convert); + + bytes_in_buffer = read - (newline_index + 1); + memmove(_bytes.ptr(), _bytes.ptr() + bytes_to_convert, bytes_in_buffer); + + if (bytes_in_buffer > 0) { + _append_to_pipe(_bytes.ptr(), bytes_in_buffer); + } + + return OK; +} + +Error SubProcess::send_signal(const int p_signal) { + //Not Yet Impl + ERR_FAIL_V(ERR_BUG); +} + +Error SubProcess::send_data(const String &p_data) { + //Not Yet Impl + ERR_FAIL_V(ERR_BUG); +} + +bool SubProcess::is_process_running() const { + if (_process_id == 0) { + return false; + } + + if (!_process_started) { + return false; + } + + DWORD dw_exit_code = 0; + if (!GetExitCodeProcess(_process_info.pi.hProcess, &dw_exit_code)) { + return false; + } + + if (dw_exit_code != STILL_ACTIVE) { + return false; + } + + return true; +} + +String SubProcess::_quote_command_line_argument(const String &p_text) const { + for (int i = 0; i < p_text.size(); i++) { + CharType c = p_text[i]; + if (c == ' ' || c == '&' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^' || c == '=' || c == ';' || c == '!' || c == '\'' || c == '+' || c == ',' || c == '`' || c == '~') { + return "\"" + p_text + "\""; + } + } + return p_text; +} + +void SubProcess::_append_to_pipe(char *p_bytes, int p_size) { + // Try to convert from default ANSI code page to Unicode. + LocalVector wchars; + int total_wchars = MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, nullptr, 0); + if (total_wchars > 0) { + wchars.resize(total_wchars); + if (MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, wchars.ptr(), total_wchars) == 0) { + wchars.clear(); + } + } + + if (_pipe_mutex) { + _pipe_mutex->lock(); + } + if (wchars.empty()) { + // Let's hope it's compatible with UTF-8. + _pipe += String::utf8(p_bytes, p_size); + } else { + _pipe += String(wchars.ptr(), total_wchars); + } + if (_pipe_mutex) { + _pipe_mutex->unlock(); + } +} + +SubProcess::SubProcess() { + _blocking = false; + + _read_output = true; + + _read_std = true; + _read_std_err = false; + + _use_pipe_mutex = false; + + _pipe_mutex = NULL; + + _open_console = false; + + _process_id = ProcessID(); + _exitcode = 0; + + _pipe_handles[0] = NULL; + _pipe_handles[1] = NULL; + + _process_started = false; + + ZeroMemory(&_process_info.si, sizeof(_process_info.si)); + _process_info.si.cb = sizeof(_process_info.si); + ZeroMemory(&_process_info.pi, sizeof(_process_info.pi)); +} +SubProcess::~SubProcess() { + stop(); +} + +#else + +#include +#include +#include +#include +#include +#include +#include + +Error SubProcess::start() { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(ERR_BUG); +#else + if (_executable_path.empty()) { + return ERR_FILE_BAD_PATH; + } + + if (is_process_running()) { + return ERR_BUSY; + } + + if (_blocking && _read_output) { + String argss; + argss = "\"" + _executable_path + "\""; + + for (int i = 0; i < _arguments.size(); i++) { + argss += String(" \"") + _arguments[i] + "\""; + } + + if (_read_std_err) { + argss += " 2>&1"; // Read stderr too + } else { + argss += " 2>/dev/null"; //silence stderr + } + FILE *f = popen(argss.utf8().get_data(), "r"); + + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'."); + + char buf[65535]; + + while (fgets(buf, 65535, f)) { + if (_pipe_mutex) { + _pipe_mutex->lock(); + } + _pipe += String::utf8(buf); + if (_pipe_mutex) { + _pipe_mutex->unlock(); + } + } + int rv = pclose(f); + + _exitcode = WEXITSTATUS(rv); + + return OK; + } + + if (!_blocking && _read_output) { + String argss; + argss = "\"" + _executable_path + "\""; + + for (int i = 0; i < _arguments.size(); i++) { + argss += String(" \"") + _arguments[i] + "\""; + } + + if (_read_std_err) { + argss += " 2>&1"; // Read stderr too + } else { + argss += " 2>/dev/null"; //silence stderr + } + + _process_fp = popen(argss.utf8().get_data(), "r"); + + ERR_FAIL_COND_V_MSG(!_process_fp, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'."); + + return OK; + } + + // We just run it, no need to worry about output + + pid_t pid = fork(); + ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK); + + if (pid == 0) { + // is child + + if (!_blocking) { + // For non blocking calls, create a new session-ID so parent won't wait for it. + // This ensures the process won't go zombie at end. + setsid(); + } + + Vector cs; + cs.push_back(_executable_path.utf8()); + for (int i = 0; i < _arguments.size(); i++) { + cs.push_back(_arguments[i].utf8()); + } + + Vector args; + for (int i = 0; i < cs.size(); i++) { + args.push_back((char *)cs[i].get_data()); + } + args.push_back(0); + + execvp(_executable_path.utf8().get_data(), &args[0]); + // still alive? something failed.. + fprintf(stderr, "**ERROR** SubProcess::execute - Could not create child process while executing: %s\n", _executable_path.utf8().get_data()); + raise(SIGKILL); + } + + if (_blocking) { + int status; + waitpid(pid, &status, 0); + + _exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status; + } else { + _process_id = pid; + } + + return OK; +#endif +} + +Error SubProcess::stop() { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(ERR_BUG); +#else + if (_process_fp) { + int rv = pclose(_process_fp); + _process_fp = NULL; + _exitcode = WEXITSTATUS(rv); + _process_id = 0; + return OK; + } + + if (_process_id) { + int ret = ::kill(_process_id, SIGKILL); + + if (!ret) { + //avoid zombie process + int st; + ::waitpid(_process_id, &st, 0); + } + + _process_id = 0; + + return ret ? ERR_INVALID_PARAMETER : OK; + } + + return OK; +#endif +} + +Error SubProcess::poll() { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(ERR_BUG); +#else + + if (_process_fp) { + if (fgets(_process_buf, 65535, _process_fp)) { + if (_pipe_mutex) { + _pipe_mutex->lock(); + } + _pipe = String::utf8(_process_buf); + if (_pipe_mutex) { + _pipe_mutex->unlock(); + } + } else { + // The process finished + // Cleanup: + stop(); + return ERR_FILE_EOF; + } + } + + return OK; +#endif +} + +Error SubProcess::send_signal(const int p_signal) { + //Not Yet Impl + ERR_FAIL_V(ERR_BUG); +} + +Error SubProcess::send_data(const String &p_data) { + //Not Yet Impl + ERR_FAIL_V(ERR_BUG); +} + +bool SubProcess::is_process_running() const { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(false); +#else + + if (_process_fp) { + return !feof(_process_fp); + } + + if (_process_id == 0) { + return false; + } + + int status = 0; + if (waitpid(_process_id, &status, WNOHANG) != 0) { + return false; + } + + return true; +#endif +} + +SubProcess::SubProcess() { + _blocking = false; + + _read_output = true; + + _read_std = true; + _read_std_err = false; + + _use_pipe_mutex = false; + + _pipe_mutex = NULL; + + _open_console = false; + + _process_id = ProcessID(); + _exitcode = 0; + + _process_fp = NULL; +} +SubProcess::~SubProcess() { + stop(); +} + +#endif + +SubProcess *SubProcess::create() { + return memnew(SubProcess()); +} + +String SubProcess::get_executable_path() const { + return _executable_path; +} +void SubProcess::set_executable_path(const String &p_executable_path) { + ERR_FAIL_COND(is_process_running()); + + _executable_path = p_executable_path; +} + +Vector SubProcess::get_arguments() const { + return _arguments; +} +void SubProcess::set_arguments(const Vector &p_arguments) { + ERR_FAIL_COND(is_process_running()); + + _arguments = p_arguments; +} + +bool SubProcess::get_blocking() const { + return _blocking; +} +void SubProcess::set_blocking(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _blocking = p_value; +} + +bool SubProcess::get_read_output() const { + return _read_output; +} +void SubProcess::set_read_output(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _read_output = p_value; +} + +bool SubProcess::get_read_std() const { + return _read_std; +} +void SubProcess::set_read_std(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _read_std = p_value; +} + +bool SubProcess::get_read_std_err() const { + return _read_std_err; +} +void SubProcess::set_read_std_err(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _read_std_err = p_value; +} + +bool SubProcess::get_use_pipe_mutex() const { + return _use_pipe_mutex; +} +void SubProcess::set_use_pipe_mutex(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _use_pipe_mutex = p_value; +} + +bool SubProcess::get_open_console() const { + return _open_console; +} +void SubProcess::set_open_console(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _open_console = p_value; +} + +Error SubProcess::run(const String &p_executable_path, const Vector &p_arguments, bool p_output, bool p_blocking, bool p_read_std_err, bool p_use_pipe_mutex, bool p_open_console) { + if (is_process_running()) { + return ERR_ALREADY_IN_USE; + } + + String _executable_path = p_executable_path; + Vector _arguments = p_arguments; + + _blocking = p_blocking; + + _read_output = p_output; + + _read_std = true; + _read_std_err = p_read_std_err; + + _use_pipe_mutex = p_use_pipe_mutex; + + _open_console = p_open_console; + + _setup_pipe_mutex(); + + return start(); +} + +/* +SubProcess::SubProcess() { + _blocking = false; + + _read_output = true; + + _read_std = true; + _read_std_err = false; + + _use_pipe_mutex = false; + + _pipe_mutex = NULL; + + _open_console = false; + + _process_id = ProcessID(); + _exitcode = 0; +}; +*/ + +void SubProcess::_setup_pipe_mutex() { + if (_use_pipe_mutex) { + if (!_pipe_mutex) { + _pipe_mutex = memnew(Mutex); + } + } else { + if (_pipe_mutex) { + memdelete(_pipe_mutex); + _pipe_mutex = NULL; + } + } +} diff --git a/sfw/core/sub_process.h b/sfw/core/sub_process.h new file mode 100644 index 0000000..f91fb3b --- /dev/null +++ b/sfw/core/sub_process.h @@ -0,0 +1,196 @@ +#ifndef SUB_PROCESS_H +#define SUB_PROCESS_H + +/*************************************************************************/ +/* sub_process.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +//--STRIP +#include "core/list.h" +#include "core/math_defs.h" +#include "core/memory.h" +#include "core/mutex.h" +#include "core/typedefs.h" +#include "core/ustring.h" + +#include +//--STRIP + +#if defined(_WIN64) || defined(_WIN32) + +//--STRIP +#include "core/local_vector.h" +//--STRIP + +typedef struct tagLOGCONTEXTW { + WCHAR lcName[40]; + UINT lcOptions; + UINT lcStatus; + UINT lcLocks; + UINT lcMsgBase; + UINT lcDevice; + UINT lcPktRate; + DWORD lcPktData; + DWORD lcPktMode; + DWORD lcMoveMask; + DWORD lcBtnDnMask; + DWORD lcBtnUpMask; + LONG lcInOrgX; + LONG lcInOrgY; + LONG lcInOrgZ; + LONG lcInExtX; + LONG lcInExtY; + LONG lcInExtZ; + LONG lcOutOrgX; + LONG lcOutOrgY; + LONG lcOutOrgZ; + LONG lcOutExtX; + LONG lcOutExtY; + LONG lcOutExtZ; + DWORD lcSensX; + DWORD lcSensY; + DWORD lcSensZ; + BOOL lcSysMode; + int lcSysOrgX; + int lcSysOrgY; + int lcSysExtX; + int lcSysExtY; + DWORD lcSysSensX; + DWORD lcSysSensY; +} LOGCONTEXTW; + +typedef HANDLE(WINAPI *WTOpenPtr)(HWND p_window, LOGCONTEXTW *p_ctx, BOOL p_enable); + +#else +#endif + +/** + * Multi-Platform abstraction for running and communicating with sub processes + */ + +class SubProcess { +public: + typedef int64_t ProcessID; + + static SubProcess *create(); + + String get_executable_path() const; + void set_executable_path(const String &p_executable_path); + + Vector get_arguments() const; + void set_arguments(const Vector &p_arguments); + + bool get_blocking() const; + void set_blocking(const bool p_value); + + bool get_read_output() const; + void set_read_output(const bool p_value); + + bool get_read_std() const; + void set_read_std(const bool p_value); + + bool get_read_std_err() const; + void set_read_std_err(const bool p_value); + + bool get_use_pipe_mutex() const; + void set_use_pipe_mutex(const bool p_value); + + bool get_open_console() const; + void set_open_console(const bool p_value); + + String get_data() const { + return _pipe; + } + + int get_process_id() const { + return _process_id; + } + + int get_exitcode() const { + return _exitcode; + } + + virtual Error start(); + virtual Error stop(); + virtual Error poll(); + virtual Error send_signal(const int p_signal); + virtual Error send_data(const String &p_data); + virtual bool is_process_running() const; + + Error run(const String &p_executable_path, const Vector &p_arguments, bool p_output = true, bool p_blocking = true, bool p_read_std_err = false, bool p_use_pipe_mutex = false, bool p_open_console = false); + + SubProcess(); + virtual ~SubProcess(); + +protected: + void _setup_pipe_mutex(); + + String _executable_path; + Vector _arguments; + + bool _blocking; + + bool _read_output; + + bool _read_std; + bool _read_std_err; + + String _pipe; + + bool _use_pipe_mutex; + + Mutex *_pipe_mutex; + + bool _open_console; + + ProcessID _process_id; + int _exitcode; + +#if defined(_WIN64) || defined(_WIN32) + + String _quote_command_line_argument(const String &p_text) const; + void _append_to_pipe(char *p_bytes, int p_size); + + struct ProcessInfo { + STARTUPINFO si; + PROCESS_INFORMATION pi; + }; + + bool _process_started; + HANDLE _pipe_handles[2]; + ProcessInfo _process_info; + LocalVector _bytes; + +#else + FILE *_process_fp; + char _process_buf[65535]; +#endif +}; + +struct SubProcessRef { + SubProcess *f; + + _FORCE_INLINE_ bool is_null() const { return f == nullptr; } + _FORCE_INLINE_ bool is_valid() const { return f != nullptr; } + + _FORCE_INLINE_ operator bool() const { return f != nullptr; } + _FORCE_INLINE_ operator SubProcess *() { return f; } + + _FORCE_INLINE_ SubProcess *operator->() { + return f; + } + + SubProcessRef(SubProcess *fa) { f = fa; } + SubProcessRef(SubProcessRef &&other) { + f = other.f; + other.f = nullptr; + } + ~SubProcessRef() { + if (f) { + memdelete(f); + } + } +}; + +#endif diff --git a/tools/merger/sfw_core.cpp.inl b/tools/merger/sfw_core.cpp.inl index df7099e..d23bd3f 100644 --- a/tools/merger/sfw_core.cpp.inl +++ b/tools/merger/sfw_core.cpp.inl @@ -204,6 +204,18 @@ //--STRIP {{FILE:sfw/core/socket.cpp}} +//--STRIP +//Win Only +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//--STRIP +{{FILE:sfw/core/sub_process.cpp}} + //--STRIP //#include "core/pool_vector.h" //#include "core/string_name.h" diff --git a/tools/merger/sfw_core.h.inl b/tools/merger/sfw_core.h.inl index be218ee..dba58f2 100644 --- a/tools/merger/sfw_core.h.inl +++ b/tools/merger/sfw_core.h.inl @@ -425,6 +425,19 @@ //--STRIP {{FILE:sfw/core/socket.h}} +//--STRIP +//#include "core/list.h" +//#include "core/math_defs.h" +//#include "core/memory.h" +//#include "core/mutex.h" +//#include "core/typedefs.h" +//#include "core/ustring.h" +//#include +//Win Only +//#include "core/local_vector.h" +//--STRIP +{{FILE:sfw/core/sub_process.h}} + //--STRIP //no includes //--STRIP diff --git a/tools/merger/sfw_full.cpp.inl b/tools/merger/sfw_full.cpp.inl index 42ef475..dccb732 100644 --- a/tools/merger/sfw_full.cpp.inl +++ b/tools/merger/sfw_full.cpp.inl @@ -376,6 +376,18 @@ //--STRIP {{FILE:sfw/core/socket.cpp}} +//--STRIP +//Win Only +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//--STRIP +{{FILE:sfw/core/sub_process.cpp}} + //--STRIP //#include "core/pool_vector.h" //#include "core/string_name.h" diff --git a/tools/merger/sfw_full.h.inl b/tools/merger/sfw_full.h.inl index d41f09d..285f1c5 100644 --- a/tools/merger/sfw_full.h.inl +++ b/tools/merger/sfw_full.h.inl @@ -415,10 +415,6 @@ //--STRIP {{FILE:sfw/core/dir_access.h}} -//--STRIP -//no includes -//--STRIP -{{FILE:sfw/core/sfw_core.h}} //--STRIP //#include "int_types.h" @@ -430,6 +426,24 @@ //--STRIP {{FILE:sfw/core/socket.h}} +//--STRIP +//#include "core/list.h" +//#include "core/math_defs.h" +//#include "core/memory.h" +//#include "core/mutex.h" +//#include "core/typedefs.h" +//#include "core/ustring.h" +//#include +//Win Only +//#include "core/local_vector.h" +//--STRIP +{{FILE:sfw/core/sub_process.h}} + +//--STRIP +//no includes +//--STRIP +{{FILE:sfw/core/sfw_core.h}} + //=================== OBJECT SECTION =================== //--STRIP