diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2019-06-12 09:05:40 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-06-12 09:05:40 -0400 |
| commit | 9d514e65f00dde0e309f33591f31fbf7f132a005 (patch) | |
| tree | 7e3a751377651ef9eda06f0b1ad345af1796c596 /source/core/unix | |
| parent | fc083a75b94ac4b4e735b4a7ff566191b9123f74 (diff) | |
Runtime execution of Visual Studio Compiler (#978)
* Work in progress to be able to invoke VS from within code.
* First pass at windows version of refactor of OSProcessSpawner
* Closer to getting VS path lookup working.
* Make OSString assignable/ctor able
* Work out program files directory directly, so don't have to expand %%.
* WIP: Improve handling of process spawning.
* Add support for splitting input by line.
* * Correctly locates visual studio install
* Added functionality to invoke vs via cmd
* Add option to execute the command line.
* Handle in ProcessUtil for windows -> WinHandle.
* Rename files slang-win-visual-studio-util.cpp/.h and slang-process-util.h
* First pass at unix/linux version of ProcessUtil.
* Fix reading Visual Studio path from the registry.
* Get compiling on linux with.
* Fix vcvarsall.bat name
* Use ProcessUtil to execute external code.
* Remove OSProcessSpawner.
* Remove includes for "os.h" where no longer needed.
* Fix tabbing issue in premake5.lua
Remove test code from slang-test-main.cpp
* Fix premake4.lua tabbing issue.
* Small fixes to slang-process-util.h
Init ExecuteResult on Win execute.
* Improve comments.
* Fix bug in StringUtil::calcLines - with oddly terminated source input being able to read past end.
Make slang-generate use StringUtil over it's own impl.
* Fix off by one bug in working out Visual Studio version.
* Fix bug in calculating Visual Studio Version
* Fix compilation on linux with string parameter being passed to messageFormat.
* Remove erroneous use of kOSError codes - use Result.
Diffstat (limited to 'source/core/unix')
| -rw-r--r-- | source/core/unix/slang-unix-process-util.cpp | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/source/core/unix/slang-unix-process-util.cpp b/source/core/unix/slang-unix-process-util.cpp new file mode 100644 index 000000000..7795463b7 --- /dev/null +++ b/source/core/unix/slang-unix-process-util.cpp @@ -0,0 +1,234 @@ +// slang-unix-process-util.cpp +#include "../slang-process-util.h" + +#include "../slang-common.h" +#include "../slang-string-util.h" + +#include <stdio.h> +#include <stdlib.h> + +//#include <dirent.h> +#include <errno.h> +#include <poll.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +namespace Slang { + + +/* static */UnownedStringSlice ProcessUtil::getExecutableSuffix() +{ + return UnownedStringSlice::fromLiteral(""); +} + +static void _appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) +{ + // TODO(JS): This escaping is not complete... ! + if (slice.indexOf(' ') >= 0 || slice.indexOf('"') >= 0) + { + out << "\""; + + const char* cur = slice.begin(); + const char* end = slice.end(); + + while (cur < end) + { + char c = *cur++; + switch (c) + { + case '\"': + { + // Escape quotes. + out << "\\\""; + break; + } + default: + out.append(c); + } + } + + out << "\""; + + return; + } + + out << slice; +} + +/* static */String ProcessUtil::getCommandLineString(const CommandLine& commandLine) +{ + StringBuilder cmd; + _appendEscaped(commandLine.m_executable.getUnownedSlice(), cmd); + for (const auto& arg : commandLine.m_args) + { + cmd << " "; + _appendEscaped(arg.getUnownedSlice(), cmd); + } + return cmd.ToString(); +} + +/* static */SlangResult ProcessUtil::execute(const CommandLine& commandLine, ExecuteResult& outExecuteResult) +{ + outExecuteResult.init(); + + List<char const*> argPtrs; + // Add the command + argPtrs.add(commandLine.m_executable.getBuffer()); + // Add all the args + for (auto arg : commandLine.m_args) + { + argPtrs.add(arg.getBuffer()); + } + // Terminate with a null + argPtrs.add(nullptr); + + int stdoutPipe[2]; + int stderrPipe[2]; + + if (pipe(stdoutPipe) == -1) + return SLANG_FAIL; + + if (pipe(stderrPipe) == -1) + return SLANG_FAIL; + + pid_t childProcessID = fork(); + if (childProcessID == -1) + return SLANG_FAIL; + + if (childProcessID == 0) + { + // We are the child process. + + dup2(stdoutPipe[1], STDOUT_FILENO); + dup2(stderrPipe[1], STDERR_FILENO); + + close(stdoutPipe[0]); + close(stdoutPipe[1]); + + close(stderrPipe[0]); + close(stderrPipe[1]); + + execvp(argPtrs[0], (char* const*)&argPtrs[0]); + + // If we get here, then `exec` failed + fprintf(stderr, "error: `exec` failed\n"); + return SLANG_FAIL; + } + else + { + // We are the parent process + + close(stdoutPipe[1]); + close(stderrPipe[1]); + + int stdoutFD = stdoutPipe[0]; + int stderrFD = stderrPipe[0]; + + pollfd pollInfos[2]; + nfds_t pollInfoCount = 2; + + pollInfos[0].fd = stdoutFD; + pollInfos[0].events = POLLIN; + pollInfos[0].revents = 0; + pollInfos[1].fd = stderrFD; + pollInfos[1].events = POLLIN; + pollInfos[1].revents = 0; + + int remainingCount = 2; + int iterations = 0; + while (remainingCount) + { + // Safeguard against infinite loop: + iterations++; + if (iterations > 10000) + { + fprintf(stderr, "poll(): %d iterations\n", iterations); + return SLANG_FAIL; + } + + // Set a timeout of ten seconds; + // we really shouldn't wait too long... + int pollTimeout = 10000; + int pollResult = poll(pollInfos, pollInfoCount, pollTimeout); + if (pollResult <= 0) + { + // If there was a signal that got in + // the way, then retry... + if (pollResult == -1 && errno == EINTR) + continue; + + // timeout or error... + return SLANG_FAIL; + } + + enum { kBufferSize = 1024 }; + char buffer[kBufferSize]; + + if (pollInfos[0].revents) + { + auto count = read(stdoutFD, buffer, kBufferSize); + if (count <= 0) + { + // end-of-file + close(stdoutFD); + pollInfos[0].fd = -1; + remainingCount--; + } + + outExecuteResult.standardOutput.append(buffer, buffer + count); + } + + if (pollInfos[1].revents) + { + auto count = read(stderrFD, buffer, kBufferSize); + if (count <= 0) + { + // end-of-file + close(stderrFD); + pollInfos[1].fd = -1; + remainingCount--; + } + + outExecuteResult.standardError.append(buffer, buffer + count); + } + } + + int childStatus = 0; + iterations = 0; + for (;;) + { + // Safeguard against infinite loop: + iterations++; + if (iterations > 10000) + { + fprintf(stderr, "waitpid(): %d iterations\n", iterations); + return SLANG_FAIL; + } + + pid_t terminatedProcessID = waitpid(childProcessID, &childStatus, 0); + if (terminatedProcessID == -1) + { + return SLANG_FAIL; + } + + if (terminatedProcessID == childProcessID) + { + if (WIFEXITED(childStatus)) + { + outExecuteResult.resultCode = (int)(int8_t)WEXITSTATUS(childStatus); + } + else + { + outExecuteResult.resultCode = 1; + } + return SLANG_OK; + } + } + } + + return SLANG_FAIL; +} + +} // namespace Slang |
