1
0

cmcldeps.cxx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. /*
  2. ninja's subprocess.h
  3. */
  4. // Copyright 2012 Google Inc. All Rights Reserved.
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License");
  7. // you may not use this file except in compliance with the License.
  8. // You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. #ifndef NINJA_SUBPROCESS_H_
  18. #define NINJA_SUBPROCESS_H_
  19. #include <string>
  20. #include <vector>
  21. #include <queue>
  22. using namespace std;
  23. #ifdef _WIN32
  24. #include <windows.h>
  25. #else
  26. #include <signal.h>
  27. #endif
  28. //#include "exit_status.h"
  29. enum ExitStatus {
  30. ExitSuccess,
  31. ExitFailure,
  32. ExitInterrupted
  33. };
  34. /// Subprocess wraps a single async subprocess. It is entirely
  35. /// passive: it expects the caller to notify it when its fds are ready
  36. /// for reading, as well as call Finish() to reap the child once done()
  37. /// is true.
  38. struct Subprocess {
  39. ~Subprocess();
  40. /// Returns ExitSuccess on successful process exit, ExitInterrupted if
  41. /// the process was interrupted, ExitFailure if it otherwise failed.
  42. ExitStatus Finish();
  43. bool Done() const;
  44. const string& GetOutput() const;
  45. int ExitCode() const { return exit_code_; }
  46. private:
  47. Subprocess();
  48. bool Start(struct SubprocessSet* set, const string& command);
  49. void OnPipeReady();
  50. string buf_;
  51. #ifdef _WIN32
  52. /// Set up pipe_ as the parent-side pipe of the subprocess; return the
  53. /// other end of the pipe, usable in the child process.
  54. HANDLE SetupPipe(HANDLE ioport);
  55. HANDLE child_;
  56. HANDLE pipe_;
  57. OVERLAPPED overlapped_;
  58. char overlapped_buf_[4 << 10];
  59. bool is_reading_;
  60. int exit_code_;
  61. #else
  62. int fd_;
  63. pid_t pid_;
  64. #endif
  65. friend struct SubprocessSet;
  66. };
  67. /// SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
  68. /// DoWork() waits for any state change in subprocesses; finished_
  69. /// is a queue of subprocesses as they finish.
  70. struct SubprocessSet {
  71. SubprocessSet();
  72. ~SubprocessSet();
  73. Subprocess* Add(const string& command);
  74. bool DoWork();
  75. Subprocess* NextFinished();
  76. void Clear();
  77. vector<Subprocess*> running_;
  78. queue<Subprocess*> finished_;
  79. #ifdef _WIN32
  80. static BOOL WINAPI NotifyInterrupted(DWORD dwCtrlType);
  81. static HANDLE ioport_;
  82. #else
  83. static void SetInterruptedFlag(int signum);
  84. static bool interrupted_;
  85. struct sigaction old_act_;
  86. sigset_t old_mask_;
  87. #endif
  88. };
  89. #endif // NINJA_SUBPROCESS_H_
  90. /*
  91. ninja's util functions
  92. */
  93. static void Fatal(const char* msg, ...) {
  94. va_list ap;
  95. fprintf(stderr, "ninja: FATAL: ");
  96. va_start(ap, msg);
  97. vfprintf(stderr, msg, ap);
  98. va_end(ap);
  99. fprintf(stderr, "\n");
  100. #ifdef _WIN32
  101. // On Windows, some tools may inject extra threads.
  102. // exit() may block on locks held by those threads, so forcibly exit.
  103. fflush(stderr);
  104. fflush(stdout);
  105. ExitProcess(1);
  106. #else
  107. exit(1);
  108. #endif
  109. }
  110. #ifdef _WIN32
  111. string GetLastErrorString() {
  112. DWORD err = GetLastError();
  113. char* msg_buf;
  114. FormatMessageA(
  115. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  116. FORMAT_MESSAGE_FROM_SYSTEM |
  117. FORMAT_MESSAGE_IGNORE_INSERTS,
  118. NULL,
  119. err,
  120. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  121. (char*)&msg_buf,
  122. 0,
  123. NULL);
  124. string msg = msg_buf;
  125. LocalFree(msg_buf);
  126. return msg;
  127. }
  128. #endif
  129. #define snprintf _snprintf
  130. /*
  131. ninja's subprocess-win32.cc
  132. */
  133. // Copyright 2012 Google Inc. All Rights Reserved.
  134. //
  135. // Licensed under the Apache License, Version 2.0 (the "License");
  136. // you may not use this file except in compliance with the License.
  137. // You may obtain a copy of the License at
  138. //
  139. // http://www.apache.org/licenses/LICENSE-2.0
  140. //
  141. // Unless required by applicable law or agreed to in writing, software
  142. // distributed under the License is distributed on an "AS IS" BASIS,
  143. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  144. // See the License for the specific language governing permissions and
  145. // limitations under the License.
  146. //#include "subprocess.h"
  147. #include <stdio.h>
  148. #include <algorithm>
  149. //#include "util.h"
  150. namespace {
  151. void Win32Fatal(const char* function) {
  152. Fatal("%s: %s", function, GetLastErrorString().c_str());
  153. }
  154. } // anonymous namespace
  155. Subprocess::Subprocess() : child_(NULL) , overlapped_(), is_reading_(false), exit_code_(1) {
  156. }
  157. Subprocess::~Subprocess() {
  158. if (pipe_) {
  159. if (!CloseHandle(pipe_))
  160. Win32Fatal("CloseHandle");
  161. }
  162. // Reap child if forgotten.
  163. if (child_)
  164. Finish();
  165. }
  166. HANDLE Subprocess::SetupPipe(HANDLE ioport) {
  167. char pipe_name[100];
  168. snprintf(pipe_name, sizeof(pipe_name),
  169. "\\\\.\\pipe\\ninja_pid%u_sp%p", GetCurrentProcessId(), this);
  170. pipe_ = ::CreateNamedPipeA(pipe_name,
  171. PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
  172. PIPE_TYPE_BYTE,
  173. PIPE_UNLIMITED_INSTANCES,
  174. 0, 0, INFINITE, NULL);
  175. if (pipe_ == INVALID_HANDLE_VALUE)
  176. Win32Fatal("CreateNamedPipe");
  177. if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)this, 0))
  178. Win32Fatal("CreateIoCompletionPort");
  179. memset(&overlapped_, 0, sizeof(overlapped_));
  180. if (!ConnectNamedPipe(pipe_, &overlapped_) &&
  181. GetLastError() != ERROR_IO_PENDING) {
  182. Win32Fatal("ConnectNamedPipe");
  183. }
  184. // Get the write end of the pipe as a handle inheritable across processes.
  185. HANDLE output_write_handle = CreateFile(pipe_name, GENERIC_WRITE, 0,
  186. NULL, OPEN_EXISTING, 0, NULL);
  187. HANDLE output_write_child;
  188. if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
  189. GetCurrentProcess(), &output_write_child,
  190. 0, TRUE, DUPLICATE_SAME_ACCESS)) {
  191. Win32Fatal("DuplicateHandle");
  192. }
  193. CloseHandle(output_write_handle);
  194. return output_write_child;
  195. }
  196. bool Subprocess::Start(SubprocessSet* set, const string& command) {
  197. HANDLE child_pipe = SetupPipe(set->ioport_);
  198. SECURITY_ATTRIBUTES security_attributes;
  199. memset(&security_attributes, 0, sizeof(SECURITY_ATTRIBUTES));
  200. security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  201. security_attributes.bInheritHandle = TRUE;
  202. // Must be inheritable so subprocesses can dup to children.
  203. HANDLE nul = CreateFile("NUL", GENERIC_READ,
  204. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  205. &security_attributes, OPEN_EXISTING, 0, NULL);
  206. if (nul == INVALID_HANDLE_VALUE)
  207. Fatal("couldn't open nul");
  208. STARTUPINFOA startup_info;
  209. memset(&startup_info, 0, sizeof(startup_info));
  210. startup_info.cb = sizeof(STARTUPINFO);
  211. startup_info.dwFlags = STARTF_USESTDHANDLES;
  212. startup_info.hStdInput = nul;
  213. startup_info.hStdOutput = child_pipe;
  214. startup_info.hStdError = child_pipe;
  215. PROCESS_INFORMATION process_info;
  216. memset(&process_info, 0, sizeof(process_info));
  217. // Do not prepend 'cmd /c' on Windows, this breaks command
  218. // lines greater than 8,191 chars.
  219. if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL,
  220. /* inherit handles */ TRUE, CREATE_NEW_PROCESS_GROUP,
  221. NULL, NULL,
  222. &startup_info, &process_info)) {
  223. DWORD error = GetLastError();
  224. if (error == ERROR_FILE_NOT_FOUND) { // file (program) not found error is treated as a normal build action failure
  225. if (child_pipe)
  226. CloseHandle(child_pipe);
  227. CloseHandle(pipe_);
  228. CloseHandle(nul);
  229. pipe_ = NULL;
  230. // child_ is already NULL;
  231. buf_ = "CreateProcess failed: The system cannot find the file specified.\n";
  232. return true;
  233. } else {
  234. Win32Fatal("CreateProcess"); // pass all other errors to Win32Fatal
  235. }
  236. }
  237. // Close pipe channel only used by the child.
  238. if (child_pipe)
  239. CloseHandle(child_pipe);
  240. CloseHandle(nul);
  241. CloseHandle(process_info.hThread);
  242. child_ = process_info.hProcess;
  243. return true;
  244. }
  245. void Subprocess::OnPipeReady() {
  246. DWORD bytes;
  247. if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
  248. if (GetLastError() == ERROR_BROKEN_PIPE) {
  249. CloseHandle(pipe_);
  250. pipe_ = NULL;
  251. return;
  252. }
  253. Win32Fatal("GetOverlappedResult");
  254. }
  255. if (is_reading_ && bytes)
  256. buf_.append(overlapped_buf_, bytes);
  257. memset(&overlapped_, 0, sizeof(overlapped_));
  258. is_reading_ = true;
  259. if (!::ReadFile(pipe_, overlapped_buf_, sizeof(overlapped_buf_),
  260. &bytes, &overlapped_)) {
  261. if (GetLastError() == ERROR_BROKEN_PIPE) {
  262. CloseHandle(pipe_);
  263. pipe_ = NULL;
  264. return;
  265. }
  266. if (GetLastError() != ERROR_IO_PENDING)
  267. Win32Fatal("ReadFile");
  268. }
  269. // Even if we read any bytes in the readfile call, we'll enter this
  270. // function again later and get them at that point.
  271. }
  272. ExitStatus Subprocess::Finish() {
  273. if (!child_)
  274. return ExitFailure;
  275. // TODO: add error handling for all of these.
  276. WaitForSingleObject(child_, INFINITE);
  277. DWORD exit_code = 0;
  278. GetExitCodeProcess(child_, &exit_code);
  279. CloseHandle(child_);
  280. child_ = NULL;
  281. exit_code_ = exit_code;
  282. return exit_code == 0 ? ExitSuccess :
  283. exit_code == CONTROL_C_EXIT ? ExitInterrupted :
  284. ExitFailure;
  285. }
  286. bool Subprocess::Done() const {
  287. return pipe_ == NULL;
  288. }
  289. const string& Subprocess::GetOutput() const {
  290. return buf_;
  291. }
  292. HANDLE SubprocessSet::ioport_;
  293. SubprocessSet::SubprocessSet() {
  294. ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
  295. if (!ioport_)
  296. Win32Fatal("CreateIoCompletionPort");
  297. if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE))
  298. Win32Fatal("SetConsoleCtrlHandler");
  299. }
  300. SubprocessSet::~SubprocessSet() {
  301. Clear();
  302. SetConsoleCtrlHandler(NotifyInterrupted, FALSE);
  303. CloseHandle(ioport_);
  304. }
  305. BOOL WINAPI SubprocessSet::NotifyInterrupted(DWORD dwCtrlType) {
  306. if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
  307. if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL))
  308. Win32Fatal("PostQueuedCompletionStatus");
  309. return TRUE;
  310. }
  311. return FALSE;
  312. }
  313. Subprocess *SubprocessSet::Add(const string& command) {
  314. Subprocess *subprocess = new Subprocess;
  315. if (!subprocess->Start(this, command)) {
  316. delete subprocess;
  317. return 0;
  318. }
  319. if (subprocess->child_)
  320. running_.push_back(subprocess);
  321. else
  322. finished_.push(subprocess);
  323. return subprocess;
  324. }
  325. bool SubprocessSet::DoWork() {
  326. DWORD bytes_read;
  327. Subprocess* subproc;
  328. OVERLAPPED* overlapped;
  329. if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc,
  330. &overlapped, INFINITE)) {
  331. if (GetLastError() != ERROR_BROKEN_PIPE)
  332. Win32Fatal("GetQueuedCompletionStatus");
  333. }
  334. if (!subproc) // A NULL subproc indicates that we were interrupted and is
  335. // delivered by NotifyInterrupted above.
  336. return true;
  337. subproc->OnPipeReady();
  338. if (subproc->Done()) {
  339. vector<Subprocess*>::iterator end =
  340. std::remove(running_.begin(), running_.end(), subproc);
  341. if (running_.end() != end) {
  342. finished_.push(subproc);
  343. running_.resize(end - running_.begin());
  344. }
  345. }
  346. return false;
  347. }
  348. Subprocess* SubprocessSet::NextFinished() {
  349. if (finished_.empty())
  350. return NULL;
  351. Subprocess* subproc = finished_.front();
  352. finished_.pop();
  353. return subproc;
  354. }
  355. void SubprocessSet::Clear() {
  356. for (vector<Subprocess*>::iterator i = running_.begin();
  357. i != running_.end(); ++i) {
  358. if ((*i)->child_)
  359. if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, GetProcessId((*i)->child_)))
  360. Win32Fatal("GenerateConsoleCtrlEvent");
  361. }
  362. for (vector<Subprocess*>::iterator i = running_.begin();
  363. i != running_.end(); ++i)
  364. delete *i;
  365. running_.clear();
  366. }
  367. // Copyright 2011 Google Inc. All Rights Reserved.
  368. //
  369. // Licensed under the Apache License, Version 2.0 (the "License");
  370. // you may not use this file except in compliance with the License.
  371. // You may obtain a copy of the License at
  372. //
  373. // http://www.apache.org/licenses/LICENSE-2.0
  374. //
  375. // Unless required by applicable law or agreed to in writing, software
  376. // distributed under the License is distributed on an "AS IS" BASIS,
  377. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  378. // See the License for the specific language governing permissions and
  379. // limitations under the License.
  380. // Wrapper around cl that adds /showIncludes to command line, and uses that to
  381. // generate .d files that match the style from gcc -MD.
  382. //
  383. // /showIncludes is equivalent to -MD, not -MMD, that is, system headers are
  384. // included.
  385. #include <windows.h>
  386. #include <sstream>
  387. //#include "subprocess.h"
  388. //#include "util.h"
  389. // We don't want any wildcard expansion.
  390. // See http://msdn.microsoft.com/en-us/library/zay8tzh6(v=vs.85).aspx
  391. void _setargv() {}
  392. static void usage(const char* msg) {
  393. Fatal("%s\n\nusage:\n"
  394. " cldeps "
  395. "<source file> "
  396. "<output path for *.d file> "
  397. "<output path for *.obj file> "
  398. "<prefix of /showIncludes> "
  399. "<path to cl> "
  400. "<rest of command ...>\n", msg);
  401. }
  402. static string trimLeadingSpace(const string& cmdline) {
  403. int i = 0;
  404. for (; cmdline[i] == ' '; ++i)
  405. ;
  406. return cmdline.substr(i);
  407. }
  408. static void doEscape(string& str, const string& search, const string& repl) {
  409. string::size_type pos = 0;
  410. while ((pos = str.find(search, pos)) != string::npos) {
  411. str.replace(pos, search.size(), repl);
  412. pos += repl.size();
  413. }
  414. }
  415. // Strips one argument from the cmdline and returns it. "surrounding quotes"
  416. // are removed from the argument if there were any.
  417. static string getArg(string& cmdline) {
  418. string ret;
  419. bool in_quoted = false;
  420. unsigned int i = 0;
  421. cmdline = trimLeadingSpace(cmdline);
  422. for (;; ++i) {
  423. if (i >= cmdline.size())
  424. usage("Couldn't parse arguments.");
  425. if (!in_quoted && cmdline[i] == ' ')
  426. break; // "a b" "x y"
  427. if (cmdline[i] == '"')
  428. in_quoted = !in_quoted;
  429. }
  430. ret = cmdline.substr(0, i);
  431. if (ret[0] == '"' && ret[i - 1] == '"')
  432. ret = ret.substr(1, ret.size() - 2);
  433. cmdline = cmdline.substr(i);
  434. return ret;
  435. }
  436. static void parseCommandLine(LPTSTR wincmdline,
  437. string& srcfile, string& dfile, string& objfile, string& prefix, string& clpath, string& rest) {
  438. string cmdline(wincmdline);
  439. /* self */ getArg(cmdline);
  440. srcfile = getArg(cmdline);
  441. std::string::size_type pos = srcfile.rfind("\\");
  442. if (pos != string::npos) {
  443. srcfile = srcfile.substr(pos + 1);
  444. } else {
  445. srcfile = "";
  446. }
  447. dfile = getArg(cmdline);
  448. objfile = getArg(cmdline);
  449. prefix = getArg(cmdline);
  450. clpath = getArg(cmdline);
  451. rest = trimLeadingSpace(cmdline);
  452. }
  453. static void outputDepFile(const string& dfile, const string& objfile,
  454. vector<string>& incs) {
  455. // strip duplicates
  456. sort(incs.begin(), incs.end());
  457. incs.erase(unique(incs.begin(), incs.end()), incs.end());
  458. FILE* out = fopen(dfile.c_str(), "wb");
  459. // FIXME should this be fatal or not? delete obj? delete d?
  460. if (!out)
  461. return;
  462. string tmp = objfile;
  463. doEscape(tmp, " ", "\\ ");
  464. fprintf(out, "%s: \\\n", tmp.c_str());
  465. for (vector<string>::iterator i(incs.begin()); i != incs.end(); ++i) {
  466. tmp = *i;
  467. doEscape(tmp, "\\", "\\\\");
  468. doEscape(tmp, " ", "\\ ");
  469. //doEscape(tmp, "(", "("); // TODO ninja cant read ( and )
  470. //doEscape(tmp, ")", ")");
  471. fprintf(out, "%s \\\n", tmp.c_str());
  472. }
  473. fprintf(out, "\n");
  474. fclose(out);
  475. }
  476. bool startsWith(const std::string& str, const std::string& what) {
  477. return str.compare(0, what.size(), what) == 0;
  478. }
  479. bool contains(const std::string& str, const std::string& what) {
  480. return str.find(what) != std::string::npos;
  481. }
  482. int main() {
  483. // Use the Win32 api instead of argc/argv so we can avoid interpreting the
  484. // rest of command line after the .d and .obj. Custom parsing seemed
  485. // preferable to the ugliness you get into in trying to re-escape quotes for
  486. // subprocesses, so by avoiding argc/argv, the subprocess is called with
  487. // the same command line verbatim.
  488. string srcfile, dfile, objfile, prefix, clpath, rest;
  489. parseCommandLine(GetCommandLine(), srcfile, dfile, objfile, prefix, clpath, rest);
  490. #if 0
  491. fprintf(stderr, "\n\ncmcldebug:\n");
  492. fprintf(stderr, ".d : %s\n", dfile.c_str());
  493. fprintf(stderr, "OBJ : %s\n", objfile.c_str());
  494. fprintf(stderr, "CL : %s\n", clpath.c_str());
  495. fprintf(stderr, "REST: %s\n", rest.c_str());
  496. fprintf(stderr, "\n\n");
  497. #endif
  498. SubprocessSet subprocs;
  499. Subprocess* subproc = subprocs.Add(clpath + " /showIncludes " + rest);
  500. if(!subproc)
  501. return 2;
  502. while ((subproc = subprocs.NextFinished()) == NULL) {
  503. subprocs.DoWork();
  504. }
  505. bool success = subproc->Finish() == ExitSuccess;
  506. int exit_code = subproc->ExitCode();
  507. string output = subproc->GetOutput();
  508. delete subproc;
  509. // process the include directives and output everything else
  510. stringstream ss(output);
  511. string line;
  512. vector<string> includes;
  513. bool isFirstLine = true; // cl prints always first the source filename
  514. std::string sysHeadersCamel = "Program Files (x86)\\Microsoft ";
  515. std::string sysHeadersLower = "program files (x86)\\microsoft ";
  516. while (getline(ss, line)) {
  517. if (startsWith(line, prefix)) {
  518. if (!contains(line, sysHeadersCamel) && !contains(line, sysHeadersLower)) {
  519. string inc = trimLeadingSpace(line.substr(prefix.size()).c_str());
  520. if (inc[inc.size() - 1] == '\r') // blech, stupid \r\n
  521. inc = inc.substr(0, inc.size() - 1);
  522. includes.push_back(inc);
  523. }
  524. } else {
  525. if (!isFirstLine || !startsWith(line, srcfile)) {
  526. fprintf(stdout, "%s\n", line.c_str());
  527. } else {
  528. isFirstLine = false;
  529. }
  530. }
  531. }
  532. if (!success)
  533. return exit_code;
  534. // don't update .d until/unless we succeed compilation
  535. outputDepFile(dfile, objfile, includes);
  536. return 0;
  537. }