Ninja
|
00001 // Copyright 2011 Google Inc. All Rights Reserved. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // http://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 00015 #include "msvc_helper.h" 00016 00017 #include <algorithm> 00018 #include <stdio.h> 00019 #include <string.h> 00020 #include <windows.h> 00021 00022 #include "includes_normalize.h" 00023 #include "util.h" 00024 00025 namespace { 00026 00027 /// Return true if \a input ends with \a needle. 00028 bool EndsWith(const string& input, const string& needle) { 00029 return (input.size() >= needle.size() && 00030 input.substr(input.size() - needle.size()) == needle); 00031 } 00032 00033 string Replace(const string& input, const string& find, const string& replace) { 00034 string result = input; 00035 size_t start_pos = 0; 00036 while ((start_pos = result.find(find, start_pos)) != string::npos) { 00037 result.replace(start_pos, find.length(), replace); 00038 start_pos += replace.length(); 00039 } 00040 return result; 00041 } 00042 00043 } // anonymous namespace 00044 00045 string EscapeForDepfile(const string& path) { 00046 // Depfiles don't escape single \. 00047 return Replace(path, " ", "\\ "); 00048 } 00049 00050 // static 00051 string CLParser::FilterShowIncludes(const string& line) { 00052 static const char kMagicPrefix[] = "Note: including file: "; 00053 const char* in = line.c_str(); 00054 const char* end = in + line.size(); 00055 00056 if (end - in > (int)sizeof(kMagicPrefix) - 1 && 00057 memcmp(in, kMagicPrefix, sizeof(kMagicPrefix) - 1) == 0) { 00058 in += sizeof(kMagicPrefix) - 1; 00059 while (*in == ' ') 00060 ++in; 00061 return line.substr(in - line.c_str()); 00062 } 00063 return ""; 00064 } 00065 00066 // static 00067 bool CLParser::IsSystemInclude(string path) { 00068 transform(path.begin(), path.end(), path.begin(), ::tolower); 00069 // TODO: this is a heuristic, perhaps there's a better way? 00070 return (path.find("program files") != string::npos || 00071 path.find("microsoft visual studio") != string::npos); 00072 } 00073 00074 // static 00075 bool CLParser::FilterInputFilename(string line) { 00076 transform(line.begin(), line.end(), line.begin(), ::tolower); 00077 // TODO: other extensions, like .asm? 00078 return EndsWith(line, ".c") || 00079 EndsWith(line, ".cc") || 00080 EndsWith(line, ".cxx") || 00081 EndsWith(line, ".cpp"); 00082 } 00083 00084 string CLParser::Parse(const string& output) { 00085 string filtered_output; 00086 00087 // Loop over all lines in the output to process them. 00088 size_t start = 0; 00089 while (start < output.size()) { 00090 size_t end = output.find_first_of("\r\n", start); 00091 if (end == string::npos) 00092 end = output.size(); 00093 string line = output.substr(start, end - start); 00094 00095 string include = FilterShowIncludes(line); 00096 if (!include.empty()) { 00097 include = IncludesNormalize::Normalize(include, NULL); 00098 if (!IsSystemInclude(include)) 00099 includes_.insert(include); 00100 } else if (FilterInputFilename(line)) { 00101 // Drop it. 00102 // TODO: if we support compiling multiple output files in a single 00103 // cl.exe invocation, we should stash the filename. 00104 } else { 00105 filtered_output.append(line); 00106 filtered_output.append("\n"); 00107 } 00108 00109 if (end < output.size() && output[end] == '\r') 00110 ++end; 00111 if (end < output.size() && output[end] == '\n') 00112 ++end; 00113 start = end; 00114 } 00115 00116 return filtered_output; 00117 } 00118 00119 int CLWrapper::Run(const string& command, string* output) { 00120 SECURITY_ATTRIBUTES security_attributes = {}; 00121 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); 00122 security_attributes.bInheritHandle = TRUE; 00123 00124 // Must be inheritable so subprocesses can dup to children. 00125 HANDLE nul = CreateFile("NUL", GENERIC_READ, 00126 FILE_SHARE_READ | FILE_SHARE_WRITE | 00127 FILE_SHARE_DELETE, 00128 &security_attributes, OPEN_EXISTING, 0, NULL); 00129 if (nul == INVALID_HANDLE_VALUE) 00130 Fatal("couldn't open nul"); 00131 00132 HANDLE stdout_read, stdout_write; 00133 if (!CreatePipe(&stdout_read, &stdout_write, &security_attributes, 0)) 00134 Win32Fatal("CreatePipe"); 00135 00136 if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) 00137 Win32Fatal("SetHandleInformation"); 00138 00139 PROCESS_INFORMATION process_info = {}; 00140 STARTUPINFO startup_info = {}; 00141 startup_info.cb = sizeof(STARTUPINFO); 00142 startup_info.hStdInput = nul; 00143 startup_info.hStdError = stdout_write; 00144 startup_info.hStdOutput = stdout_write; 00145 startup_info.dwFlags |= STARTF_USESTDHANDLES; 00146 00147 if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL, 00148 /* inherit handles */ TRUE, 0, 00149 env_block_, NULL, 00150 &startup_info, &process_info)) { 00151 Win32Fatal("CreateProcess"); 00152 } 00153 00154 if (!CloseHandle(nul) || 00155 !CloseHandle(stdout_write)) { 00156 Win32Fatal("CloseHandle"); 00157 } 00158 00159 // Read all output of the subprocess. 00160 DWORD read_len = 1; 00161 while (read_len) { 00162 char buf[64 << 10]; 00163 read_len = 0; 00164 if (!::ReadFile(stdout_read, buf, sizeof(buf), &read_len, NULL) && 00165 GetLastError() != ERROR_BROKEN_PIPE) { 00166 Win32Fatal("ReadFile"); 00167 } 00168 output->append(buf, read_len); 00169 } 00170 00171 // Wait for it to exit and grab its exit code. 00172 if (WaitForSingleObject(process_info.hProcess, INFINITE) == WAIT_FAILED) 00173 Win32Fatal("WaitForSingleObject"); 00174 DWORD exit_code = 0; 00175 if (!GetExitCodeProcess(process_info.hProcess, &exit_code)) 00176 Win32Fatal("GetExitCodeProcess"); 00177 00178 if (!CloseHandle(stdout_read) || 00179 !CloseHandle(process_info.hProcess) || 00180 !CloseHandle(process_info.hThread)) { 00181 Win32Fatal("CloseHandle"); 00182 } 00183 00184 return exit_code; 00185 }