]> git.tdb.fi Git - builder.git/commitdiff
Move the VS project and solution generators to the MSVC plugin
authorMikko Rasa <tdb@tdb.fi>
Wed, 28 Dec 2022 13:47:10 +0000 (15:47 +0200)
committerMikko Rasa <tdb@tdb.fi>
Wed, 28 Dec 2022 15:39:13 +0000 (17:39 +0200)
21 files changed:
plugins/base/baseplugin.cpp
plugins/base/basetools.cpp
plugins/base/vcxprojectfile.cpp [deleted file]
plugins/base/vcxprojectfile.h [deleted file]
plugins/base/vcxprojectgenerator.cpp [deleted file]
plugins/base/vcxprojectgenerator.h [deleted file]
plugins/base/vssolutionfile.cpp [deleted file]
plugins/base/vssolutionfile.h [deleted file]
plugins/base/vssolutiongenerator.cpp [deleted file]
plugins/base/vssolutiongenerator.h [deleted file]
plugins/msvc/microsofttools.cpp
plugins/msvc/msvcplugin.cpp
plugins/msvc/msvcplugin.h
plugins/msvc/vcxprojectfile.cpp [new file with mode: 0644]
plugins/msvc/vcxprojectfile.h [new file with mode: 0644]
plugins/msvc/vcxprojectgenerator.cpp [new file with mode: 0644]
plugins/msvc/vcxprojectgenerator.h [new file with mode: 0644]
plugins/msvc/vssolutionfile.cpp [new file with mode: 0644]
plugins/msvc/vssolutionfile.h [new file with mode: 0644]
plugins/msvc/vssolutiongenerator.cpp [new file with mode: 0644]
plugins/msvc/vssolutiongenerator.h [new file with mode: 0644]

index b43c851fbdf63cb6bab239a8fa9f633b90cffa5e..96ce2faed0c390bd67177f854b3849e102381f9d 100644 (file)
@@ -4,8 +4,6 @@
 #include "basetools.h"
 #include "compilecommandsjson.h"
 #include "pkgconfigfile.h"
-#include "vcxprojectfile.h"
-#include "vssolutionfile.h"
 
 void BasePlugin::add_tools(Toolchain &toolchain, const Architecture &) const
 {
@@ -22,12 +20,6 @@ void BasePlugin::create_targets(SourcePackage &spkg) const
                builder.get_build_graph().get_target("install")->add_dependency(*builder.get_toolchain().get_tool("CP").create_target(*pc));
        }
 
-       if(native_arch.get_system()=="windows")
-       {
-               new VcxProjectFile(builder, spkg);
-               new VsSolutionFile(builder, spkg);
-       }
-
        new CompileCommandsJson(builder, spkg);
 }
 
index d7502a812dc097f4268072c4a7724e7e4bc0f2f6..2ad3e3a4b8db580a4311d93c296c80df33bc929b 100644 (file)
@@ -3,15 +3,11 @@
 #include "compilecommandsgenerator.h"
 #include "pkgconfiggenerator.h"
 #include "tar.h"
-#include "vcxprojectgenerator.h"
-#include "vssolutiongenerator.h"
 
 BaseTools::BaseTools(Builder &builder)
 {
        add_tool(new Copy(builder));
        add_tool(new Tar(builder));
        add_tool(new PkgConfigGenerator(builder));
-       add_tool(new VcxProjectGenerator(builder));
-       add_tool(new VsSolutionGenerator(builder));
        add_tool(new CompileCommandsGenerator(builder));
 }
diff --git a/plugins/base/vcxprojectfile.cpp b/plugins/base/vcxprojectfile.cpp
deleted file mode 100644 (file)
index 3ec7da1..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <msp/builder/builder.h>
-#include <msp/builder/sourcepackage.h>
-#include <msp/crypto/md5.h>
-#include <msp/strings/format.h>
-#include "vcxprojectfile.h"
-
-using namespace Msp;
-
-VcxProjectFile::VcxProjectFile(Builder &b, const SourcePackage &p):
-       FileTarget(b, p, p.get_source_directory()/(p.get_name()+".vcxproj"))
-{
-       tool = &builder.get_toolchain().get_tool("VCXG");
-
-       char digest[16];
-       Crypto::MD5(package->get_name()).get_digest(digest, sizeof(digest));
-       digest[6] = 3;
-       digest[8] = (digest[6]&0x3F)|0x80;
-       for(unsigned j=0; j<sizeof(digest); ++j)
-       {
-               if(j==4 || j==6 || j==8 || j==10)
-                       guid += '-';
-               guid += format("%02x", static_cast<unsigned char>(digest[j]));
-       }
-}
diff --git a/plugins/base/vcxprojectfile.h b/plugins/base/vcxprojectfile.h
deleted file mode 100644 (file)
index 1f85d0e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef VCXPROJECTFILE_H_
-#define VCXPROJECTFILE_H_
-
-#include <msp/builder/filetarget.h>
-
-class VcxProjectFile: public FileTarget
-{
-private:
-       std::string guid;
-
-public:
-       VcxProjectFile(Builder &, const SourcePackage &);
-
-       const char *get_type() const override { return "VcxProjectFile"; }
-
-       const std::string &get_guid() const { return guid; }
-};
-
-#endif
diff --git a/plugins/base/vcxprojectgenerator.cpp b/plugins/base/vcxprojectgenerator.cpp
deleted file mode 100644 (file)
index 7cb9faf..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#include <msp/builder/builder.h>
-#include <msp/builder/csourcefile.h>
-#include <msp/builder/executable.h>
-#include <msp/builder/sourcepackage.h>
-#include <msp/core/application.h>
-#include <msp/fs/utils.h>
-#include <msp/io/print.h>
-#include <msp/strings/utils.h>
-#include "vcxprojectfile.h"
-#include "vcxprojectgenerator.h"
-
-using namespace std;
-using namespace Msp;
-
-VcxProjectGenerator::VcxProjectGenerator(Builder &b):
-       Tool(b, "VCXG")
-{
-       set_run_internal(_run);
-}
-
-Target *VcxProjectGenerator::create_target(const vector<Target *> &, const string &)
-{
-       throw logic_error("Not implemented");
-}
-
-bool VcxProjectGenerator::_run(const VcxProjectFile &project)
-{
-       const SourcePackage &spkg = *project.get_package();
-       Builder &builder = spkg.get_builder();
-
-       IO::BufferedFile out(project.get_path().str(), IO::M_WRITE);
-       IO::print(out, "<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n");
-
-       IO::print(out, "\t<ItemGroup Label=\"ProjectConfigurations\">\n");
-       vector<string> build_types = builder.get_build_types();
-       const char *platforms[] = { "Win32", "x64" };
-       for(const char *p: platforms)
-               for(const string &b: build_types)
-               {
-                       IO::print(out, "\t\t<ProjectConfiguration Include=\"%s|%s\">\n", b, p);
-                       IO::print(out, "\t\t\t<Configuration>%s</Configuration>\n", b);
-                       IO::print(out, "\t\t\t<Platform>%s</Platform>\n", p);
-                       IO::print(out, "\t\t</ProjectConfiguration>\n");
-               }
-       IO::print(out, "\t</ItemGroup>\n");
-
-       IO::print(out, "\t<PropertyGroup Label=\"Globals\">\n");
-       IO::print(out, "\t\t<VCProjectVersion>15.0</VCProjectVersion>\n");
-       IO::print(out, "\t\t<Keyword>MakeFileProj</Keyword>\n");
-       IO::print(out, "\t\t<ProjectGuid>{%s}</ProjectGuid>\n", project.get_guid());
-       IO::print(out, "\t</PropertyGroup>\n");
-
-       IO::print(out, "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n");
-
-       const Executable *exe = 0;
-       for(const Target *t: builder.get_build_graph().get_target("world")->get_dependencies())
-               if(t->get_package()==&spkg)
-                       if((exe = dynamic_cast<const Executable *>(t)))
-                               break;
-
-       const char *argv0 = Application::get_argv0();
-       const string &toolchain = builder.get_current_arch().get_toolchain();
-       for(const char *p: platforms)
-               for(const string &b: build_types)
-               {
-                       string base_cmd = format("%s --arch=%s-%s --build-type=%s --prefix=%s", argv0, p, toolchain, b, builder.get_prefix());
-                       IO::print(out, "\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='%s|%s'\" Label=\"Configuration\">\n", b, p);
-                       IO::print(out, "\t\t<ConfigurationType>MakeFile</ConfigurationType>\n");
-                       IO::print(out, "\t\t<NMakeBuildCommandLine>%s</NMakeBuildCommandLine>\n", base_cmd);
-                       IO::print(out, "\t\t<NMakeCleanCommandLine>%s -c</NMakeCleanCommandLine>\n", base_cmd);
-                       IO::print(out, "\t\t<NMakeReBuildCommandLine>%s -B</NMakeReBuildCommandLine>\n", base_cmd);
-                       if(exe)
-                               IO::print(out, "\t\t<NMakeOutput>%s</NMakeOutput>\n", exe->get_path());
-                       IO::print(out, "\t</PropertyGroup>\n");
-               }
-
-       IO::print(out, "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n");
-
-       vector<const FileTarget *> sources;
-       vector<const FileTarget *> includes;
-       vector<const FileTarget *> others;
-       BuildInfo build_info;
-       for(const auto &kvp: builder.get_build_graph().get_targets())
-               if(kvp.second->get_package()==&spkg)
-               {
-                       if(kvp.second->is_buildable())
-                       {
-                               BuildInfo tgt_binfo;
-                               kvp.second->collect_build_info(tgt_binfo);
-                               build_info.update_from(tgt_binfo, BuildInfo::CHAINED);
-                       }
-                       else if(const FileTarget *file = dynamic_cast<const FileTarget *>(kvp.second))
-                       {
-                               if(dynamic_cast<const CSourceFile *>(file))
-                               {
-                                       string ext = tolower(FS::extpart(FS::basename(file->get_path())));
-                                       if(ext==".h" || ext==".hpp")
-                                               includes.push_back(file);
-                                       else
-                                               sources.push_back(file);
-                               }
-                               else
-                                       others.push_back(file);
-                       }
-               }
-
-       if(!build_info.incpath.empty())
-       {
-               IO::print(out, "\t<PropertyGroup>\n");
-               string path_str;
-               for(const FS::Path &p: build_info.incpath)
-                       append(path_str, ";", p.str());
-               IO::print(out, "\t\t<NMakeIncludeSearchPath>%s</NMakeIncludeSearchPath>\n", path_str);
-               IO::print(out, "\t</PropertyGroup>\n");
-       }
-
-       IO::print(out, "\t<ItemGroup>\n");
-       for(const FileTarget *s: sources)
-               IO::print(out, "\t\t<ClCompile Include=\"%s\" />\n", s->get_path());
-       IO::print(out, "\t</ItemGroup>\n");
-
-       IO::print(out, "\t<ItemGroup>\n");
-       for(const FileTarget *i: includes)
-               IO::print(out, "\t\t<ClInclude Include=\"%s\" />\n", i->get_path());
-       IO::print(out, "\t</ItemGroup>\n");
-
-       IO::print(out, "\t<ItemGroup>\n");
-       for(const FileTarget *t: others)
-               IO::print(out, "\t\t<None Include=\"%s\" />\n", t->get_path());
-       IO::print(out, "\t</ItemGroup>\n");
-
-       IO::print(out, "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n");
-       IO::print(out, "</Project>\n");
-
-       return true;
-}
diff --git a/plugins/base/vcxprojectgenerator.h b/plugins/base/vcxprojectgenerator.h
deleted file mode 100644 (file)
index ce96a54..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef VCXPROJECTGENERATOR_H_
-#define VCXPROJECTGENERATOR_H_
-
-#include <msp/builder/tool.h>
-
-class VcxProjectFile;
-
-class VcxProjectGenerator: public Tool
-{
-public:
-       VcxProjectGenerator(Builder &);
-
-       Target *create_target(const std::vector<Target *> &, const std::string &) override;
-
-private:
-       static bool _run(const VcxProjectFile &);
-};
-
-#endif
diff --git a/plugins/base/vssolutionfile.cpp b/plugins/base/vssolutionfile.cpp
deleted file mode 100644 (file)
index 38908df..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#include <msp/builder/builder.h>
-#include <msp/builder/sourcepackage.h>
-#include <msp/core/algorithm.h>
-#include "vssolutionfile.h"
-
-using namespace std;
-using namespace Msp;
-
-VsSolutionFile::VsSolutionFile(Builder &b, const SourcePackage &p):
-       FileTarget(b, p, p.get_source_directory()/(p.get_name()+".sln"))
-{
-       tool = &builder.get_toolchain().get_tool("VSSG");
-}
-
-void VsSolutionFile::find_dependencies()
-{
-       find_dependencies(*package);
-}
-
-void VsSolutionFile::find_dependencies(const SourcePackage &spkg)
-{
-       if(FileTarget *project = builder.get_vfs().get_target(spkg.get_source_directory()/(spkg.get_name()+".vcxproj")))
-               if(!any_equals(depends, static_cast<Target *>(project)))
-               {
-                       add_dependency(*project);
-
-                       for(const Package *r: spkg.get_required_packages())
-                               if(const SourcePackage *s = dynamic_cast<const SourcePackage *>(r))
-                                       find_dependencies(*s);
-               }
-}
diff --git a/plugins/base/vssolutionfile.h b/plugins/base/vssolutionfile.h
deleted file mode 100644 (file)
index 2c1e602..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef VSSOLUTIONFILE_H_
-#define VSSOLUTIONFILE_H_
-
-#include <msp/builder/filetarget.h>
-
-class VsSolutionFile: public FileTarget
-{
-public:
-       VsSolutionFile(Builder &, const SourcePackage &);
-
-       const char *get_type() const override { return "VsSolutionFile"; }
-protected:
-       void find_dependencies() override;
-       void find_dependencies(const SourcePackage &);
-};
-
-#endif
diff --git a/plugins/base/vssolutiongenerator.cpp b/plugins/base/vssolutiongenerator.cpp
deleted file mode 100644 (file)
index 60602e1..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <cstring>
-#include <msp/builder/builder.h>
-#include <msp/builder/sourcepackage.h>
-#include <msp/io/file.h>
-#include <msp/io/print.h>
-#include "vcxprojectfile.h"
-#include "vssolutionfile.h"
-#include "vssolutiongenerator.h"
-
-using namespace std;
-using namespace Msp;
-
-VsSolutionGenerator::VsSolutionGenerator(Builder &b):
-       Tool(b, "VSSG")
-{
-       set_run_internal(_run);
-}
-
-Target *VsSolutionGenerator::create_target(const vector<Target *> &, const string &)
-{
-       throw logic_error("Not implemented");
-}
-
-bool VsSolutionGenerator::_run(const VsSolutionFile &solution)
-{
-       const SourcePackage &spkg = *solution.get_package();
-       Builder &builder = spkg.get_builder();
-
-       IO::BufferedFile out(solution.get_path().str(), IO::M_WRITE);
-       IO::print(out, "Microsoft Visual Studio Solution File, Format Version 12.00\n");
-       IO::print(out, "MinimumVisualStudioVersion = 10.0.40219.1\n");
-
-       vector<const VcxProjectFile *> projects;
-       for(const Target *t: solution.get_dependencies())
-               if(const VcxProjectFile *project = dynamic_cast<const VcxProjectFile *>(t))
-                       projects.push_back(project);
-
-       for(const VcxProjectFile *p: projects)
-       {
-               const SourcePackage *pkg = p->get_package();
-               IO::print(out, "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"%s\", \"%s\", \"{%s}\"\nEndProject\n",
-                       pkg->get_name(), p->get_path(), p->get_guid());
-       }
-
-       vector<string> build_types = builder.get_build_types();
-       const char *platforms[] = { "x86", "x64" };
-
-       IO::print(out, "Global\n");
-       IO::print(out, "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n");
-       for(const string &t: build_types)
-               for(const char *p: platforms)
-                       IO::print(out, "\t\t%s|%s = %s|%s\n", t, p, t, p);
-       IO::print(out, "\tEndGlobalSection\n");
-       IO::print(out, "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n");
-       for(const VcxProjectFile *p: projects)
-               for(const string &t: build_types)
-                       for(const char *f: platforms)
-                       {
-                               const char *project_platform = (!strcmp(f, "x86") ? "Win32" : f);
-                               IO::print(out, "\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n", p->get_guid(), t, f, t, project_platform);
-                               if(p->get_package()==&spkg)
-                                       IO::print(out, "\t\t{%s}.%s|%s.Build.0 = %s|%s\n", p->get_guid(), t, f, t, project_platform);
-                       }
-       IO::print(out, "\tEndGlobalSection\n");
-       IO::print(out, "EndGlobal\n");
-
-       return true;
-}
diff --git a/plugins/base/vssolutiongenerator.h b/plugins/base/vssolutiongenerator.h
deleted file mode 100644 (file)
index c98fcb2..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef VSSOLUTIONGENERATOR_H_
-#define VSSOLUTIONGENERATOR_H_
-
-#include <msp/builder/tool.h>
-
-class VsSolutionFile;
-
-class VsSolutionGenerator: public Tool
-{
-public:
-       VsSolutionGenerator(Builder &);
-
-       Target *create_target(const std::vector<Target *> &, const std::string &) override;
-
-private:
-       static bool _run(const VsSolutionFile &);
-};
-
-#endif
index 0370f455d34b5c6a0bae7c1720bd0fa5de922354..03905b6584aeebbebd2ef473e35b5148b50f4e4c 100644 (file)
@@ -10,6 +10,8 @@
 #include "msvcarchiver.h"
 #include "msvccompiler.h"
 #include "msvclinker.h"
+#include "vcxprojectgenerator.h"
+#include "vssolutiongenerator.h"
 
 using namespace std;
 using namespace Msp;
@@ -25,6 +27,9 @@ MicrosoftTools::MicrosoftTools(Builder &builder, const Architecture &arch):
        add_tool(new MsvcCompiler(builder, arch, "CXX", *this));
        add_tool(new MsvcLinker(builder, arch, *this));
        add_tool(new MsvcArchiver(builder, arch, *this));
+
+       add_tool(new VcxProjectGenerator(builder));
+       add_tool(new VsSolutionGenerator(builder));
 }
 
 void MicrosoftTools::find_vc_bin_dir(Builder &builder, const Architecture &arch)
index 1a4fe7b54aca98c28f666a4d092d0af51683fc99..9ebf24a5f517809894bdfc81a09c038983fbc1c1 100644 (file)
@@ -1,6 +1,9 @@
 #include <msp/builder/architecture.h>
+#include <msp/builder/builder.h>
 #include "microsofttools.h"
 #include "msvcplugin.h"
+#include "vcxprojectfile.h"
+#include "vssolutionfile.h"
 
 void MsvcPlugin::add_tools(Toolchain &toolchain, const Architecture &arch) const
 {
@@ -8,6 +11,17 @@ void MsvcPlugin::add_tools(Toolchain &toolchain, const Architecture &arch) const
                toolchain.add_toolchain(new MicrosoftTools(builder, arch));
 }
 
+void MsvcPlugin::create_targets(SourcePackage &spkg) const
+{
+       const Architecture &native_arch = builder.get_native_arch();
+
+       if(native_arch.get_system()=="windows")
+       {
+               new VcxProjectFile(builder, spkg);
+               new VsSolutionFile(builder, spkg);
+       }
+}
+
 
 extern "C"
 Plugin *create_plugin(Builder &builder)
index 78190d39f7a55740b1337704f1ea189b8b27e781..c47b7d9197f1fe17db137bb82794040d64727bc8 100644 (file)
@@ -9,6 +9,7 @@ public:
        MsvcPlugin(Builder &b): Plugin(b) { }
 
        void add_tools(Toolchain &, const Architecture &) const override;
+       void create_targets(SourcePackage &) const override;
 };
 
 #endif
diff --git a/plugins/msvc/vcxprojectfile.cpp b/plugins/msvc/vcxprojectfile.cpp
new file mode 100644 (file)
index 0000000..3ec7da1
--- /dev/null
@@ -0,0 +1,24 @@
+#include <msp/builder/builder.h>
+#include <msp/builder/sourcepackage.h>
+#include <msp/crypto/md5.h>
+#include <msp/strings/format.h>
+#include "vcxprojectfile.h"
+
+using namespace Msp;
+
+VcxProjectFile::VcxProjectFile(Builder &b, const SourcePackage &p):
+       FileTarget(b, p, p.get_source_directory()/(p.get_name()+".vcxproj"))
+{
+       tool = &builder.get_toolchain().get_tool("VCXG");
+
+       char digest[16];
+       Crypto::MD5(package->get_name()).get_digest(digest, sizeof(digest));
+       digest[6] = 3;
+       digest[8] = (digest[6]&0x3F)|0x80;
+       for(unsigned j=0; j<sizeof(digest); ++j)
+       {
+               if(j==4 || j==6 || j==8 || j==10)
+                       guid += '-';
+               guid += format("%02x", static_cast<unsigned char>(digest[j]));
+       }
+}
diff --git a/plugins/msvc/vcxprojectfile.h b/plugins/msvc/vcxprojectfile.h
new file mode 100644 (file)
index 0000000..1f85d0e
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef VCXPROJECTFILE_H_
+#define VCXPROJECTFILE_H_
+
+#include <msp/builder/filetarget.h>
+
+class VcxProjectFile: public FileTarget
+{
+private:
+       std::string guid;
+
+public:
+       VcxProjectFile(Builder &, const SourcePackage &);
+
+       const char *get_type() const override { return "VcxProjectFile"; }
+
+       const std::string &get_guid() const { return guid; }
+};
+
+#endif
diff --git a/plugins/msvc/vcxprojectgenerator.cpp b/plugins/msvc/vcxprojectgenerator.cpp
new file mode 100644 (file)
index 0000000..7cb9faf
--- /dev/null
@@ -0,0 +1,136 @@
+#include <msp/builder/builder.h>
+#include <msp/builder/csourcefile.h>
+#include <msp/builder/executable.h>
+#include <msp/builder/sourcepackage.h>
+#include <msp/core/application.h>
+#include <msp/fs/utils.h>
+#include <msp/io/print.h>
+#include <msp/strings/utils.h>
+#include "vcxprojectfile.h"
+#include "vcxprojectgenerator.h"
+
+using namespace std;
+using namespace Msp;
+
+VcxProjectGenerator::VcxProjectGenerator(Builder &b):
+       Tool(b, "VCXG")
+{
+       set_run_internal(_run);
+}
+
+Target *VcxProjectGenerator::create_target(const vector<Target *> &, const string &)
+{
+       throw logic_error("Not implemented");
+}
+
+bool VcxProjectGenerator::_run(const VcxProjectFile &project)
+{
+       const SourcePackage &spkg = *project.get_package();
+       Builder &builder = spkg.get_builder();
+
+       IO::BufferedFile out(project.get_path().str(), IO::M_WRITE);
+       IO::print(out, "<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n");
+
+       IO::print(out, "\t<ItemGroup Label=\"ProjectConfigurations\">\n");
+       vector<string> build_types = builder.get_build_types();
+       const char *platforms[] = { "Win32", "x64" };
+       for(const char *p: platforms)
+               for(const string &b: build_types)
+               {
+                       IO::print(out, "\t\t<ProjectConfiguration Include=\"%s|%s\">\n", b, p);
+                       IO::print(out, "\t\t\t<Configuration>%s</Configuration>\n", b);
+                       IO::print(out, "\t\t\t<Platform>%s</Platform>\n", p);
+                       IO::print(out, "\t\t</ProjectConfiguration>\n");
+               }
+       IO::print(out, "\t</ItemGroup>\n");
+
+       IO::print(out, "\t<PropertyGroup Label=\"Globals\">\n");
+       IO::print(out, "\t\t<VCProjectVersion>15.0</VCProjectVersion>\n");
+       IO::print(out, "\t\t<Keyword>MakeFileProj</Keyword>\n");
+       IO::print(out, "\t\t<ProjectGuid>{%s}</ProjectGuid>\n", project.get_guid());
+       IO::print(out, "\t</PropertyGroup>\n");
+
+       IO::print(out, "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n");
+
+       const Executable *exe = 0;
+       for(const Target *t: builder.get_build_graph().get_target("world")->get_dependencies())
+               if(t->get_package()==&spkg)
+                       if((exe = dynamic_cast<const Executable *>(t)))
+                               break;
+
+       const char *argv0 = Application::get_argv0();
+       const string &toolchain = builder.get_current_arch().get_toolchain();
+       for(const char *p: platforms)
+               for(const string &b: build_types)
+               {
+                       string base_cmd = format("%s --arch=%s-%s --build-type=%s --prefix=%s", argv0, p, toolchain, b, builder.get_prefix());
+                       IO::print(out, "\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='%s|%s'\" Label=\"Configuration\">\n", b, p);
+                       IO::print(out, "\t\t<ConfigurationType>MakeFile</ConfigurationType>\n");
+                       IO::print(out, "\t\t<NMakeBuildCommandLine>%s</NMakeBuildCommandLine>\n", base_cmd);
+                       IO::print(out, "\t\t<NMakeCleanCommandLine>%s -c</NMakeCleanCommandLine>\n", base_cmd);
+                       IO::print(out, "\t\t<NMakeReBuildCommandLine>%s -B</NMakeReBuildCommandLine>\n", base_cmd);
+                       if(exe)
+                               IO::print(out, "\t\t<NMakeOutput>%s</NMakeOutput>\n", exe->get_path());
+                       IO::print(out, "\t</PropertyGroup>\n");
+               }
+
+       IO::print(out, "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n");
+
+       vector<const FileTarget *> sources;
+       vector<const FileTarget *> includes;
+       vector<const FileTarget *> others;
+       BuildInfo build_info;
+       for(const auto &kvp: builder.get_build_graph().get_targets())
+               if(kvp.second->get_package()==&spkg)
+               {
+                       if(kvp.second->is_buildable())
+                       {
+                               BuildInfo tgt_binfo;
+                               kvp.second->collect_build_info(tgt_binfo);
+                               build_info.update_from(tgt_binfo, BuildInfo::CHAINED);
+                       }
+                       else if(const FileTarget *file = dynamic_cast<const FileTarget *>(kvp.second))
+                       {
+                               if(dynamic_cast<const CSourceFile *>(file))
+                               {
+                                       string ext = tolower(FS::extpart(FS::basename(file->get_path())));
+                                       if(ext==".h" || ext==".hpp")
+                                               includes.push_back(file);
+                                       else
+                                               sources.push_back(file);
+                               }
+                               else
+                                       others.push_back(file);
+                       }
+               }
+
+       if(!build_info.incpath.empty())
+       {
+               IO::print(out, "\t<PropertyGroup>\n");
+               string path_str;
+               for(const FS::Path &p: build_info.incpath)
+                       append(path_str, ";", p.str());
+               IO::print(out, "\t\t<NMakeIncludeSearchPath>%s</NMakeIncludeSearchPath>\n", path_str);
+               IO::print(out, "\t</PropertyGroup>\n");
+       }
+
+       IO::print(out, "\t<ItemGroup>\n");
+       for(const FileTarget *s: sources)
+               IO::print(out, "\t\t<ClCompile Include=\"%s\" />\n", s->get_path());
+       IO::print(out, "\t</ItemGroup>\n");
+
+       IO::print(out, "\t<ItemGroup>\n");
+       for(const FileTarget *i: includes)
+               IO::print(out, "\t\t<ClInclude Include=\"%s\" />\n", i->get_path());
+       IO::print(out, "\t</ItemGroup>\n");
+
+       IO::print(out, "\t<ItemGroup>\n");
+       for(const FileTarget *t: others)
+               IO::print(out, "\t\t<None Include=\"%s\" />\n", t->get_path());
+       IO::print(out, "\t</ItemGroup>\n");
+
+       IO::print(out, "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n");
+       IO::print(out, "</Project>\n");
+
+       return true;
+}
diff --git a/plugins/msvc/vcxprojectgenerator.h b/plugins/msvc/vcxprojectgenerator.h
new file mode 100644 (file)
index 0000000..ce96a54
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef VCXPROJECTGENERATOR_H_
+#define VCXPROJECTGENERATOR_H_
+
+#include <msp/builder/tool.h>
+
+class VcxProjectFile;
+
+class VcxProjectGenerator: public Tool
+{
+public:
+       VcxProjectGenerator(Builder &);
+
+       Target *create_target(const std::vector<Target *> &, const std::string &) override;
+
+private:
+       static bool _run(const VcxProjectFile &);
+};
+
+#endif
diff --git a/plugins/msvc/vssolutionfile.cpp b/plugins/msvc/vssolutionfile.cpp
new file mode 100644 (file)
index 0000000..38908df
--- /dev/null
@@ -0,0 +1,31 @@
+#include <msp/builder/builder.h>
+#include <msp/builder/sourcepackage.h>
+#include <msp/core/algorithm.h>
+#include "vssolutionfile.h"
+
+using namespace std;
+using namespace Msp;
+
+VsSolutionFile::VsSolutionFile(Builder &b, const SourcePackage &p):
+       FileTarget(b, p, p.get_source_directory()/(p.get_name()+".sln"))
+{
+       tool = &builder.get_toolchain().get_tool("VSSG");
+}
+
+void VsSolutionFile::find_dependencies()
+{
+       find_dependencies(*package);
+}
+
+void VsSolutionFile::find_dependencies(const SourcePackage &spkg)
+{
+       if(FileTarget *project = builder.get_vfs().get_target(spkg.get_source_directory()/(spkg.get_name()+".vcxproj")))
+               if(!any_equals(depends, static_cast<Target *>(project)))
+               {
+                       add_dependency(*project);
+
+                       for(const Package *r: spkg.get_required_packages())
+                               if(const SourcePackage *s = dynamic_cast<const SourcePackage *>(r))
+                                       find_dependencies(*s);
+               }
+}
diff --git a/plugins/msvc/vssolutionfile.h b/plugins/msvc/vssolutionfile.h
new file mode 100644 (file)
index 0000000..2c1e602
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef VSSOLUTIONFILE_H_
+#define VSSOLUTIONFILE_H_
+
+#include <msp/builder/filetarget.h>
+
+class VsSolutionFile: public FileTarget
+{
+public:
+       VsSolutionFile(Builder &, const SourcePackage &);
+
+       const char *get_type() const override { return "VsSolutionFile"; }
+protected:
+       void find_dependencies() override;
+       void find_dependencies(const SourcePackage &);
+};
+
+#endif
diff --git a/plugins/msvc/vssolutiongenerator.cpp b/plugins/msvc/vssolutiongenerator.cpp
new file mode 100644 (file)
index 0000000..60602e1
--- /dev/null
@@ -0,0 +1,68 @@
+#include <cstring>
+#include <msp/builder/builder.h>
+#include <msp/builder/sourcepackage.h>
+#include <msp/io/file.h>
+#include <msp/io/print.h>
+#include "vcxprojectfile.h"
+#include "vssolutionfile.h"
+#include "vssolutiongenerator.h"
+
+using namespace std;
+using namespace Msp;
+
+VsSolutionGenerator::VsSolutionGenerator(Builder &b):
+       Tool(b, "VSSG")
+{
+       set_run_internal(_run);
+}
+
+Target *VsSolutionGenerator::create_target(const vector<Target *> &, const string &)
+{
+       throw logic_error("Not implemented");
+}
+
+bool VsSolutionGenerator::_run(const VsSolutionFile &solution)
+{
+       const SourcePackage &spkg = *solution.get_package();
+       Builder &builder = spkg.get_builder();
+
+       IO::BufferedFile out(solution.get_path().str(), IO::M_WRITE);
+       IO::print(out, "Microsoft Visual Studio Solution File, Format Version 12.00\n");
+       IO::print(out, "MinimumVisualStudioVersion = 10.0.40219.1\n");
+
+       vector<const VcxProjectFile *> projects;
+       for(const Target *t: solution.get_dependencies())
+               if(const VcxProjectFile *project = dynamic_cast<const VcxProjectFile *>(t))
+                       projects.push_back(project);
+
+       for(const VcxProjectFile *p: projects)
+       {
+               const SourcePackage *pkg = p->get_package();
+               IO::print(out, "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"%s\", \"%s\", \"{%s}\"\nEndProject\n",
+                       pkg->get_name(), p->get_path(), p->get_guid());
+       }
+
+       vector<string> build_types = builder.get_build_types();
+       const char *platforms[] = { "x86", "x64" };
+
+       IO::print(out, "Global\n");
+       IO::print(out, "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n");
+       for(const string &t: build_types)
+               for(const char *p: platforms)
+                       IO::print(out, "\t\t%s|%s = %s|%s\n", t, p, t, p);
+       IO::print(out, "\tEndGlobalSection\n");
+       IO::print(out, "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n");
+       for(const VcxProjectFile *p: projects)
+               for(const string &t: build_types)
+                       for(const char *f: platforms)
+                       {
+                               const char *project_platform = (!strcmp(f, "x86") ? "Win32" : f);
+                               IO::print(out, "\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n", p->get_guid(), t, f, t, project_platform);
+                               if(p->get_package()==&spkg)
+                                       IO::print(out, "\t\t{%s}.%s|%s.Build.0 = %s|%s\n", p->get_guid(), t, f, t, project_platform);
+                       }
+       IO::print(out, "\tEndGlobalSection\n");
+       IO::print(out, "EndGlobal\n");
+
+       return true;
+}
diff --git a/plugins/msvc/vssolutiongenerator.h b/plugins/msvc/vssolutiongenerator.h
new file mode 100644 (file)
index 0000000..c98fcb2
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef VSSOLUTIONGENERATOR_H_
+#define VSSOLUTIONGENERATOR_H_
+
+#include <msp/builder/tool.h>
+
+class VsSolutionFile;
+
+class VsSolutionGenerator: public Tool
+{
+public:
+       VsSolutionGenerator(Builder &);
+
+       Target *create_target(const std::vector<Target *> &, const std::string &) override;
+
+private:
+       static bool _run(const VsSolutionFile &);
+};
+
+#endif