/// <summary> /// Link the resulting object files /// </summary> private async Task CheckLinkLibraryAsync( string path, Recipe recipe, string objectDirectory, string binaryDirectory, bool force) { var allFiles = new List <string>(recipe.Source); if (recipe.Type == RecipeType.Library) { allFiles.Add(recipe.Public); } // Convert all source files into objects var objectFiles = recipe.Source.Select(file => $"{objectDirectory.EnsureTrailingSlash()}{Path.GetFileNameWithoutExtension(file)}.{_compiler.ObjectFileExtension}").ToList(); // Add the modules object too objectFiles.Add($"{objectDirectory.EnsureTrailingSlash()}{Path.GetFileNameWithoutExtension(recipe.Public)}.{_compiler.ObjectFileExtension}"); var targetLibraryFile = Path.Combine(binaryDirectory, $"{recipe.Name}.{_compiler.StaticLibraryFileExtension}"); if (force || BuildRequiredChecker.IsOutdated(path, targetLibraryFile, objectFiles)) { Log.Info("Link library"); var args = new LinkerArguments() { Name = recipe.Name, RootDirectory = path, OutputDirectory = binaryDirectory, SourceFiles = objectFiles, }; // Ensure the object directory exists var objectDirectry = Path.Combine(args.RootDirectory, binaryDirectory); if (!Directory.Exists(objectDirectry)) { Directory.CreateDirectory(objectDirectry); } // Link await _compiler.LinkLibraryAsync(args); } else { Log.Info("Static library up to date."); } }
/// <summary> /// Compile the module file /// </summary> private async Task <bool> CheckCompileModuleAsync( string path, Recipe recipe, BuildState buildState, IList <string> includePaths, string objectDirectory, string binaryDirectory, bool force) { var outputFilename = $"{Path.GetFileNameWithoutExtension(recipe.Public)}.{_compiler.ModuleFileExtension}"; var outputFile = Path.Combine(objectDirectory, outputFilename); bool requiresBuild = true; if (!force) { // Add all of the direct dependencies as module references var modules = new List <string>(); var defines = new List <string>(); bool isRecursive = false; await BuildDependencyModuleReferences(path, binaryDirectory, recipe, modules, defines, isRecursive); // The dependencies for this file are all of the direct module references var dependencies = new List <string>(); dependencies.AddRange(modules); if (!BuildRequiredChecker.IsSourceFileOutdated(path, buildState, outputFile, recipe.Public, dependencies)) { // TODO : This is a hack. We need to actually look through all of the imports for the module file Log.Info("Module file is up to date."); requiresBuild = false; } } if (requiresBuild) { await CompileModuleAsync( path, recipe, buildState, includePaths, objectDirectory, binaryDirectory); } return(requiresBuild); }
/// <summary> /// Compile the supporting source files /// </summary> private async Task <bool> CheckCompileSourceAsync( string path, Recipe recipe, BuildState buildState, IList <string> includePaths, string objectDirectory, string binaryDirectory, bool force) { var modules = new List <string>(); var defines = new List <string>(); defines.Add("SOUP_BUILD"); if (recipe.Type == RecipeType.Library) { // Add a reference to our own modules interface definition var modulePath = Path.Combine( objectDirectory, $"{Path.GetFileNameWithoutExtension(recipe.Public)}.{_compiler.ModuleFileExtension}"); modules.Add(modulePath); defines.Add(BuildRecipeNamespaceDefine(recipe)); } // Add all of the direct dependencies as module references // and set their version defintions // TODO: MSVC requires all trasnsitive modules also bool isRecursive = _compiler.Name == "MSVC"; await BuildDependencyModuleReferences(path, binaryDirectory, recipe, modules, defines, isRecursive); var source = new List <string>(); // All files are dependent on the parent module and all referenced modules var sharedDependecies = new List <string>(); sharedDependecies.AddRange(modules); // Check if the precompiled module should be compiled if (recipe.Type == RecipeType.Library) { // Add the precompile module to the list of shared dependencies // TODO: Could optimize this to not do file datetime checks over again var moduleFile = Path.Combine(path, objectDirectory, $"{Path.GetFileNameWithoutExtension(recipe.Public)}.{_compiler.ModuleFileExtension}"); sharedDependecies.Add(moduleFile); var moduleOutputFile = Path.Combine(path, objectDirectory, $"{Path.GetFileNameWithoutExtension(recipe.Public)}.{_compiler.ObjectFileExtension}"); if (force || BuildRequiredChecker.IsOutdated(path, moduleOutputFile, sharedDependecies)) { // HACK if (_compiler.Name == "Clang") { source.Add(moduleFile); } } } // Check if each source file is out of date and requires a rebuild foreach (var sourceFile in recipe.Source) { var outputFile = Path.Combine(objectDirectory, $"{Path.GetFileNameWithoutExtension(sourceFile)}.{_compiler.ObjectFileExtension}"); if (force || BuildRequiredChecker.IsSourceFileOutdated(path, buildState, outputFile, sourceFile, sharedDependecies)) { source.Add(sourceFile); } } if (source.Count == 0) { Log.Info("All source is up to date."); return(false); } else { Log.Info("Compile Source"); var args = new CompileArguments() { Standard = Compiler.LanguageStandard.Latest, RootDirectory = path, OutputDirectory = objectDirectory, PreprocessorDefinitions = defines, SourceFiles = source, IncludeDirectories = includePaths, Modules = modules, GenerateIncludeTree = true, }; // Ensure the object directory exists var objectDirectry = Path.Combine(args.RootDirectory, objectDirectory); if (!Directory.Exists(objectDirectry)) { Directory.CreateDirectory(objectDirectry); } // Compile each file var result = await _compiler.CompileAsync(args); // Save the build state if (result.HeaderIncludeFiles != null) { buildState.UpdateIncludeTree(result.HeaderIncludeFiles); } return(true); } }