commit 90071202f19f39aee7ba09d5503104bbd8a86cdf
parent ce5bb17ec62ac6a586a2c3446438d0a808f09c26
Author: Kyle Milz <kyle@0x30.net>
Date: Fri, 13 Jan 2017 01:46:30 -0700
inst: split frontend into os dep/indep parts
Diffstat:
M | Jamfile | | | 6 | ++++++ |
M | inst_fe.cc | | | 304 | ++++++++----------------------------------------------------------------------- |
M | inst_fe.h | | | 33 | ++++++++++++++++++++++++--------- |
A | inst_feunix.cc | | | 161 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | inst_feunix.h | | | 18 | ++++++++++++++++++ |
A | inst_fewin32.cc | | | 170 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | inst_fewin32.h | | | 18 | ++++++++++++++++++ |
M | inst_main.cc | | | 20 | +++++++++++++++----- |
8 files changed, 441 insertions(+), 289 deletions(-)
diff --git a/Jamfile b/Jamfile
@@ -64,6 +64,12 @@ INST_SRCS =
inst_action.cc
inst_visitor.cc ;
+if $(NT) {
+ INST_SRCS += inst_fewin32.cc ;
+} else {
+ INST_SRCS += inst_feunix.cc ;
+}
+
Stringize lib_h.h : lib.h ;
ObjectC++Flags $(INST_SRCS) : $(INST_CFLAGS) ;
diff --git a/inst_fe.cc b/inst_fe.cc
@@ -14,106 +14,56 @@
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#include "inst_action.h" // InstrumentActionFactory
-#include "inst_frontend.h"
+#include "inst_fe.h"
#include "lib.h" // citrun_major, citrun_minor
#include "prefix.h" // prefix
-#include <sys/stat.h> // stat
-
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>
#include <cstdio> // tmpnam
#include <cstring> // strcmp
-#include <fstream> // ifstream, ofstream
#include <iostream> // cerr
#include <llvm/Support/raw_os_ostream.h>
#include <sstream> // ostringstream
-#ifdef _WIN32
-#include <windows.h> // CreateProcess
-#include <Shlwapi.h> // PathFindOnPath
-
-#define PATH_SEP ';'
-#else // _WIN32
-#include <sys/time.h> // utimes
-#include <sys/utsname.h> // uname
-#include <sys/wait.h> // waitpid
-
-#include <err.h>
-#include <unistd.h> // execvp, fork, getpid, unlink
-
-#define PATH_SEP ':'
-#endif // _WIN32
-
-#define xstr(x) make_str(x)
-#define make_str(x) #x
-
static llvm::cl::OptionCategory ToolingCategory("citrun_inst options");
-#ifdef _WIN32
-static void
-Err(int code, const char *fmt)
-{
- char buf[256];
-
- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL);
-
- std::cerr << fmt << ": " << buf << std::endl;
- ExitProcess(code);
-}
-#endif // _WIN32
-
InstFrontend::InstFrontend(int argc, char *argv[], bool is_citrun_inst) :
+ m_start_time(std::chrono::high_resolution_clock::now()),
m_args(argv, argv + argc),
- m_log(is_citrun_inst),
m_is_citruninst(is_citrun_inst),
- m_start_time(std::chrono::high_resolution_clock::now())
+ m_log(is_citrun_inst)
{
- log_identity();
-
- m_compilers_path = prefix ;
- m_lib_path = prefix ;
-
-#ifdef _WIN32
- m_compilers_path.append("\\compilers");
- m_lib_path.append("\\libcitrun.lib");
-#else
- m_compilers_path.append("/compilers");
- m_lib_path.append("/libcitrun.a");
-#endif // _WIN32
-
- m_log << "Compilers path = '" << m_compilers_path << "'" << std::endl;
-
#ifndef _WIN32
// Sometimes we're not called as citrun_inst so force that here.
setprogname("citrun_inst");
#endif // _WIN32
-
- if (m_is_citruninst == false)
- clean_PATH();
}
void
InstFrontend::log_identity()
{
m_log << ">> citrun_inst v" << citrun_major << "." << citrun_minor;
-#ifdef _WIN32
- m_log << " (Windows x86)";
-#else // _WIN32
- struct utsname utsname;
-
- if (uname(&utsname) == -1)
- m_log << " (Unknown OS)";
- else
- m_log << " (" << utsname.sysname << "-" << utsname.release
- << " " << utsname.machine << ")";
-#endif // _WIN32
+ log_os_str();
m_log << " called as " << m_args[0] << std::endl;
}
+void
+InstFrontend::get_paths()
+{
+ m_compilers_path = prefix ;
+ m_compilers_path += dir_sep();
+ m_compilers_path.append("compilers");
+
+ m_lib_path = prefix ;
+ m_lib_path += dir_sep();
+ m_lib_path += lib_name();
+
+ m_log << "Compilers path = '" << m_compilers_path << "'" << std::endl;
+}
+
//
// Tries to remove m_compilers_path from PATH otherwise it exits easily.
//
@@ -122,6 +72,9 @@ InstFrontend::clean_PATH()
{
char *path;
+ if (m_is_citruninst == true)
+ return;
+
if ((path = std::getenv("PATH")) == NULL) {
std::cerr << "Error: PATH is not set." << std::endl;
m_log << "Error: PATH is not set." << std::endl;
@@ -137,14 +90,14 @@ InstFrontend::clean_PATH()
bool first_component = 1;
bool found_citrun_path = 0;
- while (std::getline(path_ss, component, PATH_SEP)) {
+ while (std::getline(path_ss, component, path_sep())) {
if (component == m_compilers_path) {
found_citrun_path = 1;
continue;
}
if (first_component == 0)
- new_path << PATH_SEP;
+ new_path << path_sep();
// It wasn't m_compilers_path, keep it
new_path << component;
@@ -157,16 +110,9 @@ InstFrontend::clean_PATH()
exit(1);
}
-#ifdef _WIN32
- if (SetEnvironmentVariableA("Path", new_path.str().c_str()) == 0)
- Err(1, "SetEnvironmentVariableA");
-#else // _WIN32
- if (setenv("PATH", new_path.str().c_str(), 1))
- err(1, "setenv");
-#endif // _WIN32
+ set_path(new_path.str());
}
-
// Returns true if value ends with suffix, false otherwise.
static bool
ends_with(std::string const &value, std::string const &suffix)
@@ -177,37 +123,6 @@ ends_with(std::string const &value, std::string const &suffix)
return std::equal(suffix.rbegin(), suffix.rend(), value.rbegin());
}
-// Copies one file to another preserving timestamps.
-static void
-copy_file(std::string const &dst_fn, std::string const &src_fn)
-{
- struct stat sb;
- struct timeval st_tim[2];
-
- // Save original access and modification times
- if (stat(src_fn.c_str(), &sb) < 0)
- err(1, "stat");
-#ifdef __APPLE__
- TIMESPEC_TO_TIMEVAL(&st_tim[0], &sb.st_atimespec);
- TIMESPEC_TO_TIMEVAL(&st_tim[1], &sb.st_mtimespec);
-#else
- TIMESPEC_TO_TIMEVAL(&st_tim[0], &sb.st_atim);
- TIMESPEC_TO_TIMEVAL(&st_tim[1], &sb.st_mtim);
-#endif
-
- std::ifstream src(src_fn, std::ios::binary);
- std::ofstream dst(dst_fn, std::ios::binary);
-
- dst << src.rdbuf();
-
- src.close();
- dst.close();
-
- // Restore the original access and modification time
- if (utimes(dst_fn.c_str(), st_tim) < 0)
- err(1, "utimes");
-}
-
//
// Guess if the argument is a sourcefile. If it is stash a backup of the file
// and sync the timestamps.
@@ -238,46 +153,6 @@ InstFrontend::save_if_srcfile(char *arg)
}
//
-// Careful guessing if we're linking. Use an absolute path to libcitrun to
-// avoid link failures.
-//
-void
-InstFrontend::if_link_add_runtime(bool object_arg, bool compile_arg)
-{
-#ifdef _WIN32
- bool linking = false;
-
- if (std::strcmp(m_args[0], "link") == 0)
- // If we're called as link.exe we're linking for sure.
- linking = true;
- if (!compile_arg && m_source_files.size() > 0)
- // cl.exe main.c
- linking = true;
-
- if (!linking)
- return;
-#else // _WIN32
- bool linking = false;
-
- if (!object_arg && !compile_arg && m_source_files.size() > 0)
- // Assume single line a.out compilation
- // $ gcc main.c
- linking = true;
- else if (object_arg && !compile_arg)
- // gcc -o main main.o fib.o while.o
- // gcc -o main main.c fib.c
- linking = true;
-
- if (!linking)
- return;
-#endif // _WIN32
-
- m_log << "Link detected, adding '"<< m_lib_path
- << "' to command line." << std::endl;
- m_args.push_back(const_cast<char *>(m_lib_path.c_str()));
-}
-
-//
// Walks the entire command line taking action on important arguments.
//
void
@@ -309,8 +184,11 @@ InstFrontend::process_cmdline()
save_if_srcfile(arg);
}
- // If linking is detected append libcitrun.a to the command line.
- if_link_add_runtime(object_arg, compile_arg);
+ if (is_link(object_arg, compile_arg)) {
+ m_log << "Link detected, adding '"<< m_lib_path
+ << "' to command line." << std::endl;
+ m_args.push_back(const_cast<char *>(m_lib_path.c_str()));
+ }
m_log << "Modified command line is '";
for (auto &arg : m_args)
@@ -424,127 +302,3 @@ InstFrontend::compile_instrumented()
// Rewritten compile failed. Run again without modified src.
exec_compiler();
}
-
-#ifdef _WIN32
-//
-// On Windows the best exec alternative is to CreateProcess, wait for it to
-// finish and exit with its exit code. Windows has execvp, but it looks to
-// CreateProcess and then itself exit, leading to race conditions.
-//
-void
-InstFrontend::exec_compiler()
-{
- if (m_is_citruninst) {
- m_log << "Running as citrun_inst, not calling exec()" << std::endl;
- exit(0);
- }
-
- exit(fork_compiler());
-}
-
-//
-// On Windows this is a straighforward conversion. We do our own PATH lookup
-// because the default one CreateProcess does will find our cl.exe again
-// instead of searching the PATH for a new one.
-//
-int
-InstFrontend::fork_compiler()
-{
- DWORD exit = -1;
- STARTUPINFOA si;
- PROCESS_INFORMATION pi;
-
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- ZeroMemory(&pi, sizeof(pi));
-
- char real_cc[MAX_PATH];
- std::strcpy(real_cc, m_args[0]);
-
- if (!ends_with(real_cc, ".exe") && !ends_with(real_cc, ".EXE"))
- std::strcat(real_cc, ".exe");
-
- if (PathFindOnPathA(real_cc, NULL) == FALSE)
- m_log << "PathFindOnPathA failed for " << real_cc << std::endl;
-
- std::stringstream argv;
- for (unsigned int i = 1; i < m_args.size(); ++i)
- argv << " " << m_args[i];
-
- if (!CreateProcessA(real_cc,
- (LPSTR) argv.str().c_str(),
- NULL,
- NULL,
- FALSE,
- 0,
- NULL,
- NULL,
- &si,
- &pi))
- Err(1, "CreateProcess");
-
- m_log << "Forked compiler '" << real_cc << "' "
- << "pid is '" << pi.dwProcessId << "'" << std::endl;
-
- if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)
- Err(1, "WaitForSingleObject");
-
- if (GetExitCodeProcess(pi.hProcess, &exit) == FALSE)
- Err(1, "GetExitCodeProcess");
-
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
-
- return exit;
-}
-#else // _WIN32
-//
-// Execute the compiler by calling execvp(3) on the m_args vector.
-//
-void
-InstFrontend::exec_compiler()
-{
- if (m_is_citruninst) {
- m_log << "Running as citrun_inst, not calling exec()" << std::endl;
- exit(0);
- }
-
- // Null termination explicitly mentioned in execvp(3).
- m_args.push_back(NULL);
- if (execvp(m_args[0], &m_args[0]))
- err(1, "execvp");
-}
-
-//
-// fork(2) then execute the compiler and wait for it to finish. Returns exit
-// code of native compiler.
-//
-int
-InstFrontend::fork_compiler()
-{
- pid_t child_pid;
- int status;
- int exit = -1;
-
- if ((child_pid = fork()) < 0)
- err(1, "fork");
-
- // If in child execute compiler.
- if (child_pid == 0)
- exec_compiler();
-
- m_log << "Forked compiler '" << m_args[0] << "' "
- << "pid is '" << child_pid << "'" << std::endl;
-
- // Wait for the child to finish so we can get its exit code.
- if (waitpid(child_pid, &status, 0) < 0)
- err(1, "waitpid");
-
- // Decode the exit code from status.
- if (WIFEXITED(status))
- exit = WEXITSTATUS(status);
-
- // Return the exit code of the native compiler.
- return exit;
-}
-#endif // _WIN32
diff --git a/inst_fe.h b/inst_fe.h
@@ -1,3 +1,7 @@
+//
+// Instrument Frontend.
+// Takes command lines and instruments source code.
+//
#include "inst_log.h"
#include <chrono> // std::chrono::high_resolution_clock
@@ -6,26 +10,37 @@
class InstFrontend
{
- void log_identity();
- void clean_PATH();
void save_if_srcfile(char *);
- void if_link_add_runtime(bool, bool);
- int fork_compiler();
- void exec_compiler();
void restore_original_src();
- std::vector<char *> m_args;
- InstrumentLogger m_log;
- bool m_is_citruninst;
std::string m_compilers_path;
std::string m_lib_path;
std::chrono::high_resolution_clock::time_point m_start_time;
- std::vector<std::string> m_source_files;
std::map<std::string, std::string> m_temp_file_map;
+ // Implemented by operating system specific classes.
+ virtual void log_os_str() = 0;
+ virtual char dir_sep() = 0;
+ virtual char path_sep() = 0;
+ virtual std::string lib_name() = 0;
+ virtual void set_path(std::string const &) = 0;
+ virtual bool is_link(bool, bool) = 0;
+ virtual void copy_file(std::string const &, std::string const &) = 0;
+ virtual void exec_compiler() = 0;
+ virtual int fork_compiler() = 0;
+
+protected:
+ std::vector<char *> m_args;
+ bool m_is_citruninst;
+ std::vector<std::string> m_source_files;
+ InstrumentLogger m_log;
+
public:
InstFrontend(int, char *argv[], bool);
+ void log_identity();
+ void get_paths();
+ void clean_PATH();
void process_cmdline();
void instrument();
void compile_instrumented();
diff --git a/inst_feunix.cc b/inst_feunix.cc
@@ -0,0 +1,161 @@
+//
+// Copyright (c) 2016 Kyle Milz <kyle@0x30.net>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+#include "inst_feunix.h"
+
+#include <sys/stat.h> // stat
+#include <sys/time.h> // utimes
+#include <sys/utsname.h> // uname
+#include <sys/wait.h> // waitpid
+
+#include <err.h>
+#include <fstream> // ifstream, ofstream
+#include <unistd.h> // execvp, fork, getpid, unlink
+
+
+char
+InstFrontendUnix::dir_sep()
+{
+ return '/';
+}
+
+char
+InstFrontendUnix::path_sep()
+{
+ return ':';
+}
+
+std::string
+InstFrontendUnix::lib_name()
+{
+ return "libcitrun.a";
+}
+
+void
+InstFrontendUnix::log_os_str()
+{
+ struct utsname utsname;
+
+ if (uname(&utsname) == -1)
+ m_log << " (Unknown OS)";
+ else
+ m_log << " (" << utsname.sysname << "-" << utsname.release
+ << " " << utsname.machine << ")";
+}
+
+void
+InstFrontendUnix::set_path(std::string const &new_path)
+{
+ if (setenv("PATH", new_path.c_str(), 1))
+ err(1, "setenv");
+}
+
+//
+// Copies one file to another preserving timestamps.
+//
+void
+InstFrontendUnix::copy_file(std::string const &dst_fn, std::string const &src_fn)
+{
+ struct stat sb;
+ struct timeval st_tim[2];
+
+ // Save original access and modification times
+ if (stat(src_fn.c_str(), &sb) < 0)
+ err(1, "stat");
+#ifdef __APPLE__
+ TIMESPEC_TO_TIMEVAL(&st_tim[0], &sb.st_atimespec);
+ TIMESPEC_TO_TIMEVAL(&st_tim[1], &sb.st_mtimespec);
+#else
+ TIMESPEC_TO_TIMEVAL(&st_tim[0], &sb.st_atim);
+ TIMESPEC_TO_TIMEVAL(&st_tim[1], &sb.st_mtim);
+#endif
+
+ std::ifstream src(src_fn, std::ios::binary);
+ std::ofstream dst(dst_fn, std::ios::binary);
+
+ dst << src.rdbuf();
+
+ src.close();
+ dst.close();
+
+ // Restore the original access and modification time
+ if (utimes(dst_fn.c_str(), st_tim) < 0)
+ err(1, "utimes");
+}
+
+bool
+InstFrontendUnix::is_link(bool object_arg, bool compile_arg)
+{
+ if (!object_arg && !compile_arg && m_source_files.size() > 0)
+ // Assume single line a.out compilation
+ // $ gcc main.c
+ return true;
+ else if (object_arg && !compile_arg)
+ // gcc -o main main.o fib.o while.o
+ // gcc -o main main.c fib.c
+ return true;
+
+ return false;
+}
+
+//
+// Execute the compiler by calling execvp(3) on the m_args vector.
+//
+void
+InstFrontendUnix::exec_compiler()
+{
+ if (m_is_citruninst) {
+ m_log << "Running as citrun_inst, not calling exec()" << std::endl;
+ exit(0);
+ }
+
+ // Null termination explicitly mentioned in execvp(3).
+ m_args.push_back(NULL);
+ if (execvp(m_args[0], &m_args[0]))
+ err(1, "execvp");
+}
+
+//
+// fork(2) then execute the compiler and wait for it to finish. Returns exit
+// code of native compiler.
+//
+int
+InstFrontendUnix::fork_compiler()
+{
+ pid_t child_pid;
+ int status;
+ int exit = -1;
+
+ if ((child_pid = fork()) < 0)
+ err(1, "fork");
+
+ // If in child execute compiler.
+ if (child_pid == 0)
+ exec_compiler();
+
+ m_log << "Forked compiler '" << m_args[0] << "' "
+ << "pid is '" << child_pid << "'" << std::endl;
+
+ // Wait for the child to finish so we can get its exit code.
+ if (waitpid(child_pid, &status, 0) < 0)
+ err(1, "waitpid");
+
+ // Decode the exit code from status.
+ if (WIFEXITED(status))
+ exit = WEXITSTATUS(status);
+
+ // Return the exit code of the native compiler.
+ return exit;
+}
diff --git a/inst_feunix.h b/inst_feunix.h
@@ -0,0 +1,18 @@
+#include "inst_fe.h"
+
+class InstFrontendUnix : public InstFrontend
+{
+ // Use InstFrontend's constructor
+ using InstFrontend::InstFrontend;
+
+ // Mandatory interface implementation.
+ char dir_sep();
+ char path_sep();
+ std::string lib_name();
+ void log_os_str();
+ void set_path(std::string const &);
+ bool is_link(bool, bool);
+ void copy_file(std::string const &, std::string const &);
+ void exec_compiler();
+ int fork_compiler();
+};
diff --git a/inst_fewin32.cc b/inst_fewin32.cc
@@ -0,0 +1,170 @@
+//
+// Copyright (c) 2016 Kyle Milz <kyle@0x30.net>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+#include "inst_fewin32.h"
+
+#include <windows.h> // CreateProcess
+#include <Shlwapi.h> // PathFindOnPath
+
+#include <cstdio> // tmpnam
+#include <cstring> // strcmp
+#include <fstream> // ifstream, ofstream
+#include <iostream> // cerr
+#include <sstream> // ostringstream
+
+#define PATH_SEP ';'
+
+
+static void
+Err(int code, const char *fmt)
+{
+ char buf[256];
+
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL);
+
+ std::cerr << fmt << ": " << buf << std::endl;
+ ExitProcess(code);
+}
+
+char
+InstFrontendWin32::dir_sep()
+{
+ return '\\';
+}
+
+char
+InstFrontendWin32::path_sep()
+{
+ return ';';
+}
+
+std::string
+InstFrontendWin32::lib_name()
+{
+ return "libcitrun.lib";
+}
+
+void
+InstFrontendWin32::log_os_str()
+{
+ m_log << " (Windows x86)";
+}
+
+void
+InstFrontendWin32::set_path(std::string const & new_path)
+{
+ if (SetEnvironmentVariableA("Path", new_path.c_str()) == 0)
+ Err(1, "SetEnvironmentVariableA");
+}
+
+void
+InstFrontendWin32::copy_file(std::string const &dst_fn, std::string const &src_fn)
+{
+ // TODO: Timestamp saving.
+
+ std::ifstream src(src_fn, std::ios::binary);
+ std::ofstream dst(dst_fn, std::ios::binary);
+
+ dst << src.rdbuf();
+
+ src.close();
+ dst.close();
+}
+
+int
+InstFrontendWin32::is_link(bool object_arg, bool compile_arg)
+{
+ if (std::strcmp(m_args[0], "link") == 0)
+ // If we're called as link.exe we're linking for sure.
+ return true;
+ if (!compile_arg && m_source_files.size() > 0)
+ // cl.exe main.c
+ return true;
+
+ return false;
+}
+
+//
+// On Windows the best exec alternative is to CreateProcess, wait for it to
+// finish and exit with its exit code. Windows has execvp, but it looks to
+// CreateProcess and then itself exit, leading to race conditions.
+//
+void
+InstFrontendWin32::exec_compiler()
+{
+ if (m_is_citruninst) {
+ m_log << "Running as citrun_inst, not calling exec()" << std::endl;
+ exit(0);
+ }
+
+ exit(fork_compiler());
+}
+
+//
+// On Windows this is a straighforward conversion. We do our own PATH lookup
+// because the default one CreateProcess does will find our cl.exe again
+// instead of searching the PATH for a new one.
+//
+int
+InstFrontendWin32::fork_compiler()
+{
+ DWORD exit = -1;
+ STARTUPINFOA si;
+ PROCESS_INFORMATION pi;
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ ZeroMemory(&pi, sizeof(pi));
+
+ char real_cc[MAX_PATH];
+ std::strcpy(real_cc, m_args[0]);
+
+ if (!ends_with(real_cc, ".exe") && !ends_with(real_cc, ".EXE"))
+ std::strcat(real_cc, ".exe");
+
+ if (PathFindOnPathA(real_cc, NULL) == FALSE)
+ m_log << "PathFindOnPathA failed for " << real_cc << std::endl;
+
+ std::stringstream argv;
+ for (unsigned int i = 1; i < m_args.size(); ++i)
+ argv << " " << m_args[i];
+
+ if (!CreateProcessA(real_cc,
+ (LPSTR) argv.str().c_str(),
+ NULL,
+ NULL,
+ FALSE,
+ 0,
+ NULL,
+ NULL,
+ &si,
+ &pi))
+ Err(1, "CreateProcess");
+
+ m_log << "Forked compiler '" << real_cc << "' "
+ << "pid is '" << pi.dwProcessId << "'" << std::endl;
+
+ if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)
+ Err(1, "WaitForSingleObject");
+
+ if (GetExitCodeProcess(pi.hProcess, &exit) == FALSE)
+ Err(1, "GetExitCodeProcess");
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return exit;
+}
diff --git a/inst_fewin32.h b/inst_fewin32.h
@@ -0,0 +1,18 @@
+#include "inst_fe.h"
+
+class InstFrontendWin32 : public InstFrontend
+{
+ // Use InstFrontend's constructor
+ using InstFrontend::InstFrontend;
+
+ // Mandatory interface implementation.
+ char dir_sep();
+ char path_sep();
+ std::string lib_name();
+ void log_os_str();
+ void set_path(std::string const &);
+ bool is_link(bool, bool);
+ void copy_file(std::string const &, std::string const &);
+ void exec_compiler();
+ int fork_compiler();
+};
diff --git a/inst_main.cc b/inst_main.cc
@@ -13,18 +13,20 @@
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
-#include "inst_frontend.h" // InstFrontend
-
-#include <cstring> // strcmp
-
#ifdef _WIN32
#include <windows.h>
#include <Shlwapi.h> // PathFindFileNameA
+
+#include "inst_win32.h"
#else /* _WIN32 */
#include <err.h>
#include <libgen.h> // basename
+
+#include "inst_feunix.h" // InstFrontend
#endif /* _WIN32 */
+#include <cstring> // strcmp
+
int
main(int argc, char *argv[])
@@ -50,7 +52,15 @@ main(int argc, char *argv[])
if (std::strcmp(argv[0], base_name) != 0)
argv[0] = base_name;
- InstFrontend main(argc, argv, is_citrun_inst);
+#ifdef _WIN32
+ InstFrontendWin32 main(argc, argv, is_citrun_inst);
+#else
+ InstFrontendUnix main(argc, argv, is_citrun_inst);
+#endif
+
+ main.log_identity();
+ main.get_paths();
+ main.clean_PATH();
main.process_cmdline();
main.instrument();