]> git.tdb.fi Git - builder.git/blob - source/msvccompiler.cpp
Add drivers for the MSVC toolchain
[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 }
38
39 Target *MsvcCompiler::create_source(const Component &comp, const FS::Path &path) const
40 {
41         return new CSourceFile(builder, comp, path);
42 }
43
44 Target *MsvcCompiler::create_source(const FS::Path &path) const
45 {
46         return new CSourceFile(builder, path);
47 }
48
49 Target *MsvcCompiler::create_target(const list<Target *> &sources, const string &)
50 {
51         if(sources.size()!=1)
52                 throw invalid_argument("MsvcCompiler::create_target");
53         SourceFile &source = dynamic_cast<SourceFile &>(*sources.front());
54         ObjectFile *obj = new ObjectFile(builder, *source.get_component(), source);
55         obj->set_tool(*this);
56         return obj;
57 }
58
59 string MsvcCompiler::create_build_signature(const BuildInfo &binfo) const
60 {
61         string result = FS::basename(executable->get_path());
62         result += ',';
63         if(binfo.debug)
64                 result += 'g';
65         if(binfo.optimize)
66         {
67                 result += 'O';
68                 result += (binfo.optimize<0 ? '1' : binfo.optimize==1 ? 'x' : '2');
69         }
70         if(binfo.libmode<=BuildInfo::STATIC)
71                 result += 't';
72         return result;
73 }
74
75 void MsvcCompiler::do_prepare()
76 {
77         const FS::Path &vc_base_dir = ms_tools.get_vc_base_dir();
78         system_path.push_back(vc_base_dir/"include");
79
80         const FS::Path &win_sdk_dir = ms_tools.get_windows_sdk_dir();
81         const string &win_sdk_ver = ms_tools.get_windows_sdk_version();
82         system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"ucrt");
83         system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"shared");
84         system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"um");
85
86         string path;
87         for(SearchPath::const_iterator i=system_path.begin(); i!=system_path.end(); ++i)
88         {
89                 append(path, ";", i->str());
90                 builder.get_logger().log("tools", format("Got %s system path: %s", tag, *i));
91         }
92
93         setenv("INCLUDE", path);
94 }
95
96 Task *MsvcCompiler::run(const Target &target) const
97 {
98         const ObjectFile &object = dynamic_cast<const ObjectFile &>(target);
99
100         ExternalTask::Arguments argv;
101         argv.push_back(executable->get_path().str());
102         argv.push_back("/nologo");
103         argv.push_back("/c");
104
105         BuildInfo binfo;
106         target.collect_build_info(binfo);
107
108         if(binfo.standards.count(tag))
109         {
110                 string std = get_item(binfo.standards, tag);
111                 if(std!="c++11" && std!="c99")
112                         argv.push_back("/std:"+std);
113         }
114
115         if(binfo.warning_level>=1)
116         {
117                 argv.push_back(format("/W%d", binfo.warning_level));
118                 if(binfo.fatal_warnings)
119                         argv.push_back("/WX");
120                 if(binfo.warning_level>=3)
121                         argv.push_back("/permissive-");
122
123                 argv.push_back("/wd4068");  // Unknown pragma
124                 if(binfo.warning_level<4)
125                 {
126                         argv.push_back("/wd4244");  // Narrowing conversion on arg or return
127                         argv.push_back("/wd4267");  // Narrowing conversion
128                 }
129         }
130         else
131                 argv.push_back("/w");
132
133         for(BuildInfo::PathList::const_iterator i=binfo.local_incpath.begin(); i!=binfo.local_incpath.end(); ++i)
134         {
135                 argv.push_back("/I");
136                 argv.push_back(i->str());
137         }
138         for(BuildInfo::PathList::const_iterator i=binfo.incpath.begin(); i!=binfo.incpath.end(); ++i)
139         {
140                 argv.push_back("/I");
141                 argv.push_back(i->str());
142         }
143
144         for(BuildInfo::DefineMap::const_iterator i=binfo.defines.begin(); i!=binfo.defines.end(); ++i)
145         {
146                 argv.push_back("/D");
147                 if(i->second.empty())
148                         argv.push_back(i->first);
149                 else
150                         argv.push_back(format("%s=%s", i->first, i->second));
151         }
152
153         if(binfo.debug)
154                 argv.push_back("/Z7");
155         if(binfo.optimize)
156         {
157                 if(binfo.optimize<0)
158                         argv.push_back("/O1");
159                 else if(binfo.optimize==1)
160                         argv.push_back("/Ox");
161                 else
162                         argv.push_back("/O2");
163         }
164
165         if(binfo.libmode<=BuildInfo::STATIC)
166                 argv.push_back(binfo.debug ? "/MTd" : "/MT");
167         else
168                 argv.push_back(binfo.debug ? "/MDd" : "/MD");
169
170         argv.push_back("/EHsc");
171
172         FS::Path obj_path = object.get_path();
173         FS::Path src_path = object.get_source().get_path();
174         FS::Path work_dir = object.get_component()->get_package().get_source_directory();
175
176         argv.push_back("/Fo"+relative(obj_path, work_dir).str());
177         argv.push_back(relative(src_path, work_dir).str());
178
179         return new ExternalTask(argv, work_dir);
180 }