fe_unix.cc (3932B)
1 // 2 // Copyright (c) 2016 Kyle Milz <kyle@0x30.net> 3 // 4 // Permission to use, copy, modify, and distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 // 16 #include "fe_unix.h" 17 18 #include <sys/stat.h> // stat 19 #include <sys/time.h> // utimes 20 #include <sys/utsname.h> // uname 21 #include <sys/wait.h> // waitpid 22 23 #include <err.h> 24 #include <fstream> // ifstream, ofstream 25 #include <unistd.h> // execvp, fork, getpid, unlink 26 27 28 char 29 InstFrontendUnix::dir_sep() 30 { 31 return '/'; 32 } 33 34 char 35 InstFrontendUnix::path_sep() 36 { 37 return ':'; 38 } 39 40 std::string 41 InstFrontendUnix::lib_name() 42 { 43 return "lib/libcitrun.a"; 44 } 45 46 void 47 InstFrontendUnix::log_os_str() 48 { 49 struct utsname utsname; 50 51 if (uname(&utsname) == -1) 52 m_log << " (Unknown OS)"; 53 else 54 m_log << " (" << utsname.sysname << "-" << utsname.release 55 << " " << utsname.machine << ")"; 56 57 // Sometimes we're not called as citrun_inst so force that here. 58 setprogname("citrun_inst"); 59 } 60 61 void 62 InstFrontendUnix::set_path(std::string const &new_path) 63 { 64 if (setenv("PATH", new_path.c_str(), 1)) 65 err(1, "setenv"); 66 } 67 68 // 69 // Copies one file to another preserving timestamps. 70 // 71 void 72 InstFrontendUnix::copy_file(std::string const &dst_fn, std::string const &src_fn) 73 { 74 struct stat sb; 75 struct timeval st_tim[2]; 76 77 // Save original access and modification times 78 if (stat(src_fn.c_str(), &sb) < 0) 79 err(1, "stat"); 80 #ifdef __APPLE__ 81 TIMESPEC_TO_TIMEVAL(&st_tim[0], &sb.st_atimespec); 82 TIMESPEC_TO_TIMEVAL(&st_tim[1], &sb.st_mtimespec); 83 #else 84 TIMESPEC_TO_TIMEVAL(&st_tim[0], &sb.st_atim); 85 TIMESPEC_TO_TIMEVAL(&st_tim[1], &sb.st_mtim); 86 #endif 87 88 std::ifstream src(src_fn, std::ios::binary); 89 std::ofstream dst(dst_fn, std::ios::binary); 90 91 dst << src.rdbuf(); 92 93 src.close(); 94 dst.close(); 95 96 // 97 // Restore the original access and modification time, it's not critical 98 // if it fails. 99 // 100 if (utimes(dst_fn.c_str(), st_tim) < 0) 101 warn("utimes"); 102 } 103 104 bool 105 InstFrontendUnix::is_link(bool object_arg, bool compile_arg) 106 { 107 if (!object_arg && !compile_arg && m_source_files.size() > 0) 108 // Assume single line a.out compilation 109 // $ gcc main.c 110 return true; 111 else if (object_arg && !compile_arg) 112 // gcc -o main main.o fib.o while.o 113 // gcc -o main main.c fib.c 114 return true; 115 116 return false; 117 } 118 119 // 120 // Execute the compiler by calling execvp(3) on the m_args vector. 121 // 122 void 123 InstFrontendUnix::exec_compiler() 124 { 125 if (m_is_citruninst) { 126 m_log << "Running as citrun_inst, not calling exec()" << std::endl; 127 exit(0); 128 } 129 130 // Null termination explicitly mentioned in execvp(3). 131 m_args.push_back(NULL); 132 if (execvp(m_args[0], &m_args[0])) 133 err(1, "execvp"); 134 } 135 136 // 137 // fork(2) then execute the compiler and wait for it to finish. Returns exit 138 // code of native compiler. 139 // 140 int 141 InstFrontendUnix::fork_compiler() 142 { 143 pid_t child_pid; 144 int status; 145 int exit = -1; 146 147 if ((child_pid = fork()) < 0) 148 err(1, "fork"); 149 150 // If in child execute compiler. 151 if (child_pid == 0) 152 exec_compiler(); 153 154 m_log << "Forked compiler '" << m_args[0] << "' " 155 << "pid is '" << child_pid << "'" << std::endl; 156 157 // Wait for the child to finish so we can get its exit code. 158 if (waitpid(child_pid, &status, 0) < 0) 159 err(1, "waitpid"); 160 161 // Decode the exit code from status. 162 if (WIFEXITED(status)) 163 exit = WEXITSTATUS(status); 164 165 // Return the exit code of the native compiler. 166 return exit; 167 }