|  | 
| 19 | 19 | #include "xinspect.hpp" | 
| 20 | 20 | #include "xmagics/os.hpp" | 
| 21 | 21 | #include <iostream> | 
|  | 22 | +#include <fcntl.h> | 
|  | 23 | +#include <unistd.h> | 
| 22 | 24 | #ifndef EMSCRIPTEN | 
| 23 | 25 | #include "xmagics/xassist.hpp" | 
| 24 | 26 | #endif | 
|  | 
| 27 | 29 | 
 | 
| 28 | 30 | using Args = std::vector<const char*>; | 
| 29 | 31 | 
 | 
|  | 32 | +static int g_stdin_pipe[2] = {-1, -1}; | 
|  | 33 | +static int g_stdout_pipe[2] = {-1, -1}; | 
|  | 34 | +static int g_stderr_pipe[2] = {-1, -1}; | 
|  | 35 | +static bool g_pipes_initialized = false; | 
|  | 36 | + | 
|  | 37 | +// Initialize global pipes once | 
|  | 38 | +void init_global_pipes() { | 
|  | 39 | +    if (!g_pipes_initialized) { | 
|  | 40 | +        if (pipe(g_stdin_pipe) == 0 && pipe(g_stdout_pipe) == 0 && pipe(g_stderr_pipe) == 0) { | 
|  | 41 | +            g_pipes_initialized = true; | 
|  | 42 | +        } else { | 
|  | 43 | +            throw std::runtime_error("Failed to create global pipes"); | 
|  | 44 | +        } | 
|  | 45 | +    } | 
|  | 46 | +} | 
|  | 47 | + | 
| 30 | 48 | void* createInterpreter(const Args& ExtraArgs = {}) | 
| 31 | 49 | { | 
| 32 | 50 |     Args ClangArgs = {/*"-xc++"*/"-v"}; | 
| @@ -56,13 +74,61 @@ void* createInterpreter(const Args& ExtraArgs = {}) | 
| 56 | 74 |         return Cpp::CreateInterpreter(ClangArgs /*, {"-cuda"}*/); | 
| 57 | 75 |     } | 
| 58 | 76 | 
 | 
| 59 |  | -    return Cpp::CreateInterpreter(ClangArgs, {}, true); | 
|  | 77 | +    init_global_pipes(); | 
|  | 78 | + | 
|  | 79 | +    return Cpp::CreateInterpreter(ClangArgs, {}, true, g_stdin_pipe[0], g_stdout_pipe[1], g_stderr_pipe[1]); | 
| 60 | 80 | } | 
| 61 | 81 | 
 | 
| 62 | 82 | using namespace std::placeholders; | 
| 63 | 83 | 
 | 
| 64 | 84 | namespace xcpp | 
| 65 | 85 | { | 
|  | 86 | +    class GlobalPipeRedirectRAII { | 
|  | 87 | +    private: | 
|  | 88 | +        std::string captured_stderr; | 
|  | 89 | +         | 
|  | 90 | +        std::string read_all_from_fd(int fd) { | 
|  | 91 | +            std::string result; | 
|  | 92 | +            char buffer[4096]; | 
|  | 93 | +            ssize_t bytes_read; | 
|  | 94 | +             | 
|  | 95 | +            // Set non-blocking to avoid hanging | 
|  | 96 | +            int flags = fcntl(fd, F_GETFL, 0); | 
|  | 97 | +            fcntl(fd, F_SETFL, flags | O_NONBLOCK); | 
|  | 98 | +             | 
|  | 99 | +            while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) { | 
|  | 100 | +                result.append(buffer, bytes_read); | 
|  | 101 | +            } | 
|  | 102 | +             | 
|  | 103 | +            // Restore original flags | 
|  | 104 | +            fcntl(fd, F_SETFL, flags); | 
|  | 105 | +            return result; | 
|  | 106 | +        } | 
|  | 107 | + | 
|  | 108 | +        void write_to_fd(int fd, const std::string& data) { | 
|  | 109 | +            write(fd, data.c_str(), data.length()); | 
|  | 110 | +        } | 
|  | 111 | +         | 
|  | 112 | +    public: | 
|  | 113 | +        GlobalPipeRedirectRAII(const std::string& input_data = "") { | 
|  | 114 | +            if (!input_data.empty() && g_stdin_pipe[1] != -1) { | 
|  | 115 | +                write_to_fd(g_stdin_pipe[1], input_data); | 
|  | 116 | +                close(g_stdin_pipe[1]); // Close write end to signal EOF | 
|  | 117 | +            } | 
|  | 118 | +        } | 
|  | 119 | +        ~GlobalPipeRedirectRAII() { | 
|  | 120 | +            // Read any pending output from pipes | 
|  | 121 | +            std::string stdout_content = read_all_from_fd(g_stdout_pipe[0]); | 
|  | 122 | +            captured_stderr = read_all_from_fd(g_stderr_pipe[0]); | 
|  | 123 | +             | 
|  | 124 | +            // Output captured stdout content | 
|  | 125 | +            if (!stdout_content.empty()) { | 
|  | 126 | +                std::cout << stdout_content; | 
|  | 127 | +            } | 
|  | 128 | +        } | 
|  | 129 | +         | 
|  | 130 | +        const std::string& get_captured_stderr() const { return captured_stderr; } | 
|  | 131 | +    }; | 
| 66 | 132 |     struct StreamRedirectRAII { | 
| 67 | 133 |       std::string &err; | 
| 68 | 134 |       StreamRedirectRAII(std::string &e) : err(e) { | 
| @@ -180,11 +246,20 @@ __get_cxx_version () | 
| 180 | 246 |         m_code_to_execution_count_map[code].push_back(execution_count); | 
| 181 | 247 |         m_execution_count_to_code_map[execution_count] = code; | 
| 182 | 248 | 
 | 
|  | 249 | +        bool use_out_of_process = g_pipes_initialized; | 
|  | 250 | + | 
| 183 | 251 |         // Attempt normal evaluation | 
| 184 | 252 |         try | 
| 185 | 253 |         { | 
| 186 |  | -            StreamRedirectRAII R(err); | 
| 187 |  | -            compilation_result = Cpp::Process(code.c_str()); | 
|  | 254 | +            if (use_out_of_process) { | 
|  | 255 | +                std::string input_for_process = ""; | 
|  | 256 | +                GlobalPipeRedirectRAII redirect(input_for_process); | 
|  | 257 | +                compilation_result = Cpp::Process(code.c_str()); | 
|  | 258 | +                err = redirect.get_captured_stderr(); | 
|  | 259 | +            } else { | 
|  | 260 | +                StreamRedirectRAII R(err); | 
|  | 261 | +                compilation_result = Cpp::Process(code.c_str()); | 
|  | 262 | +            } | 
| 188 | 263 |         } | 
| 189 | 264 |         catch (std::exception& e) | 
| 190 | 265 |         { | 
|  | 
0 commit comments