+#include <msp/core/environ.h>
+#include <msp/core/maputils.h>
+#include <msp/fs/utils.h>
+#include <msp/strings/format.h>
+#include <msp/strings/utils.h>
+#include "builder.h"
+#include "component.h"
+#include "csourcefile.h"
+#include "externaltask.h"
+#include "microsofttools.h"
+#include "msvccompiler.h"
+#include "objectfile.h"
+#include "sourcepackage.h"
+
+using namespace std;
+using namespace Msp;
+
+MsvcCompiler::MsvcCompiler(Builder &b, const Architecture &a, const string &t, const MicrosoftTools &m):
+ Tool(b, a, t),
+ ms_tools(m)
+{
+ if(tag=="CC")
+ {
+ input_suffixes.push_back(".c");
+ aux_suffixes.push_back(".h");
+ }
+ else if(tag=="CXX")
+ {
+ input_suffixes.push_back(".cpp");
+ input_suffixes.push_back(".cc");
+ aux_suffixes.push_back(".hpp");
+ }
+ else
+ throw invalid_argument("MsvcCompiler::MsvcCompiler");
+
+ set_command((ms_tools.get_vc_bin_dir()/"cl.exe").str(), false);
+}
+
+Target *MsvcCompiler::create_source(const Component &comp, const FS::Path &path) const
+{
+ return new CSourceFile(builder, comp, path);
+}
+
+Target *MsvcCompiler::create_source(const FS::Path &path) const
+{
+ return new CSourceFile(builder, path);
+}
+
+Target *MsvcCompiler::create_target(const list<Target *> &sources, const string &)
+{
+ if(sources.size()!=1)
+ throw invalid_argument("MsvcCompiler::create_target");
+ SourceFile &source = dynamic_cast<SourceFile &>(*sources.front());
+ ObjectFile *obj = new ObjectFile(builder, *source.get_component(), source);
+ obj->set_tool(*this);
+ return obj;
+}
+
+string MsvcCompiler::create_build_signature(const BuildInfo &binfo) const
+{
+ string result = FS::basename(executable->get_path());
+ result += ',';
+ if(binfo.debug)
+ result += 'g';
+ if(binfo.optimize)
+ {
+ result += 'O';
+ result += (binfo.optimize<0 ? '1' : binfo.optimize==1 ? 'x' : '2');
+ }
+ if(binfo.libmode<=BuildInfo::STATIC)
+ result += 't';
+ return result;
+}
+
+void MsvcCompiler::do_prepare()
+{
+ const FS::Path &vc_base_dir = ms_tools.get_vc_base_dir();
+ system_path.push_back(vc_base_dir/"include");
+
+ const FS::Path &win_sdk_dir = ms_tools.get_windows_sdk_dir();
+ const string &win_sdk_ver = ms_tools.get_windows_sdk_version();
+ system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"ucrt");
+ system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"shared");
+ system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"um");
+
+ string path;
+ for(SearchPath::const_iterator i=system_path.begin(); i!=system_path.end(); ++i)
+ {
+ append(path, ";", i->str());
+ builder.get_logger().log("tools", format("Got %s system path: %s", tag, *i));
+ }
+
+ setenv("INCLUDE", path);
+}
+
+Task *MsvcCompiler::run(const Target &target) const
+{
+ const ObjectFile &object = dynamic_cast<const ObjectFile &>(target);
+
+ ExternalTask::Arguments argv;
+ argv.push_back(executable->get_path().str());
+ argv.push_back("/nologo");
+ argv.push_back("/c");
+
+ BuildInfo binfo;
+ target.collect_build_info(binfo);
+
+ if(binfo.standards.count(tag))
+ {
+ string std = get_item(binfo.standards, tag);
+ if(std!="c++11" && std!="c99")
+ argv.push_back("/std:"+std);
+ }
+
+ if(binfo.warning_level>=1)
+ {
+ argv.push_back(format("/W%d", binfo.warning_level));
+ if(binfo.fatal_warnings)
+ argv.push_back("/WX");
+ if(binfo.warning_level>=3)
+ argv.push_back("/permissive-");
+
+ argv.push_back("/wd4068"); // Unknown pragma
+ if(binfo.warning_level<4)
+ {
+ argv.push_back("/wd4244"); // Narrowing conversion on arg or return
+ argv.push_back("/wd4267"); // Narrowing conversion
+ }
+ }
+ else
+ argv.push_back("/w");
+
+ for(BuildInfo::PathList::const_iterator i=binfo.local_incpath.begin(); i!=binfo.local_incpath.end(); ++i)
+ {
+ argv.push_back("/I");
+ argv.push_back(i->str());
+ }
+ for(BuildInfo::PathList::const_iterator i=binfo.incpath.begin(); i!=binfo.incpath.end(); ++i)
+ {
+ argv.push_back("/I");
+ argv.push_back(i->str());
+ }
+
+ for(BuildInfo::DefineMap::const_iterator i=binfo.defines.begin(); i!=binfo.defines.end(); ++i)
+ {
+ argv.push_back("/D");
+ if(i->second.empty())
+ argv.push_back(i->first);
+ else
+ argv.push_back(format("%s=%s", i->first, i->second));
+ }
+
+ if(binfo.debug)
+ argv.push_back("/Z7");
+ if(binfo.optimize)
+ {
+ if(binfo.optimize<0)
+ argv.push_back("/O1");
+ else if(binfo.optimize==1)
+ argv.push_back("/Ox");
+ else
+ argv.push_back("/O2");
+ }
+
+ if(binfo.libmode<=BuildInfo::STATIC)
+ argv.push_back(binfo.debug ? "/MTd" : "/MT");
+ else
+ argv.push_back(binfo.debug ? "/MDd" : "/MD");
+
+ argv.push_back("/EHsc");
+
+ FS::Path obj_path = object.get_path();
+ FS::Path src_path = object.get_source().get_path();
+ FS::Path work_dir = object.get_component()->get_package().get_source_directory();
+
+ argv.push_back("/Fo"+relative(obj_path, work_dir).str());
+ argv.push_back(relative(src_path, work_dir).str());
+
+ return new ExternalTask(argv, work_dir);
+}