1695b41eeSopenharmony_ci// Copyright 2011 Google Inc. All Rights Reserved.
2695b41eeSopenharmony_ci//
3695b41eeSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4695b41eeSopenharmony_ci// you may not use this file except in compliance with the License.
5695b41eeSopenharmony_ci// You may obtain a copy of the License at
6695b41eeSopenharmony_ci//
7695b41eeSopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8695b41eeSopenharmony_ci//
9695b41eeSopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10695b41eeSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11695b41eeSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12695b41eeSopenharmony_ci// See the License for the specific language governing permissions and
13695b41eeSopenharmony_ci// limitations under the License.
14695b41eeSopenharmony_ci
15695b41eeSopenharmony_ci#include "msvc_helper.h"
16695b41eeSopenharmony_ci
17695b41eeSopenharmony_ci#include <fcntl.h>
18695b41eeSopenharmony_ci#include <io.h>
19695b41eeSopenharmony_ci#include <stdio.h>
20695b41eeSopenharmony_ci#include <windows.h>
21695b41eeSopenharmony_ci
22695b41eeSopenharmony_ci#include "clparser.h"
23695b41eeSopenharmony_ci#include "util.h"
24695b41eeSopenharmony_ci
25695b41eeSopenharmony_ci#include "getopt.h"
26695b41eeSopenharmony_ci
27695b41eeSopenharmony_ciusing namespace std;
28695b41eeSopenharmony_ci
29695b41eeSopenharmony_cinamespace {
30695b41eeSopenharmony_ci
31695b41eeSopenharmony_civoid Usage() {
32695b41eeSopenharmony_ci  printf(
33695b41eeSopenharmony_ci"usage: ninja -t msvc [options] -- cl.exe /showIncludes /otherArgs\n"
34695b41eeSopenharmony_ci"options:\n"
35695b41eeSopenharmony_ci"  -e ENVFILE load environment block from ENVFILE as environment\n"
36695b41eeSopenharmony_ci"  -o FILE    write output dependency information to FILE.d\n"
37695b41eeSopenharmony_ci"  -p STRING  localized prefix of msvc's /showIncludes output\n"
38695b41eeSopenharmony_ci         );
39695b41eeSopenharmony_ci}
40695b41eeSopenharmony_ci
41695b41eeSopenharmony_civoid PushPathIntoEnvironment(const string& env_block) {
42695b41eeSopenharmony_ci  const char* as_str = env_block.c_str();
43695b41eeSopenharmony_ci  while (as_str[0]) {
44695b41eeSopenharmony_ci    if (_strnicmp(as_str, "path=", 5) == 0) {
45695b41eeSopenharmony_ci      _putenv(as_str);
46695b41eeSopenharmony_ci      return;
47695b41eeSopenharmony_ci    } else {
48695b41eeSopenharmony_ci      as_str = &as_str[strlen(as_str) + 1];
49695b41eeSopenharmony_ci    }
50695b41eeSopenharmony_ci  }
51695b41eeSopenharmony_ci}
52695b41eeSopenharmony_ci
53695b41eeSopenharmony_civoid WriteDepFileOrDie(const char* object_path, const CLParser& parse) {
54695b41eeSopenharmony_ci  string depfile_path = string(object_path) + ".d";
55695b41eeSopenharmony_ci  FILE* depfile = fopen(depfile_path.c_str(), "w");
56695b41eeSopenharmony_ci  if (!depfile) {
57695b41eeSopenharmony_ci    unlink(object_path);
58695b41eeSopenharmony_ci    Fatal("opening %s: %s", depfile_path.c_str(),
59695b41eeSopenharmony_ci          GetLastErrorString().c_str());
60695b41eeSopenharmony_ci  }
61695b41eeSopenharmony_ci  if (fprintf(depfile, "%s: ", object_path) < 0) {
62695b41eeSopenharmony_ci    unlink(object_path);
63695b41eeSopenharmony_ci    fclose(depfile);
64695b41eeSopenharmony_ci    unlink(depfile_path.c_str());
65695b41eeSopenharmony_ci    Fatal("writing %s", depfile_path.c_str());
66695b41eeSopenharmony_ci  }
67695b41eeSopenharmony_ci  const set<string>& headers = parse.includes_;
68695b41eeSopenharmony_ci  for (set<string>::const_iterator i = headers.begin();
69695b41eeSopenharmony_ci       i != headers.end(); ++i) {
70695b41eeSopenharmony_ci    if (fprintf(depfile, "%s\n", EscapeForDepfile(*i).c_str()) < 0) {
71695b41eeSopenharmony_ci      unlink(object_path);
72695b41eeSopenharmony_ci      fclose(depfile);
73695b41eeSopenharmony_ci      unlink(depfile_path.c_str());
74695b41eeSopenharmony_ci      Fatal("writing %s", depfile_path.c_str());
75695b41eeSopenharmony_ci    }
76695b41eeSopenharmony_ci  }
77695b41eeSopenharmony_ci  fclose(depfile);
78695b41eeSopenharmony_ci}
79695b41eeSopenharmony_ci
80695b41eeSopenharmony_ci}  // anonymous namespace
81695b41eeSopenharmony_ci
82695b41eeSopenharmony_ciint MSVCHelperMain(int argc, char** argv) {
83695b41eeSopenharmony_ci  const char* output_filename = NULL;
84695b41eeSopenharmony_ci  const char* envfile = NULL;
85695b41eeSopenharmony_ci
86695b41eeSopenharmony_ci  const option kLongOptions[] = {
87695b41eeSopenharmony_ci    { "help", no_argument, NULL, 'h' },
88695b41eeSopenharmony_ci    { NULL, 0, NULL, 0 }
89695b41eeSopenharmony_ci  };
90695b41eeSopenharmony_ci  int opt;
91695b41eeSopenharmony_ci  string deps_prefix;
92695b41eeSopenharmony_ci  while ((opt = getopt_long(argc, argv, "e:o:p:h", kLongOptions, NULL)) != -1) {
93695b41eeSopenharmony_ci    switch (opt) {
94695b41eeSopenharmony_ci      case 'e':
95695b41eeSopenharmony_ci        envfile = optarg;
96695b41eeSopenharmony_ci        break;
97695b41eeSopenharmony_ci      case 'o':
98695b41eeSopenharmony_ci        output_filename = optarg;
99695b41eeSopenharmony_ci        break;
100695b41eeSopenharmony_ci      case 'p':
101695b41eeSopenharmony_ci        deps_prefix = optarg;
102695b41eeSopenharmony_ci        break;
103695b41eeSopenharmony_ci      case 'h':
104695b41eeSopenharmony_ci      default:
105695b41eeSopenharmony_ci        Usage();
106695b41eeSopenharmony_ci        return 0;
107695b41eeSopenharmony_ci    }
108695b41eeSopenharmony_ci  }
109695b41eeSopenharmony_ci
110695b41eeSopenharmony_ci  string env;
111695b41eeSopenharmony_ci  if (envfile) {
112695b41eeSopenharmony_ci    string err;
113695b41eeSopenharmony_ci    if (ReadFile(envfile, &env, &err) != 0)
114695b41eeSopenharmony_ci      Fatal("couldn't open %s: %s", envfile, err.c_str());
115695b41eeSopenharmony_ci    PushPathIntoEnvironment(env);
116695b41eeSopenharmony_ci  }
117695b41eeSopenharmony_ci
118695b41eeSopenharmony_ci  char* command = GetCommandLineA();
119695b41eeSopenharmony_ci  command = strstr(command, " -- ");
120695b41eeSopenharmony_ci  if (!command) {
121695b41eeSopenharmony_ci    Fatal("expected command line to end with \" -- command args\"");
122695b41eeSopenharmony_ci  }
123695b41eeSopenharmony_ci  command += 4;
124695b41eeSopenharmony_ci
125695b41eeSopenharmony_ci  CLWrapper cl;
126695b41eeSopenharmony_ci  if (!env.empty())
127695b41eeSopenharmony_ci    cl.SetEnvBlock((void*)env.data());
128695b41eeSopenharmony_ci  string output;
129695b41eeSopenharmony_ci  int exit_code = cl.Run(command, &output);
130695b41eeSopenharmony_ci
131695b41eeSopenharmony_ci  if (output_filename) {
132695b41eeSopenharmony_ci    CLParser parser;
133695b41eeSopenharmony_ci    string err;
134695b41eeSopenharmony_ci    if (!parser.Parse(output, deps_prefix, &output, &err))
135695b41eeSopenharmony_ci      Fatal("%s\n", err.c_str());
136695b41eeSopenharmony_ci    WriteDepFileOrDie(output_filename, parser);
137695b41eeSopenharmony_ci  }
138695b41eeSopenharmony_ci
139695b41eeSopenharmony_ci  if (output.empty())
140695b41eeSopenharmony_ci    return exit_code;
141695b41eeSopenharmony_ci
142695b41eeSopenharmony_ci  // CLWrapper's output already as \r\n line endings, make sure the C runtime
143695b41eeSopenharmony_ci  // doesn't expand this to \r\r\n.
144695b41eeSopenharmony_ci  _setmode(_fileno(stdout), _O_BINARY);
145695b41eeSopenharmony_ci  // Avoid printf and C strings, since the actual output might contain null
146695b41eeSopenharmony_ci  // bytes like UTF-16 does (yuck).
147695b41eeSopenharmony_ci  fwrite(&output[0], 1, output.size(), stdout);
148695b41eeSopenharmony_ci
149695b41eeSopenharmony_ci  return exit_code;
150695b41eeSopenharmony_ci}
151