private IEnumerable <IDictionary <string, string> > GetProjectEntries(Builder builder, Project project, Project.Configuration config) { var context = new CompileCommandGenerationContext(builder, project, config); var resolverParams = new[] { new VariableAssignment("project", context.Project), new VariableAssignment("target", context.Configuration.Target), new VariableAssignment("conf", context.Configuration) }; context.EnvironmentVariableResolver = PlatformRegistry.Get <IPlatformDescriptor>(config.Platform).GetPlatformEnvironmentResolver(resolverParams); var factory = new CompileCommandFactory(context); var database = project.GetSourceFilesForConfigurations(new[] { config }) .Except(config.ResolvedSourceFilesBuildExclude) .Where(f => project.SourceFilesCPPExtensions.Contains(Path.GetExtension(f))) .Select(factory.CreateCompileCommand); foreach (var cc in database) { CompileCommandGenerated?.Invoke(context, cc); yield return(new Dictionary <string, string> { { "directory", cc.Directory }, { "command", cc.Command }, { "file", cc.File }, }); } }
public CompileCommandFactory(CompileCommandGenerationContext context) { var isClang = context.Configuration.Platform.IsUsingClang(); var isMicrosoft = context.Configuration.Platform.IsMicrosoft(); _compiler = isClang ? "clang.exe" : "clang-cl.exe"; _config = context.Configuration; _outputExtension = isMicrosoft ? ".obj" : ".o"; _outputDirectory = _config.IntermediatePath; _projectDirectory = context.ProjectDirectoryCapitalized; _flags = isClang ? s_clangFlags : s_vcFlags; s_optionGenerator.GenerateOptions(context, ProjectOptionGenerationLevel.Compiler); var argsList = new List <string>(); argsList.Add(isClang ? "-c" : "/c"); // Precomp arguments flags are actually written by the bff generator (see bff.template.cs) // Therefore, the CommandLineOptions entries only contain the pch name and file. if (_config.PrecompSource != null) { _precompFile = Path.Combine(_projectDirectory, context.Options[PrecompFileKey]); string name; if (_flags.ContainsKey(CompilerFlags.PrecompPath)) { argsList.Add(string.Format(_flags[CompilerFlags.PrecompPath], _precompFile)); name = context.Options[PrecompNameKey]; } else { name = _precompFile; } _createPrecompArgument = string.Format(_flags[CompilerFlags.CreatePrecomp], name); _usePrecompArgument = string.Format(_flags[CompilerFlags.UsePrecomp], name); } // AdditionalCompilerOptions are referenced from Options in the bff template. context.CommandLineOptions.Add(AdditionalOptionsKey, context.Options[AdditionalOptionsKey]); FillIncludeDirectoriesOptions(context); var validOptions = context.CommandLineOptions .Where(IsValidOption) .ToDictionary(kvp => kvp.Key, FlattenMultilineArgument); if (isMicrosoft) { // Required to avoid errors in VC headers. var flag = isClang ? "-D" : "/D"; var value = validOptions.ContainsKey("ExceptionHandling") ? 1 : 0; argsList.Add($"{flag}_HAS_EXCEPTIONS={value}"); } argsList.AddRange(validOptions.Values); _arguments = string.Join(" ", argsList); }
internal static string CmdLineConvertIncludePathsFunc(CompileCommandGenerationContext context, string include, string prefix) { // if the include is below the global root, we compute the relative path, // otherwise it's probably a system include for which we keep the full path string resolvedInclude = context.EnvironmentVariableResolver.Resolve(include); if (resolvedInclude.StartsWith(context.Project.RootPath, StringComparison.OrdinalIgnoreCase)) { resolvedInclude = Util.PathGetRelative(context.ProjectDirectory, resolvedInclude, true); } return($@"{prefix}""{resolvedInclude}"""); }
private void SelectPreprocessorDefinitions(CompileCommandGenerationContext context, string platformDefineSwitch) { var defines = new Strings(); defines.AddRange(context.Options.ExplicitDefines); defines.AddRange(context.Configuration.Defines); foreach (string define in defines.SortedValues) { if (!string.IsNullOrWhiteSpace(define)) { _arguments.Add(string.Format(@"{0}{1}{2}{1}", platformDefineSwitch, Util.DoubleQuotes, define.Replace(Util.DoubleQuotes, Util.EscapedDoubleQuotes))); } } }
private void FillIncludeDirectoriesOptions(CompileCommandGenerationContext context) { // TODO: really not ideal, refactor and move the properties we need from it someplace else var platformVcxproj = PlatformRegistry.Query <IPlatformVcxproj>(context.Configuration.Platform); var includePaths = new OrderableStrings(platformVcxproj.GetIncludePaths(context)); var resourceIncludePaths = new OrderableStrings(platformVcxproj.GetResourceIncludePaths(context)); context.CommandLineOptions["AdditionalIncludeDirectories"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["AdditionalResourceIncludeDirectories"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["AdditionalUsingDirectories"] = FileGeneratorUtilities.RemoveLineTag; var platformDescriptor = PlatformRegistry.Get <IPlatformDescriptor>(context.Configuration.Platform); string defaultCmdLineIncludePrefix = _flags[CompilerFlags.IncludePath]; // Fill include dirs var dirs = new List <string>(); var platformIncludePaths = platformVcxproj.GetPlatformIncludePathsWithPrefix(context); var platformIncludePathsPrefixed = platformIncludePaths.Select(p => CmdLineConvertIncludePathsFunc(context, p.Path, p.CmdLinePrefix)).ToList(); dirs.AddRange(platformIncludePathsPrefixed); // TODO: move back up, just below the creation of the dirs list dirs.AddRange(includePaths.Select(p => CmdLineConvertIncludePathsFunc(context, p, defaultCmdLineIncludePrefix))); if (dirs.Any()) { context.CommandLineOptions["AdditionalIncludeDirectories"] = string.Join(" ", dirs); _arguments.AddRange(dirs); } // Fill resource include dirs var resourceDirs = new List <string>(); resourceDirs.AddRange(resourceIncludePaths.Select(p => CmdLineConvertIncludePathsFunc(context, p, defaultCmdLineIncludePrefix))); if (Options.GetObject <Options.Vc.General.PlatformToolset>(context.Configuration).IsLLVMToolchain() && Options.GetObject <Options.Vc.LLVM.UseClangCl>(context.Configuration) == Options.Vc.LLVM.UseClangCl.Enable) { // with LLVM as toolchain, we are still using the default resource compiler, so we need the default include prefix // TODO: this is not great, ideally we would need the prefix to be per "compiler", and a platform can have many var platformIncludePathsDefaultPrefix = platformIncludePaths.Select(p => CmdLineConvertIncludePathsFunc(context, p.Path, defaultCmdLineIncludePrefix)); resourceDirs.AddRange(platformIncludePathsDefaultPrefix); } else { resourceDirs.AddRange(platformIncludePathsPrefixed); } if (resourceDirs.Any()) { context.CommandLineOptions["AdditionalResourceIncludeDirectories"] = string.Join(" ", resourceDirs); _arguments.AddRange(resourceDirs); } // Fill using dirs Strings additionalUsingDirectories = Options.GetStrings <Options.Vc.Compiler.AdditionalUsingDirectories>(context.Configuration); additionalUsingDirectories.AddRange(context.Configuration.AdditionalUsingDirectories); additionalUsingDirectories.AddRange(platformVcxproj.GetCxUsingPath(context)); if (additionalUsingDirectories.Any()) { var cmdAdditionalUsingDirectories = additionalUsingDirectories.Select(p => CmdLineConvertIncludePathsFunc(context, p, "/AI")); context.CommandLineOptions["AdditionalUsingDirectories"] = string.Join(" ", cmdAdditionalUsingDirectories); _arguments.AddRange(cmdAdditionalUsingDirectories); } }