private static void LoadTestDependencyBuildInput( IBuildState buildState, IValueTable activeState, BuildArguments arguments) { if (activeState.TryGetValue("Dependencies", out var dependenciesValue)) { var dependenciesTable = dependenciesValue.AsTable(); if (dependenciesTable.TryGetValue("Test", out var testValue)) { var testDependenciesTable = testValue.AsTable(); foreach (var dependencyName in testDependenciesTable) { // Combine the core dependency build inputs for the core build task buildState.LogTrace(TraceLevel.Information, "Combine Test Dependency: " + dependencyName.Key); var dependencyTable = dependencyName.Value.AsTable(); if (dependencyTable.TryGetValue("Build", out var buildValue)) { var dependencyBuildTable = buildValue.AsTable(); if (dependencyBuildTable.TryGetValue("ModuleDependencies", out var moduleDependenciesValue)) { arguments.ModuleDependencies = CombineUnique( arguments.ModuleDependencies, moduleDependenciesValue.AsList().Select(value => new Path(value.AsString()))); } if (dependencyBuildTable.TryGetValue("RuntimeDependencies", out var runtimeDependenciesValue)) { arguments.RuntimeDependencies = CombineUnique( arguments.RuntimeDependencies, runtimeDependenciesValue.AsList().Select(value => new Path(value.AsString()))); } if (dependencyBuildTable.TryGetValue("LinkDependencies", out var linkDependenciesValue)) { arguments.LinkDependencies = CombineUnique( arguments.LinkDependencies, linkDependenciesValue.AsList().Select(value => new Path(value.AsString()))); } } } } } }
/// <summary> /// Compile the module and source files /// </summary> private void CoreCompile( IBuildState buildState, BuildArguments arguments, BuildResult result) { // Ensure there are actually files to build if (arguments.ModuleInterfacePartitionSourceFiles.Count != 0 || !arguments.ModuleInterfaceSourceFile.IsEmpty || arguments.SourceFiles.Count != 0) { // Setup the shared properties var compileArguments = new SharedCompileArguments() { Standard = arguments.LanguageStandard, Optimize = Convert(arguments.OptimizationLevel), SourceRootDirectory = arguments.SourceRootDirectory, TargetRootDirectory = arguments.TargetRootDirectory, ObjectDirectory = arguments.ObjectDirectory, IncludeDirectories = arguments.IncludeDirectories, IncludeModules = arguments.ModuleDependencies, PreprocessorDefinitions = arguments.PreprocessorDefinitions, GenerateSourceDebugInfo = arguments.GenerateSourceDebugInfo, EnableWarningsAsErrors = arguments.EnableWarningsAsErrors, DisabledWarnings = arguments.DisabledWarnings, EnabledWarnings = arguments.EnabledWarnings, CustomProperties = arguments.CustomProperties, }; // Compile the resource file if present if (!arguments.ResourceFile.IsEmpty) { buildState.LogTrace(TraceLevel.Information, "Generate Resource File Compile: " + arguments.ResourceFile.ToString()); var compiledResourceFile = arguments.ObjectDirectory + new Path(arguments.ResourceFile.GetFileName()); compiledResourceFile.SetFileExtension(_compiler.ResourceFileExtension); var compileResourceFileArguments = new ResourceCompileArguments() { SourceFile = arguments.ResourceFile, TargetFile = compiledResourceFile, }; // Add the resource file arguments to the shared build definition compileArguments.ResourceFile = compileResourceFileArguments; } // Build up the entire Interface Dependency Closure for each file var partitionInterfaceDependencyLookup = new Dictionary <Path, IReadOnlyList <Path> >(); foreach (var file in arguments.ModuleInterfacePartitionSourceFiles) { partitionInterfaceDependencyLookup.Add(file.File, file.Imports); } // Compile the individual module interface partition translation units var compileInterfacePartitionUnits = new List <InterfaceUnitCompileArguments>(); var allPartitionInterfaces = new List <Path>(); foreach (var file in arguments.ModuleInterfacePartitionSourceFiles) { buildState.LogTrace(TraceLevel.Information, "Generate Module Interface Partition Compile Operation: " + file.File.ToString()); var objectModuleInterfaceFile = arguments.ObjectDirectory + new Path(file.File.GetFileName()); objectModuleInterfaceFile.SetFileExtension(_compiler.ModuleFileExtension); var interfaceDependencyClosure = new HashSet <Path>(); BuildClosure(interfaceDependencyClosure, file.File, partitionInterfaceDependencyLookup); if (interfaceDependencyClosure.Contains(file.File)) { throw new InvalidOperationException($"Circular partition references in: {file.File}"); } var partitionImports = new List <Path>(); foreach (var import in interfaceDependencyClosure) { var importInterface = arguments.ObjectDirectory + new Path(import.GetFileName()); importInterface.SetFileExtension(_compiler.ModuleFileExtension); partitionImports.Add(arguments.TargetRootDirectory + importInterface); } var compileFileArguments = new InterfaceUnitCompileArguments() { SourceFile = file.File, TargetFile = arguments.ObjectDirectory + new Path(file.File.GetFileName()), IncludeModules = partitionImports, ModuleInterfaceTarget = objectModuleInterfaceFile, }; compileFileArguments.TargetFile.SetFileExtension(_compiler.ObjectFileExtension); compileInterfacePartitionUnits.Add(compileFileArguments); allPartitionInterfaces.Add(arguments.TargetRootDirectory + objectModuleInterfaceFile); } // Add all partition unit interface files as module dependencies since MSVC does not // combine the interfaces into the final interface unit foreach (var module in allPartitionInterfaces) { result.ModuleDependencies.Add(module); } compileArguments.InterfacePartitionUnits = compileInterfacePartitionUnits; // Compile the module interface unit if present if (!arguments.ModuleInterfaceSourceFile.IsEmpty) { buildState.LogTrace(TraceLevel.Information, "Generate Module Interface Unit Compile: " + arguments.ModuleInterfaceSourceFile.ToString()); var objectModuleInterfaceFile = arguments.ObjectDirectory + new Path(arguments.ModuleInterfaceSourceFile.GetFileName()); objectModuleInterfaceFile.SetFileExtension(_compiler.ModuleFileExtension); var binaryOutputModuleInterfaceFile = arguments.BinaryDirectory + new Path(arguments.TargetName + "." + _compiler.ModuleFileExtension); var compileModuleFileArguments = new InterfaceUnitCompileArguments() { SourceFile = arguments.ModuleInterfaceSourceFile, TargetFile = arguments.ObjectDirectory + new Path(arguments.ModuleInterfaceSourceFile.GetFileName()), IncludeModules = allPartitionInterfaces, ModuleInterfaceTarget = objectModuleInterfaceFile, }; compileModuleFileArguments.TargetFile.SetFileExtension(_compiler.ObjectFileExtension); // Add the interface unit arguments to the shared build definition compileArguments.InterfaceUnit = compileModuleFileArguments; // Copy the binary module interface to the binary directory after compiling var copyInterfaceOperation = SharedOperations.CreateCopyFileOperation( arguments.TargetRootDirectory, objectModuleInterfaceFile, binaryOutputModuleInterfaceFile); result.BuildOperations.Add(copyInterfaceOperation); // Add output module interface to the parent set of modules // This will allow the module implementation units access as well as downstream // dependencies to the public interface. result.ModuleDependencies.Add( binaryOutputModuleInterfaceFile.HasRoot ? binaryOutputModuleInterfaceFile : arguments.TargetRootDirectory + binaryOutputModuleInterfaceFile); } // Compile the individual translation units var compileImplementationUnits = new List <TranslationUnitCompileArguments>(compileArguments.ImplementationUnits); foreach (var file in arguments.SourceFiles) { buildState.LogTrace(TraceLevel.Information, "Generate Compile Operation: " + file.ToString()); var compileFileArguments = new TranslationUnitCompileArguments(); compileFileArguments.SourceFile = file; compileFileArguments.TargetFile = arguments.ObjectDirectory + new Path(file.GetFileName()); compileFileArguments.TargetFile.SetFileExtension(_compiler.ObjectFileExtension); compileImplementationUnits.Add(compileFileArguments); } compileArguments.ImplementationUnits = compileImplementationUnits; // Compile all source files as a single call var compileOperations = _compiler.CreateCompileOperations(compileArguments); foreach (var operation in compileOperations) { result.BuildOperations.Add(operation); } } }
/// <summary> /// Link the library /// </summary> private void CoreLink( IBuildState buildState, BuildArguments arguments, BuildResult result) { buildState.LogTrace(TraceLevel.Information, "CoreLink"); Path targetFile; var implementationFile = new Path(); switch (arguments.TargetType) { case BuildTargetType.StaticLibrary: targetFile = arguments.BinaryDirectory + new Path(arguments.TargetName + "." + _compiler.StaticLibraryFileExtension); break; case BuildTargetType.DynamicLibrary: targetFile = arguments.BinaryDirectory + new Path(arguments.TargetName + "." + _compiler.DynamicLibraryFileExtension); implementationFile = arguments.BinaryDirectory + new Path(arguments.TargetName + "." + _compiler.StaticLibraryFileExtension); break; case BuildTargetType.Executable: case BuildTargetType.WindowsApplication: targetFile = arguments.BinaryDirectory + new Path(arguments.TargetName + ".exe"); break; default: throw new InvalidOperationException("Unknown build target type."); } buildState.LogTrace(TraceLevel.Information, "Linking target"); var linkArguments = new LinkArguments() { TargetFile = targetFile, TargetArchitecture = arguments.TargetArchitecture, ImplementationFile = implementationFile, TargetRootDirectory = arguments.TargetRootDirectory, LibraryPaths = arguments.LibraryPaths, GenerateSourceDebugInfo = arguments.GenerateSourceDebugInfo, }; // Only resolve link libraries if not a library ourself if (arguments.TargetType != BuildTargetType.StaticLibrary) { linkArguments.ExternalLibraryFiles = arguments.PlatformLinkDependencies; linkArguments.LibraryFiles = arguments.LinkDependencies; } // Translate the target type into the link target // and determine what dependencies to inject into downstream builds switch (arguments.TargetType) { case BuildTargetType.StaticLibrary: { linkArguments.TargetType = LinkTarget.StaticLibrary; // Add the library as a link dependency and all recursive libraries result.LinkDependencies = new List <Path>(arguments.LinkDependencies); var absoluteTargetFile = linkArguments.TargetFile.HasRoot ? linkArguments.TargetFile : linkArguments.TargetRootDirectory + linkArguments.TargetFile; result.LinkDependencies.Add(absoluteTargetFile); break; } case BuildTargetType.DynamicLibrary: { linkArguments.TargetType = LinkTarget.DynamicLibrary; // Add the DLL as a runtime dependency var absoluteTargetFile = linkArguments.TargetFile.HasRoot ? linkArguments.TargetFile : linkArguments.TargetRootDirectory + linkArguments.TargetFile; result.RuntimeDependencies.Add(absoluteTargetFile); // Clear out all previous link dependencies and replace with the // single implementation library for the DLL var absoluteImplementationFile = linkArguments.ImplementationFile.HasRoot ? linkArguments.ImplementationFile : linkArguments.TargetRootDirectory + linkArguments.ImplementationFile; result.LinkDependencies.Add(absoluteImplementationFile); // Set the targe file result.TargetFile = absoluteTargetFile; break; } case BuildTargetType.Executable: { linkArguments.TargetType = LinkTarget.Executable; // Add the Executable as a runtime dependency var absoluteTargetFile = linkArguments.TargetFile.HasRoot ? linkArguments.TargetFile : linkArguments.TargetRootDirectory + linkArguments.TargetFile; result.RuntimeDependencies.Add(absoluteTargetFile); // All link dependencies stop here. // Set the targe file result.TargetFile = absoluteTargetFile; break; } case BuildTargetType.WindowsApplication: { linkArguments.TargetType = LinkTarget.WindowsApplication; // Add the Executable as a runtime dependency var absoluteTargetFile = linkArguments.TargetFile.HasRoot ? linkArguments.TargetFile : linkArguments.TargetRootDirectory + linkArguments.TargetFile; result.RuntimeDependencies.Add(absoluteTargetFile); // All link dependencies stop here. // Set the targe file result.TargetFile = absoluteTargetFile; break; } default: { throw new InvalidOperationException("Unknown build target type."); } } // Build up the set of object files var objectFiles = new List <Path>(); // Add the resource file if present if (!arguments.ResourceFile.IsEmpty) { var compiledResourceFile = arguments.ObjectDirectory + new Path(arguments.ResourceFile.GetFileName()); compiledResourceFile.SetFileExtension(_compiler.ResourceFileExtension); objectFiles.Add(compiledResourceFile); } // Add the partition object files foreach (var sourceFile in arguments.ModuleInterfacePartitionSourceFiles) { var objectFile = arguments.ObjectDirectory + new Path(sourceFile.File.GetFileName()); objectFile.SetFileExtension(_compiler.ObjectFileExtension); objectFiles.Add(objectFile); } // Add the module interface object file if present if (!arguments.ModuleInterfaceSourceFile.IsEmpty) { var objectFile = arguments.ObjectDirectory + new Path(arguments.ModuleInterfaceSourceFile.GetFileName()); objectFile.SetFileExtension(_compiler.ObjectFileExtension); objectFiles.Add(objectFile); } // Add the implementation unit object files foreach (var sourceFile in arguments.SourceFiles) { var objectFile = arguments.ObjectDirectory + new Path(sourceFile.GetFileName()); objectFile.SetFileExtension(_compiler.ObjectFileExtension); objectFiles.Add(objectFile); } linkArguments.ObjectFiles = objectFiles; // Perform the link buildState.LogTrace(TraceLevel.Information, "Generate Link Operation: " + linkArguments.TargetFile.ToString()); var linkOperation = _compiler.CreateLinkOperation(linkArguments); result.BuildOperations.Add(linkOperation); // Pass along the link arguments for internal access result.InternalLinkDependencies = new List <Path>(arguments.LinkDependencies); foreach (var file in linkArguments.ObjectFiles) { result.InternalLinkDependencies.Add(file); } }