| // Copyright 2011 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "msvc_helper.h" |
| |
| #include <fcntl.h> |
| #include <io.h> |
| #include <stdio.h> |
| #include <windows.h> |
| |
| #include "clparser.h" |
| #include "util.h" |
| |
| #include "getopt.h" |
| |
| using namespace std; |
| |
| namespace { |
| |
| void Usage() { |
| printf( |
| "usage: ninja -t msvc [options] -- cl.exe /showIncludes /otherArgs\n" |
| "options:\n" |
| " -e ENVFILE load environment block from ENVFILE as environment\n" |
| " -o FILE write output dependency information to FILE.d\n" |
| " -p STRING localized prefix of msvc's /showIncludes output\n" |
| ); |
| } |
| |
| void PushPathIntoEnvironment(const string& env_block) { |
| const char* as_str = env_block.c_str(); |
| while (as_str[0]) { |
| if (_strnicmp(as_str, "path=", 5) == 0) { |
| _putenv(as_str); |
| return; |
| } else { |
| as_str = &as_str[strlen(as_str) + 1]; |
| } |
| } |
| } |
| |
| void WriteDepFileOrDie(const char* object_path, const CLParser& parse) { |
| string depfile_path = string(object_path) + ".d"; |
| FILE* depfile = fopen(depfile_path.c_str(), "w"); |
| if (!depfile) { |
| unlink(object_path); |
| Fatal("opening %s: %s", depfile_path.c_str(), |
| GetLastErrorString().c_str()); |
| } |
| if (fprintf(depfile, "%s: ", object_path) < 0) { |
| unlink(object_path); |
| fclose(depfile); |
| unlink(depfile_path.c_str()); |
| Fatal("writing %s", depfile_path.c_str()); |
| } |
| const set<string>& headers = parse.includes_; |
| for (set<string>::const_iterator i = headers.begin(); |
| i != headers.end(); ++i) { |
| if (fprintf(depfile, "%s\n", EscapeForDepfile(*i).c_str()) < 0) { |
| unlink(object_path); |
| fclose(depfile); |
| unlink(depfile_path.c_str()); |
| Fatal("writing %s", depfile_path.c_str()); |
| } |
| } |
| fclose(depfile); |
| } |
| |
| } // anonymous namespace |
| |
| int MSVCHelperMain(int argc, char** argv) { |
| const char* output_filename = NULL; |
| const char* envfile = NULL; |
| |
| const option kLongOptions[] = { |
| { "help", no_argument, NULL, 'h' }, |
| { NULL, 0, NULL, 0 } |
| }; |
| int opt; |
| string deps_prefix; |
| while ((opt = getopt_long(argc, argv, "e:o:p:h", kLongOptions, NULL)) != -1) { |
| switch (opt) { |
| case 'e': |
| envfile = optarg; |
| break; |
| case 'o': |
| output_filename = optarg; |
| break; |
| case 'p': |
| deps_prefix = optarg; |
| break; |
| case 'h': |
| default: |
| Usage(); |
| return 0; |
| } |
| } |
| |
| string env; |
| if (envfile) { |
| string err; |
| if (ReadFile(envfile, &env, &err) != 0) |
| Fatal("couldn't open %s: %s", envfile, err.c_str()); |
| PushPathIntoEnvironment(env); |
| } |
| |
| char* command = GetCommandLineA(); |
| command = strstr(command, " -- "); |
| if (!command) { |
| Fatal("expected command line to end with \" -- command args\""); |
| } |
| command += 4; |
| |
| CLWrapper cl; |
| if (!env.empty()) |
| cl.SetEnvBlock((void*)env.data()); |
| string output; |
| int exit_code = cl.Run(command, &output); |
| |
| if (output_filename) { |
| CLParser parser; |
| string err; |
| if (!parser.Parse(output, deps_prefix, &output, &err)) |
| Fatal("%s\n", err.c_str()); |
| WriteDepFileOrDie(output_filename, parser); |
| } |
| |
| if (output.empty()) |
| return exit_code; |
| |
| // CLWrapper's output already as \r\n line endings, make sure the C runtime |
| // doesn't expand this to \r\r\n. |
| _setmode(_fileno(stdout), _O_BINARY); |
| // Avoid printf and C strings, since the actual output might contain null |
| // bytes like UTF-16 does (yuck). |
| fwrite(&output[0], 1, output.size(), stdout); |
| |
| return exit_code; |
| } |