Convert( this IStripToolSettings settings, Bam.Core.StringArray commandLine) { var module = (settings as Bam.Core.Settings).Module; if (settings.Verbose && !module.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.OSX)) { commandLine.Add("-v"); } if (settings.PreserveTimestamp && !module.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.OSX)) { commandLine.Add("-p"); } if (settings.StripDebugSymbols) { commandLine.Add("-S"); } if (settings.StripLocalSymbols) { commandLine.Add("-x"); } }
Convert( this IObjCopyToolSettings settings, Bam.Core.StringArray commandLine) { var objCopy = (settings as Bam.Core.Settings).Module as ObjCopyModule; switch (settings.Mode) { case EObjCopyToolMode.OnlyKeepDebug: commandLine.Add(System.String.Format("--only-keep-debug {0} {1}", objCopy.SourceModule.GeneratedPaths[objCopy.SourceKey].Parse(), objCopy.GeneratedPaths[ObjCopyModule.Key].Parse())); break; case EObjCopyToolMode.AddGNUDebugLink: commandLine.Add(System.String.Format("--add-gnu-debuglink={0} {1}", objCopy.GeneratedPaths[ObjCopyModule.Key].Parse(), objCopy.SourceModule.GeneratedPaths[objCopy.SourceKey].Parse())); break; default: throw new Bam.Core.Exception("Unrecognized objcopy mode, {0}", settings.Mode.ToString()); } if (settings.Verbose) { commandLine.Add("-v"); } }
GetPackageHash( StringArray sourceCode, StringArray definitions, Array <BamAssemblyDescription> bamAssemblies) { int hashCode = 0; foreach (var source in sourceCode) { hashCode ^= source.GetHashCode(); } foreach (var define in definitions) { hashCode ^= define.GetHashCode(); } foreach (var assembly in bamAssemblies) { var assemblyPath = System.IO.Path.Combine(Graph.Instance.ProcessState.ExecutableDirectory, assembly.Name) + ".dll"; var lastModifiedDate = System.IO.File.GetLastWriteTime(assemblyPath); hashCode ^= lastModifiedDate.GetHashCode(); } var hash = hashCode.ToString(); return(hash); }
protected DynamicExtensionModule( string moduleName, Bam.Core.StringArray sourceFiles) : this(moduleName, sourceFiles, null, null, null, null, null) { }
ISharedObjectSymbolicLinkPolicy.Symlink( SharedObjectSymbolicLink sender, Bam.Core.ExecutionContext context, Bam.Core.PreBuiltTool tool, ConsoleApplication target) { var commandLine = new Bam.Core.StringArray(); commandLine.Add("-s"); commandLine.Add("-f"); var sourceFile = sender.CreateTokenizedString("@filename($(0))", target.GeneratedPaths[ConsoleApplication.Key]); lock (sourceFile) { if (!sourceFile.IsParsed) { sourceFile.Parse(); } } commandLine.Add(sourceFile.ToStringQuoteIfNecessary()); var destination = sender.CreateTokenizedString("@dir($(0))/$(1)", target.GeneratedPaths[ConsoleApplication.Key], target.Macros[sender.Macros["SymlinkUsage"].ToString()]); lock (destination) { if (!destination.IsParsed) { destination.Parse(); } } commandLine.Add(destination.ToStringQuoteIfNecessary()); CommandLineProcessor.Processor.Execute(context, tool, commandLine); }
ISharedObjectSymbolicLinkPolicy.Symlink( SharedObjectSymbolicLink sender, Bam.Core.ExecutionContext context, Bam.Core.PreBuiltTool tool, ConsoleApplication target) { var meta = new MakeFileBuilder.MakeFileMeta(sender); var rule = meta.AddRule(); // since this is not a referenced type, need to specify a variable name for the MakeFile var variableName = new System.Text.StringBuilder(); variableName.Append(target.GetType().Name); // this is what it's building the symlink for variableName.Append("_"); variableName.Append(sender.Macros["SymlinkUsage"].ToString()); // intended usage rule.AddTarget(sender.GeneratedPaths[SharedObjectSymbolicLink.Key], variableName: variableName.ToString()); rule.AddPrerequisite(target, C.ConsoleApplication.Key); var commandLineArgs = new Bam.Core.StringArray(); commandLineArgs.Add("-s"); commandLineArgs.Add("-f"); var command = new System.Text.StringBuilder(); command.AppendFormat("{0} {1} $(notdir $<) $@ {2}", CommandLineProcessor.Processor.StringifyTool(tool), commandLineArgs.ToString(' '), CommandLineProcessor.Processor.TerminatingArgs(tool)); rule.AddShellCommand(command.ToString()); }
Init() { base.Init(); var publishRoot = this.CreateTokenizedString("$(packagebuilddir)/$(config)/PublicHeaders"); this.PublicPatch((settings, appliedTo) => { if (settings is C.ICommonPreprocessorSettings preprocessor) { preprocessor.IncludePaths.AddUnique(publishRoot); } }); var headerPaths = new Bam.Core.StringArray { "src/x86/ffitarget.h", "include/ffi_common.h" }; foreach (var header in headerPaths) { this.IncludeFiles <CopyNonPublicHeadersToPublic>("$(packagedir)/Modules/_ctypes/libffi/" + header, publishRoot, null); } }
protected DynamicExtensionModule( string moduleName, Bam.Core.StringArray sourceFiles, Bam.Core.Module.PrivatePatchDelegate compilationPatch) : this(moduleName, sourceFiles, null, compilationPatch, null, null, null) { }
ISharedObjectSymbolicLinkPolicy.Symlink( ConsoleApplication sender, Bam.Core.ExecutionContext context, Bam.Core.PreBuiltTool tool, Bam.Core.TokenizedString linkname, Bam.Core.TokenizedString target) { var commandLine = new Bam.Core.StringArray(); commandLine.Add("-s"); commandLine.Add("-f"); commandLine.Add(sender.CreateTokenizedString("@filename($(0))", target).Parse()); commandLine.Add(sender.CreateTokenizedString("@dir($(0))/$(1)", target, linkname).Parse()); CommandLineProcessor.Processor.Execute(context, tool, commandLine); }
Convert( this IInstallNameToolSettings settings, Bam.Core.StringArray commandLine) { switch (settings.Mode) { case EInstallNameToolMode.UpdateIDName: commandLine.Add("-id"); break; case EInstallNameToolMode.ChangeIDName: commandLine.Add("-change"); break; } }
Convert( this ICopyFileSettings settings, Bam.Core.StringArray commandLine) { var module = (settings as Bam.Core.Settings).Module; if (module.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.Windows)) { if (settings.Force) { commandLine.Add("/Y"); } if (settings.Verbose) { commandLine.Add("/F"); } if (settings.Recursive) { commandLine.Add("/S"); } if (settings.PreserveAllAttributes) { commandLine.Add("/K"); // copy attributes // TODO: this causes 'access denied' errors, although not clear why //commandLine.Add("/O"); // copy ownership and ACL commandLine.Add("/B"); // copy symbolic link itself, not the target } } else { if (settings.Force) { commandLine.Add("-f"); } if (settings.Verbose) { commandLine.Add("-v"); } if (settings.Recursive) { commandLine.Add("-R"); } if (settings.PreserveAllAttributes) { commandLine.Add("-a"); } } }
protected DynamicExtensionModule( string moduleName, Bam.Core.StringArray sourceFiles, Bam.Core.StringArray libraries, Bam.Core.Module.PrivatePatchDelegate compilationPatch, Bam.Core.Module.PrivatePatchDelegate linkerPatch, Bam.Core.StringArray assemblerFiles, Bam.Core.Module.PrivatePatchDelegate assemberPatch) { this.ModuleName = moduleName; this.SourceFiles = sourceFiles; this.LibsToLink = libraries; this.CompilationPatch = compilationPatch; this.LinkerPatch = linkerPatch; this.AssemblerFiles = (null != assemblerFiles) ? assemblerFiles : null; this.AssemblerPatch = assemberPatch; }
Convert( this IMakeLinkSettings settings, Bam.Core.StringArray commandLine) { var module = (settings as Bam.Core.Settings).Module; if (module.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.Windows)) { if (settings.Force) { // no switch } if (settings.Verbose) { // no switch } if (settings.SymbolicLink) { // no switch } if (settings.DoNotDereferenceTarget) { // no switch } } else { if (settings.Force) { commandLine.Add("-f"); } if (settings.Verbose) { commandLine.Add("-v"); } if (settings.SymbolicLink) { commandLine.Add("-s"); } if (settings.DoNotDereferenceTarget) { commandLine.Add("-n"); } } }
ISharedObjectSymbolicLinkPolicy.Symlink( ConsoleApplication sender, Bam.Core.ExecutionContext context, Bam.Core.PreBuiltTool tool, Bam.Core.TokenizedString linkname, Bam.Core.TokenizedString target) { var makeMeta = sender.MetaData as MakeFileBuilder.MakeFileMeta; var rule = makeMeta.Rules[0]; var commandLineArgs = new Bam.Core.StringArray(); commandLineArgs.Add("-s"); commandLineArgs.Add("-f"); rule.AddShellCommand(System.String.Format(@"{0} {1} $(notdir $@) $(dir $@)/{2} {3}", CommandLineProcessor.Processor.StringifyTool(tool), commandLineArgs.ToString(' '), linkname.Parse(), CommandLineProcessor.Processor.TerminatingArgs(tool))); }
IProceduralHeaderFromToolOutputPolicy.HeaderFromToolOutput( ProceduralHeaderFileFromToolOutput sender, ExecutionContext context, TokenizedString outputPath, ICommandLineTool tool) { var toolProject = (tool as Bam.Core.Module).MetaData as VSSolutionBuilder.VSProject; var toolConfig = toolProject.GetConfiguration(tool as Bam.Core.Module); var output = outputPath.Parse(); var commands = new Bam.Core.StringArray(); commands.Add(System.String.Format("IF NOT EXIST {0} MKDIR {0}", System.IO.Path.GetDirectoryName(output))); commands.Add(System.String.Format("{0} > {1}", CommandLineProcessor.Processor.StringifyTool(tool), output)); toolConfig.AddPostBuildCommands(commands); // alias the tool's project so that inter-project dependencies can be set up sender.MetaData = toolProject; }
IProceduralHeaderFromToolOutputPolicy.HeaderFromToolOutput( ProceduralHeaderFileFromToolOutput sender, ExecutionContext context, TokenizedString outputPath, ICommandLineTool tool) { var toolTarget = (tool as Bam.Core.Module).MetaData as XcodeBuilder.Target; var toolConfiguration = toolTarget.GetConfiguration(tool as Bam.Core.Module); var output = outputPath.Parse(); var commands = new Bam.Core.StringArray(); commands.Add(System.String.Format("[[ ! -d {0} ]] && mkdir -p {0}", System.IO.Path.GetDirectoryName(output))); commands.Add(System.String.Format("{0} > {1}", CommandLineProcessor.Processor.StringifyTool(tool), output)); toolTarget.AddPostBuildCommands(commands, toolConfiguration); // alias the tool's target so that inter-target dependencies can be set up sender.MetaData = toolTarget; }
Convert( this IZipSettings settings, Bam.Core.StringArray commandLine) { var module = (settings as Bam.Core.Settings).Module; if (module.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.Windows)) { if (settings.Verbose) { commandLine.Add("-bb3"); } if (settings.RecursivePaths) { commandLine.Add("-r"); } if (settings.Update) { commandLine.Add("u"); } else { commandLine.Add("a"); } } else { if (settings.Verbose) { commandLine.Add("-v"); } if (settings.RecursivePaths) { commandLine.Add("-r"); } if (settings.Update) { commandLine.Add("-u"); } } }
ILinkingPolicy.Link( ConsoleApplication sender, Bam.Core.ExecutionContext context, Bam.Core.TokenizedString executablePath, System.Collections.ObjectModel.ReadOnlyCollection<Bam.Core.Module> objectFiles, System.Collections.ObjectModel.ReadOnlyCollection<Bam.Core.Module> headers, System.Collections.ObjectModel.ReadOnlyCollection<Bam.Core.Module> libraries, System.Collections.ObjectModel.ReadOnlyCollection<Bam.Core.Module> frameworks) { // any libraries added prior to here, need to be moved to the end // they are external dependencies, and thus all built modules (to be added now) may have // a dependency on them (and not vice versa) var linker = sender.Settings as C.ICommonLinkerSettings; var externalLibs = linker.Libraries; linker.Libraries = new Bam.Core.StringArray(); foreach (var library in libraries) { (sender.Tool as C.LinkerTool).ProcessLibraryDependency(sender as CModule, library as CModule); } linker.Libraries.AddRange(externalLibs); var executableDir = System.IO.Path.GetDirectoryName(executablePath.ToString()); if (!System.IO.Directory.Exists(executableDir)) { System.IO.Directory.CreateDirectory(executableDir); } var commandLine = new Bam.Core.StringArray(); // first object files foreach (var input in objectFiles) { commandLine.Add(input.GeneratedPaths[C.ObjectFile.Key].ToString()); } // then all options (sender.Settings as CommandLineProcessor.IConvertToCommandLine).Convert(commandLine); CommandLineProcessor.Processor.Execute(context, sender.Tool as Bam.Core.ICommandLineTool, commandLine); }
IProceduralHeaderFromToolOutputPolicy.HeaderFromToolOutput( ProceduralHeaderFileFromToolOutput sender, ExecutionContext context, TokenizedString outputPath, ICommandLineTool tool) { var meta = new MakeFileBuilder.MakeFileMeta(sender); var rule = meta.AddRule(); rule.AddTarget(outputPath); rule.AddPrerequisite(tool.Executable); var args = new Bam.Core.StringArray(); args.Add("$< > $@"); rule.AddShellCommand(args.ToString(' ')); var outputDir = System.IO.Path.GetDirectoryName(outputPath.Parse()); meta.CommonMetaData.AddDirectory(outputDir); }
ILinkingPolicy.Link( ConsoleApplication sender, Bam.Core.ExecutionContext context, Bam.Core.TokenizedString executablePath, System.Collections.ObjectModel.ReadOnlyCollection<Bam.Core.Module> objectFiles, System.Collections.ObjectModel.ReadOnlyCollection<Bam.Core.Module> headers, System.Collections.ObjectModel.ReadOnlyCollection<Bam.Core.Module> libraries, System.Collections.ObjectModel.ReadOnlyCollection<Bam.Core.Module> frameworks) { // any libraries added prior to here, need to be moved to the end // they are external dependencies, and thus all built modules (to be added now) may have // a dependency on them (and not vice versa) var linker = sender.Settings as C.ICommonLinkerSettings; var externalLibs = linker.Libraries; linker.Libraries = new Bam.Core.StringArray(); foreach (var library in libraries) { (sender.Tool as C.LinkerTool).ProcessLibraryDependency(sender as CModule, library as CModule); } linker.Libraries.AddRange(externalLibs); var commandLineArgs = new Bam.Core.StringArray(); (sender.Settings as CommandLineProcessor.IConvertToCommandLine).Convert(commandLineArgs); var meta = new MakeFileBuilder.MakeFileMeta(sender); var rule = meta.AddRule(); rule.AddTarget(executablePath); foreach (var module in objectFiles) { rule.AddPrerequisite(module, C.ObjectFile.Key); } foreach (var module in libraries) { if (module is StaticLibrary) { rule.AddPrerequisite(module, C.StaticLibrary.Key); } else if (module is IDynamicLibrary) { if (module.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.Windows)) { rule.AddPrerequisite(module, C.DynamicLibrary.ImportLibraryKey); } else { rule.AddPrerequisite(module, C.DynamicLibrary.Key); } } else if (module is CSDKModule) { continue; } else if (module is OSXFramework) { continue; } else { throw new Bam.Core.Exception("Unknown module library type: {0}", module.GetType()); } } var tool = sender.Tool as Bam.Core.ICommandLineTool; var commands = new System.Text.StringBuilder(); commands.AppendFormat("{0} $^ {1} {2}", CommandLineProcessor.Processor.StringifyTool(tool), commandLineArgs.ToString(' '), CommandLineProcessor.Processor.TerminatingArgs(tool)); rule.AddShellCommand(commands.ToString()); var executableDir = System.IO.Path.GetDirectoryName(executablePath.ToString()); meta.CommonMetaData.Directories.AddUnique(executableDir); meta.CommonMetaData.ExtendEnvironmentVariables(tool.EnvironmentVariables); }
IdentifyAllPackages( bool allowDuplicates = false, bool enforceBamAssemblyVersions = true) { var packageRepos = new System.Collections.Generic.LinkedList <System.Tuple <string, PackageDefinition> >(); int reposHWM = 0; foreach (var repo in Graph.Instance.PackageRepositories) { EnqueuePackageRepositoryToVisit(packageRepos, ref reposHWM, repo, null); } var masterDefinitionFile = GetMasterPackage(); foreach (var repo in masterDefinitionFile.PackageRepositories) { EnqueuePackageRepositoryToVisit(packageRepos, ref reposHWM, repo, masterDefinitionFile); } // read the definition files of any package found in the package roots var candidatePackageDefinitions = new Array <PackageDefinition>(); candidatePackageDefinitions.Add(masterDefinitionFile); var packageReposVisited = 0; Log.Detail("Querying package repositories..."); while (packageRepos.Count > 0) { var repoTuple = packageRepos.First(); packageRepos.RemoveFirst(); var repo = repoTuple.Item1; if (!System.IO.Directory.Exists(repo)) { var message = new System.Text.StringBuilder(); message.AppendFormat("Package repository directory {0} does not exist.", repo); message.AppendLine(); message.AppendFormat("Repository requested from {0}", repoTuple.Item2.XMLFilename); message.AppendLine(); throw new Exception(message.ToString()); } // faster than System.IO.Directory.GetDirectories(repo, BamSubFolder, System.IO.SearchOption.AllDirectories); // when there are deep directories StringArray candidatePackageDirs = new StringArray(); var possiblePackages = System.IO.Directory.GetDirectories(repo, "*", System.IO.SearchOption.TopDirectoryOnly); foreach (var packageDir in possiblePackages) { var possibleBamFolder = System.IO.Path.Combine(packageDir, BamSubFolder); if (System.IO.Directory.Exists(possibleBamFolder)) { candidatePackageDirs.Add(packageDir); } } Graph.Instance.PackageRepositories.Add(repo); foreach (var packageDir in candidatePackageDirs) { var packageDefinitionPath = GetPackageDefinitionPathname(packageDir); // ignore any duplicates (can be found due to nested repositories) if (null != candidatePackageDefinitions.FirstOrDefault(item => item.XMLFilename == packageDefinitionPath)) { continue; } var definitionFile = new PackageDefinition(packageDefinitionPath); definitionFile.Read(); candidatePackageDefinitions.Add(definitionFile); foreach (var newRepo in definitionFile.PackageRepositories) { EnqueuePackageRepositoryToVisit(packageRepos, ref reposHWM, newRepo, definitionFile); } } ++packageReposVisited; Log.DetailProgress("{0,3}%", (int)(100 * ((float)packageReposVisited / reposHWM))); } #if DEBUG if (packageReposVisited != reposHWM) { throw new Exception("Inconsistent package repository count: {0} added, {1} visited", reposHWM, packageReposVisited); } #endif // defaults come from // - the master definition file // - command line args (these trump the mdf) // and only requires resolving when referenced var packageDefinitions = new Array <PackageDefinition>(); PackageDefinition.ResolveDependencies(masterDefinitionFile, packageDefinitions, candidatePackageDefinitions); // now resolve any duplicate names using defaults // unless duplicates are allowed var duplicatePackageNames = packageDefinitions.GroupBy(item => item.Name).Where(item => item.Count() > 1).Select(item => item.Key); var uniquePackageNames = packageDefinitions.GroupBy(item => item.Name).Where(item => item.Count() == 1).Select(item => item.Key); var versionSpeciferArgs = new Options.PackageDefaultVersion(); var packageVersionSpecifiers = CommandLineProcessor.Evaluate(versionSpeciferArgs); if ((duplicatePackageNames.Count() > 0) && !allowDuplicates) { var toRemove = new Array <PackageDefinition>(); foreach (var dupName in duplicatePackageNames) { var duplicates = packageDefinitions.Where(item => item.Name == dupName); var resolvedDuplicate = TryToResolveDuplicate(masterDefinitionFile, dupName, duplicates, packageDefinitions, packageVersionSpecifiers, toRemove); if (null != resolvedDuplicate) { continue; } // try removing any packages that have already been resolved // which can remove additional packages (recursive check) because they had been added solely by those we are just about to remove packageDefinitions.RemoveAll(PackagesToRemove(toRemove, packageDefinitions, masterDefinitionFile)); packageDefinitions.RemoveAll(toRemove); // and if that has reduced the duplicates for this package down to a single version, we're good to carry on var numDuplicates = duplicates.Count(); if (1 == numDuplicates) { toRemove.Clear(); continue; } // otherwise, error var resolveErrorMessage = new System.Text.StringBuilder(); if (numDuplicates > 0) { resolveErrorMessage.AppendFormat("Unable to resolve to a single version of package {0}. Use --{0}.version=<version> to resolve.", dupName); resolveErrorMessage.AppendLine(); resolveErrorMessage.AppendLine("Available versions of the package are:"); foreach (var dup in duplicates) { resolveErrorMessage.AppendFormat("\t{0}", dup.Version); resolveErrorMessage.AppendLine(); } } else { resolveErrorMessage.AppendFormat("No version of package {0} has been determined to be available.", dupName); resolveErrorMessage.AppendLine(); if (toRemove.Count() > 0) { resolveErrorMessage.AppendFormat("If there were any references to {0}, they may have been removed from consideration by the following packages being discarded:", dupName); resolveErrorMessage.AppendLine(); foreach (var removed in toRemove) { resolveErrorMessage.AppendFormat("\t{0}", removed.FullName); resolveErrorMessage.AppendLine(); } } resolveErrorMessage.AppendFormat("Please add an explicit dependency to (a version of) the {0} package either in your master package or one of its dependencies.", dupName); resolveErrorMessage.AppendLine(); } throw new Exception(resolveErrorMessage.ToString()); } // finally, clean up the package definition list to use, with all those that need to be deleted packageDefinitions.RemoveAll(toRemove); } // ensure that all packages with a single version in the definition files, does not have a command line override // that refers to a completely different version foreach (var uniquePkgName in uniquePackageNames) { foreach (var versionSpecifier in packageVersionSpecifiers) { if (!versionSpecifier.Contains(uniquePkgName)) { continue; } var versionFromDefinition = packageDefinitions.First(item => item.Name == uniquePkgName).Version; if (versionSpecifier[1] != versionFromDefinition) { var noMatchMessage = new System.Text.StringBuilder(); noMatchMessage.AppendFormat("Command line version specified, {0}, could not resolve to one of the available versions of package {1}:", versionSpecifier[1], uniquePkgName); noMatchMessage.AppendLine(); noMatchMessage.AppendFormat("\t{0}", versionFromDefinition); noMatchMessage.AppendLine(); throw new Exception(noMatchMessage.ToString()); } } } if (enforceBamAssemblyVersions) { // for all packages that make up this assembly, ensure that their requirements on the version of the Bam // assemblies are upheld, prior to compiling the code foreach (var pkgDefn in packageDefinitions) { pkgDefn.ValidateBamAssemblyRequirements(); } } Graph.Instance.SetPackageDefinitions(packageDefinitions); }
CompilePackageAssembly( bool enforceBamAssemblyVersions = true, bool enableClean = true) { // validate build root if (null == Graph.Instance.BuildRoot) { throw new Exception("Build root has not been specified"); } var gatherSourceProfile = new TimeProfile(ETimingProfiles.GatherSource); gatherSourceProfile.StartProfile(); IdentifyAllPackages(enforceBamAssemblyVersions: enforceBamAssemblyVersions); var cleanFirst = CommandLineProcessor.Evaluate(new Options.CleanFirst()); if (enableClean && cleanFirst && System.IO.Directory.Exists(Graph.Instance.BuildRoot)) { Log.Info("Deleting build root '{0}'", Graph.Instance.BuildRoot); try { // make sure no files are read-only, which may have happened as part of collation preserving file attributes var dirInfo = new System.IO.DirectoryInfo(Graph.Instance.BuildRoot); foreach (var file in dirInfo.EnumerateFiles("*", System.IO.SearchOption.AllDirectories)) { file.Attributes &= ~System.IO.FileAttributes.ReadOnly; } System.IO.Directory.Delete(Graph.Instance.BuildRoot, true); } catch (System.IO.IOException ex) { Log.Info("Failed to delete build root, because {0}. Continuing", ex.Message); } } BuildModeUtilities.ValidateBuildModePackage(); var definitions = new StringArray(); // gather source files var sourceCode = new StringArray(); int packageIndex = 0; foreach (var package in Graph.Instance.Packages) { Log.DebugMessage("{0}: '{1}' @ '{2}'", packageIndex, package.Version, (package.PackageRepositories.Count > 0) ? package.PackageRepositories[0] : "Not in a repository"); // to compile with debug information, you must compile the files // to compile without, we need to file contents to hash the source if (Graph.Instance.CompileWithDebugSymbols) { var scripts = package.GetScriptFiles(); sourceCode.AddRange(scripts); Log.DebugMessage(scripts.ToString("\n\t")); } else { foreach (var scriptFile in package.GetScriptFiles()) { using (var reader = new System.IO.StreamReader(scriptFile)) { sourceCode.Add(reader.ReadToEnd()); } Log.DebugMessage("\t'{0}'", scriptFile); } } foreach (var define in package.Definitions) { if (!definitions.Contains(define)) { definitions.Add(define); } } ++packageIndex; } // add/remove other definitions definitions.Add(VersionDefineForCompiler); definitions.Add(HostPlatformDefineForCompiler); definitions.Sort(); gatherSourceProfile.StopProfile(); var assemblyCompileProfile = new TimeProfile(ETimingProfiles.AssemblyCompilation); assemblyCompileProfile.StartProfile(); // assembly is written to the build root var cachedAssemblyPathname = System.IO.Path.Combine(Graph.Instance.BuildRoot, ".CachedPackageAssembly"); cachedAssemblyPathname = System.IO.Path.Combine(cachedAssemblyPathname, Graph.Instance.MasterPackage.Name) + ".dll"; var hashPathName = System.IO.Path.ChangeExtension(cachedAssemblyPathname, "hash"); string thisHashCode = null; var cacheAssembly = !CommandLineProcessor.Evaluate(new Options.DisableCacheAssembly()); string compileReason = null; if (Graph.Instance.CompileWithDebugSymbols) { compileReason = "debug symbols were enabled"; } else { // can an existing assembly be reused? thisHashCode = GetPackageHash(sourceCode, definitions, Graph.Instance.MasterPackage.BamAssemblies); if (cacheAssembly) { if (System.IO.File.Exists(hashPathName)) { using (var reader = new System.IO.StreamReader(hashPathName)) { var diskHashCode = reader.ReadLine(); if (diskHashCode.Equals(thisHashCode)) { Log.DebugMessage("Cached assembly used '{0}', with hash {1}", cachedAssemblyPathname, diskHashCode); Log.Detail("Re-using existing package assembly"); Graph.Instance.ScriptAssemblyPathname = cachedAssemblyPathname; assemblyCompileProfile.StopProfile(); return; } else { compileReason = "package source has changed since the last compile"; } } } else { compileReason = "no previously compiled package assembly exists"; } } else { compileReason = "user has disabled package assembly caching"; } } // use the compiler in the current runtime version to build the assembly of packages var clrVersion = System.Environment.Version; var compilerVersion = System.String.Format("v{0}.{1}", clrVersion.Major, clrVersion.Minor); Log.Detail("Compiling package assembly (C# compiler {0}{1}), because {2}.", compilerVersion, Graph.Instance.ProcessState.TargetFrameworkVersion != null ? (", targetting " + Graph.Instance.ProcessState.TargetFrameworkVersion) : string.Empty, compileReason); var providerOptions = new System.Collections.Generic.Dictionary <string, string>(); providerOptions.Add("CompilerVersion", compilerVersion); if (Graph.Instance.ProcessState.RunningMono) { Log.DebugMessage("Compiling assembly for Mono"); } using (var provider = new Microsoft.CSharp.CSharpCodeProvider(providerOptions)) { var compilerParameters = new System.CodeDom.Compiler.CompilerParameters(); compilerParameters.TreatWarningsAsErrors = true; compilerParameters.WarningLevel = 4; compilerParameters.GenerateExecutable = false; compilerParameters.GenerateInMemory = false; if (Graph.Instance.CompileWithDebugSymbols) { compilerParameters.OutputAssembly = System.IO.Path.Combine(System.IO.Path.GetTempPath(), Graph.Instance.MasterPackage.Name) + ".dll"; } else { compilerParameters.OutputAssembly = cachedAssemblyPathname; } var compilerOptions = "/checked+ /unsafe-"; if (Graph.Instance.CompileWithDebugSymbols) { compilerParameters.IncludeDebugInformation = true; compilerOptions += " /optimize-"; } else { compilerOptions += " /optimize+"; } compilerOptions += " /platform:anycpu"; // define strings compilerOptions += " /define:" + definitions.ToString(';'); compilerParameters.CompilerOptions = compilerOptions; if (provider.Supports(System.CodeDom.Compiler.GeneratorSupport.Resources)) { // Bam assembly // TODO: Q: why is it only for the master package? Why not all of them, which may have additional dependencies? foreach (var assembly in Graph.Instance.MasterPackage.BamAssemblies) { var assemblyFileName = System.String.Format("{0}.dll", assembly.Name); var assemblyPathName = System.IO.Path.Combine(Graph.Instance.ProcessState.ExecutableDirectory, assemblyFileName); compilerParameters.ReferencedAssemblies.Add(assemblyPathName); } // DotNet assembly foreach (var desc in Graph.Instance.MasterPackage.DotNetAssemblies) { var assemblyFileName = System.String.Format("{0}.dll", desc.Name); compilerParameters.ReferencedAssemblies.Add(assemblyFileName); } if (Graph.Instance.ProcessState.RunningMono) { compilerParameters.ReferencedAssemblies.Add("Mono.Posix.dll"); } } else { throw new Exception("C# compiler does not support Resources"); } // this will create the build root directory as necessary IOWrapper.CreateDirectory(System.IO.Path.GetDirectoryName(compilerParameters.OutputAssembly)); var results = Graph.Instance.CompileWithDebugSymbols ? provider.CompileAssemblyFromFile(compilerParameters, sourceCode.ToArray()) : provider.CompileAssemblyFromSource(compilerParameters, sourceCode.ToArray()); if (results.Errors.HasErrors || results.Errors.HasWarnings) { var message = new System.Text.StringBuilder(); message.AppendFormat("Failed to compile package '{0}'. There are {1} errors.", Graph.Instance.MasterPackage.FullName, results.Errors.Count); message.AppendLine(); foreach (System.CodeDom.Compiler.CompilerError error in results.Errors) { message.AppendFormat("\t{0}({1}): {2} {3}", error.FileName, error.Line, error.ErrorNumber, error.ErrorText); message.AppendLine(); } if (!Graph.Instance.CompileWithDebugSymbols) { message.AppendLine(); ICommandLineArgument debugOption = new Options.UseDebugSymbols(); message.AppendFormat("Use the {0}/{1} command line option with bam for more accurate error messages.", debugOption.LongName, debugOption.ShortName); message.AppendLine(); } message.AppendLine(); ICommandLineArgument createDebugProjectOption = new Options.CreateDebugProject(); message.AppendFormat("Use the {0}/{1} command line option with bam to create an editable IDE project containing the build scripts.", createDebugProjectOption.LongName, createDebugProjectOption.ShortName); message.AppendLine(); throw new Exception(message.ToString()); } if (!Graph.Instance.CompileWithDebugSymbols) { if (cacheAssembly) { using (var writer = new System.IO.StreamWriter(hashPathName)) { writer.WriteLine(thisHashCode); } } else { // will not throw if the file doesn't exist System.IO.File.Delete(hashPathName); } } Log.DebugMessage("Written assembly to '{0}'", compilerParameters.OutputAssembly); Graph.Instance.ScriptAssemblyPathname = compilerParameters.OutputAssembly; } assemblyCompileProfile.StopProfile(); }
CommandLineProcessor.IConvertToCommandLine.Convert( Bam.Core.StringArray commandLine) { CommandLineProcessor.Conversion.Convert(typeof(CommandLineImplementation), this, commandLine); }
ILinkingPolicy.Link( ConsoleApplication sender, Bam.Core.ExecutionContext context, Bam.Core.TokenizedString executablePath, System.Collections.ObjectModel.ReadOnlyCollection <Bam.Core.Module> objectFiles, System.Collections.ObjectModel.ReadOnlyCollection <Bam.Core.Module> headers, System.Collections.ObjectModel.ReadOnlyCollection <Bam.Core.Module> libraries) { // any libraries added prior to here, need to be moved to the end // they are external dependencies, and thus all built modules (to be added now) may have // a dependency on them (and not vice versa) var linker = sender.Settings as C.ICommonLinkerSettings; var externalLibs = linker.Libraries; linker.Libraries = new Bam.Core.StringArray(); foreach (var library in libraries) { (sender.Tool as C.LinkerTool).ProcessLibraryDependency(sender as CModule, library as CModule); } linker.Libraries.AddRange(externalLibs); var commandLineArgs = new Bam.Core.StringArray(); (sender.Settings as CommandLineProcessor.IConvertToCommandLine).Convert(commandLineArgs); var meta = new MakeFileBuilder.MakeFileMeta(sender); var rule = meta.AddRule(); rule.AddTarget(executablePath); string objExt = null; // try to get the object file extension from a compiled source file foreach (var module in objectFiles) { if (null == objExt) { objExt = module.Tool.Macros["objext"].ToString(); } if (!(module as C.ObjectFileBase).PerformCompilation) { continue; } rule.AddPrerequisite(module, C.ObjectFile.Key); } foreach (var module in libraries) { if (module is StaticLibrary) { rule.AddPrerequisite(module, C.StaticLibrary.Key); } else if (module is IDynamicLibrary) { var dynLib = module as IDynamicLibrary; if (dynLib.LinkerNameSymbolicLink != null) { var linkerNameSymLink = dynLib.LinkerNameSymbolicLink; rule.AddPrerequisite(linkerNameSymLink, C.SharedObjectSymbolicLink.Key); } else { rule.AddPrerequisite(module, C.DynamicLibrary.Key); } } else if (module is CSDKModule) { continue; } else if (module is OSXFramework) { continue; } else if (module is HeaderLibrary) { continue; } else { throw new Bam.Core.Exception("Unknown module library type: {0}", module.GetType()); } } var tool = sender.Tool as Bam.Core.ICommandLineTool; var commands = new System.Text.StringBuilder(); // if there were no object files, you probably intended to use all prerequisites anyway var filter = (null != objExt) ? System.String.Format("$(filter %{0},$^)", objExt) : "$^"; commands.AppendFormat("{0} {1} {2} {3}", CommandLineProcessor.Processor.StringifyTool(tool), filter, commandLineArgs.ToString(' '), CommandLineProcessor.Processor.TerminatingArgs(tool)); rule.AddShellCommand(commands.ToString()); var executableDir = System.IO.Path.GetDirectoryName(executablePath.ToString()); meta.CommonMetaData.AddDirectory(executableDir); meta.CommonMetaData.ExtendEnvironmentVariables(tool.EnvironmentVariables); }
Convert( this IDSymUtilToolSettings settings, Bam.Core.StringArray commandLine) { }
ILinkingPolicy.Link( ConsoleApplication sender, Bam.Core.ExecutionContext context, Bam.Core.TokenizedString executablePath, System.Collections.ObjectModel.ReadOnlyCollection <Bam.Core.Module> objectFiles, System.Collections.ObjectModel.ReadOnlyCollection <Bam.Core.Module> headers, System.Collections.ObjectModel.ReadOnlyCollection <Bam.Core.Module> libraries, System.Collections.ObjectModel.ReadOnlyCollection <Bam.Core.Module> frameworks) { // any libraries added prior to here, need to be moved to the end // they are external dependencies, and thus all built modules (to be added now) may have // a dependency on them (and not vice versa) var linker = sender.Settings as C.ICommonLinkerSettings; var externalLibs = linker.Libraries; linker.Libraries = new Bam.Core.StringArray(); foreach (var library in libraries) { (sender.Tool as C.LinkerTool).ProcessLibraryDependency(sender as CModule, library as CModule); } linker.Libraries.AddRange(externalLibs); var commandLineArgs = new Bam.Core.StringArray(); (sender.Settings as CommandLineProcessor.IConvertToCommandLine).Convert(commandLineArgs); var meta = new MakeFileBuilder.MakeFileMeta(sender); var rule = meta.AddRule(); rule.AddTarget(executablePath); foreach (var module in objectFiles) { rule.AddPrerequisite(module, C.ObjectFile.Key); } foreach (var module in libraries) { if (module is StaticLibrary) { rule.AddPrerequisite(module, C.StaticLibrary.Key); } else if (module is IDynamicLibrary) { if (module.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.Windows)) { rule.AddPrerequisite(module, C.DynamicLibrary.ImportLibraryKey); } else { rule.AddPrerequisite(module, C.DynamicLibrary.Key); } } else if (module is CSDKModule) { continue; } else if (module is OSXFramework) { continue; } else { throw new Bam.Core.Exception("Unknown module library type: {0}", module.GetType()); } } var tool = sender.Tool as Bam.Core.ICommandLineTool; var commands = new System.Text.StringBuilder(); commands.AppendFormat("{0} $^ {1} {2}", CommandLineProcessor.Processor.StringifyTool(tool), commandLineArgs.ToString(' '), CommandLineProcessor.Processor.TerminatingArgs(tool)); rule.AddShellCommand(commands.ToString()); var executableDir = System.IO.Path.GetDirectoryName(executablePath.ToString()); meta.CommonMetaData.Directories.AddUnique(executableDir); meta.CommonMetaData.ExtendEnvironmentVariables(tool.EnvironmentVariables); }