]> git.tdb.fi Git - builder.git/blob - source/msvccompiler.cpp
Redesign how tools are run
[builder.git] / source / msvccompiler.cpp
1 #include <msp/core/environ.h>
2 #include <msp/core/maputils.h>
3 #include <msp/fs/utils.h>
4 #include <msp/strings/format.h>
5 #include <msp/strings/utils.h>
6 #include "builder.h"
7 #include "component.h"
8 #include "csourcefile.h"
9 #include "externaltask.h"
10 #include "microsofttools.h"
11 #include "msvccompiler.h"
12 #include "objectfile.h"
13 #include "sourcepackage.h"
14
15 using namespace std;
16 using namespace Msp;
17
18 MsvcCompiler::MsvcCompiler(Builder &b, const Architecture &a, const string &t, const MicrosoftTools &m):
19         Tool(b, a, t),
20         ms_tools(m)
21 {
22         if(tag=="CC")
23         {
24                 input_suffixes.push_back(".c");
25                 aux_suffixes.push_back(".h");
26         }
27         else if(tag=="CXX")
28         {
29                 input_suffixes.push_back(".cpp");
30                 input_suffixes.push_back(".cc");
31                 aux_suffixes.push_back(".hpp");
32         }
33         else
34                 throw invalid_argument("MsvcCompiler::MsvcCompiler");
35
36         set_command((ms_tools.get_vc_bin_dir()/"cl.exe").str(), false);
37         set_run(_run);
38 }
39
40 Target *MsvcCompiler::create_source(const Component &comp, const FS::Path &path) const
41 {
42         return new CSourceFile(builder, comp, path);
43 }
44
45 Target *MsvcCompiler::create_source(const FS::Path &path) const
46 {
47         return new CSourceFile(builder, path);
48 }
49
50 Target *MsvcCompiler::create_target(const vector<Target *> &sources, const string &)
51 {
52         if(sources.size()!=1)
53                 throw invalid_argument("MsvcCompiler::create_target");
54         SourceFile &source = dynamic_cast<SourceFile &>(*sources.front());
55         ObjectFile *obj = new ObjectFile(builder, *source.get_component(), source);
56         obj->set_tool(*this);
57         return obj;
58 }
59
60 string MsvcCompiler::create_build_signature(const BuildInfo &binfo) const
61 {
62         string result = Tool::create_build_signature(binfo);
63         result += ',';
64         if(binfo.debug)
65                 result += 'g';
66         if(binfo.optimize)
67         {
68                 result += 'O';
69                 result += (binfo.optimize<0 ? '1' : binfo.optimize==1 ? 'x' : '2');
70         }
71         if(binfo.libmode<=BuildInfo::STATIC)
72                 result += 't';
73         return result;
74 }
75
76 void MsvcCompiler::do_prepare()
77 {
78         const FS::Path &vc_base_dir = ms_tools.get_vc_base_dir();
79         system_path.push_back(vc_base_dir/"include");
80
81         const FS::Path &win_sdk_dir = ms_tools.get_windows_sdk_dir();
82         const string &win_sdk_ver = ms_tools.get_windows_sdk_version();
83         system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"ucrt");
84         system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"shared");
85         system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"um");
86
87         string path;
88         for(const FS::Path &p: system_path)
89         {
90                 append(path, ";", p.str());
91                 builder.get_logger().log("tools", "Got %s system path: %s", tag, p);
92         }
93
94         setenv("INCLUDE", path);
95 }
96
97 Task *MsvcCompiler::_run(const ObjectFile &object)
98 {
99         const Tool &tool = *object.get_tool();
100
101         ExternalTask::Arguments argv;
102         argv.push_back(tool.get_executable()->get_path().str());
103         argv.push_back("/nologo");
104         argv.push_back("/c");
105
106         BuildInfo binfo;
107         object.collect_build_info(binfo);
108
109         if(binfo.standards.count(tool.get_tag()))
110         {
111                 const BuildInfo::LanguageStandard &std = get_item(binfo.standards, tool.get_tag());
112                 if((tool.get_tag()=="CXX" && std.year>2011) || (tool.get_tag()=="CC" && std.year>1999))
113                         argv.push_back("/std:"+std.str());
114         }
115
116         if(binfo.warning_level>=1)
117         {
118                 argv.push_back(format("/W%d", binfo.warning_level));
119                 if(binfo.fatal_warnings)
120                         argv.push_back("/WX");
121                 if(binfo.warning_level>=3)
122                         argv.push_back("/permissive-");
123
124                 argv.push_back("/wd4068");  // Unknown pragma
125                 if(binfo.warning_level<4)
126                 {
127                         argv.push_back("/wd4244");  // Narrowing conversion on arg or return
128                         argv.push_back("/wd4267");  // Narrowing conversion
129                 }
130         }
131         else
132                 argv.push_back("/w");
133
134         for(const FS::Path &p: binfo.local_incpath)
135         {
136                 argv.push_back("/I");
137                 argv.push_back(p.str());
138         }
139         for(const FS::Path &p: binfo.incpath)
140         {
141                 argv.push_back("/I");
142                 argv.push_back(p.str());
143         }
144
145         for(const auto &kvp: binfo.defines)
146         {
147                 argv.push_back("/D");
148                 if(kvp.second.empty())
149                         argv.push_back(kvp.first);
150                 else
151                         argv.push_back(format("%s=%s", kvp.first, kvp.second));
152         }
153
154         if(binfo.debug)
155                 argv.push_back("/Z7");
156         if(binfo.optimize)
157         {
158                 if(binfo.optimize<0)
159                         argv.push_back("/O1");
160                 else if(binfo.optimize==1)
161                         argv.push_back("/Ox");
162                 else
163                         argv.push_back("/O2");
164         }
165
166         if(binfo.libmode<=BuildInfo::STATIC)
167                 argv.push_back(binfo.debug ? "/MTd" : "/MT");
168         else
169                 argv.push_back(binfo.debug ? "/MDd" : "/MD");
170
171         argv.push_back("/EHsc");
172
173         FS::Path obj_path = object.get_path();
174         FS::Path src_path = object.get_source().get_path();
175         FS::Path work_dir = object.get_component()->get_package().get_source_directory();
176
177         argv.push_back("/Fo"+relative(obj_path, work_dir).str());
178         argv.push_back(relative(src_path, work_dir).str());
179
180         return new ExternalTask(argv, work_dir);
181 }