summaryrefslogtreecommitdiffstats
path: root/tools/slang-test/os.cpp
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 /tools/slang-test/os.cpp
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 'tools/slang-test/os.cpp')
-rw-r--r--tools/slang-test/os.cpp469
1 files changed, 0 insertions, 469 deletions
diff --git a/tools/slang-test/os.cpp b/tools/slang-test/os.cpp
index a938a71e7..eceeef2d7 100644
--- a/tools/slang-test/os.cpp
+++ b/tools/slang-test/os.cpp
@@ -123,266 +123,6 @@ OSFindFilesResult osFindChildDirectories(
return result;
}
-// OSProcessSpawner
-
-struct OSProcessSpawner_ReaderThreadInfo
-{
- HANDLE file;
- String output;
-};
-
-static DWORD WINAPI osReaderThreadProc(LPVOID threadParam)
-{
- OSProcessSpawner_ReaderThreadInfo* info = (OSProcessSpawner_ReaderThreadInfo*)threadParam;
- HANDLE file = info->file;
-
- static const int kChunkSize = 1024;
- char buffer[kChunkSize];
-
- StringBuilder outputBuilder;
-
- // We need to re-write the output to deal with line
- // endings, so we check for paired '\r' and '\n'
- // characters, which may span chunks.
- int prevChar = -1;
-
- for (;;)
- {
- DWORD bytesRead = 0;
- BOOL readResult = ReadFile(file, buffer, kChunkSize, &bytesRead, nullptr);
-
- if (!readResult || GetLastError() == ERROR_BROKEN_PIPE)
- {
- break;
- }
-
- // walk the buffer and rewrite to eliminate '\r' '\n' pairs
- char* readCursor = buffer;
- char const* end = buffer + bytesRead;
- char* writeCursor = buffer;
-
- while (readCursor != end)
- {
- int p = prevChar;
- int c = *readCursor++;
- prevChar = c;
- switch (c)
- {
- case '\r': case '\n':
- // swallow input if '\r' and '\n' appear in sequence
- if ((p ^ c) == ('\r' ^ '\n'))
- {
- // but don't swallow the next byte
- prevChar = -1;
- continue;
- }
- // always replace '\r' with '\n'
- c = '\n';
- break;
-
- default:
- break;
- }
-
- *writeCursor++ = (char)c;
- }
- bytesRead = (DWORD)(writeCursor - buffer);
-
- // Note: Current "core" implementation gives no way to know
- // the length of the buffer, so we ultimately have
- // to just assume null termination...
- outputBuilder.Append(buffer, bytesRead);
- }
-
- info->output = outputBuilder.ProduceString();
-
- return 0;
-}
-
-void OSProcessSpawner::pushExecutableName(
- Slang::String executableName)
-{
- executableName_ = executableName;
- commandLine_.Append(executableName);
- isExecutablePath_ = false;
-}
-
-void OSProcessSpawner::pushExecutablePath(
- Slang::String executablePath)
-{
- executableName_ = executablePath;
- commandLine_.Append(executablePath);
- isExecutablePath_ = true;
-}
-
-void OSProcessSpawner::pushArgument(
- Slang::String argument)
-{
- // TODO(tfoley): handle cases where arguments need some escaping
- commandLine_.Append(" ");
- commandLine_.Append(argument);
-
- argumentList_.add(argument);
-}
-
-Slang::String OSProcessSpawner::getCommandLine()
-{
- return commandLine_;
-}
-
-OSError OSProcessSpawner::spawnAndWaitForCompletion()
-{
- SECURITY_ATTRIBUTES securityAttributes;
- securityAttributes.nLength = sizeof(securityAttributes);
- securityAttributes.lpSecurityDescriptor = nullptr;
- securityAttributes.bInheritHandle = true;
-
- // create stdout pipe for child process
- HANDLE childStdOutReadTmp = nullptr;
- HANDLE childStdOutWrite = nullptr;
- if (!CreatePipe(&childStdOutReadTmp, &childStdOutWrite, &securityAttributes, 0))
- {
- return kOSError_OperationFailed;
- }
-
- // create stderr pipe for child process
- HANDLE childStdErrReadTmp = nullptr;
- HANDLE childStdErrWrite = nullptr;
- if (!CreatePipe(&childStdErrReadTmp, &childStdErrWrite, &securityAttributes, 0))
- {
- return kOSError_OperationFailed;
- }
-
- // create stdin pipe for child process
- HANDLE childStdInRead = nullptr;
- HANDLE childStdInWriteTmp = nullptr;
- if (!CreatePipe(&childStdInRead, &childStdInWriteTmp, &securityAttributes, 0))
- {
- return kOSError_OperationFailed;
- }
-
- HANDLE currentProcess = GetCurrentProcess();
-
- // create a non-inheritable duplicate of the stdout reader
- HANDLE childStdOutRead = nullptr;
- if (!DuplicateHandle(
- currentProcess, childStdOutReadTmp,
- currentProcess, &childStdOutRead,
- 0, FALSE, DUPLICATE_SAME_ACCESS))
- {
- return kOSError_OperationFailed;
- }
- if (!CloseHandle(childStdOutReadTmp))
- {
- return kOSError_OperationFailed;
- }
-
- // create a non-inheritable duplicate of the stderr reader
- HANDLE childStdErrRead = nullptr;
- if (!DuplicateHandle(
- currentProcess, childStdErrReadTmp,
- currentProcess, &childStdErrRead,
- 0, FALSE, DUPLICATE_SAME_ACCESS))
- {
- return kOSError_OperationFailed;
- }
- if (!CloseHandle(childStdErrReadTmp))
- {
- return kOSError_OperationFailed;
- }
-
- // create a non-inheritable duplicate of the stdin writer
- HANDLE childStdInWrite = nullptr;
- if (!DuplicateHandle(
- currentProcess, childStdInWriteTmp,
- currentProcess, &childStdInWrite,
- 0, FALSE, DUPLICATE_SAME_ACCESS))
- {
- return kOSError_OperationFailed;
- }
- if (!CloseHandle(childStdInWriteTmp))
- {
- return kOSError_OperationFailed;
- }
-
- // Now we can actually get around to starting a process
- PROCESS_INFORMATION processInfo;
- ZeroMemory(&processInfo, sizeof(processInfo));
-
- // TODO: switch to proper wide-character versions of these...
- STARTUPINFOW startupInfo;
- ZeroMemory(&startupInfo, sizeof(startupInfo));
- startupInfo.cb = sizeof(startupInfo);
- startupInfo.hStdError = childStdErrWrite;
- startupInfo.hStdOutput = childStdOutWrite;
- startupInfo.hStdInput = childStdInRead;
- startupInfo.dwFlags = STARTF_USESTDHANDLES;
-
- // `CreateProcess` requires write access to this, for some reason...
- BOOL success = CreateProcessW(
- isExecutablePath_ ? executableName_.toWString().begin() : nullptr,
- (LPWSTR)commandLine_.ToString().toWString().begin(),
- nullptr,
- nullptr,
- true,
- CREATE_NO_WINDOW,
- nullptr, // TODO: allow specifying environment variables?
- nullptr,
- &startupInfo,
- &processInfo);
- if (!success)
- {
- return kOSError_OperationFailed;
- }
-
- // close handles we are now done with
- CloseHandle(processInfo.hThread);
- CloseHandle(childStdOutWrite);
- CloseHandle(childStdErrWrite);
- CloseHandle(childStdInRead);
-
- // Create a thread to read from the child's stdout.
- OSProcessSpawner_ReaderThreadInfo stdOutThreadInfo;
- stdOutThreadInfo.file = childStdOutRead;
- HANDLE stdOutThread = CreateThread(nullptr, 0, &osReaderThreadProc, (LPVOID)&stdOutThreadInfo, 0, nullptr);
-
- // Create a thread to read from the child's stderr.
- OSProcessSpawner_ReaderThreadInfo stdErrThreadInfo;
- stdErrThreadInfo.file = childStdErrRead;
- HANDLE stdErrThread = CreateThread(nullptr, 0, &osReaderThreadProc, (LPVOID)&stdErrThreadInfo, 0, nullptr);
-
- // wait for the process to exit
- // TODO: set a timeout as a safety measure...
- WaitForSingleObject(processInfo.hProcess, INFINITE);
-
- // get exit code for process
- DWORD childExitCode = 0;
- if (!GetExitCodeProcess(processInfo.hProcess, &childExitCode))
- {
- return kOSError_OperationFailed;
- }
-
- // wait for the reader threads
- WaitForSingleObject(stdOutThread, INFINITE);
- WaitForSingleObject(stdErrThread, INFINITE);
-
- CloseHandle(processInfo.hProcess);
- CloseHandle(childStdOutRead);
- CloseHandle(childStdErrRead);
- CloseHandle(childStdInWrite);
-
- standardOutput_ = stdOutThreadInfo.output;
- standardError_ = stdErrThreadInfo.output;
- resultCode_ = childExitCode;
-
- return kOSError_None;
-}
-
-char const* osGetExecutableSuffix()
-{
- return ".exe";
-}
-
#else
static bool advance(OSFindFilesResult& result)
@@ -475,213 +215,4 @@ OSFindFilesResult osFindChildDirectories(
return result;
}
-// OSProcessSpawner
-
-void OSProcessSpawner::pushExecutableName(
- Slang::String executableName)
-{
- executableName_ = executableName;
- arguments_.add(executableName);
- isExecutablePath_ = false;
-}
-
-void OSProcessSpawner::pushExecutablePath(
- Slang::String executablePath)
-{
- executableName_ = executablePath;
- arguments_.add(executablePath);
- isExecutablePath_ = true;
-}
-
-void OSProcessSpawner::pushArgument(
- Slang::String argument)
-{
- arguments_.add(argument);
- argumentList_.add(argument);
-}
-
-Slang::String OSProcessSpawner::getCommandLine()
-{
- Slang::UInt argCount = arguments_.getCount();
-
- Slang::StringBuilder sb;
- for(Slang::UInt ii = 0; ii < argCount; ++ii)
- {
- if(ii != 0) sb << " ";
- sb << arguments_[ii];
- }
- return sb.ProduceString();
-}
-
-OSError OSProcessSpawner::spawnAndWaitForCompletion()
-{
- List<char const*> argPtrs;
- for(auto arg : arguments_)
- {
- argPtrs.add(arg.getBuffer());
- }
- argPtrs.add(NULL);
-
- int stdoutPipe[2];
- int stderrPipe[2];
-
- if(pipe(stdoutPipe) == -1)
- return kOSError_OperationFailed;
-
- if(pipe(stderrPipe) == -1)
- return kOSError_OperationFailed;
-
- pid_t childProcessID = fork();
- if (childProcessID == -1)
- return kOSError_OperationFailed;
-
- 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");
- exit(1);
- }
- 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 kOSError_OperationFailed;
- }
-
- // 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 kOSError_OperationFailed;
- }
-
- 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--;
- }
-
- 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--;
- }
-
- 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 kOSError_OperationFailed;
- }
-
-
- pid_t terminatedProcessID = waitpid(
- childProcessID,
- &childStatus,
- 0);
- if (terminatedProcessID == -1)
- {
- return kOSError_OperationFailed;
- }
-
- if(terminatedProcessID == childProcessID)
- {
- if(WIFEXITED(childStatus))
- {
- resultCode_ = (int)(int8_t)WEXITSTATUS(childStatus);
- }
- else
- {
- resultCode_ = 1;
- }
-
- return kOSError_None;
- }
- }
-
- }
-
- return kOSError_OperationFailed;
-}
-
-char const* osGetExecutableSuffix()
-{
- return "";
-}
-
#endif