]> git.tdb.fi Git - builder.git/blob - source/msvccompiler.cpp
7d751dea1882ecf2ea3cde2d946856c5768f10eb
[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(ToolData &tool) const
77 {
78         const std::string &tool_tag = static_cast<Tool &>(tool).get_tag();
79
80         const FS::Path &vc_base_dir = ms_tools.get_vc_base_dir();
81         tool.system_path.push_back(vc_base_dir/"include");
82
83         const FS::Path &win_sdk_dir = ms_tools.get_windows_sdk_dir();
84         const string &win_sdk_ver = ms_tools.get_windows_sdk_version();
85         tool.system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"ucrt");
86         tool.system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"shared");
87         tool.system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"um");
88
89         string path;
90         for(const FS::Path &p: tool.system_path)
91         {
92                 append(path, ";", p.str());
93                 builder.get_logger().log("tools", "Got %s system path: %s", tool_tag, p);
94         }
95
96         setenv("INCLUDE", path);
97 }
98
99 Task *MsvcCompiler::_run(const ObjectFile &object)
100 {
101         const Tool &tool = *object.get_tool();
102
103         ExternalTask::Arguments argv;
104         argv.push_back(tool.get_executable()->get_path().str());
105         argv.push_back("/nologo");
106         argv.push_back("/c");
107
108         BuildInfo binfo;
109         object.collect_build_info(binfo);
110
111         if(binfo.standards.count(tool.get_tag()))
112         {
113                 const BuildInfo::LanguageStandard &std = get_item(binfo.standards, tool.get_tag());
114                 if((tool.get_tag()=="CXX" && std.year>2011) || (tool.get_tag()=="CC" && std.year>1999))
115                         argv.push_back("/std:"+std.str());
116         }
117
118         if(binfo.warning_level>=1)
119         {
120                 argv.push_back(format("/W%d", binfo.warning_level));
121                 if(binfo.fatal_warnings)
122                         argv.push_back("/WX");
123                 if(binfo.warning_level>=3)
124                         argv.push_back("/permissive-");
125
126                 argv.push_back("/wd4068");  // Unknown pragma
127                 if(binfo.warning_level<4)
128                 {
129                         argv.push_back("/wd4244");  // Narrowing conversion on arg or return
130                         argv.push_back("/wd4267");  // Narrowing conversion
131                 }
132         }
133         else
134                 argv.push_back("/w");
135
136         for(const FS::Path &p: binfo.local_incpath)
137         {
138                 argv.push_back("/I");
139                 argv.push_back(p.str());
140         }
141         for(const FS::Path &p: binfo.incpath)
142         {
143                 argv.push_back("/I");
144                 argv.push_back(p.str());
145         }
146
147         for(const auto &kvp: binfo.defines)
148         {
149                 argv.push_back("/D");
150                 if(kvp.second.empty())
151                         argv.push_back(kvp.first);
152                 else
153                         argv.push_back(format("%s=%s", kvp.first, kvp.second));
154         }
155
156         if(binfo.debug)
157                 argv.push_back("/Z7");
158         if(binfo.optimize)
159         {
160                 if(binfo.optimize<0)
161                         argv.push_back("/O1");
162                 else if(binfo.optimize==1)
163                         argv.push_back("/Ox");
164                 else
165                         argv.push_back("/O2");
166         }
167
168         if(binfo.libmode<=BuildInfo::STATIC)
169                 argv.push_back(binfo.debug ? "/MTd" : "/MT");
170         else
171                 argv.push_back(binfo.debug ? "/MDd" : "/MD");
172
173         argv.push_back("/EHsc");
174
175         FS::Path obj_path = object.get_path();
176         FS::Path src_path = object.get_source().get_path();
177         FS::Path work_dir = object.get_component()->get_package().get_source_directory();
178
179         argv.push_back("/Fo"+relative(obj_path, work_dir).str());
180         argv.push_back(relative(src_path, work_dir).str());
181
182         return new ExternalTask(argv, work_dir);
183 }