示例#1
0
        /// <summary>
        /// Copy runtime dependencies
        /// </summary>
        private void CopyRuntimeDependencies(
            BuildArguments arguments,
            BuildResult result)
        {
            if (arguments.TargetType == BuildTargetType.Executable ||
                arguments.TargetType == BuildTargetType.WindowsApplication ||
                arguments.TargetType == BuildTargetType.DynamicLibrary)
            {
                foreach (var source in arguments.RuntimeDependencies)
                {
                    var target    = arguments.BinaryDirectory + new Path(source.GetFileName());
                    var operation = SharedOperations.CreateCopyFileOperation(
                        arguments.TargetRootDirectory,
                        source,
                        target);
                    result.BuildOperations.Add(operation);

                    // Add the copied file as the new runtime dependency
                    result.RuntimeDependencies.Add(target);
                }
            }
            else
            {
                // Pass along all runtime dependencies in their original location
                foreach (var source in arguments.RuntimeDependencies)
                {
                    result.RuntimeDependencies.Add(source);
                }
            }
        }
示例#2
0
        /// <summary>
        /// Generate the required build operations for the requested build
        /// </summary>
        public BuildResult Execute(
            IBuildState buildState,
            BuildArguments arguments)
        {
            var result = new BuildResult();

            // All dependencies must include the entire interface dependency closure
            result.ModuleDependencies = new List <Path>(arguments.ModuleDependencies);

            // Ensure the output directories exists as the first step
            result.BuildOperations.Add(
                SharedOperations.CreateCreateDirectoryOperation(
                    arguments.TargetRootDirectory,
                    arguments.ObjectDirectory));
            result.BuildOperations.Add(
                SharedOperations.CreateCreateDirectoryOperation(
                    arguments.TargetRootDirectory,
                    arguments.BinaryDirectory));

            // Perform the core compilation of the source files
            CoreCompile(buildState, arguments, result);

            // Link the final target after all of the compile graph is done
            CoreLink(buildState, arguments, result);

            // Copy previous runtime dependencies after linking has completed
            CopyRuntimeDependencies(arguments, result);

            return(result);
        }
示例#3
0
        /// <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);
                }
            }
        }
示例#4
0
        /// <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);
            }
        }