1 module mage.msbuild.link; 2 3 import mage; 4 import mage.msbuild : VSInfo; 5 import mage.msbuild.cpp; 6 import mage.util.option; 7 8 import std.range; 9 import std.typetuple : allSatisfy; 10 11 12 struct Link 13 { 14 string subSystem; 15 string genDebugInfo; 16 string enableCOMDATFolding; 17 string optimizeReferences; 18 string[] dependencies; 19 bool inheritDependencies = true; 20 Option!bool debugSymbols; 21 Path debugSymbolsFile; 22 } 23 24 auto createLink(ref MSBuildConfig cfg, ref in VSInfo info, ref Environment env) 25 { 26 // TODO Split this up so it becomes more readable and understandable... 27 28 auto link = Link(); 29 30 auto _link = log.forcedBlock("Link +++ +++ +++ +++ +++ +++ +++ +++"); 31 32 env.prettyPrint(); 33 34 if(auto var = env.first("linkTargets")) 35 { 36 auto linkTargets = var.get!(Target[]); 37 38 // Here's the idea: 39 // 1. Check for the existance of linkTargets (above). 40 // 2. Iterate all linkTargets and see whether their configurations match one of ours. 41 // 2.1.1 First, check for ExternalTarget types. These are pre-built binaries, specifying only a set of configurations and libs for them. 42 // 2.1.2 Set a linker dependency for the first matching configuration and continue with the loop. 43 // 2.2.1 Check for a vcxproj file property on the target. If it is a dependency of ours, this property is set and contains the outputFile. 44 // 2.2.2 Check for a matching config and use that outputFile as our dependency. 45 46 auto _ = log.Block("Processing Link Targets"); 47 48 foreach(ref linkTarget; linkTargets) 49 { 50 auto linkTargetName = linkTarget["name"].toString(); 51 log.info("Target: %s", linkTargetName); 52 53 auto linkTargetEnv = Environment("%s_ltenv".format(linkTargetName), linkTarget.properties, G.env); 54 linkTargetEnv.prettyPrint(); 55 56 auto configMatches = matchingConfigurations(env, linkTargetEnv).filter!(a => a[0].name == cfg.name); 57 58 if(configMatches.empty) { 59 log.error("No matching configurations found between `%s' and `%s'.", env["name"].toString(), linkTargetName); 60 } 61 else { 62 auto __ = log.Block("Matching configs"); 63 foreach(ref match; configMatches) 64 { 65 auto ___ = log.Block("Match"); 66 match[0].properties.prettyPrint(); 67 match[1].properties.prettyPrint(); 68 } 69 } 70 71 if(linkTarget.isExternal) 72 { 73 foreach(ref match; configMatches) 74 { 75 log.trace(`External link dependency config: %s`, *match[1]); 76 auto libPath = (*match[1])["lib"].get!Path; 77 if(!libPath.isAbsolute) { 78 libPath = env["mageFilePath"].get!Path.parent ~ libPath; 79 } 80 link.dependencies ~= libPath.normalizedData; 81 } 82 } 83 else 84 { 85 auto pProj = linkTarget.tryGet("%s_vcxproj".format(info.genName)); 86 if(pProj is null) 87 { 88 log.warning(`Link target "%s" can not be added to linker dependencies at this time. ` 89 `You might have a cyclic dependency.`.format(linkTargetName)); 90 continue; 91 } 92 93 auto proj = pProj.get!(MSBuildProject*); 94 foreach(ref match; configMatches) 95 { 96 // Find the matching msbuild project's config. 97 auto vcxprojConfig = proj.configs.find!(a => a.name == match[1].name); 98 link.dependencies ~= vcxprojConfig.front.link.dependencies[]; 99 link.dependencies ~= vcxprojConfig.front.outputFile.normalizedData; 100 } 101 } 102 } 103 } 104 105 if(auto var = env.first("debugSymbols")) { 106 link.debugSymbols = var.get!bool; 107 } 108 109 log.trace("Looking for debugSymbolsFile property setting..."); 110 if(auto var = env.first("debugSymbolsFile")) { 111 log.trace("Found debugSymbolsFile property setting."); 112 link.debugSymbolsFile = var.get!Path; 113 } 114 115 // TODO 116 117 return link; 118 }