public static string GenerateTaskCommandLine( ToolTask Task, string[] PropertiesToSkip, IEnumerable <ProjectMetadata> MetaDataList) { foreach (ProjectMetadata MetaData in MetaDataList) { if (PropertiesToSkip.Contains(MetaData.Name)) { continue; } var MatchingProps = Task.GetType().GetProperties().Where(prop => prop.Name == MetaData.Name); if (MatchingProps.Any() && !string.IsNullOrEmpty(MetaData.EvaluatedValue)) { string EvaluatedValue = MetaData.EvaluatedValue.Trim(); if (MetaData.Name == "AdditionalIncludeDirectories") { EvaluatedValue = EvaluatedValue.Replace("\\\\", "\\"); EvaluatedValue = EvaluatedValue.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); } PropertyInfo propInfo = MatchingProps.First(); //Dubious if (propInfo.PropertyType.IsArray && propInfo.PropertyType.GetElementType() == typeof(string)) { propInfo.SetValue(Task, Convert.ChangeType(EvaluatedValue.Split(';'), propInfo.PropertyType)); } else { propInfo.SetValue(Task, Convert.ChangeType(EvaluatedValue, propInfo.PropertyType)); } } } var GenCmdLineMethod = Task.GetType().GetRuntimeMethods().Where(meth => meth.Name == "GenerateCommandLine").First(); //Dubious return(GenCmdLineMethod.Invoke(Task, new object[] { Type.Missing, Type.Missing }) as string); }
static private void GenerateBffFromVcxproj(string Config, string Platform) { Project ActiveProject = CurrentProject.Proj; string MD5hash = "wafflepalooza"; PreBuildBatchFile = ""; PostBuildBatchFile = ""; bool FileChanged = HasFileChanged(ActiveProject.FullPath, Platform, Config, out MD5hash); string configType = ActiveProject.GetProperty("ConfigurationType").EvaluatedValue; switch (configType) { case "DynamicLibrary": BuildOutput = BuildType.DynamicLib; break; case "StaticLibrary": BuildOutput = BuildType.StaticLib; break; default: case "Application": BuildOutput = BuildType.Application; break; } PlatformToolsetVersion = ActiveProject.GetProperty("PlatformToolsetVersion").EvaluatedValue; string OutDir = ActiveProject.GetProperty("OutDir").EvaluatedValue; string IntDir = ActiveProject.GetProperty("IntDir").EvaluatedValue; StringBuilder OutputString = new StringBuilder(MD5hash + "\n\n"); OutputString.AppendFormat(".VSBasePath = '{0}'\n", ActiveProject.GetProperty("VSInstallDir").EvaluatedValue); VCBasePath = ActiveProject.GetProperty("VCInstallDir").EvaluatedValue; OutputString.AppendFormat(".VCBasePath = '{0}'\n", VCBasePath); WindowsSDKTarget = ActiveProject.GetProperty("WindowsTargetPlatformVersion") != null?ActiveProject.GetProperty("WindowsTargetPlatformVersion").EvaluatedValue : "8.1"; OutputString.AppendFormat(".WindowsSDKBasePath = '{0}'\n\n", ActiveProject.GetProperty("WindowsSdkDir").EvaluatedValue); OutputString.Append("Settings\n{\n\t.Environment = \n\t{\n"); OutputString.AppendFormat("\t\t\"INCLUDE={0}\",\n", ActiveProject.GetProperty("IncludePath").EvaluatedValue); OutputString.AppendFormat("\t\t\"LIB={0}\",\n", ActiveProject.GetProperty("LibraryPath").EvaluatedValue); OutputString.AppendFormat("\t\t\"LIBPATH={0}\",\n", ActiveProject.GetProperty("ReferencePath").EvaluatedValue); OutputString.AppendFormat("\t\t\"PATH={0}\"\n", ActiveProject.GetProperty("Path").EvaluatedValue); OutputString.AppendFormat("\t\t\"TMP={0}\"\n", ActiveProject.GetProperty("Temp").EvaluatedValue); OutputString.AppendFormat("\t\t\"TEMP={0}\"\n", ActiveProject.GetProperty("Temp").EvaluatedValue); OutputString.AppendFormat("\t\t\"SystemRoot={0}\"\n", ActiveProject.GetProperty("SystemRoot").EvaluatedValue); OutputString.Append("\t}\n}\n\n"); StringBuilder CompilerString = new StringBuilder("Compiler('msvc')\n{\n"); string CompilerRoot = CompilerRoot = VCBasePath + "bin/"; if (Platform == "Win64" || Platform == "x64") { CompilerString.Append("\t.Root = '$VSBasePath$/VC/bin/amd64'\n"); CompilerRoot += "amd64/"; } else if (Platform == "Win32" || Platform == "x86" || true) //Hmm. { CompilerString.Append("\t.Root = '$VSBasePath$/VC/bin'\n"); } CompilerString.Append("\t.Executable = '$Root$/cl.exe'\n"); CompilerString.Append("\t.ExtraFiles =\n\t{\n"); CompilerString.Append("\t\t'$Root$/c1.dll'\n"); CompilerString.Append("\t\t'$Root$/c1xx.dll'\n"); CompilerString.Append("\t\t'$Root$/c2.dll'\n"); if (File.Exists(CompilerRoot + "1033/clui.dll")) //Check English first... { CompilerString.Append("\t\t'$Root$/1033/clui.dll'\n"); } else { var numericDirectories = Directory.GetDirectories(CompilerRoot).Where(d => Path.GetFileName(d).All(char.IsDigit)); var cluiDirectories = numericDirectories.Where(d => Directory.GetFiles(d, "clui.dll").Any()); if (cluiDirectories.Any()) { CompilerString.AppendFormat("\t\t'$Root$/{0}/clui.dll'\n", Path.GetFileName(cluiDirectories.First())); } } CompilerString.Append("\t\t'$Root$/mspdbsrv.exe'\n"); CompilerString.Append("\t\t'$Root$/mspdbcore.dll'\n"); CompilerString.AppendFormat("\t\t'$Root$/mspft{0}.dll'\n", PlatformToolsetVersion); CompilerString.AppendFormat("\t\t'$Root$/msobj{0}.dll'\n", PlatformToolsetVersion); CompilerString.AppendFormat("\t\t'$Root$/mspdb{0}.dll'\n", PlatformToolsetVersion); CompilerString.AppendFormat("\t\t'$VSBasePath$/VC/redist/{0}/Microsoft.VC{1}.CRT/msvcp{1}.dll'\n", Platform == "Win32" ? "x86" : "x64", PlatformToolsetVersion); CompilerString.AppendFormat("\t\t'$VSBasePath$/VC/redist/{0}/Microsoft.VC{1}.CRT/vccorlib{1}.dll'\n", Platform == "Win32" ? "x86" : "x64", PlatformToolsetVersion); CompilerString.Append("\t}\n"); //End extra files CompilerString.Append("}\n\n"); //End compiler CompilerString.Append("Compiler('rc')\n{\n"); CompilerString.Append("\t.Executable = '$WindowsSDKBasePath$\\bin\\x64\\rc.exe'\n"); CompilerString.Append("\t.CompilerFamily = 'custom'\n"); CompilerString.Append("}\n\n"); //End rc compiler OutputString.Append(CompilerString); if (ActiveProject.GetItems("PreBuildEvent").Any()) { var buildEvent = ActiveProject.GetItems("PreBuildEvent").First(); if (buildEvent.Metadata.Any()) { var mdPi = buildEvent.Metadata.First(); if (!string.IsNullOrEmpty(mdPi.EvaluatedValue)) { string BatchText = "call \"" + VCBasePath + "vcvarsall.bat\" " + (Platform == "Win32" ? "x86" : "x64") + " " + (PlatformToolsetVersion == "140" ? WindowsSDKTarget : "") + "\n"; PreBuildBatchFile = Path.Combine(ActiveProject.DirectoryPath, Path.GetFileNameWithoutExtension(ActiveProject.FullPath) + "_prebuild.bat"); File.WriteAllText(PreBuildBatchFile, BatchText + mdPi.EvaluatedValue); OutputString.Append("Exec('prebuild') \n{\n"); OutputString.AppendFormat("\t.ExecExecutable = '{0}' \n", PreBuildBatchFile); OutputString.AppendFormat("\t.ExecInput = '{0}' \n", PreBuildBatchFile); OutputString.AppendFormat("\t.ExecOutput = '{0}' \n", PreBuildBatchFile + ".txt"); OutputString.Append("\t.ExecUseStdOutAsOutput = true \n"); OutputString.Append("}\n\n"); } } } string CompilerOptions = ""; List <ObjectListNode> ObjectLists = new List <ObjectListNode>(); var CompileItems = ActiveProject.GetItems("ClCompile"); string PrecompiledHeaderString = ""; foreach (var Item in CompileItems) { if (Item.DirectMetadata.Any()) { if (Item.DirectMetadata.Where(dmd => dmd.Name == "ExcludedFromBuild" && dmd.EvaluatedValue == "true").Any()) { continue; } if (Item.DirectMetadata.Where(dmd => dmd.Name == "PrecompiledHeader" && dmd.EvaluatedValue == "Create").Any()) { ToolTask CLtask = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.CL")); CLtask.GetType().GetProperty("Sources").SetValue(CLtask, new TaskItem[] { new TaskItem() }); string pchCompilerOptions = GenerateTaskCommandLine(CLtask, new string[] { "PrecompiledHeaderOutputFile", "ObjectFileName", "AssemblerListingLocation" }, Item.Metadata) + " /FS"; PrecompiledHeaderString = "\t.PCHOptions = '" + string.Format("\"%1\" /Fp\"%2\" /Fo\"%3\" {0} '\n", pchCompilerOptions); PrecompiledHeaderString += "\t.PCHInputFile = '" + Item.EvaluatedInclude + "'\n"; PrecompiledHeaderString += "\t.PCHOutputFile = '" + Item.GetMetadataValue("PrecompiledHeaderOutputFile") + "'\n"; break; //Assumes only one pch... } } } foreach (var Item in CompileItems) { bool ExcludePrecompiledHeader = false; if (Item.DirectMetadata.Any()) { if (Item.DirectMetadata.Where(dmd => dmd.Name == "ExcludedFromBuild" && dmd.EvaluatedValue == "true").Any()) { continue; } if (Item.DirectMetadata.Where(dmd => dmd.Name == "PrecompiledHeader" && dmd.EvaluatedValue == "Create").Any()) { continue; } if (Item.DirectMetadata.Where(dmd => dmd.Name == "PrecompiledHeader" && dmd.EvaluatedValue == "NotUsing").Any()) { ExcludePrecompiledHeader = true; } } ToolTask Task = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.CL")); Task.GetType().GetProperty("Sources").SetValue(Task, new TaskItem[] { new TaskItem() }); //CPPTasks throws an exception otherwise... string TempCompilerOptions = GenerateTaskCommandLine(Task, new string[] { "ObjectFileName", "AssemblerListingLocation" }, Item.Metadata) + " /FS"; if (Path.GetExtension(Item.EvaluatedInclude) == ".c") { TempCompilerOptions += " /TC"; } else { TempCompilerOptions += " /TP"; } CompilerOptions = TempCompilerOptions; string FormattedCompilerOptions = string.Format("\"%1\" /Fo\"%2\" {0}", TempCompilerOptions); var MatchingNodes = ObjectLists.Where(el => el.AddIfMatches(Item.EvaluatedInclude, "msvc", IntDir, FormattedCompilerOptions, ExcludePrecompiledHeader ? "" : PrecompiledHeaderString)); if (!MatchingNodes.Any()) { ObjectLists.Add(new ObjectListNode(Item.EvaluatedInclude, "msvc", IntDir, FormattedCompilerOptions, ExcludePrecompiledHeader ? "" : PrecompiledHeaderString)); } } PrecompiledHeaderString = ""; var ResourceCompileItems = ActiveProject.GetItems("ResourceCompile"); foreach (var Item in ResourceCompileItems) { if (Item.DirectMetadata.Any()) { if (Item.DirectMetadata.Where(dmd => dmd.Name == "ExcludedFromBuild" && dmd.EvaluatedValue == "true").Any()) { continue; } } ToolTask Task = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.RC")); string ResourceCompilerOptions = GenerateTaskCommandLine(Task, new string[] { "ResourceOutputFileName", "DesigntimePreprocessorDefinitions" }, Item.Metadata); string formattedCompilerOptions = string.Format("{0} /fo\"%2\" \"%1\"", ResourceCompilerOptions); var MatchingNodes = ObjectLists.Where(el => el.AddIfMatches(Item.EvaluatedInclude, "rc", IntDir, formattedCompilerOptions, PrecompiledHeaderString)); if (!MatchingNodes.Any()) { ObjectLists.Add(new ObjectListNode(Item.EvaluatedInclude, "rc", IntDir, formattedCompilerOptions, PrecompiledHeaderString, ".res")); } } int ActionNumber = 0; foreach (ObjectListNode ObjList in ObjectLists) { OutputString.Append(ObjList.ToString(ActionNumber)); ActionNumber++; } if (ActionNumber > 0) { HasCompileActions = true; } else { HasCompileActions = false; Console.WriteLine("Project has no actions to compile."); } string CompileActions = string.Join(",", Enumerable.Range(0, ActionNumber).ToList().ConvertAll(x => string.Format("'action_{0}'", x)).ToArray()); if (BuildOutput == BuildType.Application || BuildOutput == BuildType.DynamicLib) { OutputString.AppendFormat("{0}('output')\n{{", BuildOutput == BuildType.Application ? "Executable" : "DLL"); if (Platform == "Win32" || Platform == "x86") { OutputString.Append("\t.Linker = '$VSBasePath$\\VC\\bin\\link.exe'\n"); } else { OutputString.Append("\t.Linker = '$VSBasePath$\\VC\\bin\\amd64\\link.exe'\n"); } var LinkDefinitions = ActiveProject.ItemDefinitions["Link"]; string OutputFile = LinkDefinitions.GetMetadataValue("OutputFile").Replace('\\', '/'); if (HasCompileActions) { string DependencyOutputPath = LinkDefinitions.GetMetadataValue("ImportLibrary"); if (Path.IsPathRooted(DependencyOutputPath)) { DependencyOutputPath = DependencyOutputPath.Replace('\\', '/'); } else { DependencyOutputPath = Path.Combine(ActiveProject.DirectoryPath, DependencyOutputPath).Replace('\\', '/'); } foreach (var deps in CurrentProject.Dependents) { deps.AdditionalLinkInputs += " \"" + DependencyOutputPath + "\" "; } } ToolTask Task = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.Link")); string LinkerOptions = GenerateTaskCommandLine(Task, new string[] { "OutputFile", "ProfileGuidedDatabase" }, LinkDefinitions.Metadata); if (!string.IsNullOrEmpty(CurrentProject.AdditionalLinkInputs)) { LinkerOptions += CurrentProject.AdditionalLinkInputs; } OutputString.AppendFormat("\t.LinkerOptions = '\"%1\" /OUT:\"%2\" {0}'\n", LinkerOptions.Replace("'", "^'")); OutputString.AppendFormat("\t.LinkerOutput = '{0}'\n", OutputFile); OutputString.Append("\t.Libraries = { "); OutputString.Append(CompileActions); OutputString.Append(" }\n"); OutputString.Append("}\n\n"); } else if (BuildOutput == BuildType.StaticLib) { OutputString.Append("Library('output')\n{"); OutputString.Append("\t.Compiler = 'msvc'\n"); OutputString.Append(string.Format("\t.CompilerOptions = '\"%1\" /Fo\"%2\" /c {0}'\n", CompilerOptions)); OutputString.Append(string.Format("\t.CompilerOutputPath = \"{0}\"\n", IntDir)); if (Platform == "Win32" || Platform == "x86") { OutputString.Append("\t.Librarian = '$VSBasePath$\\VC\\bin\\lib.exe'\n"); } else { OutputString.Append("\t.Librarian = '$VSBasePath$\\VC\\bin\\amd64\\lib.exe'\n"); } var LibDefinitions = ActiveProject.ItemDefinitions["Lib"]; string OutputFile = LibDefinitions.GetMetadataValue("OutputFile").Replace('\\', '/'); if (HasCompileActions) { string DependencyOutputPath = ""; if (Path.IsPathRooted(OutputFile)) { DependencyOutputPath = Path.GetFullPath(OutputFile).Replace('\\', '/'); } else { DependencyOutputPath = Path.Combine(ActiveProject.DirectoryPath, OutputFile).Replace('\\', '/'); } foreach (var deps in CurrentProject.Dependents) { deps.AdditionalLinkInputs += " \"" + DependencyOutputPath + "\" "; } } ToolTask task = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.LIB")); string linkerOptions = GenerateTaskCommandLine(task, new string[] { "OutputFile" }, LibDefinitions.Metadata); if (!string.IsNullOrEmpty(CurrentProject.AdditionalLinkInputs)) { linkerOptions += CurrentProject.AdditionalLinkInputs; } OutputString.AppendFormat("\t.LibrarianOptions = '\"%1\" /OUT:\"%2\" {0}'\n", linkerOptions); OutputString.AppendFormat("\t.LibrarianOutput = '{0}'\n", OutputFile); OutputString.Append("\t.LibrarianAdditionalInputs = { "); OutputString.Append(CompileActions); OutputString.Append(" }\n"); OutputString.Append("}\n\n"); } if (ActiveProject.GetItems("PostBuildEvent").Any()) { ProjectItem BuildEvent = ActiveProject.GetItems("PostBuildEvent").First(); if (BuildEvent.Metadata.Any()) { ProjectMetadata MetaData = BuildEvent.Metadata.First(); if (!string.IsNullOrEmpty(MetaData.EvaluatedValue)) { string BatchText = "call \"" + VCBasePath + "vcvarsall.bat\" " + (Platform == "Win32" ? "x86" : "x64") + " " + (PlatformToolsetVersion == "140" ? WindowsSDKTarget : "") + "\n"; PostBuildBatchFile = Path.Combine(ActiveProject.DirectoryPath, Path.GetFileNameWithoutExtension(ActiveProject.FullPath) + "_postbuild.bat"); File.WriteAllText(PostBuildBatchFile, BatchText + MetaData.EvaluatedValue); OutputString.Append("Exec('postbuild') \n{\n"); OutputString.AppendFormat("\t.ExecExecutable = '{0}' \n", PostBuildBatchFile); OutputString.AppendFormat("\t.ExecInput = '{0}' \n", PostBuildBatchFile); OutputString.AppendFormat("\t.ExecOutput = '{0}' \n", PostBuildBatchFile + ".txt"); OutputString.Append("\t.PreBuildDependencies = 'output' \n"); OutputString.Append("\t.ExecUseStdOutAsOutput = true \n"); OutputString.Append("}\n\n"); } } } OutputString.AppendFormat("Alias ('all')\n{{\n\t.Targets = {{ '{0}' }}\n}} ", string.IsNullOrEmpty(PostBuildBatchFile) ? "output" : "postbuild"); if (FileChanged || CommandLineOptions.AlwaysRegenerate) { File.WriteAllText(BFFOutputFilePath, OutputString.ToString()); } }
/// <summary> /// Returns the command line with arguments that a ToolTask will execute /// </summary> /// <param name="task">The ToolTask</param> /// <returns></returns> public static string GetToolTaskCommand(ToolTask task) { MethodInfo method = task.GetType().GetMethod("GenerateCommandLineCommands", BindingFlags.Instance | BindingFlags.NonPublic); return((string)method.Invoke(task, null)); }
/// <summary> /// Returns the full path to the command that will be executed by a ToolTask /// </summary> /// <param name="task">The ToolTask</param> /// <returns></returns> public static string GetToolTaskToolPath(ToolTask task) { MethodInfo method = task.GetType().GetMethod("GenerateFullPathToTool", BindingFlags.Instance | BindingFlags.NonPublic); return((string)method.Invoke(task, null)); }
static private void GenerateBffFromVcxproj(string Config, string Platform) { Project ActiveProject = CurrentProject.Proj; string MD5hash = "wafflepalooza"; PreBuildBatchFile = ""; PostBuildBatchFile = ""; bool FileChanged = HasFileChanged(ActiveProject.FullPath, Platform, Config, out MD5hash); string configType = ActiveProject.GetProperty("ConfigurationType").EvaluatedValue; switch (configType) { case "DynamicLibrary": BuildOutput = BuildType.DynamicLib; break; case "StaticLibrary": BuildOutput = BuildType.StaticLib; break; default: case "Application": BuildOutput = BuildType.Application; break; } //PlatformToolsetVersion = ActiveProject.GetProperty("PlatformToolsetVersion").EvaluatedValue; string OutDir = ActiveProject.GetProperty("OutDir").EvaluatedValue; string IntDir = ActiveProject.GetProperty("IntDir").EvaluatedValue; StringBuilder OutputString = new StringBuilder(MD5hash + "\n\n"); OutputString.AppendFormat(".VSBasePath = '{0}'\n", ActiveProject.GetProperty("VSInstallDir").EvaluatedValue); VCBasePath = ActiveProject.GetProperty("VCInstallDir").EvaluatedValue; OutputString.AppendFormat(".VCBasePath = '{0}'\n", VCBasePath); if (Platform == "Win32" || Platform == "x86") { VCExePath = ActiveProject.GetProperty("VC_ExecutablePath_x86_x86").EvaluatedValue; } else { VCExePath = ActiveProject.GetProperty("VC_ExecutablePath_x64_x64").EvaluatedValue; } OutputString.AppendFormat(".VCExePath = '{0}'\n", VCExePath); WindowsSDKTarget = ActiveProject.GetProperty("WindowsTargetPlatformVersion") != null?ActiveProject.GetProperty("WindowsTargetPlatformVersion").EvaluatedValue : "8.1"; string winSdkDir = ActiveProject.GetProperty("WindowsSdkDir").EvaluatedValue; OutputString.AppendFormat(".WindowsSDKBasePath = '{0}'\n\n", winSdkDir); OutputString.Append("Settings\n{\n\t.Environment = \n\t{\n"); OutputString.AppendFormat("\t\t\"INCLUDE={0}\",\n", ActiveProject.GetProperty("IncludePath").EvaluatedValue); OutputString.AppendFormat("\t\t\"LIB={0}\",\n", ActiveProject.GetProperty("LibraryPath").EvaluatedValue); OutputString.AppendFormat("\t\t\"LIBPATH={0}\",\n", ActiveProject.GetProperty("ReferencePath").EvaluatedValue); OutputString.AppendFormat("\t\t\"PATH={0}\"\n", ActiveProject.GetProperty("Path").EvaluatedValue); OutputString.AppendFormat("\t\t\"TMP={0}\"\n", ActiveProject.GetProperty("Temp").EvaluatedValue); OutputString.AppendFormat("\t\t\"TEMP={0}\"\n", ActiveProject.GetProperty("Temp").EvaluatedValue); OutputString.AppendFormat("\t\t\"SystemRoot={0}\"\n", ActiveProject.GetProperty("SystemRoot").EvaluatedValue); OutputString.Append("\t}\n}\n\n"); StringBuilder CompilerString = new StringBuilder("Compiler('msvc')\n{\n"); string CompilerRoot = VCExePath; CompilerString.Append("\t.Root = '$VCExePath$'\n"); CompilerString.Append("\t.Executable = '$Root$\\cl.exe'\n"); CompilerString.Append("\t.ExtraFiles =\n\t{\n"); CompilerString.Append("\t\t'$Root$\\c1.dll'\n"); CompilerString.Append("\t\t'$Root$\\c1xx.dll'\n"); CompilerString.Append("\t\t'$Root$\\c2.dll'\n"); CompilerString.Append("\t\t'$Root$\\atlprov.dll'\n"); // Only needed if using ATL if (File.Exists(CompilerRoot + "1033\\clui.dll")) //Check English first... { CompilerString.Append("\t\t'$Root$\\1033\\clui.dll'\n"); } else { var numericDirectories = Directory.GetDirectories(CompilerRoot).Where(d => Path.GetFileName(d).All(char.IsDigit)); var cluiDirectories = numericDirectories.Where(d => Directory.GetFiles(d, "clui.dll").Any()); if (cluiDirectories.Any()) { CompilerString.AppendFormat("\t\t'$Root$\\{0}\\clui.dll'\n", Path.GetFileName(cluiDirectories.First())); CompilerString.AppendFormat(string.Format("\t\t'$Root$\\{0}\\mspft{1}ui.dll'\n", Path.GetFileName(cluiDirectories.First()), PlatformToolsetVersion)); // Localized messages for static analysis https://www.fastbuild.org/docs/functions/compiler.html } } CompilerString.Append("\t\t'$Root$\\mspdbsrv.exe'\n"); CompilerString.Append("\t\t'$Root$\\mspdbcore.dll'\n"); CompilerString.AppendFormat("\t\t'$Root$\\mspft{0}.dll'\n", PlatformToolsetVersion); CompilerString.AppendFormat("\t\t'$Root$\\msobj{0}.dll'\n", PlatformToolsetVersion); CompilerString.AppendFormat("\t\t'$Root$\\mspdb{0}.dll'\n", PlatformToolsetVersion); var redistDirs = Directory.GetDirectories(VCBasePath.ToString() + "Redist\\MSVC\\", "*", SearchOption.TopDirectoryOnly); if (redistDirs.Length > 0) { Regex regex = new Regex(@"\d{2}\.\d{2}\.\d{5}$"); string redistDir = redistDirs.First((s) => { return(regex.IsMatch(s)); }); if (Compiler == WindowsCompiler.VisualStudio2019) { //CompilerString.AppendFormat("\t\t'{0}\\x64\\Microsoft.VC142.CRT\\msvcp{1}.dll'\n", redistDir, PlatformToolsetVersion); //CompilerString.AppendFormat("\t\t'{0}\\x64\\Microsoft.VC142.CRT\\vccorlib{1}.dll'\n", redistDir, PlatformToolsetVersion); //CompilerString.AppendFormat("\t\t'{0}\\x64\\Microsoft.VC142.CRT\\vcruntime{1}.dll'\n", redistDir, PlatformToolsetVersion); //CompilerString.AppendFormat("\t\t'{0}\\x64\\Microsoft.VC142.CRT\\vcruntime{1}_1.dll'\n", redistDir, PlatformToolsetVersion); // Required as of 16.5.1 (14.25.28610) } else if (Compiler == WindowsCompiler.VisualStudio2017) { //VS 2017 is really confusing in terms of version numbers and paths so these values might need to be modified depending on what version of the tool chain you // chose to install. CompilerString.AppendFormat("\t\t'{0}\\x64\\Microsoft.VC141.CRT\\msvcp{1}.dll'\n", redistDir, PlatformToolsetVersion); CompilerString.AppendFormat("\t\t'{0}\\x64\\Microsoft.VC141.CRT\\vccorlib{1}.dll'\n", redistDir, PlatformToolsetVersion); } } CompilerString.AppendFormat("\t\t'$Root$\\tbbmalloc.dll'\n"); //导入依赖目录 foreach (string path in CommandLineOptions.ThirdParty) { string dir = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); //统一到windows的反斜杠 \ if (dir.Last() != Path.DirectorySeparatorChar) { AddExtraFiles(CompilerString, path); } else { AddExtraFiles(CompilerString, Path.GetDirectoryName(dir)); } } //foreach (string path in FASTBuild_Toolchain) //{ // AddExtraFiles(CompilerString, path); //} // CompilerString.Append("\t}\n"); //End extra files CompilerString.Append("}\n\n"); //End compiler string rcPath = "\\bin\\" + WindowsSDKTarget + "\\x64\\rc.exe"; if (!File.Exists(winSdkDir + rcPath)) { rcPath = "\\bin\\x64\\rc.exe"; } CompilerString.Append("Compiler('rc')\n{\n"); CompilerString.Append("\t.Executable = '$WindowsSDKBasePath$" + rcPath + "'\n"); CompilerString.Append("\t.CompilerFamily = 'custom'\n"); CompilerString.Append("}\n\n"); //End rc compiler OutputString.Append(CompilerString); if (ActiveProject.GetItems("PreBuildEvent").Any()) { var buildEvent = ActiveProject.GetItems("PreBuildEvent").First(); if (buildEvent.Metadata.Any()) { var mdPi = buildEvent.Metadata.First(); if (!string.IsNullOrEmpty(mdPi.EvaluatedValue)) { string BatchText = "call \"" + VCBasePath + "Auxiliary\\Build\\vcvarsall.bat\" " + (Platform == "Win32" ? "x86" : "x64") + " " + WindowsSDKTarget + "\n"; PreBuildBatchFile = Path.Combine(ActiveProject.DirectoryPath, Path.GetFileNameWithoutExtension(ActiveProject.FullPath) + "_prebuild.bat"); File.WriteAllText(PreBuildBatchFile, BatchText + mdPi.EvaluatedValue); OutputString.Append("Exec('prebuild') \n{\n"); OutputString.AppendFormat("\t.ExecExecutable = '{0}' \n", PreBuildBatchFile); OutputString.AppendFormat("\t.ExecInput = '{0}' \n", PreBuildBatchFile); OutputString.AppendFormat("\t.ExecOutput = '{0}' \n", PreBuildBatchFile + ".txt"); OutputString.Append("\t.ExecUseStdOutAsOutput = true \n"); OutputString.Append("}\n\n"); } } } string CompilerOptions = ""; List <ObjectListNode> ObjectLists = new List <ObjectListNode>(); var CompileItems = ActiveProject.GetItems("ClCompile"); string PrecompiledHeaderString = ""; foreach (var Item in CompileItems) { if (Item.DirectMetadata.Any()) { if (Item.DirectMetadata.Where(dmd => dmd.Name == "ExcludedFromBuild" && dmd.EvaluatedValue == "true").Any()) { continue; } if (Item.DirectMetadata.Where(dmd => dmd.Name == "PrecompiledHeader" && dmd.EvaluatedValue == "Create").Any()) { ToolTask CLtask = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.CL")); CLtask.GetType().GetProperty("Sources").SetValue(CLtask, new TaskItem[] { new TaskItem() }); string pchCompilerOptions = GenerateTaskCommandLine(CLtask, new string[] { "PrecompiledHeaderOutputFile", "ObjectFileName", "AssemblerListingLocation" }, Item.Metadata) + " /FS"; PrecompiledHeaderString = "\t.PCHOptions = '" + string.Format("\"%1\" /Fp\"%2\" /Fo\"%3\" {0} '\n", pchCompilerOptions); PrecompiledHeaderString += "\t.PCHInputFile = '" + Item.EvaluatedInclude + "'\n"; PrecompiledHeaderString += "\t.PCHOutputFile = '" + Item.GetMetadataValue("PrecompiledHeaderOutputFile") + "'\n"; break; //Assumes only one pch... } } } foreach (var Item in CompileItems) { bool ExcludePrecompiledHeader = false; if (Item.DirectMetadata.Any()) { if (Item.DirectMetadata.Where(dmd => dmd.Name == "ExcludedFromBuild" && dmd.EvaluatedValue == "true").Any()) { continue; } if (Item.DirectMetadata.Where(dmd => dmd.Name == "PrecompiledHeader" && dmd.EvaluatedValue == "Create").Any()) { continue; } if (Item.DirectMetadata.Where(dmd => dmd.Name == "PrecompiledHeader" && dmd.EvaluatedValue == "NotUsing").Any()) { ExcludePrecompiledHeader = true; } } ToolTask Task = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.CL")); Task.GetType().GetProperty("Sources").SetValue(Task, new TaskItem[] { new TaskItem() }); //CPPTasks throws an exception otherwise... string TempCompilerOptions = GenerateTaskCommandLine(Task, new string[] { "ObjectFileName", "AssemblerListingLocation" }, Item.Metadata) + " /FS"; if (Path.GetExtension(Item.EvaluatedInclude) == ".c") { TempCompilerOptions += " /TC"; } else { TempCompilerOptions += " /TP"; } CompilerOptions = TempCompilerOptions; string FormattedCompilerOptions = string.Format("\"%1\" /Fo\"%2\" {0}", TempCompilerOptions); var MatchingNodes = ObjectLists.Where(el => el.AddIfMatches(Item.EvaluatedInclude, "msvc", IntDir, FormattedCompilerOptions, ExcludePrecompiledHeader ? "" : PrecompiledHeaderString)); if (!MatchingNodes.Any()) { ObjectLists.Add(new ObjectListNode(Item.EvaluatedInclude, "msvc", IntDir, FormattedCompilerOptions, ExcludePrecompiledHeader ? "" : PrecompiledHeaderString)); } } PrecompiledHeaderString = ""; var ResourceCompileItems = ActiveProject.GetItems("ResourceCompile"); foreach (var Item in ResourceCompileItems) { if (Item.DirectMetadata.Any()) { if (Item.DirectMetadata.Where(dmd => dmd.Name == "ExcludedFromBuild" && dmd.EvaluatedValue == "true").Any()) { continue; } } ToolTask Task = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.RC")); string ResourceCompilerOptions = GenerateTaskCommandLine(Task, new string[] { "ResourceOutputFileName", "DesigntimePreprocessorDefinitions" }, Item.Metadata); string formattedCompilerOptions = string.Format("{0} /fo\"%2\" \"%1\"", ResourceCompilerOptions); var MatchingNodes = ObjectLists.Where(el => el.AddIfMatches(Item.EvaluatedInclude, "rc", IntDir, formattedCompilerOptions, PrecompiledHeaderString)); if (!MatchingNodes.Any()) { ObjectLists.Add(new ObjectListNode(Item.EvaluatedInclude, "rc", IntDir, formattedCompilerOptions, PrecompiledHeaderString, ".res")); } } int ActionNumber = 0; foreach (ObjectListNode ObjList in ObjectLists) { OutputString.Append(ObjList.ToString(ActionNumber)); ActionNumber++; } if (ActionNumber > 0) { HasCompileActions = true; } else { HasCompileActions = false; Console.WriteLine("Project has no actions to compile."); } string CompileActions = string.Join(",", Enumerable.Range(0, ActionNumber).ToList().ConvertAll(x => string.Format("'action_{0}'", x)).ToArray()); if (BuildOutput == BuildType.Application || BuildOutput == BuildType.DynamicLib) { OutputString.AppendFormat("{0}('output')\n{{", BuildOutput == BuildType.Application ? "Executable" : "DLL"); OutputString.Append("\t.Linker = '$VCExePath$\\link.exe'\n"); var LinkDefinitions = ActiveProject.ItemDefinitions["Link"]; string OutputFile = LinkDefinitions.GetMetadataValue("OutputFile").Replace('\\', '/'); if (HasCompileActions) { string DependencyOutputPath = LinkDefinitions.GetMetadataValue("ImportLibrary"); if (Path.IsPathRooted(DependencyOutputPath)) { DependencyOutputPath = DependencyOutputPath.Replace('\\', '/'); } else { DependencyOutputPath = Path.Combine(ActiveProject.DirectoryPath, DependencyOutputPath).Replace('\\', '/'); } foreach (var deps in CurrentProject.Dependents) { deps.AdditionalLinkInputs += " \"" + DependencyOutputPath + "\" "; } } ToolTask Task = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.Link")); string LinkerOptions = GenerateTaskCommandLine(Task, new string[] { "OutputFile", "ProfileGuidedDatabase" }, LinkDefinitions.Metadata); if (!string.IsNullOrEmpty(CurrentProject.AdditionalLinkInputs)) { LinkerOptions += CurrentProject.AdditionalLinkInputs; } OutputString.AppendFormat("\t.LinkerOptions = '\"%1\" /OUT:\"%2\" {0}'\n", LinkerOptions.Replace("'", "^'")); OutputString.AppendFormat("\t.LinkerOutput = '{0}'\n", OutputFile); OutputString.Append("\t.Libraries = { "); OutputString.Append(CompileActions); OutputString.Append(" }\n"); OutputString.Append("}\n\n"); } else if (BuildOutput == BuildType.StaticLib) { OutputString.Append("Library('output')\n{"); OutputString.Append("\t.Compiler = 'msvc'\n"); OutputString.Append(string.Format("\t.CompilerOptions = '\"%1\" /Fo\"%2\" /c {0}'\n", CompilerOptions)); OutputString.Append(string.Format("\t.CompilerOutputPath = \"{0}\"\n", IntDir)); OutputString.Append("\t.Librarian = '$VCExePath$\\lib.exe'\n"); var LibDefinitions = ActiveProject.ItemDefinitions["Lib"]; string OutputFile = LibDefinitions.GetMetadataValue("OutputFile").Replace('\\', '/'); if (HasCompileActions) { string DependencyOutputPath = ""; if (Path.IsPathRooted(OutputFile)) { DependencyOutputPath = Path.GetFullPath(OutputFile).Replace('\\', '/'); } else { DependencyOutputPath = Path.Combine(ActiveProject.DirectoryPath, OutputFile).Replace('\\', '/'); } foreach (var deps in CurrentProject.Dependents) { deps.AdditionalLinkInputs += " \"" + DependencyOutputPath + "\" "; } } ToolTask task = (ToolTask)Activator.CreateInstance(CPPTasksAssembly.GetType("Microsoft.Build.CPPTasks.LIB")); string linkerOptions = GenerateTaskCommandLine(task, new string[] { "OutputFile" }, LibDefinitions.Metadata); if (!string.IsNullOrEmpty(CurrentProject.AdditionalLinkInputs)) { linkerOptions += CurrentProject.AdditionalLinkInputs; } OutputString.AppendFormat("\t.LibrarianOptions = '\"%1\" /OUT:\"%2\" {0}'\n", linkerOptions); OutputString.AppendFormat("\t.LibrarianOutput = '{0}'\n", OutputFile); OutputString.Append("\t.LibrarianAdditionalInputs = { "); OutputString.Append(CompileActions); OutputString.Append(" }\n"); OutputString.Append("}\n\n"); } if (ActiveProject.GetItems("PostBuildEvent").Any()) { ProjectItem BuildEvent = ActiveProject.GetItems("PostBuildEvent").First(); if (BuildEvent.Metadata.Any()) { ProjectMetadata MetaData = BuildEvent.Metadata.First(); if (!string.IsNullOrEmpty(MetaData.EvaluatedValue)) { string BatchText = "call \"" + VCBasePath + "Auxiliary\\Build\\vcvarsall.bat\" " + (Platform == "Win32" ? "x86" : "x64") + " " + WindowsSDKTarget + "\n"; PostBuildBatchFile = Path.Combine(ActiveProject.DirectoryPath, Path.GetFileNameWithoutExtension(ActiveProject.FullPath) + "_postbuild.bat"); File.WriteAllText(PostBuildBatchFile, BatchText + MetaData.EvaluatedValue); OutputString.Append("Exec('postbuild') \n{\n"); OutputString.AppendFormat("\t.ExecExecutable = '{0}' \n", PostBuildBatchFile); OutputString.AppendFormat("\t.ExecInput = '{0}' \n", PostBuildBatchFile); OutputString.AppendFormat("\t.ExecOutput = '{0}' \n", PostBuildBatchFile + ".txt"); OutputString.Append("\t.PreBuildDependencies = 'output' \n"); OutputString.Append("\t.ExecUseStdOutAsOutput = true \n"); OutputString.Append("}\n\n"); } } } OutputString.AppendFormat("Alias ('all')\n{{\n\t.Targets = {{ '{0}' }}\n}}", string.IsNullOrEmpty(PostBuildBatchFile) ? "output" : "postbuild"); if (FileChanged || CommandLineOptions.AlwaysRegenerate) { File.WriteAllText(BFFOutputFilePath, OutputString.ToString()); } }