• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "msvc_helper.h"
16 
17 #include <fcntl.h>
18 #include <io.h>
19 #include <stdio.h>
20 #include <windows.h>
21 
22 #include "clparser.h"
23 #include "util.h"
24 
25 #include "getopt.h"
26 
27 namespace {
28 
Usage()29 void Usage() {
30   printf(
31 "usage: ninja -t msvc [options] -- cl.exe /showIncludes /otherArgs\n"
32 "options:\n"
33 "  -e ENVFILE load environment block from ENVFILE as environment\n"
34 "  -o FILE    write output dependency information to FILE.d\n"
35 "  -p STRING  localized prefix of msvc's /showIncludes output\n"
36          );
37 }
38 
PushPathIntoEnvironment(const string & env_block)39 void PushPathIntoEnvironment(const string& env_block) {
40   const char* as_str = env_block.c_str();
41   while (as_str[0]) {
42     if (_strnicmp(as_str, "path=", 5) == 0) {
43       _putenv(as_str);
44       return;
45     } else {
46       as_str = &as_str[strlen(as_str) + 1];
47     }
48   }
49 }
50 
WriteDepFileOrDie(const char * object_path,const CLParser & parse)51 void WriteDepFileOrDie(const char* object_path, const CLParser& parse) {
52   string depfile_path = string(object_path) + ".d";
53   FILE* depfile = fopen(depfile_path.c_str(), "w");
54   if (!depfile) {
55     unlink(object_path);
56     Fatal("opening %s: %s", depfile_path.c_str(),
57           GetLastErrorString().c_str());
58   }
59   if (fprintf(depfile, "%s: ", object_path) < 0) {
60     unlink(object_path);
61     fclose(depfile);
62     unlink(depfile_path.c_str());
63     Fatal("writing %s", depfile_path.c_str());
64   }
65   const set<string>& headers = parse.includes_;
66   for (set<string>::const_iterator i = headers.begin();
67        i != headers.end(); ++i) {
68     if (fprintf(depfile, "%s\n", EscapeForDepfile(*i).c_str()) < 0) {
69       unlink(object_path);
70       fclose(depfile);
71       unlink(depfile_path.c_str());
72       Fatal("writing %s", depfile_path.c_str());
73     }
74   }
75   fclose(depfile);
76 }
77 
78 }  // anonymous namespace
79 
MSVCHelperMain(int argc,char ** argv)80 int MSVCHelperMain(int argc, char** argv) {
81   const char* output_filename = NULL;
82   const char* envfile = NULL;
83 
84   const option kLongOptions[] = {
85     { "help", no_argument, NULL, 'h' },
86     { NULL, 0, NULL, 0 }
87   };
88   int opt;
89   string deps_prefix;
90   while ((opt = getopt_long(argc, argv, "e:o:p:h", kLongOptions, NULL)) != -1) {
91     switch (opt) {
92       case 'e':
93         envfile = optarg;
94         break;
95       case 'o':
96         output_filename = optarg;
97         break;
98       case 'p':
99         deps_prefix = optarg;
100         break;
101       case 'h':
102       default:
103         Usage();
104         return 0;
105     }
106   }
107 
108   string env;
109   if (envfile) {
110     string err;
111     if (ReadFile(envfile, &env, &err) != 0)
112       Fatal("couldn't open %s: %s", envfile, err.c_str());
113     PushPathIntoEnvironment(env);
114   }
115 
116   char* command = GetCommandLineA();
117   command = strstr(command, " -- ");
118   if (!command) {
119     Fatal("expected command line to end with \" -- command args\"");
120   }
121   command += 4;
122 
123   CLWrapper cl;
124   if (!env.empty())
125     cl.SetEnvBlock((void*)env.data());
126   string output;
127   int exit_code = cl.Run(command, &output);
128 
129   if (output_filename) {
130     CLParser parser;
131     string err;
132     if (!parser.Parse(output, deps_prefix, &output, &err))
133       Fatal("%s\n", err.c_str());
134     WriteDepFileOrDie(output_filename, parser);
135   }
136 
137   if (output.empty())
138     return exit_code;
139 
140   // CLWrapper's output already as \r\n line endings, make sure the C runtime
141   // doesn't expand this to \r\r\n.
142   _setmode(_fileno(stdout), _O_BINARY);
143   // Avoid printf and C strings, since the actual output might contain null
144   // bytes like UTF-16 does (yuck).
145   fwrite(&output[0], 1, output.size(), stdout);
146 
147   return exit_code;
148 }
149