1 module mage.msbuild.vcxproj; 2 3 import mage; 4 import mage.msbuild.clcompile; 5 import mage.msbuild.link; 6 import mage.msbuild.cpp; 7 import xml = mage.util.xml; 8 9 10 void generateFile(in MSBuildProject proj, in Path outFile) 11 { 12 import mage.util.stream : FileStream; 13 14 auto _ = log.Block("Generate .vcxproj in %s", outFile); 15 16 xml.Doc doc; 17 log.info("Generate vcxproj xml in memory..."); 18 doc.append(proj); 19 log.info("Writing vcxproj file..."); 20 if(!outFile.parent.exists) { 21 outFile.parent.mkdir(); 22 } 23 auto s = FileStream(outFile); 24 xml.serialize(s, doc); 25 } 26 27 // XML 28 xml.Element* append(P)(ref P parent, in MSBuildProject proj) 29 if(xml.isSomeParent!P) 30 { 31 auto c = parent.child("Project"); 32 with(c) 33 { 34 attr("DefaultTargets", "Build"); 35 attr("ToolsVersion", proj.toolsVersion); 36 attr("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003"); 37 with(child("ItemGroup")) { 38 attr("Label", "ProjectConfigurations"); 39 foreach(cfg; proj.configs) { 40 with(child("ProjectConfiguration")) { 41 attr("Include", "%s|%s".format(cfg.name, cfg.architecture)); 42 child("Configuration").text(cfg.name); 43 child("Platform").text(cfg.architecture); 44 } 45 } 46 } 47 with(child("PropertyGroup")) { 48 attr("Label", "Globals"); 49 child("ProjectGuid").text(`{76793D1E-7BA3-4DBD-A492-2B831B56D616}`); 50 child("Keyword").text("Win32Proj"); 51 child("RootNamespace").text("one"); 52 } 53 with(child("Import")) { 54 attr("Project", `$(VCTargetsPath)\Microsoft.Cpp.Default.props`); 55 } 56 foreach(cfg; proj.configs) { 57 with(child("PropertyGroup")) { 58 attr("Condition", `'$(Configuration)|$(Platform)'=='%s|%s'`.format(cfg.name, cfg.architecture)); 59 attr("Label", "Configuration"); 60 assert(cfg.type, "Need a configuration type!"); 61 child("ConfigurationType").text(cfg.type); 62 if(cfg.useDebugLibs) { 63 child("UseDebugLibraries").text(cfg.useDebugLibs.unwrap().to!string()); 64 } 65 if(cfg.platformToolset) { 66 child("PlatformToolset").text(cfg.platformToolset); 67 } 68 if(cfg.wholeProgramOptimization) { 69 child("WholeProgramOptimization").text(cfg.wholeProgramOptimization.unwrap().to!string()); 70 } 71 if(cfg.characterSet) { 72 child("CharacterSet").text(cfg.characterSet); 73 } 74 } 75 } 76 with(child("Import")) { 77 attr("Project", `$(VCTargetsPath)\Microsoft.Cpp.props`); 78 } 79 with(child("ImportGroup")) { 80 attr("Label", "ExtensionSettings"); 81 } 82 with(child("ImportGroup")) { 83 attr("Label", "PropertySheets"); 84 attr("Condition", "'$(Configuration)|$(Platform)'=='Debug|Win32'"); 85 with(child("Import")) { 86 attr("Project", `$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props`); 87 attr("Condition", `exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')`); 88 attr("Label", `LocalAppDataPlatform`); 89 } 90 } 91 with(child("ImportGroup")) { 92 attr("Label", "PropertySheets"); 93 attr("Condition", `'$(Configuration)|$(Platform)'=='Release|Win32'`); 94 with(child("Import")) { 95 attr("Project", `$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props`); 96 attr("Condition", `exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')`); 97 attr("Label", `LocalAppDataPlatform`); 98 } 99 } 100 with(child("PropertyGroup")) { 101 attr("Label", "UserMacros"); 102 } 103 foreach(cfg; proj.configs) { 104 with(child("PropertyGroup")) { 105 attr("Condition", `'$(Configuration)|$(Platform)'=='%s|%s'`.format(cfg.name, cfg.architecture)); 106 if(cfg.linkIncremental) { 107 child("LinkIncremental").text(cfg.linkIncremental.unwrap().to!string()); 108 } 109 // Explicitly add a trailing slash to silence the MSBuild warning MSB8004. 110 child("OutDir").text(cfg.outputFile.parent.normalizedData ~ "/"); 111 child("IntDir").text(cfg.intermediatesDir.normalizedData ~ "/"); 112 child("TargetName").text(cfg.outputFile.stem); 113 child("TargetExt").text(cfg.outputFile.extension); 114 } 115 } 116 // Item definition groups 117 foreach(cfg; proj.configs) { 118 log.trace("Writing config: %s", cfg.name); 119 auto n = child("ItemDefinitionGroup"); 120 with(n) { 121 attr("Condition", `'$(Configuration)|$(Platform)'=='%s|%s'`.format(cfg.name, cfg.architecture)); 122 (*n).append(cfg.clCompile); 123 (*n).append(cfg.link); 124 } 125 } 126 foreach(cfg; proj.configs) { 127 128 if(cfg.compilationUnits.length) 129 { 130 with(child("ItemGroup")) 131 { 132 attr("Condition", `'$(Configuration)|$(Platform)'=='%s|%s'`.format(cfg.name, cfg.architecture)); 133 foreach(file; cfg.compilationUnits) { 134 with(child("ClCompile")) { 135 attr("Include", file.windowsData); 136 } 137 } 138 } 139 } 140 141 if(cfg.headerFiles.length) 142 { 143 with(child("ItemGroup")) 144 { 145 attr("Condition", `'$(Configuration)|$(Platform)'=='%s|%s'`.format(cfg.name, cfg.architecture)); 146 foreach(file; cfg.headerFiles) { 147 with(child("ClInclude")) { 148 attr("Include", file.windowsData); 149 } 150 } 151 } 152 } 153 } 154 with(child("Import")) { 155 attr("Project", `$(VCTargetsPath)\Microsoft.Cpp.targets`); 156 } 157 with(child("ImportGroup")) { 158 attr("Label", `ExtensionTargets`); 159 } 160 } // /Project 161 return c; 162 } 163 164 xml.Element* append(P)(ref P parent, ref in ClCompile cl) 165 if(xml.isSomeParent!P) 166 { 167 auto n = parent.child("ClCompile"); 168 with(n) { 169 if(!cl.includePaths.empty) { 170 auto paths = cl.includePaths.map!(a => normalizedData(a.exists ? a.resolved() : a)).array; 171 if(cl.inheritIncludePaths) { 172 paths ~= "%(AdditionalIncludeDirectories)"; 173 } 174 child("AdditionalIncludeDirectories").text("%-(%s;%)".format(paths)); 175 } 176 if(cl.pch) { 177 child("PrecompiledHeader").text(cl.pch); 178 } 179 if(cl.warningLevel) { 180 child("WarningLevel").text(cl.warningLevel); 181 } 182 if(cl.optimization) { 183 child("Optimization").text(cl.optimization); 184 } 185 if(cl.compileAs) { 186 child("CompileAs").text(cl.compileAs); 187 } 188 if(cl.functionLevelLinking) { 189 child("FunctionLevelLinking").text(cl.functionLevelLinking.unwrap().to!string()); 190 } 191 if(cl.intrinsicFunctions) { 192 child("IntrinsicFunctions").text(cl.intrinsicFunctions.unwrap().to!string()); 193 } 194 if(!cl.defines.empty) { 195 auto defs = cl.defines.dup; 196 if(cl.inheritDefines) { 197 defs ~= "%(PreprocessorDefinitions)"; 198 } 199 child("PreprocessorDefinitions").text("%-(%s;%)".format(defs)); 200 } 201 } 202 return n; 203 } 204 205 // XML 206 xml.Element* append(P)(ref P parent, in Link lnk) 207 if(xml.isSomeParent!P) 208 { 209 log.trace("Link (%s)", &lnk); 210 auto n = parent.child("Link"); 211 with(n) { 212 auto deps = lnk.dependencies.dup; 213 if(lnk.inheritDependencies) { 214 deps ~= "%(AdditionalDependencies)"; 215 } 216 if(!deps.empty) { 217 child("AdditionalDependencies").text("%-(%s;%)".format(deps)); 218 } 219 220 if(lnk.subSystem) { 221 child("SubSystem").text(lnk.subSystem); 222 } 223 if(lnk.genDebugInfo) { 224 child("GenerateDebugInformation").text(lnk.genDebugInfo); 225 } 226 if(lnk.enableCOMDATFolding) { 227 child("EnableCOMDATFolding").text(lnk.enableCOMDATFolding); 228 } 229 if(lnk.optimizeReferences) { 230 child("OptimizeReferences").text(lnk.optimizeReferences); 231 } 232 log.info("Writing debugSymbols if available."); 233 log.info("Variant value: %s", (cast()lnk.debugSymbols.value).toString()); 234 if(lnk.debugSymbols) { 235 child("GenerateDebugInformation").text(lnk.debugSymbols.unwrap().to!string()); 236 if(!lnk.debugSymbolsFile.isDot) { 237 child("ProgramDatabaseFile").text(lnk.debugSymbolsFile.normalizedData); 238 } 239 } 240 } 241 return n; 242 }