summaryrefslogtreecommitdiffstats
path: root/src/msvc_helper_main-win32.cc
blob: 3192821ac2dfdb6eab8567ec9ed7d3b9f9449eeb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// 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 <stdio.h>
#include <windows.h>

#include "util.h"

#include "getopt.h"

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"
         );
}

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>::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;
  while ((opt = getopt_long(argc, argv, "e:o:h", kLongOptions, NULL)) != -1) {
    switch (opt) {
      case 'e':
        envfile = optarg;
        break;
      case 'o':
        output_filename = 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 = GetCommandLine();
  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;
    output = parser.Parse(output);
    WriteDepFileOrDie(output_filename, parser);
  }
  printf("%s\n", output.c_str());

  return exit_code;
}