summaryrefslogtreecommitdiffstats
path: root/source/core/unix
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-06-12 09:05:40 -0400
committerGitHub <noreply@github.com>2019-06-12 09:05:40 -0400
commit9d514e65f00dde0e309f33591f31fbf7f132a005 (patch)
tree7e3a751377651ef9eda06f0b1ad345af1796c596 /source/core/unix
parentfc083a75b94ac4b4e735b4a7ff566191b9123f74 (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.cpp234
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