1 module mage.msbuild.sln;
2 
3 import mage;
4 import mage.msbuild : VSInfo;
5 import mage.msbuild.cpp;
6 
7 
8 void generateFile(ref in VSInfo info, MSBuildProject[] projects, in Path slnPath)
9 {
10   auto _ = log.Block(`Generate .sln File "%s"`, slnPath);
11   log.trace("The original list of projects: %s", projects.map!(a => a.name));
12 
13   // Prioritize those that have the "isStartup" flag set.
14   projects.partition!( a => a.isStartup );
15 
16   log.trace("The sorted list of projects: %s", projects.map!(a => a.name));
17 
18   // Collect all possible configurations.
19   string[string] cfgs;
20   foreach(proj; projects)
21   {
22     foreach(cfg; proj.configs)
23     {
24       auto cfgString = "%s|%s".format(cfg.name, cfg.architecture);
25       cfgs[cfgString] = cfgString;
26     }
27   }
28 
29   import mage.util.stream;
30   if(!slnPath.parent.exists) {
31     slnPath.parent.mkdir();
32   }
33   auto stream = FileStream(slnPath);
34   stream.indentString = "\t";
35 
36   auto __ = log.Block("Writing .sln File.");
37 
38   // Header
39   stream.writeln(`Microsoft Visual Studio Solution File, Format Version %s0`.format(info.toolsVersion));
40   stream.writeln(`# Visual Studio %s`.format(info.year));
41 
42   foreach(proj; projects)
43   {
44     auto typeID = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}";
45     auto projGuidString = "{%s}".format(proj.guid).toUpper();
46     auto _projBlock = log.forcedBlock("Processing project %s %s", proj.name, projGuidString);
47     auto projFilePath = Path(proj.name) ~ "%s.vcxproj".format(proj.name);
48     stream.writeln(`Project("%s") = "%s", "%s", "%s"`.format(typeID, proj.name, projFilePath, projGuidString));
49     stream.indent();
50     scope(exit) {
51       stream.dedent();
52       stream.writeln("EndProject");
53     }
54 
55     {
56       stream.writeln(`ProjectSection(ProjectDependencies) = postProject`);
57       stream.indent();
58       scope(exit) {
59         stream.dedent();
60         stream.writeln("EndProjectSection");
61       }
62       auto allDeps = proj.target.properties["dependencies"];
63       auto nonExternalDeps = allDeps.get!(Target[]).filter!(a => !a.isExternal);
64       auto vcxprojPropertyName = "%s_vcxproj".format(info.genName);
65       auto projDeps = nonExternalDeps.map!(a => a.properties[vcxprojPropertyName].get!(MSBuildProject*));
66       log.info("Deps: %s", projDeps.map!(a => "%s {%s}".format(a.name, a.guid.toString().toUpper())));
67       foreach(ref projDep; projDeps)
68       {
69         auto guidString = "{%s}".format(projDep.guid).toUpper();
70         log.info("Writing project dep: %s", guidString);
71         stream.writeln("%s = %s".format(guidString, guidString));
72       }
73     }
74   }
75 
76   // Global
77   {
78     stream.writeln("Global");
79     stream.indent();
80     scope(exit) {
81       stream.dedent();
82       stream.writeln("EndGlobal");
83     }
84 
85     {
86       stream.writeln("GlobalSection(SolutionConfigurationPlatforms) = preSolution");
87       stream.indent();
88       scope(exit) {
89         stream.dedent();
90         stream.writeln("EndGlobalSection");
91       }
92       foreach(cfg, _; cfgs) {
93         stream.writeln("%s = %s".format(cfg, cfg));
94       }
95     }
96 
97     {
98       stream.writeln("GlobalSection(ProjectConfigurationPlatforms) = postSolution");
99       stream.indent();
100       scope(exit) {
101         stream.dedent();
102         stream.writeln("EndGlobalSection");
103       }
104       // TODO
105       //stream.writeln("# TODO");
106       foreach(proj; projects) {
107         auto guidString = "{%s}".format(proj.guid).toUpper();
108         foreach(cfg; proj.configs) {
109           auto cfgString = "%s|%s".format(cfg.name, cfg.architecture);
110           stream.writeln("%s.%s.ActiveCfg = %s".format(guidString, cfgString, cfgString));
111           stream.writeln("%s.%s.Build.0 = %s".format(guidString, cfgString, cfgString));
112         }
113       }
114     }
115     {
116       stream.writeln("GlobalSection(ExtensibilityGlobals) = postSolution");
117       stream.indent();
118       scope(exit) {
119         stream.dedent();
120         stream.writeln("EndGlobalSection");
121       }
122     }
123     {
124       stream.writeln("GlobalSection(ExtensibilityAddIns) = postSolution");
125       stream.indent();
126       scope(exit) {
127         stream.dedent();
128         stream.writeln("EndGlobalSection");
129       }
130     }
131   } // Global
132 }