Ninja
msvc_helper_main-win32.cc
Go to the documentation of this file.
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 <fcntl.h>
00018 #include <io.h>
00019 #include <stdio.h>
00020 #include <windows.h>
00021 
00022 #include "util.h"
00023 
00024 #include "getopt.h"
00025 
00026 namespace {
00027 
00028 void Usage() {
00029   printf(
00030 "usage: ninja -t msvc [options] -- cl.exe /showIncludes /otherArgs\n"
00031 "options:\n"
00032 "  -e ENVFILE load environment block from ENVFILE as environment\n"
00033 "  -o FILE    write output dependency information to FILE.d\n"
00034          );
00035 }
00036 
00037 void PushPathIntoEnvironment(const string& env_block) {
00038   const char* as_str = env_block.c_str();
00039   while (as_str[0]) {
00040     if (_strnicmp(as_str, "path=", 5) == 0) {
00041       _putenv(as_str);
00042       return;
00043     } else {
00044       as_str = &as_str[strlen(as_str) + 1];
00045     }
00046   }
00047 }
00048 
00049 void WriteDepFileOrDie(const char* object_path, const CLParser& parse) {
00050   string depfile_path = string(object_path) + ".d";
00051   FILE* depfile = fopen(depfile_path.c_str(), "w");
00052   if (!depfile) {
00053     unlink(object_path);
00054     Fatal("opening %s: %s", depfile_path.c_str(),
00055           GetLastErrorString().c_str());
00056   }
00057   if (fprintf(depfile, "%s: ", object_path) < 0) {
00058     unlink(object_path);
00059     fclose(depfile);
00060     unlink(depfile_path.c_str());
00061     Fatal("writing %s", depfile_path.c_str());
00062   }
00063   const set<string>& headers = parse.includes_;
00064   for (set<string>::const_iterator i = headers.begin();
00065        i != headers.end(); ++i) {
00066     if (fprintf(depfile, "%s\n", EscapeForDepfile(*i).c_str()) < 0) {
00067       unlink(object_path);
00068       fclose(depfile);
00069       unlink(depfile_path.c_str());
00070       Fatal("writing %s", depfile_path.c_str());
00071     }
00072   }
00073   fclose(depfile);
00074 }
00075 
00076 }  // anonymous namespace
00077 
00078 int MSVCHelperMain(int argc, char** argv) {
00079   const char* output_filename = NULL;
00080   const char* envfile = NULL;
00081 
00082   const option kLongOptions[] = {
00083     { "help", no_argument, NULL, 'h' },
00084     { NULL, 0, NULL, 0 }
00085   };
00086   int opt;
00087   while ((opt = getopt_long(argc, argv, "e:o:h", kLongOptions, NULL)) != -1) {
00088     switch (opt) {
00089       case 'e':
00090         envfile = optarg;
00091         break;
00092       case 'o':
00093         output_filename = optarg;
00094         break;
00095       case 'h':
00096       default:
00097         Usage();
00098         return 0;
00099     }
00100   }
00101 
00102   string env;
00103   if (envfile) {
00104     string err;
00105     if (ReadFile(envfile, &env, &err) != 0)
00106       Fatal("couldn't open %s: %s", envfile, err.c_str());
00107     PushPathIntoEnvironment(env);
00108   }
00109 
00110   char* command = GetCommandLine();
00111   command = strstr(command, " -- ");
00112   if (!command) {
00113     Fatal("expected command line to end with \" -- command args\"");
00114   }
00115   command += 4;
00116 
00117   CLWrapper cl;
00118   if (!env.empty())
00119     cl.SetEnvBlock((void*)env.data());
00120   string output;
00121   int exit_code = cl.Run(command, &output);
00122 
00123   if (output_filename) {
00124     CLParser parser;
00125     output = parser.Parse(output);
00126     WriteDepFileOrDie(output_filename, parser);
00127   }
00128 
00129   // CLWrapper's output already as \r\n line endings, make sure the C runtime
00130   // doesn't expand this to \r\r\n.
00131   _setmode(_fileno(stdout), _O_BINARY);
00132   printf("%s", output.c_str());
00133 
00134   return exit_code;
00135 }