diff --git a/Sharpmake.Generators/GeneratorManager.cs b/Sharpmake.Generators/GeneratorManager.cs index e48ad7354..92804c933 100644 --- a/Sharpmake.Generators/GeneratorManager.cs +++ b/Sharpmake.Generators/GeneratorManager.cs @@ -129,45 +129,44 @@ public void Generate(Builder builder, List generatedFiles, List skipFiles) { - if (configurations[0].Platform == Platform.ios || configurations[0].Platform == Platform.mac) + DevEnv devEnv = configurations[0].Target.GetFragment(); + switch (devEnv) { - XCWorkspaceGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - if (UtilityMethods.HasFastBuildConfig(configurations)) - { - MasterBffGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - } - } - else - { - DevEnv devEnv = configurations[0].Target.GetFragment(); - switch (devEnv) - { - case DevEnv.make: + case DevEnv.make: + { + if (configurations[0].Platform == Platform.android) + MakeApplicationGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + else + MakefileGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + break; + } + case DevEnv.vs2015: + case DevEnv.vs2017: + case DevEnv.vs2019: + case DevEnv.vs2022: + { + if (UtilityMethods.HasFastBuildConfig(configurations)) { - if (configurations[0].Platform == Platform.android) - MakeApplicationGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - else - MakefileGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - break; + MasterBffGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); } - case DevEnv.vs2015: - case DevEnv.vs2017: - case DevEnv.vs2019: - case DevEnv.vs2022: - { - if (UtilityMethods.HasFastBuildConfig(configurations)) - { - MasterBffGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - } - SlnGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - break; - } - default: + SlnGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + break; + } + case DevEnv.xcode4ios: + { + if (UtilityMethods.HasFastBuildConfig(configurations)) { - throw new Error("Generate called with unknown DevEnv: " + devEnv); + MasterBffGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); } - } + + XCWorkspaceGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + break; + } + default: + { + throw new Error("Generate called with unknown DevEnv: " + devEnv); + } } } } diff --git a/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs b/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs index ec553bba9..abe491e2f 100644 --- a/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs +++ b/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs @@ -137,6 +137,14 @@ public static class Project public const string ProjectFilesHeader = @" +"; + + public const string ProjectFilesSource = +@" +"; + + public const string ProjectFilesContent = +@" "; public static string ContentSimple = diff --git a/Sharpmake.Generators/VisualStudio/Androidproj.cs b/Sharpmake.Generators/VisualStudio/Androidproj.cs index b088b9c20..b5fe178d3 100644 --- a/Sharpmake.Generators/VisualStudio/Androidproj.cs +++ b/Sharpmake.Generators/VisualStudio/Androidproj.cs @@ -275,9 +275,6 @@ private void GenerateFilesSection( // Add source files var allFiles = new List(); - var includeFiles = new List(); - var sourceFiles = new List(); - var contentFiles = new List(); foreach (string file in projectFiles) { @@ -287,56 +284,52 @@ private void GenerateFilesSection( allFiles.Sort((l, r) => { return string.Compare(l.FileNameProjectRelative, r.FileNameProjectRelative, StringComparison.InvariantCultureIgnoreCase); }); - // type -> files - var customSourceFiles = new Dictionary>(); + var sourceFiles = new List(); + var contentFiles = new List(); + foreach (var projectFile in allFiles) { - string type = null; - if (context.Project.ExtensionBuildTools.TryGetValue(projectFile.FileExtension, out type)) - { - List files = null; - if (!customSourceFiles.TryGetValue(type, out files)) - { - files = new List(); - customSourceFiles[type] = files; - } - files.Add(projectFile); - } - else if (context.Project.SourceFilesCompileExtensions.Contains(projectFile.FileExtension) || - (string.Compare(projectFile.FileExtension, ".rc", StringComparison.OrdinalIgnoreCase) == 0)) + if (context.Project.SourceFilesCompileExtensions.Contains(projectFile.FileExtension)) { sourceFiles.Add(projectFile); } - else if (string.Compare(projectFile.FileExtension, ".h", StringComparison.OrdinalIgnoreCase) == 0) - { - includeFiles.Add(projectFile); - } else { contentFiles.Add(projectFile); } } - // Write header files - if (includeFiles.Count > 0) + // Write content files + if (contentFiles.Count > 0) { + // Filter out the main 3 files from the list since they might share extensions + string[] coreFiles = + { + fileGenerator.Resolver.Resolve(context.AndroidPackageProject.AntBuildXml), + fileGenerator.Resolver.Resolve(context.AndroidPackageProject.AntProjectPropertiesFile), + fileGenerator.Resolver.Resolve(context.AndroidPackageProject.AndroidManifest), + }; + fileGenerator.Write(Template.Project.ProjectFilesBegin); - foreach (var file in includeFiles) + foreach (var file in contentFiles) { - using (fileGenerator.Declare("file", file)) - fileGenerator.Write(Template.Project.ProjectFilesHeader); + if (!coreFiles.Contains(fileGenerator.Resolver.Resolve(file.FileNameProjectRelative))) + { + using (fileGenerator.Declare("file", file)) + fileGenerator.Write(Template.Project.ContentSimple); + } } fileGenerator.Write(Template.Project.ProjectFilesEnd); } - // Write content files - if (contentFiles.Count > 0) + // Write source files + if (sourceFiles.Count > 0) { fileGenerator.Write(Template.Project.ProjectFilesBegin); - foreach (var file in contentFiles) + foreach (var file in sourceFiles) { using (fileGenerator.Declare("file", file)) - fileGenerator.Write(Template.Project.ContentSimple); + fileGenerator.Write(Template.Project.ProjectFilesSource); } fileGenerator.Write(Template.Project.ProjectFilesEnd); } diff --git a/Sharpmake.Generators/VisualStudio/Csproj.Template.cs b/Sharpmake.Generators/VisualStudio/Csproj.Template.cs index e290271db..695128c49 100644 --- a/Sharpmake.Generators/VisualStudio/Csproj.Template.cs +++ b/Sharpmake.Generators/VisualStudio/Csproj.Template.cs @@ -53,6 +53,8 @@ public static class Project [projectTypeGuids] [options.IsPublishable] [options.PublishUrl] + [options.PublishSingleFile] + [options.PublishTrimmed] [options.InstallUrl] [options.ManifestKeyFile] [options.ManifestCertificateThumbprint] diff --git a/Sharpmake.Generators/VisualStudio/Csproj.cs b/Sharpmake.Generators/VisualStudio/Csproj.cs index 20a089b2d..5356bd682 100644 --- a/Sharpmake.Generators/VisualStudio/Csproj.cs +++ b/Sharpmake.Generators/VisualStudio/Csproj.cs @@ -1179,7 +1179,7 @@ List skipFiles var preImportCustomProperties = new Dictionary(project.PreImportCustomProperties); AddPreImportCustomProperties(preImportCustomProperties, project, projectPath); - WriteCustomProperties(preImportCustomProperties, project, writer, resolver); + WriteCustomProperties(preImportCustomProperties, writer, resolver); var preImportProjects = new List(project.PreImportProjects); WriteImportProjects(preImportProjects.Distinct(EqualityComparer.Default), project, configurations.First(), writer, resolver); @@ -1281,7 +1281,7 @@ List skipFiles Write(Template.MSBuild14PropertyGroup, writer, resolver); } - WriteCustomProperties(project.CustomProperties, project, writer, resolver); + WriteCustomProperties(project.CustomProperties, writer, resolver); if (project.ProjectTypeGuids == CSharpProjectType.Wcf) { @@ -1501,6 +1501,7 @@ List skipFiles } WriteImportProjects(importProjects.Distinct(EqualityComparer.Default), project, configurations.First(), writer, resolver); + WriteCustomProperties(project.PostImportCustomProperties, writer, resolver); foreach (var element in project.UsingTasks) { @@ -1614,7 +1615,7 @@ private static void WriteImportProjects(IEnumerable importProject } // TODO: remove this and use Sharpmake.Generators.VisualStudio.VsProjCommon.WriteCustomProperties instead - private static void WriteCustomProperties(Dictionary customProperties, Project project, StreamWriter writer, Resolver resolver) + private static void WriteCustomProperties(Dictionary customProperties, StreamWriter writer, Resolver resolver) { if (customProperties.Any()) { @@ -1629,13 +1630,6 @@ private static void WriteCustomProperties(Dictionary customPrope } } - internal enum CopyToOutputDirectory - { - Never, - Always, - PreserveNewest - } - private void GenerateFiles( CSharpProject project, List configurations, @@ -1649,7 +1643,7 @@ List skipFiles foreach (var file in project.ResolvedContentFullFileNames) { string include = Util.PathGetRelative(_projectPathCapitalized, file); - itemGroups.Contents.Add(new ItemGroups.Content { Include = include, LinkFolder = project.GetLinkFolder(include) }); + itemGroups.Contents.Add(new ItemGroups.Content { Include = include, CopyToOutputDirectory = project.DefaultContentCopyOperation, LinkFolder = project.GetLinkFolder(include) }); } @@ -1741,7 +1735,7 @@ List skipFiles HashSet allContents = new HashSet(itemGroups.Contents.Select(c => c.Include)); List resolvedSources = project.ResolvedSourceFiles.Select(source => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(source))).ToList(); - List resolvedResources = project.ResourceFiles.Concat(project.ResolvedResourcesFullFileNames).Select(resource => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(resource))).Distinct().ToList(); + List resolvedResources = project.ResourceFiles.Concat(project.NonEmbeddedResourceFiles).Concat(project.ResolvedResourcesFullFileNames).Select(resource => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(resource))).Distinct().ToList(); List resolvedEmbeddedResource = project.ResourceFiles.Concat(project.AdditionalEmbeddedResource).Concat(project.AdditionalEmbeddedAssemblies).Select(f => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(f))).Distinct().ToList(); List resolvedNoneFiles = (project.NoneFiles.Select(file => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(file)))) @@ -2169,7 +2163,7 @@ List skipFiles bool runtimeTemplate = project.AdditionalRuntimeTemplates.Contains(ttFile); string expectedExtension = runtimeTemplate ? ".cs" : - Util.GetTextTemplateDirectiveParam(Path.Combine(_projectPath, ttFile), "output", "extension") ?? ".cs"; + Util.GetTextTemplateOutputExtension(Path.Combine(_projectPath, ttFile)) ?? ".cs"; if (!expectedExtension.StartsWith(".", StringComparison.Ordinal)) expectedExtension = "." + expectedExtension; string fileNameWithoutExtension = ttFile.Substring(0, ttFile.Length - TTExtension.Length); @@ -2285,6 +2279,16 @@ List skipFiles }; itemGroups.AddReference(dotNetFramework, referencesByName); } + foreach (var str in conf.InteropReferencesByName) + { + var referencesByName = new ItemGroups.Reference + { + Include = str, + Private = project.DependenciesCopyLocal.HasFlag(Project.DependenciesCopyLocalTypes.DotNetReferences) ? default(bool?) : false, + EmbedInteropTypes = true + }; + itemGroups.AddReference(dotNetFramework, referencesByName); + } } } @@ -2300,6 +2304,16 @@ List skipFiles }; itemGroups.AddReference(dotNetFramework, referencesByNameExternal); } + foreach (var str in conf.InteropReferencesByNameExternal) + { + var referencesByNameExternal = new ItemGroups.Reference + { + Include = str, + Private = project.DependenciesCopyLocal.HasFlag(Project.DependenciesCopyLocalTypes.DotNetExtensions), + EmbedInteropTypes = true + }; + itemGroups.AddReference(dotNetFramework, referencesByNameExternal); + } } foreach (var conf in configurations) @@ -2316,6 +2330,18 @@ List skipFiles }; itemGroups.AddReference(dotNetFramework, referencesByPath); } + foreach (var str in conf.InteropReferencesByPath.Select(Util.GetCapitalizedPath)) + { + var referencesByPath = new ItemGroups.Reference + { + Include = Path.GetFileNameWithoutExtension(str), + SpecificVersion = false, + HintPath = Util.PathGetRelative(_projectPathCapitalized, str), + Private = project.DependenciesCopyLocal.HasFlag(Project.DependenciesCopyLocalTypes.ExternalReferences), + EmbedInteropTypes = true + }; + itemGroups.AddReference(dotNetFramework, referencesByPath); + } foreach (var str in project.AdditionalEmbeddedAssemblies.Select(Util.GetCapitalizedPath)) { @@ -3437,6 +3463,25 @@ private Options.ExplicitOptions GenerateOptions(CSharpProject project, Project.C Options.Option(Options.CSharp.IsPublishable.Disabled, () => { options["IsPublishable"] = "false"; }) ); + if (conf.Target.GetFragment().IsDotNetCore()) + { + SelectOption + ( + Options.Option(Options.CSharp.PublishSingleFile.Enabled, () => { options["PublishSingleFile"] = "true"; }), + Options.Option(Options.CSharp.PublishSingleFile.Disabled, () => { options["PublishSingleFile"] = RemoveLineTag; }) + ); + SelectOption + ( + Options.Option(Options.CSharp.PublishTrimmed.Enabled, () => { options["PublishTrimmed"] = "true"; }), + Options.Option(Options.CSharp.PublishTrimmed.Disabled, () => { options["PublishTrimmed"] = RemoveLineTag; }) + ); + } + else + { + options["PublishSingleFile"] = RemoveLineTag; + options["PublishTrimmed"] = RemoveLineTag; + } + options["AssemblyOriginatorKeyFile"] = Options.PathOption.Get(conf, RemoveLineTag, _projectPath); options["MinimumVisualStudioVersion"] = Options.StringOption.Get(conf); options["OldToolsVersion"] = Options.StringOption.Get(conf); diff --git a/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs b/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs index 419e5da2b..0b78e15ce 100644 --- a/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs @@ -46,7 +46,6 @@ public interface IPlatformVcxproj string SharedLibraryFileFullExtension { get; } string ProgramDatabaseFileFullExtension { get; } string StaticLibraryFileFullExtension { get; } - string StaticOutputLibraryFileFullExtension { get; } bool ExcludesPrecompiledHeadersFromBuild { get; } bool HasUserAccountControlSupport { get; } diff --git a/Sharpmake.Generators/VisualStudio/PackagesConfig.cs b/Sharpmake.Generators/VisualStudio/PackagesConfig.cs index 681d2a9e1..cef5784c0 100644 --- a/Sharpmake.Generators/VisualStudio/PackagesConfig.cs +++ b/Sharpmake.Generators/VisualStudio/PackagesConfig.cs @@ -32,14 +32,27 @@ internal partial class PackagesConfig public bool IsGenerated { get; internal set; } = false; public string PackagesConfigPath => Path.Combine(_projectPath, "packages.config"); - public void Generate(Builder builder, CSharpProject project, List configurations, string projectPath, List generatedFiles, List skipFiles) + + public void Generate(Builder builder, CSharpProject project, List configurations, string projectPath, IList generatedFiles, IList skipFiles) + { + var configuration = configurations[0]; + var frameworkFlags = project.Targets.TargetPossibilities.Select(f => f.GetFragment()).Aggregate((x, y) => x | y); + var frameworks = ((DotNetFramework[])Enum.GetValues(typeof(DotNetFramework))).Where(f => frameworkFlags.HasFlag(f)).Select(f => f.ToFolderName()); + + Generate(builder, configuration, frameworks, projectPath, generatedFiles, skipFiles); + } + + public void Generate(Builder builder, Project.Configuration configuration, string framework, string projectPath, IList generatedFiles, IList skipFiles) + { + Generate(builder, configuration, new[] { framework }, projectPath, generatedFiles, skipFiles); + } + + public void Generate(Builder builder, Project.Configuration configuration, IEnumerable frameworks, string projectPath, IList generatedFiles, IList skipFiles) { _builder = builder; _projectPath = projectPath; - var configuration = configurations[0]; - var frameworkFlags = project.Targets.TargetPossibilities.Select(f => f.GetFragment()).Aggregate((x, y) => x | y); - GeneratePackagesConfig(configuration, frameworkFlags, generatedFiles, skipFiles); + GeneratePackagesConfig(configuration, frameworks, generatedFiles, skipFiles); _builder = null; } @@ -55,7 +68,7 @@ private static bool IsGenerateNeeded(string packagesConfigPath) return false; } - private void GeneratePackagesConfig(Project.Configuration conf, DotNetFramework frameworks, List generatedFiles, List skipFiles) + private void GeneratePackagesConfig(Project.Configuration conf, IEnumerable frameworks, IList generatedFiles, IList skipFiles) { var packagesConfigPath = PackagesConfigPath; @@ -83,12 +96,16 @@ private void GeneratePackagesConfig(Project.Configuration conf, DotNetFramework fileGenerator.Write(Template.Begin); // dependencies - DotNetFramework dnfs = ((DotNetFramework[])Enum.GetValues(typeof(DotNetFramework))).First(f => frameworks.HasFlag(f)); for (int i = 0; i < conf.ReferencesByNuGetPackage.SortedValues.Count; ++i) { using (fileGenerator.Declare("dependency", conf.ReferencesByNuGetPackage.SortedValues[i])) - using (fileGenerator.Declare("framework", dnfs.ToFolderName())) - fileGenerator.Write(Template.DependenciesItem); + { + foreach (var framework in frameworks) + { + using (fileGenerator.Declare("framework", framework)) + fileGenerator.Write(Template.DependenciesItem); + } + } } fileGenerator.Write(Template.End); diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs index 64714afb0..4d0fd94ee 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs @@ -157,10 +157,28 @@ public static class Project public static string ProjectConfigurationImportedTargets = @" +"; + + // Support both regular and native package types, whichever happens to exist + public static string ProjectTargetsNugetReferenceImport = +@" + +"; + + public static string ProjectTargetsNugetReferenceError = +@" "; public static string ProjectTargetsEnd = @" +"; + + public static string ProjectCustomTargetsBegin = +@" +"; + + public static string ProjectCustomTargetsEnd = +@" "; public static string ProjectConfigurationsResourceCompile = diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.cs index 62d405bce..3cd7a4b64 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.cs @@ -181,7 +181,7 @@ public static Dictionary CombineCustomFileB relativeBuildStep.AdditionalInputs.Add(relativeBuildStep.Executable); // Build the command. string command = string.Format( - "{0} {1}", + @"""{0}"" {1}", relativeBuildStep.Executable, relativeBuildStep.ExecutableArguments ); @@ -635,6 +635,20 @@ private void GenerateImpl(GenerationContext context, IList generatedFile else if (hasFastBuildConfig) GenerateBffFilesSection(context, fileGenerator); + // Generate and add reference to packages.config file for project + if (firstConf.ReferencesByNuGetPackage.Count > 0) + { + var packagesConfig = new PackagesConfig(); + packagesConfig.Generate(context.Builder, firstConf, "native", context.ProjectDirectory, generatedFiles, skipFiles); + if (packagesConfig.IsGenerated) + { + fileGenerator.Write(Template.Project.ProjectFilesBegin); + using (fileGenerator.Declare("file", new ProjectFile(context, Util.SimplifyPath(packagesConfig.PackagesConfigPath)))) + fileGenerator.Write(Template.Project.ProjectFilesNone); + fileGenerator.Write(Template.Project.ProjectFilesEnd); + } + } + // Import platform makefiles. foreach (var platform in context.PresentPlatforms.Values) platform.GenerateMakefileConfigurationVcxproj(context, fileGenerator); @@ -674,6 +688,12 @@ private void GenerateImpl(GenerationContext context, IList generatedFile } } } + + // add imports to nuget packages + foreach (var package in firstConf.ReferencesByNuGetPackage) + { + fileGenerator.WriteVerbatim(package.Resolve(fileGenerator.Resolver, Template.Project.ProjectTargetsNugetReferenceImport)); + } fileGenerator.Write(Template.Project.ProjectTargetsEnd); foreach (var element in context.Project.CustomTargets) @@ -684,6 +704,31 @@ private void GenerateImpl(GenerationContext context, IList generatedFile fileGenerator.Write(Template.TargetElement.CustomTarget); } } + + // add error checks for nuget package targets files + if (firstConf.ReferencesByNuGetPackage.Count > 0) + { + using (fileGenerator.Declare("targetName", "EnsureNuGetPackageBuildImports")) + using (fileGenerator.Declare("beforeTargets", "PrepareForBuild")) + { + fileGenerator.Write(Template.Project.ProjectCustomTargetsBegin); + } + + fileGenerator.Write(Template.Project.PropertyGroupStart); + using (fileGenerator.Declare("custompropertyname", "ErrorText")) + using (fileGenerator.Declare("custompropertyvalue", "This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.")) + { + fileGenerator.Write(Template.Project.CustomProperty); + } + fileGenerator.Write(Template.Project.PropertyGroupEnd); + + foreach (var package in firstConf.ReferencesByNuGetPackage) + { + fileGenerator.WriteVerbatim(package.Resolve(fileGenerator.Resolver, Template.Project.ProjectTargetsNugetReferenceError)); + } + + fileGenerator.Write(Template.Project.ProjectCustomTargetsEnd); + } // in case we are using fast build we do not want to write most dependencies // in the vcxproj because they are handled internally in the bff. @@ -1439,10 +1484,12 @@ IList skipFiles { fileGenerator.Write(Template.Project.ProjectFilesCustomBuildBegin); + var standardPath = Util.PathMakeStandard(file.FileNameProjectRelative); + foreach (Project.Configuration conf in context.ProjectConfigurations) { CombinedCustomFileBuildStep buildStep; - if (configurationCustomFileBuildSteps[conf].TryGetValue(file.FileNameProjectRelative, out buildStep)) + if (configurationCustomFileBuildSteps[conf].TryGetValue(standardPath, out buildStep)) { using (fileGenerator.Declare("conf", conf)) using (fileGenerator.Declare("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs index dc9ee02ee..19282af3b 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs @@ -17,8 +17,11 @@ public static partial class Android { public sealed partial class AndroidPlatform { + private const string _projectStartPlatformConditionalPart = + @"'$(Platform)'=='[platform]'"; + private const string _projectStartPlatformConditional = - @" + @" "; private const string _projectDescriptionPlatformSpecific = diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index f588bdf35..93b88abf8 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -65,8 +65,20 @@ public override string GetPlatformString(ITarget target) #region Project.Configuration.IConfigurationTasks implementation public void SetupDynamicLibraryPaths(Project.Configuration configuration, DependencySetting dependencySetting, Project.Configuration dependency) { - // Not tested. We may need to root the path like we do in SetupStaticLibraryPaths. - DefaultPlatform.SetupLibraryPaths(configuration, dependencySetting, dependency); + if (!dependency.Project.GetType().IsDefined(typeof(Export), false)) + { + if (dependencySetting.HasFlag(DependencySetting.LibraryPaths)) + configuration.AddDependencyBuiltTargetLibraryPath(dependency.TargetLibraryPath, dependency.TargetLibraryPathOrderNumber); + } + else + { + if (dependencySetting.HasFlag(DependencySetting.LibraryPaths)) + configuration.DependenciesOtherLibraryPaths.Add(dependency.TargetLibraryPath, dependency.TargetLibraryPathOrderNumber); + } + + // Refernce library using -l, build system knows to look for lib.so + if (dependencySetting.HasFlag(DependencySetting.LibraryFiles)) + configuration.AdditionalLinkerOptions.Add("-l" + dependency.TargetFileName); } public void SetupStaticLibraryPaths(Project.Configuration configuration, DependencySetting dependencySetting, Project.Configuration dependency) @@ -111,10 +123,32 @@ public IEnumerable GetPlatformLibraryPaths(Project.Configuration configu public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerationContext context, IFileGenerator generator) { - generator.Write(_projectStartPlatformConditional); + // When writing android properties section, do not add conditional properties for x64 and x86 if those + // android targets are not used. This allows arm only projects to live alongside windows x64/x86 projects in the same file + var buildTargets = context.ProjectConfigurationOptions + .Where(conf => conf.Key.Platform == Platform.android && conf.Key.Target.HaveFragment()) + .Select(conf => conf.Key.Target.GetFragment()) + .Distinct() + .Select(bt => + { + if (bt == AndroidBuildTargets.arm64_v8a) return "ARM64"; + if (bt == AndroidBuildTargets.armeabi_v7a) return "ARM"; + if (bt == AndroidBuildTargets.x86) return "x86"; + /*if (bt == AndroidBuildTargets.x86_64)*/ return "x64"; + }) + .Select(bt => + { + using (generator.Declare("platform", bt)) + return generator.Resolver.Resolve(_projectStartPlatformConditionalPart); + }); + + using (generator.Declare("condition", string.Join(" OR ", buildTargets))) + { + generator.Write(_projectStartPlatformConditional); + } string applicationType = "Android"; - string applicationTypeRevision = Options.GetOptionValue("applicationTypeRevision", context.ProjectConfigurationOptions.Values); + string applicationTypeRevision = Options.GetOptionValue("applicationTypeRevision", context.ProjectConfigurationOptions.Values, Options.Android.General.ApplicationTypeRevision.Default); string msBuildPathOverrides = string.Empty; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs index 1ece4469c..bf524e63e 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs @@ -619,6 +619,7 @@ public virtual void SelectCompilerOptions(IGenerationContext context) ); context.SelectOption( + Options.Option(Options.XCode.Compiler.LibraryStandard.CompilerDefault, () => { options["LibraryStandard"] = FileGeneratorUtilities.RemoveLineTag; cmdLineOptions["LibraryStandard"] = FileGeneratorUtilities.RemoveLineTag; }), Options.Option(Options.XCode.Compiler.LibraryStandard.CppStandard, () => { options["LibraryStandard"] = "libstdc++"; cmdLineOptions["LibraryStandard"] = "-stdlib=libstdc++"; }), Options.Option(Options.XCode.Compiler.LibraryStandard.LibCxx, () => { options["LibraryStandard"] = "libc++"; cmdLineOptions["LibraryStandard"] = "-stdlib=libc++"; }) ); @@ -645,6 +646,7 @@ public virtual void SelectCompilerOptions(IGenerationContext context) ); context.SelectOption( + Options.Option(Options.XCode.Compiler.LibraryStandard.CompilerDefault, () => { options["LibraryStandard"] = FileGeneratorUtilities.RemoveLineTag; }), Options.Option(Options.XCode.Compiler.LibraryStandard.CppStandard, () => options["LibraryStandard"] = "libstdc++"), Options.Option(Options.XCode.Compiler.LibraryStandard.LibCxx, () => options["LibraryStandard"] = "libc++") ); diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs index f0c7523f8..0a1b9aba2 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs @@ -135,7 +135,6 @@ public virtual void AddCompilerSettings(IDictionary ma public abstract string SharedLibraryFileFullExtension { get; } public abstract string ProgramDatabaseFileFullExtension { get; } public virtual string StaticLibraryFileFullExtension => ".lib"; - public virtual string StaticOutputLibraryFileFullExtension => StaticLibraryFileFullExtension; public virtual bool ExcludesPrecompiledHeadersFromBuild => false; public virtual bool HasUserAccountControlSupport => false; public virtual bool HasEditAndContinueDebuggingSupport => false; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs index 6c325b650..ebd8cbdb7 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs @@ -111,7 +111,6 @@ public void SetupStaticLibraryPaths(Project.Configuration configuration, Depende public override string ProgramDatabaseFileFullExtension => string.Empty; public override string StaticLibraryFileFullExtension => ".a"; public override string SharedLibraryFileFullExtension => ".so"; - public override string StaticOutputLibraryFileFullExtension => string.Empty; public override string ExecutableFileFullExtension => string.Empty; // Ideally the object files should be suffixed .o when compiling with FastBuild, using the CompilerOutputExtension property in ObjectLists diff --git a/Sharpmake.UnitTests/UtilTest.cs b/Sharpmake.UnitTests/UtilTest.cs index df2405c99..e2a899ce4 100644 --- a/Sharpmake.UnitTests/UtilTest.cs +++ b/Sharpmake.UnitTests/UtilTest.cs @@ -62,8 +62,6 @@ public void LeavesEmptyStringsUntouched() public void LeavesVariablesUntouched() { string expectedResult = "$(Console_SdkPackagesRoot)"; - if (!Util.IsRunningInMono()) - expectedResult = expectedResult.ToLower(); Assert.That(Util.PathMakeStandard("$(Console_SdkPackagesRoot)"), Is.EqualTo(expectedResult)); } @@ -71,8 +69,6 @@ public void LeavesVariablesUntouched() public void ProcessesPathWithTrailingBackslash() { string expectedResult = Path.Combine("rd", "project", "dev", "projects", "sharpmake", "..", "..", "extern", "Geometrics"); - if (!Util.IsRunningInMono()) - expectedResult = expectedResult.ToLower(); Assert.That(Util.PathMakeStandard(@"rd\project\dev\projects\sharpmake\..\..\extern\Geometrics\"), Is.EqualTo(expectedResult)); } @@ -80,8 +76,6 @@ public void ProcessesPathWithTrailingBackslash() public void ProcessesPathWithTrailingBackslashAndADot() { var expectedResult = Path.Combine("rd", "project", "dev", "projects", "sharpmake", "..", "..", "extern", "Microsoft.CNG", "Lib"); - if (!Util.IsRunningInMono()) - expectedResult = expectedResult.ToLower(); Assert.That(Util.PathMakeStandard(@"rd\project\dev\projects\sharpmake\..\..\extern\Microsoft.CNG\Lib\"), Is.EqualTo(expectedResult)); } @@ -89,8 +83,6 @@ public void ProcessesPathWithTrailingBackslashAndADot() public void ProcessesPathWithMultipleTrailingBackslashes() { var expectedResult = Path.Combine("rd", "project", "dev", "projects", "sharpmake", "..", "..", "extern", "Microsoft.CNG", "Lib"); - if (!Util.IsRunningInMono()) - expectedResult = expectedResult.ToLower(); Assert.That(Util.PathMakeStandard(@"rd\project\dev\projects\sharpmake\..\..\extern\Microsoft.CNG\Lib\\\"), Is.EqualTo(expectedResult)); } @@ -108,9 +100,6 @@ public void ProcessesWithAListAsArgument() }; var expectedList = listString; - if (!Util.IsRunningInMono()) - expectedList = expectedList.Select((p) => p.ToLower()).ToList(); - Util.PathMakeStandard(listString); Assert.AreEqual(expectedList, listString); @@ -753,7 +742,7 @@ public void CanBeComputedFromOutputPath() var referenceFileFullPath = outputFileFullPath.ReplaceHeadPath(outputPath, referencePath); Assert.That(referenceFileFullPath, Is.EqualTo( - Util.PathMakeStandard(@"F:\OnePath\With\Reference\with\a\file.cs", false))); + Util.PathMakeStandard(@"F:\OnePath\With\Reference\with\a\file.cs"))); } [Test] @@ -766,7 +755,7 @@ public void IsCaseInsensitiveButPreservesCase() var referenceFileFullPath = outputFileFullPath.ReplaceHeadPath(outputPath, referencePath); Assert.That(referenceFileFullPath, Is.EqualTo( - Util.PathMakeStandard(@"F:\OnePath\with\Reference\with\a\File.cs", false))); + Util.PathMakeStandard(@"F:\OnePath\with\Reference\with\a\File.cs"))); } [Test] @@ -779,7 +768,7 @@ public void AcceptsOutputPathWithoutTrailingSlash() var referenceFileFullPath = outputFileFullPath.ReplaceHeadPath(outputPath, referencePath); Assert.That(referenceFileFullPath, Is.EqualTo( - Util.PathMakeStandard(@"F:\OnePath\With\Reference\with\a\file.cs", false))); + Util.PathMakeStandard(@"F:\OnePath\With\Reference\with\a\file.cs"))); } } @@ -1000,7 +989,7 @@ public void PathGetAbsoluteStringsReturnList() string filename = Path.GetFileName(mockPath); string stringsSource = Path.GetDirectoryName(mockPath); - Assert.AreEqual(Path.Combine(stringsSource.ToLower(), filename), Util.PathGetAbsolute(stringsSource, new Strings(filename))[0]); + Assert.AreEqual(Path.Combine(stringsSource, filename), Util.PathGetAbsolute(stringsSource, new Strings(filename))[0]); File.Delete(mockPath); } @@ -1015,7 +1004,7 @@ public void PathGetAbsoluteStringsReturnString() var separator = Path.DirectorySeparatorChar; string stringsSource = mockPath.Substring(0, mockPath.IndexOf(separator)); string stringsDest = mockPath.Substring(mockPath.IndexOf(separator, mockPath.IndexOf(separator) + 1)); - string expectedOutputPath = stringsSource.ToLower() + stringsDest; + string expectedOutputPath = stringsSource + stringsDest; //v Assert.AreEqual(expectedOutputPath, Util.PathGetAbsolute(stringsSource, stringsDest)); @@ -1032,7 +1021,6 @@ public void ResolvePathString() Strings paths = new Strings(Path.GetDirectoryName(mockPath)); string root = mockPath.Substring(0, mockPath.IndexOf(Path.DirectorySeparatorChar)); Strings expectedOutputPath = new Strings(paths.Select((p) => Path.Combine(root, p))); - expectedOutputPath.ToLower(); Util.ResolvePath(root, ref paths); @@ -1057,7 +1045,7 @@ public void ResolvePathOrderableString() mockPath3.Substring(mockPath3.IndexOf(Path.DirectorySeparatorChar)), }; string root = mockPath1.Substring(0, mockPath1.IndexOf(Path.DirectorySeparatorChar)); - OrderableStrings expectedOutputPath = new OrderableStrings(paths.Select((p) => (root + p).ToLower())); + OrderableStrings expectedOutputPath = new OrderableStrings(paths.Select((p) => (root + p))); Util.ResolvePath(root, ref paths); expectedOutputPath.Sort(); @@ -1114,8 +1102,8 @@ public void PathGetRelativeOrderableStrings() Util.PathMakeStandard(stringsDest); OrderableStrings listResult = Util.PathGetRelative(stringsSource, stringsDest, false); - Assert.AreEqual(Util.PathMakeStandard(@"..\Sharpmake.Generators\Generic", !Util.IsRunningInMono()), listResult[0]); - Assert.AreEqual(Util.PathMakeStandard(@"subdir\test.txt", !Util.IsRunningInMono()), listResult[1]); + Assert.AreEqual(Util.PathMakeStandard(@"..\Sharpmake.Generators\Generic"), listResult[0]); + Assert.AreEqual(Util.PathMakeStandard(@"subdir\test.txt"), listResult[1]); Assert.AreEqual("test2.txt", listResult[2]); } @@ -1192,11 +1180,11 @@ public void GetConvertedRelativePathRoot() var root = @"C:\SharpMake\sharpmake\Sharpmake.Application\Properties"; var newRelativeToFullPath = ""; - Assert.AreEqual(Path.Combine(absolutePath.ToLower(), fileName), Util.GetConvertedRelativePath(absolutePath, fileName, newRelativeToFullPath, false, null)); + Assert.AreEqual(Path.Combine(absolutePath, fileName), Util.GetConvertedRelativePath(absolutePath, fileName, newRelativeToFullPath, false, null)); Assert.AreEqual(mockPath, Util.GetConvertedRelativePath(absolutePath, mockPath, newRelativeToFullPath, false, root)); - Assert.AreEqual(Path.Combine(absolutePath.ToLower(), fileName), Util.GetConvertedRelativePath(absolutePath, fileName, newRelativeToFullPath, false, "")); + Assert.AreEqual(Path.Combine(absolutePath, fileName), Util.GetConvertedRelativePath(absolutePath, fileName, newRelativeToFullPath, false, "")); Assert.AreEqual(absolutePath, Util.GetConvertedRelativePath(absolutePath, null, newRelativeToFullPath, false, null)); - Assert.AreEqual(Path.Combine(root.ToLower(), Path.GetTempPath()), Util.GetConvertedRelativePath(root, Path.GetTempPath(), newRelativeToFullPath, false, null)); + Assert.AreEqual(Path.Combine(root, Path.GetTempPath()), Util.GetConvertedRelativePath(root, Path.GetTempPath(), newRelativeToFullPath, false, null)); File.Delete(mockPath); } diff --git a/Sharpmake/DebugProjectGenerator.cs b/Sharpmake/DebugProjectGenerator.cs index f0fa06684..28f0536ae 100644 --- a/Sharpmake/DebugProjectGenerator.cs +++ b/Sharpmake/DebugProjectGenerator.cs @@ -322,6 +322,7 @@ public DebugProject() // ensure that no file will be automagically added SourceFilesExtensions.Clear(); ResourceFilesExtensions.Clear(); + NonEmbeddedResourceFilesExtensions.Clear(); PRIFilesExtensions.Clear(); ResourceFiles.Clear(); NoneExtensions.Clear(); diff --git a/Sharpmake/Options.CSharp.cs b/Sharpmake/Options.CSharp.cs index da5bcd067..b498252be 100644 --- a/Sharpmake/Options.CSharp.cs +++ b/Sharpmake/Options.CSharp.cs @@ -195,6 +195,20 @@ public enum UseWindowsForms Disabled } + public enum PublishSingleFile + { + Enabled, + [Default] + Disabled + } + + public enum PublishTrimmed + { + Enabled, + [Default] + Disabled + } + public class UpdateInterval : IntOption { public UpdateInterval(int interval) diff --git a/Sharpmake/Options.XCode.cs b/Sharpmake/Options.XCode.cs index 997e43fe8..88f85ed49 100644 --- a/Sharpmake/Options.XCode.cs +++ b/Sharpmake/Options.XCode.cs @@ -263,8 +263,9 @@ public IPhoneOSDeploymentTarget(string minimumVersion) public enum LibraryStandard { - CppStandard, [Default] + CompilerDefault, + CppStandard, LibCxx } diff --git a/Sharpmake/PackageReferences.cs b/Sharpmake/PackageReferences.cs index f5c0d2dbc..b0ee5cfe7 100644 --- a/Sharpmake/PackageReferences.cs +++ b/Sharpmake/PackageReferences.cs @@ -67,6 +67,15 @@ public string Resolve(Resolver resolver) } } + public string Resolve(Resolver resolver, string customTemplate) + { + using (resolver.NewScopedParameter("packageName", Name)) + using (resolver.NewScopedParameter("packageVersion", Version)) + { + return resolver.Resolve(customTemplate); + } + } + public int CompareTo(PackageReference other) { if (ReferenceEquals(this, other)) diff --git a/Sharpmake/PathUtil.cs b/Sharpmake/PathUtil.cs index fa33c961a..fb90355a3 100644 --- a/Sharpmake/PathUtil.cs +++ b/Sharpmake/PathUtil.cs @@ -40,16 +40,10 @@ public static void PathMakeStandard(IList paths) } public static string PathMakeStandard(string path) - { - return PathMakeStandard(path, !Util.IsRunningOnUnix()); - } - - public static string PathMakeStandard(string path, bool forceToLower) { // cleanup the path by replacing the other separator by the correct one for this OS // then trim every trailing separators - var standardPath = path.Replace(OtherSeparator, Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar); - return forceToLower ? standardPath.ToLower() : standardPath; + return path.Replace(OtherSeparator, Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar); } public static string EnsureTrailingSeparator(string path) @@ -797,9 +791,9 @@ internal static string ConvertToMountedUnixPath(string path) public static string ReplaceHeadPath(this string fullInputPath, string inputHeadPath, string replacementHeadPath) { // Normalize paths before comparing and combining them, to prevent false mismatch between '\\' and '/'. - fullInputPath = Util.PathMakeStandard(fullInputPath, false); - inputHeadPath = Util.PathMakeStandard(inputHeadPath, false); - replacementHeadPath = Util.PathMakeStandard(replacementHeadPath, false); + fullInputPath = PathMakeStandard(fullInputPath); + inputHeadPath = PathMakeStandard(inputHeadPath); + replacementHeadPath = PathMakeStandard(replacementHeadPath); inputHeadPath = EnsureTrailingSeparator(inputHeadPath); diff --git a/Sharpmake/Project.Configuration.cs b/Sharpmake/Project.Configuration.cs index e5e68dd89..8ecb383ef 100644 --- a/Sharpmake/Project.Configuration.cs +++ b/Sharpmake/Project.Configuration.cs @@ -1080,6 +1080,13 @@ public Options.Vc.Compiler.Exceptions GetExceptionSettingForFile(string filename return Sharpmake.Options.Vc.Compiler.Exceptions.Disable; } + /// + /// When enabled dependendent libraries will be sorted by their dependencies. This can be + /// used to fix linker errors on linux platforms that expect libraries to be included in a + /// specific order + /// + public bool AutoDependenciesOrder = false; + /// /// Gets a list of the search directories for static libraries. /// @@ -1151,7 +1158,7 @@ public void AddDependencyBuiltTargetLibraryFile(string libraryFile, int orderNum { if (_linkState != LinkState.Linking) throw new Error($"Cannot add built target lib '{libraryFile}' outside of the link process of the Project.Configuration"); - DependenciesBuiltTargetsLibraryFiles.Add(libraryFile, orderNumber); + DependenciesBuiltTargetsLibraryFiles.Add(libraryFile, orderNumber, OrderableStrings.OrderResolve.Greater); } public OrderableStrings DependenciesForceUsingFiles = new OrderableStrings(); @@ -2819,6 +2826,9 @@ internal void Resolve(string sourceRootPath, Resolver resolver) public Strings ReferencesByName = new Strings(); public Strings ReferencesByNameExternal = new Strings(); public Strings ReferencesByPath = new Strings(); + public Strings InteropReferencesByName = new Strings(); + public Strings InteropReferencesByNameExternal = new Strings(); + public Strings InteropReferencesByPath = new Strings(); public string ConditionalReferencesByPathCondition = string.Empty; public Strings ConditionalReferencesByPath = new Strings(); public Strings ForceUsingFiles = new Strings(); @@ -2826,7 +2836,7 @@ internal void Resolve(string sourceRootPath, Resolver resolver) public Strings CustomPropsFiles = new Strings(); // vs2010+ .props files public Strings CustomTargetsFiles = new Strings(); // vs2010+ .targets files - // NuGet packages (only C# for now) + // NuGet packages (C# and visual studio c++ for now) public PackageReferences ReferencesByNuGetPackage = new PackageReferences(); public bool? ReferenceOutputAssembly = null; @@ -2850,15 +2860,17 @@ private static int SortConfigurationForLink(Configuration l, Configuration r) internal class DependencyNode { - internal DependencyNode(Configuration inConfiguration, DependencySetting inDependencySetting) + internal DependencyNode(Configuration inConfiguration, DependencySetting inDependencySetting, int autoDependenciesOrder = 0) { _configuration = inConfiguration; _dependencySetting = inDependencySetting; + _autoDependenciesOrder = autoDependenciesOrder; } internal Configuration _configuration; internal DependencySetting _dependencySetting; internal Dictionary _childNodes = new Dictionary(); + internal int _autoDependenciesOrder; } public class VcxprojUserFileSettings @@ -3105,8 +3117,9 @@ internal void Link(Builder builder) if (dependencySetting.HasFlag(DependencySetting.LibraryPaths)) DependenciesOtherLibraryPaths.AddRange(dependency.LibraryPaths); + // Use dependency.TargetFileOrderNumber to make sure to group dependent libraries by their dependencies if (dependencySetting.HasFlag(DependencySetting.LibraryFiles)) - DependenciesOtherLibraryFiles.AddRange(dependency.LibraryFiles); + DependenciesOtherLibraryFiles.AddRange(dependency.LibraryFiles, dependency.TargetFileOrderNumber, OrderableStrings.OrderResolve.Greater); if (dependencySetting.HasFlag(DependencySetting.ForceUsingAssembly)) DependenciesForceUsingFiles.AddRange(dependency.ForceUsingFiles); @@ -3138,8 +3151,9 @@ internal void Link(Builder builder) if (dependencySetting.HasFlag(DependencySetting.LibraryPaths)) DependenciesOtherLibraryPaths.AddRange(dependency.LibraryPaths); + // Use dependency.TargetFileOrderNumber to make sure to group dependent libraries by their dependencies if (dependencySetting.HasFlag(DependencySetting.LibraryFiles)) - DependenciesOtherLibraryFiles.AddRange(dependency.LibraryFiles); + DependenciesOtherLibraryFiles.AddRange(dependency.LibraryFiles, dependency.TargetFileOrderNumber, OrderableStrings.OrderResolve.Greater); } } @@ -3303,6 +3317,7 @@ static private DependencyNode BuildDependencyNodeTree(Builder builder, Configura Stack visiting = new Stack(); visiting.Push(rootNode); + while (visiting.Count > 0) { DependencyNode visitedNode = visiting.Pop(); @@ -3322,6 +3337,11 @@ static private DependencyNode BuildDependencyNodeTree(Builder builder, Configura visited.Add(visitedConfiguration, visitedNode); + if (visitedConfiguration.AutoDependenciesOrder) + { + visitedConfiguration.TargetFileOrderNumber = Math.Max(visitedConfiguration.TargetFileOrderNumber, visitedNode._autoDependenciesOrder); + } + var unresolvedDependencies = new[] { visitedConfiguration.UnResolvedPublicDependencies, visitedConfiguration.UnResolvedPrivateDependencies }; foreach (Dictionary dependencies in unresolvedDependencies) { @@ -3340,7 +3360,8 @@ static private DependencyNode BuildDependencyNodeTree(Builder builder, Configura if (!visitedConfiguration._dependenciesSetting.TryGetValue(pair, out dependencySetting)) dependencySetting = DependencySetting.Default; - DependencyNode childNode = new DependencyNode(dependencyConf, dependencySetting); + // We use steps of 1000 to allow for related libraries to be grouped alongside their dependencies + DependencyNode childNode = new DependencyNode(dependencyConf, dependencySetting, visitedNode._autoDependenciesOrder + 1000); System.Diagnostics.Debug.Assert(!visitedNode._childNodes.ContainsKey(childNode)); visitedNode._childNodes.Add(childNode, dependencyType); diff --git a/Sharpmake/Project.cs b/Sharpmake/Project.cs index cf82357e5..8eee7e6f3 100644 --- a/Sharpmake/Project.cs +++ b/Sharpmake/Project.cs @@ -163,6 +163,9 @@ public int SourceFilesFiltersCount public Strings ResourceFiles = new Strings(); public Strings ResourceFilesExtensions = new Strings(); + public Strings NonEmbeddedResourceFiles = new Strings(); + public Strings NonEmbeddedResourceFilesExtensions = new Strings(); + public Strings NatvisFiles = new Strings(); public Strings NatvisFilesExtensions = new Strings(".natvis"); @@ -242,6 +245,7 @@ internal void Resolve(string sourceRootPath, Resolver resolver) public Dictionary PreImportCustomProperties = new Dictionary(); // pre import properties are added before any imports to the project xml as Value public Dictionary CustomProperties = new Dictionary(); // custom properties are added to the project xml as Value + public Dictionary PostImportCustomProperties = new Dictionary(); // additional custom properties that are added after imports public Dictionary CustomFilterMapping = new Dictionary(); /// maps relative source directory to a custom filter path for vcxproj.filter files @@ -872,7 +876,7 @@ internal virtual void ResolveSourceFiles(Builder builder) } // Only scan directory for files if needed - if (SourceFilesExtensions.Count != 0 || ResourceFilesExtensions.Count != 0 || PRIFilesExtensions.Count != 0 || NoneExtensions.Count != 0 || NoneExtensionsCopyIfNewer.Count != 0) + if (SourceFilesExtensions.Count != 0 || ResourceFilesExtensions.Count != 0 || NonEmbeddedResourceFilesExtensions.Count != 0 || PRIFilesExtensions.Count != 0 || NoneExtensions.Count != 0 || NoneExtensionsCopyIfNewer.Count != 0) { string capitalizedSourceRootPath = Util.GetCapitalizedPath(SourceRootPath); @@ -904,6 +908,7 @@ internal virtual void ResolveSourceFiles(Builder builder) AddMatchExtensionFiles(additionalFiles, ref PRIFiles, PRIFilesExtensions); AddMatchExtensionFiles(additionalFiles, ref ResourceFiles, ResourceFilesExtensions); + AddMatchExtensionFiles(additionalFiles, ref NonEmbeddedResourceFiles, NonEmbeddedResourceFilesExtensions); AddMatchExtensionFiles(additionalFiles, ref NatvisFiles, NatvisFilesExtensions); AddMatchExtensionFiles(additionalFiles, ref NoneFiles, NoneExtensions); AddMatchExtensionFiles(additionalFiles, ref NoneFilesCopyIfNewer, NoneExtensionsCopyIfNewer); @@ -932,6 +937,9 @@ internal virtual void ResolveSourceFiles(Builder builder) AddMatchExtensionFiles(files, ref ResourceFiles, ResourceFilesExtensions); Util.ResolvePath(SourceRootPath, ref ResourceFiles); + AddMatchExtensionFiles(files, ref NonEmbeddedResourceFiles, NonEmbeddedResourceFilesExtensions); + Util.ResolvePath(SourceRootPath, ref NonEmbeddedResourceFiles); + AddMatchExtensionFiles(files, ref NatvisFiles, NatvisFilesExtensions); Util.ResolvePath(SourceRootPath, ref NatvisFiles); @@ -1974,6 +1982,7 @@ public FastBuildAllProject(Type targetType) // Disable automatic source files discovery SourceFilesExtensions.Clear(); ResourceFilesExtensions.Clear(); + NonEmbeddedResourceFilesExtensions.Clear(); PRIFilesExtensions.Clear(); } } @@ -2060,6 +2069,13 @@ public enum FileType Assembly, File } + + public enum CopyToOutputDirectory + { + Never, + Always, + PreserveNewest + } public class PublishFile { @@ -2165,6 +2181,7 @@ public static void InitAspNetProject(this CSharpProject aspNetProject) aspNetProject.ContentExtension.Add(contentExtension); aspNetProject.ResourceFilesExtensions.Remove(contentExtension); + aspNetProject.NonEmbeddedResourceFilesExtensions.Remove(contentExtension); aspNetProject.EmbeddedResourceExtensions.Remove(contentExtension); aspNetProject.NoneExtensions.Add(".pubxml"); @@ -2257,6 +2274,7 @@ public void AddDefaultReferences(Configuration conf) public class CSharpProject : Project { public Strings ContentExtension = new Strings(); + public CopyToOutputDirectory? DefaultContentCopyOperation = null; public Strings VsctExtension = new Strings(".vsct"); public CSharpProjectType ProjectTypeGuids = CSharpProjectType.Default; public CSharpProjectSchema ProjectSchema = CSharpProjectSchema.Default; @@ -2674,6 +2692,8 @@ public AndroidPackageProject() : this(typeof(Target)) public AndroidPackageProject(Type targetType) : base(targetType) { + SourceFilesExtensions = new Strings(".java", ".xml"); + SourceFilesCompileExtensions = new Strings(".java"); } } } diff --git a/Sharpmake/Sharpmake.csproj b/Sharpmake/Sharpmake.csproj index c92ccbab8..0735f115d 100644 --- a/Sharpmake/Sharpmake.csproj +++ b/Sharpmake/Sharpmake.csproj @@ -176,7 +176,7 @@ - + diff --git a/Sharpmake/Strings.cs b/Sharpmake/Strings.cs index 5720edb6a..f999c613d 100644 --- a/Sharpmake/Strings.cs +++ b/Sharpmake/Strings.cs @@ -253,7 +253,14 @@ public void Add(string item) _list.Add(new StringEntry(item)); } - public void Add(string item, int orderNumber) + public enum OrderResolve + { + None, + Less, + Greater + } + + public void Add(string item, int orderNumber, OrderResolve resolveMethod = OrderResolve.None) { if (_hashSet.Add(item)) _list.Add(new StringEntry(item, orderNumber)); @@ -268,9 +275,22 @@ public void Add(string item, int orderNumber) _list[i] = new StringEntry(item, orderNumber); else if (_list[i].OrderNumber != orderNumber) { - throw new Error( - "Cannot specify 2 different non-zero order number for \"" + - item + "\": " + _list[i].OrderNumber + " and " + orderNumber); + if (resolveMethod == OrderResolve.Less) + { + if (orderNumber < _list[i].OrderNumber) + _list[i] = new StringEntry(item, orderNumber); + } + else if (resolveMethod == OrderResolve.Greater) + { + if (orderNumber > _list[i].OrderNumber) + _list[i] = new StringEntry(item, orderNumber); + } + else + { + throw new Error( + "Cannot specify 2 different non-zero order number for \"" + + item + "\": " + _list[i].OrderNumber + " and " + orderNumber); + } } } } @@ -283,18 +303,20 @@ public void AddRange(IEnumerable collection) Add(item); } - public void AddRange(OrderableStrings collection) + public void AddRange(OrderableStrings collection, int outerOrderNumber = 0, OrderResolve resolveMethod = OrderResolve.None) { List existingEntriesToAdd = null; foreach (var entry in collection._list) { + var newEntry = new StringEntry(entry.StringValue, entry.OrderNumber + outerOrderNumber); + if (_hashSet.Add(entry.StringValue)) - _list.Add(entry); - else if (entry.OrderNumber != 0) // make sure to have orderNumber + _list.Add(newEntry); + else if (newEntry.OrderNumber != 0) // make sure to have orderNumber { if (existingEntriesToAdd == null) existingEntriesToAdd = new List(); - existingEntriesToAdd.Add(entry); + existingEntriesToAdd.Add(newEntry); } } if (existingEntriesToAdd != null) @@ -309,9 +331,22 @@ public void AddRange(OrderableStrings collection) _list[i] = new StringEntry(_list[i].StringValue, orderNumber); else if (_list[i].OrderNumber != orderNumber) { - throw new Error( - "Cannot specify 2 different non-zero order number for \"" + - _list[i].StringValue + "\": " + _list[i].OrderNumber + " and " + orderNumber); + if (resolveMethod == OrderResolve.Less) + { + if (orderNumber < _list[i].OrderNumber) + _list[i] = new StringEntry(_list[i].StringValue, orderNumber); + } + else if (resolveMethod == OrderResolve.Greater) + { + if (orderNumber > _list[i].OrderNumber) + _list[i] = new StringEntry(_list[i].StringValue, orderNumber); + } + else + { + throw new Error( + "Cannot specify 2 different non-zero order number for \"" + + _list[i].StringValue + "\": " + _list[i].OrderNumber + " and " + orderNumber); + } } } } diff --git a/Sharpmake/Util.cs b/Sharpmake/Util.cs index 1852c5fd3..9d13e36c2 100644 --- a/Sharpmake/Util.cs +++ b/Sharpmake/Util.cs @@ -98,6 +98,21 @@ public static int GetDeterministicHashCode(this string str) } } + private static string GetTextTemplateDirectiveParam(string[] templateText, string directive, string paramName) + { + Regex regex = new Regex(@"<#@\s*?" + directive + @"\s+?.*?" + paramName + @"=""(?.*?)"".*?#>"); + + foreach (var line in templateText) + { + Match m = regex.Match(line); + Group g = m.Groups["paramValue"]; + if (g != null && g.Success) + return g.Value; + } + + return null; + } + /// /// Finds the first occurrence of directive and returns the /// requested param value. Ex: @@ -107,10 +122,29 @@ public static int GetDeterministicHashCode(this string str) /// and return ".txt" /// public static string GetTextTemplateDirectiveParam(string filePath, string directive, string paramName) + { + return GetTextTemplateDirectiveParam(File.ReadAllLines(filePath), directive, paramName); + } + + /// + /// Finds the output type of a template, looking for both the directive form and the Host.SetFileExtension form + /// will match: + /// <#@ output extension=".txt" #> + /// or + /// Host.SetFileExtension(".txt") + /// and return ".txt" + /// + public static string GetTextTemplateOutputExtension(string filePath) { string[] templateText = File.ReadAllLines(filePath); - Regex regex = new Regex(@"<#@\s*?" + directive + @"\s+?.*?" + paramName + @"=""(?.*?)"".*?#>"); + var output = Util.GetTextTemplateDirectiveParam(templateText, "output", "extension"); + if (output != null) + return output; + + // alternatively look for host.SetFileExtension + + Regex regex = new Regex(@"Host.SetFileExtension\(""(?.*?)""\)"); foreach (var line in templateText) { diff --git a/samples/PackageReferences/PackageReferences.sharpmake.cs b/samples/PackageReferences/PackageReferences.sharpmake.cs index 8937a4d27..a667fee2f 100644 --- a/samples/PackageReferences/PackageReferences.sharpmake.cs +++ b/samples/PackageReferences/PackageReferences.sharpmake.cs @@ -15,16 +15,16 @@ using System; using Sharpmake; -namespace CSharpPackageReference +namespace PackageReference { [Generate] - public class PackageReferences : CSharpProject + public class CSharpPackageReferences : CSharpProject { - public PackageReferences() + public CSharpPackageReferences() { AddTargets( new Target( - Platform.anycpu, + Platform.win64, DevEnv.vs2017 | DevEnv.vs2019, Optimization.Debug | Optimization.Release, OutputType.Dll, @@ -58,6 +58,41 @@ public virtual void ConfigureAll(Configuration conf, Target target) } } + [Generate] + public class CPPPackageReferences : Project + { + public CPPPackageReferences() + { + AddTargets( + new Target( + Platform.win64, + DevEnv.vs2017 | DevEnv.vs2019, + Optimization.Debug | Optimization.Release, + OutputType.Dll, + Blob.NoBlob, + BuildSystem.MSBuild, + DotNetFramework.v4_7_2 + ) + ); + + RootPath = @"[project.SharpmakeCsPath]\projects\[project.Name]"; + + // This Path will be used to get all SourceFiles in this Folder and all subFolders + SourceRootPath = @"[project.SharpmakeCsPath]\codebase\[project.Name]"; + } + + [Configure()] + public virtual void ConfigureAll(Configuration conf, Target target) + { + conf.ProjectFileName = "[project.Name].[target.DevEnv].[target.Framework]"; + conf.ProjectPath = @"[project.RootPath]"; + + conf.Options.Add(Options.CSharp.TreatWarningsAsErrors.Enabled); + + conf.ReferencesByNuGetPackage.Add("gtest-vc140-static-64", "1.1.0"); + } + } + [Generate] public class PackageReferenceSolution : CSharpSolution { @@ -65,7 +100,7 @@ public PackageReferenceSolution() { AddTargets( new Target( - Platform.anycpu, + Platform.win64, DevEnv.vs2017 | DevEnv.vs2019, Optimization.Debug | Optimization.Release, OutputType.Dll, @@ -85,7 +120,8 @@ public void ConfigureAll(Configuration conf, Target target) "[target.Framework]"); conf.SolutionPath = @"[solution.SharpmakeCsPath]\projects\"; - conf.AddProject(target); + conf.AddProject(target); + conf.AddProject(target); } [Main] diff --git a/samples/PackageReferences/codebase/CPPPackageReferences/main.cpp b/samples/PackageReferences/codebase/CPPPackageReferences/main.cpp new file mode 100644 index 000000000..acd68305a --- /dev/null +++ b/samples/PackageReferences/codebase/CPPPackageReferences/main.cpp @@ -0,0 +1,8 @@ +#define _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING +#include + +int main(int, char**) +{ + // just reference some code that comes from gtest + return testing::kMaxStackTraceDepth; +} diff --git a/samples/PackageReferences/codebase/PackageReferences/Program.cs b/samples/PackageReferences/codebase/CSharpPackageReferences/Program.cs similarity index 100% rename from samples/PackageReferences/codebase/PackageReferences/Program.cs rename to samples/PackageReferences/codebase/CSharpPackageReferences/Program.cs diff --git a/samples/PackageReferences/codebase/PackageReferences/Properties/AssemblyInfo.cs b/samples/PackageReferences/codebase/CSharpPackageReferences/Properties/AssemblyInfo.cs similarity index 100% rename from samples/PackageReferences/codebase/PackageReferences/Properties/AssemblyInfo.cs rename to samples/PackageReferences/codebase/CSharpPackageReferences/Properties/AssemblyInfo.cs