]> git.tdb.fi Git - builder.git/commitdiff
Add drivers for the MSVC toolchain
authorMikko Rasa <tdb@tdb.fi>
Tue, 31 Aug 2021 23:41:52 +0000 (02:41 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 1 Sep 2021 00:15:20 +0000 (03:15 +0300)
Shared libraries are not yet properly supported.  Import libraries are
not generated and all of my code lacks the necessary attributes anyway.

13 files changed:
Build
source/architecture.cpp
source/builder.cpp
source/microsofttools.cpp [new file with mode: 0644]
source/microsofttools.h [new file with mode: 0644]
source/msvcarchiver.cpp [new file with mode: 0644]
source/msvcarchiver.h [new file with mode: 0644]
source/msvccompiler.cpp [new file with mode: 0644]
source/msvccompiler.h [new file with mode: 0644]
source/msvclinker.cpp [new file with mode: 0644]
source/msvclinker.h [new file with mode: 0644]
source/sysutils.cpp
source/sysutils.h

diff --git a/Build b/Build
index 1abaa6c143eab9824b66bdb60333861898dd7189..2363ad785cd8a760c4cab3d8ed4d2c58cf4661e1 100644 (file)
--- a/Build
+++ b/Build
@@ -10,6 +10,14 @@ package "builder"
        program "builder"
        {
                source "source";
+               if_arch "windows"
+               {
+                       build_info
+                       {
+                               library "ole32";
+                               library "advapi32";
+                       };
+               };
                install true;
        };
 
index 75a64607a395f7726357d52887fb06e65953277c..58f435d51ec10fd8d75cbe777ef0442c8b68c1c4 100644 (file)
@@ -68,6 +68,7 @@ const char *toolchains[] =
 {
        "gnu",
        "clang",
+       "msvc",
        0
 };
 
@@ -131,6 +132,8 @@ Architecture::Architecture(Builder &b, const string &spec):
        {
                if((system=="darwin" || system=="freebsd") && builder.get_vfs().find_binary("clang"))
                        toolchain = "clang";
+               else if(system=="windows" && native)
+                       toolchain = "msvc";
                else
                        toolchain = "gnu";
        }
@@ -142,18 +145,27 @@ Architecture::Architecture(Builder &b, const string &spec):
                name += format("-%s", fpu);
        name += format("-%d-%s-%s", bits, system, toolchain);
 
-       add_pattern<ObjectFile>("%.o");
        if(system=="windows")
        {
                add_pattern<SharedLibrary>("%.dll");
-               add_pattern<SharedLibrary>("lib%.dll");
-               add_pattern<ImportLibrary>("lib%.dll.a");
-               add_pattern<StaticLibrary>("lib%.a");
-               add_pattern<StaticLibrary>("%.lib");
+               if(toolchain=="msvc")
+               {
+                       add_pattern<ObjectFile>("%.obj");
+                       add_pattern<ImportLibrary>("%.lib");
+                       add_pattern<StaticLibrary>("%_static.lib");
+               }
+               else
+               {
+                       add_pattern<ObjectFile>("%.o");
+                       add_pattern<SharedLibrary>("lib%.dll");
+                       add_pattern<ImportLibrary>("lib%.dll.a");
+                       add_pattern<StaticLibrary>("lib%.a");
+               }
                add_pattern<Executable>("%.exe");
        }
        else
        {
+               add_pattern<ObjectFile>("%.o");
                if(system=="darwin")
                        add_pattern<SharedLibrary>("lib%.dylib");
                else
index 7ef1ea1dcfd6d498969647a4cc7fe6f71f669db1..65d7da48c3cd8be5e9e568df17148f12bdc7ceac 100644 (file)
@@ -17,6 +17,7 @@
 #include "datatool.h"
 #include "gnutools.h"
 #include "installedfile.h"
+#include "microsofttools.h"
 #include "package.h"
 #include "sharedlibrary.h"
 #include "sourcepackage.h"
@@ -89,6 +90,8 @@ void Builder::add_default_tools()
        const string &arch_tc = current_arch->get_toolchain();
        if(current_arch->get_system()=="android")
                toolchain.add_toolchain(new AndroidTools(*this, *current_arch));
+       else if(arch_tc=="msvc")
+               toolchain.add_toolchain(new MicrosoftTools(*this, *current_arch));
        else if(arch_tc=="clang")
                toolchain.add_toolchain(new ClangTools(*this, *current_arch));
        else if(arch_tc=="gnu")
diff --git a/source/microsofttools.cpp b/source/microsofttools.cpp
new file mode 100644 (file)
index 0000000..05edda5
--- /dev/null
@@ -0,0 +1,79 @@
+#include <msp/core/algorithm.h>
+#include <msp/fs/dir.h>
+#include <msp/strings/format.h>
+#include <msp/strings/utils.h>
+#include "builder.h"
+#include "externaltask.h"
+#include "logger.h"
+#include "microsofttools.h"
+#include "msvcarchiver.h"
+#include "msvccompiler.h"
+#include "msvclinker.h"
+#include "sysutils.h"
+
+using namespace std;
+using namespace Msp;
+
+MicrosoftTools::MicrosoftTools(Builder &builder, const Architecture &arch)
+{
+       find_vc_bin_dir(builder, arch);
+       find_windows_sdk_dir(builder);
+
+       add_tool(new MsvcCompiler(builder, arch, "CC", *this));
+       add_tool(new MsvcCompiler(builder, arch, "CXX", *this));
+       add_tool(new MsvcLinker(builder, arch, *this));
+       add_tool(new MsvcArchiver(builder, arch, *this));
+}
+
+void MicrosoftTools::find_vc_bin_dir(Builder &builder, const Architecture &arch)
+{
+       FS::Path program_files_x86 = get_program_files_x86_dir();
+
+       ExternalTask::Arguments argv;
+       argv.push_back((program_files_x86/"Microsoft Visual Studio"/"Installer"/"vswhere.exe").str());
+       argv.push_back("-latest");
+       argv.push_back("-property");
+       argv.push_back("installationPath");
+
+       builder.get_logger().log("auxcommands", format("Running %s", join(argv.begin(), argv.end())));
+
+       string output = ExternalTask::run_and_capture_output(argv, FS::Path(), true);
+       FS::Path vs_path = strip(output);
+
+       builder.get_logger().log("tools", format("Visual Studio found in %s", vs_path));
+
+       FS::Path vc_version_fn = vs_path/"VC"/"Auxiliary"/"Build"/"Microsoft.VCToolsVersion.v142.default.txt";
+       builder.get_logger().log("files", format("Reading %s", vc_version_fn));
+       char buffer[256];
+       unsigned len = IO::File(vc_version_fn.str()).read(buffer, sizeof(buffer));
+       string vc_version = strip(string(buffer, len));
+
+       builder.get_logger().log("tools", format("Detected MSVC version %s", vc_version));
+
+       const Architecture &native_arch = builder.get_native_arch();
+       string host = (native_arch.get_bits()==64 ? "Hostx64" : "Hostx86");
+       string target = (arch.get_bits()==64 ? "x64" : "x86");
+
+       vc_base_dir = vs_path/"VC"/"Tools"/"MSVC"/vc_version;
+       vc_bin_dir = vc_base_dir/"bin"/host/target;
+}
+
+void MicrosoftTools::find_windows_sdk_dir(Builder &builder)
+{
+       win_sdk_dir = get_registry_value<string>("HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0\\InstallationFolder");
+       if(win_sdk_dir.empty())
+               win_sdk_dir = get_program_files_x86_dir()/"Windows Kits"/"10";
+
+       builder.get_logger().log("files", format("Traversing %s", win_sdk_dir/"include"));
+       vector<string> sdk_versions = FS::list_filtered(win_sdk_dir/"include", "^10\\.");
+       if(sdk_versions.empty())
+       {
+               builder.get_logger().log("problems", "No Windows SDK versions found");
+               return;
+       }
+
+       sort(sdk_versions);
+       win_sdk_version = sdk_versions.back();
+
+       builder.get_logger().log("tools", format("Windows SDK version %s found in %s", win_sdk_version, win_sdk_dir));
+}
diff --git a/source/microsofttools.h b/source/microsofttools.h
new file mode 100644 (file)
index 0000000..027499a
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef MICROSOFTTOOLS_H_
+#define MICROSOFTTOOLS_H_
+
+#include <msp/fs/path.h>
+#include "toolchain.h"
+
+class Architecture;
+class Builder;
+
+class MicrosoftTools: public Toolchain
+{
+private:
+       Msp::FS::Path vc_base_dir;
+       Msp::FS::Path vc_bin_dir;
+       Msp::FS::Path win_sdk_dir;
+       std::string win_sdk_version;
+
+public:
+       MicrosoftTools(Builder &, const Architecture &);
+
+private:
+       void find_vc_bin_dir(Builder &, const Architecture &);
+       void find_windows_sdk_dir(Builder &);
+
+public:
+       const Msp::FS::Path &get_vc_base_dir() const { return vc_base_dir; }
+       const Msp::FS::Path &get_vc_bin_dir() const { return vc_bin_dir; }
+       const Msp::FS::Path &get_windows_sdk_dir() const { return win_sdk_dir; }
+       const std::string &get_windows_sdk_version() const { return win_sdk_version; }
+};
+
+#endif
diff --git a/source/msvcarchiver.cpp b/source/msvcarchiver.cpp
new file mode 100644 (file)
index 0000000..1481184
--- /dev/null
@@ -0,0 +1,66 @@
+#include <msp/fs/utils.h>
+#include "component.h"
+#include "externaltask.h"
+#include "microsofttools.h"
+#include "msvcarchiver.h"
+#include "objectfile.h"
+#include "sourcepackage.h"
+#include "staticlibrary.h"
+
+using namespace std;
+using namespace Msp;
+
+MsvcArchiver::MsvcArchiver(Builder &b, const Architecture &a, const MicrosoftTools &m):
+       Tool(b, a, "AR"),
+       ms_tools(m)
+{
+       input_suffixes.push_back(".o");
+       processing_unit = COMPONENT;
+       set_command((ms_tools.get_vc_bin_dir()/"lib.exe").str(), false);
+}
+
+Target *MsvcArchiver::create_target(const list<Target *> &sources, const string &)
+{
+       if(sources.empty())
+               throw invalid_argument("MsvcArchiver::create_target");
+
+       list<ObjectFile *> objs;
+       for(list<Target *>::const_iterator i=sources.begin(); i!=sources.end(); ++i)
+       {
+               if(ObjectFile *obj = dynamic_cast<ObjectFile *>(*i))
+                       objs.push_back(obj);
+               else
+                       throw invalid_argument("MsvcArchiver::create_target");
+       }
+
+       const Component &comp = *objs.front()->get_component();
+       StaticLibrary *lib = new StaticLibrary(builder, comp, objs);
+       lib->set_tool(*this);
+       return lib;
+}
+
+string MsvcArchiver::create_build_signature(const BuildInfo &) const
+{
+       return FS::basename(executable->get_path());
+}
+
+Task *MsvcArchiver::run(const Target &target) const
+{
+       const StaticLibrary &lib = dynamic_cast<const StaticLibrary &>(target);
+       const Component &comp = *lib.get_component();
+
+       vector<string> argv;
+       argv.push_back(executable->get_path().str());
+       argv.push_back("/NOLOGO");
+
+       FS::Path work_dir = comp.get_package().get_source_directory();
+
+       argv.push_back("/OUT:"+relative(lib.get_path(), work_dir).str());
+
+       const Target::Dependencies &deps = lib.get_dependencies();
+       for(Target::Dependencies::const_iterator i=deps.begin(); i!=deps.end(); ++i)
+               if(ObjectFile *obj = dynamic_cast<ObjectFile *>(*i))
+                       argv.push_back(relative(obj->get_path(), work_dir).str());
+
+       return new ExternalTask(argv, work_dir);
+}
diff --git a/source/msvcarchiver.h b/source/msvcarchiver.h
new file mode 100644 (file)
index 0000000..0467ffb
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef MSVCARCHIVER_H_
+#define MSVCARCHIVER_H_
+
+#include "tool.h"
+
+class MicrosoftTools;
+
+class MsvcArchiver: public Tool
+{
+private:
+       const MicrosoftTools &ms_tools;
+
+public:
+       MsvcArchiver(Builder &, const Architecture &, const MicrosoftTools &);
+
+       virtual Target *create_target(const std::list<Target *> &, const std::string &);
+       virtual std::string create_build_signature(const BuildInfo &) const;
+
+       virtual Task *run(const Target &) const;
+};
+
+#endif
diff --git a/source/msvccompiler.cpp b/source/msvccompiler.cpp
new file mode 100644 (file)
index 0000000..12668a6
--- /dev/null
@@ -0,0 +1,180 @@
+#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);
+}
diff --git a/source/msvccompiler.h b/source/msvccompiler.h
new file mode 100644 (file)
index 0000000..2a6f91f
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef MSVCCOMPILER_H_
+#define MSVCCOMPILER_H_
+
+#include "tool.h"
+
+class MicrosoftTools;
+
+class MsvcCompiler: public Tool
+{
+private:
+       const MicrosoftTools &ms_tools;
+
+public:
+       MsvcCompiler(Builder &, const Architecture &, const std::string &, const MicrosoftTools &);
+
+       virtual Target *create_source(const Component &, const Msp::FS::Path &) const;
+       virtual Target *create_source(const Msp::FS::Path &) const;
+       virtual Target *create_target(const std::list<Target *> &, const std::string &);
+       virtual std::string create_build_signature(const BuildInfo &) const;
+
+protected:
+       virtual void do_prepare();
+
+public:
+       virtual Task *run(const Target &) const;
+};
+
+#endif
diff --git a/source/msvclinker.cpp b/source/msvclinker.cpp
new file mode 100644 (file)
index 0000000..46d89f7
--- /dev/null
@@ -0,0 +1,134 @@
+#include <msp/core/environ.h>
+#include <msp/fs/utils.h>
+#include <msp/strings/format.h>
+#include <msp/strings/utils.h>
+#include "builder.h"
+#include "component.h"
+#include "executable.h"
+#include "externaltask.h"
+#include "importlibrary.h"
+#include "microsofttools.h"
+#include "msvclinker.h"
+#include "objectfile.h"
+#include "sharedlibrary.h"
+#include "sourcepackage.h"
+#include "staticlibrary.h"
+
+using namespace std;
+using namespace Msp;
+
+MsvcLinker::MsvcLinker(Builder &b, const Architecture &a, const MicrosoftTools &m):
+       Tool(b, a, "LINK"),
+       ms_tools(m)
+{
+       input_suffixes.push_back(".o");
+       input_suffixes.push_back(".a");
+
+       processing_unit = COMPONENT;
+
+       set_command((ms_tools.get_vc_bin_dir()/"link.exe").str(), false);
+}
+
+Target *MsvcLinker::create_target(const list<Target *> &sources, const string &arg)
+{
+       if(sources.empty())
+               throw invalid_argument("MsvcLinker::create_target");
+
+       list<ObjectFile *> objs;
+       for(list<Target *>::const_iterator i=sources.begin(); i!=sources.end(); ++i)
+       {
+               if(ObjectFile *obj = dynamic_cast<ObjectFile *>(*i))
+                       objs.push_back(obj);
+               else
+                       throw invalid_argument("MsvcLinker::create_target");
+       }
+
+       const Component &comp = *objs.front()->get_component();
+       Binary *bin = 0;
+       if(arg=="shared")
+               bin = new SharedLibrary(builder, comp, objs);
+       else
+               bin = new Executable(builder, comp, objs);
+       bin->set_tool(*this);
+       return bin;
+}
+
+string MsvcLinker::create_build_signature(const BuildInfo &binfo) const
+{
+       string result = FS::basename(executable->get_path());
+       result += ',';
+       if(binfo.strip)
+               result += 's';
+       if(!binfo.libs.empty())
+       {
+               result += ",l";
+               result += join(binfo.libs.begin(), binfo.libs.end(), ",l");
+       }
+       return result;
+}
+
+void MsvcLinker::do_prepare()
+{
+       string arch_dir = (architecture->get_bits()==64 ? "x64" : "x86");
+
+       const FS::Path &vc_base_dir = ms_tools.get_vc_base_dir();
+       system_path.push_back(vc_base_dir/"lib"/arch_dir);
+
+       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/"lib"/win_sdk_ver/"ucrt"/arch_dir);
+       system_path.push_back(win_sdk_dir/"lib"/win_sdk_ver/"um"/arch_dir);
+
+       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("LIB", path);
+}
+
+Task *MsvcLinker::run(const Target &target) const
+{
+       const Binary &bin = dynamic_cast<const Binary &>(target);
+
+       vector<string> argv;
+       argv.push_back(executable->get_path().str());
+       argv.push_back("/NOLOGO");
+
+       FS::Path work_dir = bin.get_component()->get_package().get_source_directory();
+
+       if(dynamic_cast<const SharedLibrary *>(&bin))
+               argv.push_back("/DLL");
+
+       BuildInfo binfo;
+       target.collect_build_info(binfo);
+
+       /*for(BuildInfo::PathList::const_iterator i=binfo.libpath.begin(); i!=binfo.libpath.end(); ++i)
+               argv.push_back("/LIBPATH:"+i->str());*/
+       if(binfo.strip)
+               argv.push_back("/INCREMENTAL:NO");
+       else
+               argv.push_back("/DEBUG:FULL");
+
+       argv.push_back("/OUT:"+relative(bin.get_path(), work_dir).str());
+
+       const Target::Dependencies &depends = target.get_dependencies();
+       for(Target::Dependencies::const_iterator i=depends.begin(); i!=depends.end(); ++i)
+       {
+               FileTarget *file = dynamic_cast<FileTarget *>(*i);
+               Target *tgt = (*i)->get_real_target();
+
+               if(ObjectFile *obj = dynamic_cast<ObjectFile *>(tgt))
+                       argv.push_back(relative(obj->get_path(), work_dir).str());
+               else if(StaticLibrary *stlib = dynamic_cast<StaticLibrary *>(tgt))
+                       argv.push_back((file?file:stlib)->get_path().str());
+               else if(ImportLibrary *imp = dynamic_cast<ImportLibrary *>(tgt))
+                       argv.push_back((file?file:imp)->get_path().str());
+       }
+
+       argv.push_back("/SUBSYSTEM:CONSOLE");
+
+       return new ExternalTask(argv, work_dir);
+}
diff --git a/source/msvclinker.h b/source/msvclinker.h
new file mode 100644 (file)
index 0000000..50f8a7b
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef MSVCLINKER_H_
+#define MSVCLINKER_H_
+
+#include "tool.h"
+
+class MicrosoftTools;
+
+class MsvcLinker: public Tool
+{
+private:
+       const MicrosoftTools &ms_tools;
+
+public:
+       MsvcLinker(Builder &, const Architecture &, const MicrosoftTools &);
+
+       virtual Target *create_target(const std::list<Target *> &, const std::string &);
+       virtual std::string create_build_signature(const BuildInfo &) const;
+
+protected:
+       virtual void do_prepare();
+
+public:
+       virtual Task *run(const Target &) const;
+};
+
+#endif
index 8fa3d4894924333581810cb9d19a015c26573057..95867b70fcfb1b21cdca897bef91633a40bdcf53 100644 (file)
@@ -1,9 +1,16 @@
+#define _WIN32_WINNT _WIN32_WINNT_VISTA
 #define WIN32_LEAN_AND_MEAN
+#define INITGUID
 #ifdef _WIN32
 #include <windows.h>
+#include <shlobj.h>
+#include <knownfolders.h>
 #else
 #include <sys/utsname.h>
 #endif
+#include <msp/core/systemerror.h>
+#include <msp/stringcodec/utf16.h>
+#include <msp/stringcodec/utf8.h>
 #include <msp/strings/format.h>
 #include <msp/strings/utils.h>
 #include "sysutils.h"
@@ -33,3 +40,74 @@ string get_system_type()
 
        return string();
 }
+
+FS::Path get_program_files_x86_dir()
+{
+#ifdef _WIN32
+       wchar_t *program_files_x86_ptr = 0;
+       HRESULT err = SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, NULL, &program_files_x86_ptr);
+       if(err!=S_OK)
+               throw runtime_error("Can't get Program Files path");
+
+       unsigned len = wcslen(program_files_x86_ptr);
+       FS::Path program_files_x86 = StringCodec::transcode<StringCodec::Utf16Le, StringCodec::Utf8>(
+               string(reinterpret_cast<const char *>(program_files_x86_ptr), len*sizeof(wchar_t)));
+
+       CoTaskMemFree(program_files_x86_ptr);
+
+       return program_files_x86;
+#else
+       return "/mnt/c/Program Files (x86)";
+#endif
+}
+
+template<>
+string get_registry_value<string>(const string &path)
+{
+#ifdef _WIN32
+       string::size_type first_sep = path.find('\\');
+       string::size_type last_sep = path.rfind('\\');
+       string root = path.substr(0, first_sep);
+       string key_path = path.substr(first_sep+1, last_sep-first_sep-1);
+       string value_name = path.substr(last_sep+1);
+
+       HKEY root_handle;
+       if(root=="HKCR")
+               root_handle = HKEY_CLASSES_ROOT;
+       else if(root=="HKCC")
+               root_handle = HKEY_CURRENT_CONFIG;
+       else if(root=="HKCU")
+               root_handle = HKEY_CURRENT_USER;
+       else if(root=="HKLM")
+               root_handle = HKEY_LOCAL_MACHINE;
+       else if(root=="HKU")
+               root_handle = HKEY_USERS;
+       else
+               throw invalid_argument("get_registry_value");
+
+       HKEY key;
+       LSTATUS err = RegOpenKeyEx(root_handle, key_path.c_str(), 0, KEY_READ, &key);
+       if(err!=ERROR_SUCCESS)
+               throw Msp::system_error("RegOpenKey", err);
+
+       DWORD value_len;
+       err = RegGetValue(key, 0, value_name.c_str(), RRF_RT_REG_SZ, 0, 0, &value_len);
+       if(err!=ERROR_SUCCESS)
+               throw Msp::system_error("RegGetValue", err);
+
+       char *buffer = new char[value_len];
+       err = RegGetValue(key, 0, value_name.c_str(), RRF_RT_REG_SZ, 0, buffer, &value_len);
+       if(err!=ERROR_SUCCESS)
+       {
+               delete[] buffer;
+               throw Msp::system_error("RegGetValue", err);
+       }
+
+       string result(buffer);
+       delete[] buffer;
+       return result;
+#else
+       (void)path;
+       return string();
+#endif
+}
index c422b7fcf035c48c89a92c0505a76948e4bdbec2..730086968b2e68bfe61ad4ebc762a4d2f78f96c7 100644 (file)
@@ -2,7 +2,12 @@
 #define SYSUTILS_H_
 
 #include <string>
+#include <msp/fs/path.h>
 
 std::string get_system_type();
+Msp::FS::Path get_program_files_x86_dir();
+
+template<typename T>
+T get_registry_value(const std::string &);
 
 #endif