From dd451d0c5c1b7f156260f73f1806e346b6d65693 Mon Sep 17 00:00:00 2001 From: Guillaume BUCHLE Date: Tue, 21 Apr 2020 15:48:18 +0000 Subject: [PATCH 01/43] Update Solution generation in Readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5224fb5a1..71f37836f 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,8 @@ source code also comes with samples that you can study. ## Building Sharpmake -Building Sharpmake is quite straightforward. Clone the repo on GitHub, open the +Building Sharpmake is quite straightforward. Clone the repo on GitHub, run the +"bootstrap" script (".bat" for Windows, ".sh" Unix platforms), open the solution in Visual Studio and build the solution in *Release*. The binaries will be found in the *Sharpmake.Application/bin/Release*. You can run the *deploy_binaries.py* script to automatically fetch the binaries and copy them From d2c9bdef085da58d4c0e17e45152aba4c77014f0 Mon Sep 17 00:00:00 2001 From: Guillaume BUCHLE Date: Tue, 21 Apr 2020 15:49:57 +0000 Subject: [PATCH 02/43] Missing word --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71f37836f..f794d0ea7 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ source code also comes with samples that you can study. ## Building Sharpmake Building Sharpmake is quite straightforward. Clone the repo on GitHub, run the -"bootstrap" script (".bat" for Windows, ".sh" Unix platforms), open the +"bootstrap" script (".bat" for Windows, ".sh" for Unix platforms), open the solution in Visual Studio and build the solution in *Release*. The binaries will be found in the *Sharpmake.Application/bin/Release*. You can run the *deploy_binaries.py* script to automatically fetch the binaries and copy them From 3ef048d1d09721d173fd30129afdff6dd36a11f8 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Fri, 24 Apr 2020 11:18:46 +0200 Subject: [PATCH 03/43] Improve error log when the resolver cannot resolve Now we will print all the possible arguments --- Sharpmake/Resolver.cs | 100 +++++++++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 17 deletions(-) diff --git a/Sharpmake/Resolver.cs b/Sharpmake/Resolver.cs index f4d227146..c5b60fb7b 100644 --- a/Sharpmake/Resolver.cs +++ b/Sharpmake/Resolver.cs @@ -16,6 +16,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Text; @@ -302,7 +303,23 @@ public string Resolve(string str, object fallbackValue = null) if (isValidMember && !isEscaped) { - string resolveResult = GetMemberStringValue(str.Substring(memberStartIndex, endMatch - memberStartIndex), fallbackValue == null) ?? fallbackValue?.ToString(); + bool throwIfNotFound = fallbackValue == null; + + string resolveResult; + try + { + resolveResult = GetMemberStringValue(str.Substring(memberStartIndex, endMatch - memberStartIndex), throwIfNotFound) ?? fallbackValue?.ToString(); + } + catch (NotFoundException e) + { + throw new Error( + "Error: {0} in '{1}'\n{2}", + e.Message, + str, + e.Arguments + ); + } + if (resolveResult == null) { // Resolve failed. @@ -473,6 +490,31 @@ private static void GetFieldInfoOrPropertyInfo(Type type, string name, out Field propertyInfo = value.Value; } + [Serializable] + private class NotFoundException : Exception + { + private IEnumerable _arguments; + public string Arguments + { + get + { + if (_arguments == null) + return string.Empty; + + if (!_arguments.Any()) + return "The list of arguments that can be used is *Empty*"; + + return "The list of arguments that can be used is:\n- " + string.Join("\n- ", _arguments.OrderBy(x => x, StringComparer.InvariantCultureIgnoreCase)); + } + } + + public NotFoundException(string message, IEnumerable arguments = null) + : base(message) + { + _arguments = arguments; + } + } + private string GetMemberStringValue(string memberPath, bool throwIfNotFound) { string[] names = memberPath.Split(new[] { _pathSeparator }, StringSplitOptions.RemoveEmptyEntries); @@ -480,7 +522,7 @@ private string GetMemberStringValue(string memberPath, bool throwIfNotFound) if (names.Length == 0) { if (throwIfNotFound) - throw new Exception("Cannot find unnamed parameter"); + throw new NotFoundException("Cannot find unnamed parameter"); return null; } @@ -492,7 +534,8 @@ private string GetMemberStringValue(string memberPath, bool throwIfNotFound) if (!_parameters.TryGetValue(parameterName, out refCountedReference)) { if (throwIfNotFound) - throw new Exception("Cannot resolve parameter " + names[0]); + throw new NotFoundException($"Cannot resolve parameter '{parameterName}'.", _parameters.Keys); + return null; } object parameter = refCountedReference.Value; @@ -502,41 +545,64 @@ private string GetMemberStringValue(string memberPath, bool throwIfNotFound) { bool found = false; + string nameChunk = names[i]; FieldInfo fieldInfo; PropertyInfo propertyInfo; - GetFieldInfoOrPropertyInfo(parameter.GetType(), names[i], out fieldInfo, out propertyInfo); + Type parameterType = parameter.GetType(); + GetFieldInfoOrPropertyInfo(parameterType, nameChunk, out fieldInfo, out propertyInfo); if (fieldInfo != null) { parameter = fieldInfo.GetValue(parameter); found = true; } - else + else if (propertyInfo != null) { - if (propertyInfo != null) - { - parameter = propertyInfo.GetValue(parameter, null); - found = true; - } + parameter = propertyInfo.GetValue(parameter, null); + found = true; } - // IDictionary support + // IDictionary support if (!found && i == names.Length - 1 && parameter is IDictionary) { - IDictionary dictionaty = parameter as IDictionary; - if (dictionaty.Contains(names[i])) - return dictionaty[names[i]].ToString(); + var dictionary = parameter as IDictionary; + if (dictionary.Contains(nameChunk)) + return dictionary[nameChunk].ToString(); } - name += _pathSeparator + names[i]; - if (!found) { if (throwIfNotFound) - throw new Exception("Cannot find path: " + name + " in parameter path " + memberPath); + { + string currentPath = parameterName + _pathSeparator; + if (!string.IsNullOrWhiteSpace(name)) + currentPath += name + _pathSeparator; + + // get all public fields + var possibleArguments = parameterType.GetFields().Select(f => currentPath + f.Name); + + // all public properties + possibleArguments = possibleArguments.Concat(parameterType.GetProperties().Select(p => currentPath + p.Name)); + + // and dictionary keys, if they are strings + var dictionary = parameter as IDictionary; + if (dictionary != null) + { + var keysAsStrings = ((IDictionary)parameter).Keys as IEnumerable; + if (keysAsStrings != null) + possibleArguments = possibleArguments.Concat(keysAsStrings.Select(k => currentPath + k)); + } + + throw new NotFoundException( + $"Cannot find path '{nameChunk}' in parameter path '{memberPath}'.", + possibleArguments + ); + } return null; } + + name += _pathSeparator + nameChunk; } return parameter == null ? "null" : parameter.ToString(); From c833819829509ee2ed1029ade35b62981f40b988 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Sat, 25 Apr 2020 19:33:15 +0200 Subject: [PATCH 04/43] Fix dependency tracker crash when a FastBuildAll project is generated in a solution. --- Sharpmake/DependencyTracker.cs | 6 +++--- Sharpmake/Project.Configuration.cs | 2 +- Sharpmake/Project.cs | 4 ++-- Sharpmake/TrackedConfiguration.cs | 2 +- Sharpmake/TrackedProject.cs | 9 +++++---- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Sharpmake/DependencyTracker.cs b/Sharpmake/DependencyTracker.cs index 4c42e8ce7..62b3e52b9 100644 --- a/Sharpmake/DependencyTracker.cs +++ b/Sharpmake/DependencyTracker.cs @@ -18,7 +18,7 @@ namespace Sharpmake { - public class DependencyTracker + internal class DependencyTracker { public static DependencyTracker Instance { get; private set; } = new DependencyTracker(); @@ -157,10 +157,10 @@ private TrackedConfiguration FindConfiguration(Project project, Project.Configur return p.FindConfiguration(config); } - private TrackedConfiguration FindConfiguration(Type project, ITarget config) + private TrackedConfiguration FindConfiguration(Type project, ITarget target) { TrackedProject p = _projects[project.ToString()]; - return p.FindConfiguration(config); + return p.FindConfiguration(target); } private delegate void ResetVisitDelegate(); diff --git a/Sharpmake/Project.Configuration.cs b/Sharpmake/Project.Configuration.cs index 16d02a14e..410a7e69c 100644 --- a/Sharpmake/Project.Configuration.cs +++ b/Sharpmake/Project.Configuration.cs @@ -2698,7 +2698,7 @@ internal void Link(Builder builder) Trace.Assert(_linkState == LinkState.NotLinked); _linkState = LinkState.Linking; - if (builder.DumpDependencyGraph) + if (builder.DumpDependencyGraph && !Project.IsFastBuildAll) { DependencyTracker.Instance.AddDependency(DependencyType.Public, Project, this, UnResolvedPublicDependencies, _dependenciesSetting); DependencyTracker.Instance.AddDependency(DependencyType.Private, Project, this, UnResolvedPrivateDependencies, _dependenciesSetting); diff --git a/Sharpmake/Project.cs b/Sharpmake/Project.cs index 3602214ea..636e49b00 100644 --- a/Sharpmake/Project.cs +++ b/Sharpmake/Project.cs @@ -1719,9 +1719,9 @@ internal void Resolve(Builder builder, bool skipInvalidPath) } PostResolve(); - if (builder.DumpDependencyGraph) + if (builder.DumpDependencyGraph && !IsFastBuildAll) { - foreach (Project.Configuration conf in Configurations) + foreach (Configuration conf in Configurations) DependencyTracker.Instance.UpdateConfiguration(this, conf); } Resolved = true; diff --git a/Sharpmake/TrackedConfiguration.cs b/Sharpmake/TrackedConfiguration.cs index 0d2e15f53..01e5bf880 100644 --- a/Sharpmake/TrackedConfiguration.cs +++ b/Sharpmake/TrackedConfiguration.cs @@ -90,7 +90,7 @@ public string GetDisplayedName(bool verbose) public string GetConfigName() { - return _config?.Target?.ToString() ?? _configOutputType.ToString(); + return _config?.Target?.GetTargetString() ?? _configOutputType.ToString(); } public bool IsNodeVisited() diff --git a/Sharpmake/TrackedProject.cs b/Sharpmake/TrackedProject.cs index 79ef2884f..71c62a0a4 100644 --- a/Sharpmake/TrackedProject.cs +++ b/Sharpmake/TrackedProject.cs @@ -21,7 +21,7 @@ public class TrackedProject : IComparable private string GetKeyFromConfiguration(Project.Configuration config) { if (_project != null) - return config.ToString().Substring(config.ToString().IndexOf(':') + 1); + return config.Target.GetTargetString(); return ProjectString; } @@ -58,9 +58,9 @@ public TrackedConfiguration FindConfiguration(Project.Configuration config) return Configurations[GetKeyFromConfiguration(config)]; } - public TrackedConfiguration FindConfiguration(ITarget config) + public TrackedConfiguration FindConfiguration(ITarget target) { - return Configurations[config.ToString()]; + return Configurations[target.GetTargetString()]; } public bool IsExtern() @@ -73,7 +73,8 @@ public bool IsExtern() public void AddConfig(Project.Configuration config) { - Configurations.Add(config.ToString().Substring(config.ToString().IndexOf(':') + 1), new TrackedConfiguration(this, config)); + string key = GetKeyFromConfiguration(config); + Configurations.Add(key, new TrackedConfiguration(this, config)); } From 49312cb233ce31c897687e6c39f2fc1a3e3579e0 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Sun, 26 Apr 2020 12:43:01 +0200 Subject: [PATCH 05/43] Add macOS to AppVeyor CI, and various improvements - Remove the matrix in favor of a single build_scripts section that use environment variables - Skip the CI for commits where all files are in the docs directory - Ease unit-tests discovery --- .appveyor.yml | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 1076f6862..a4975721f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,6 +1,12 @@ # Sharpmake AppVeyor CI configuration -image: Visual Studio 2017 +image: +- Visual Studio 2017 +- macOS + +skip_commits: + files: + - docs/* platform: - Any CPU @@ -11,22 +17,15 @@ configuration: before_build: - cmd: bootstrap.bat +- sh: ./bootstrap.sh + +build_script: + - cmd: CompileSharpmake.bat Sharpmake.sln "%CONFIGURATION%" "%PLATFORM%" + - sh: msbuild -t:build -restore Sharpmake.sln /p:Configuration=\"$CONFIGURATION\" /p:Platform=\"$PLATFORM\" /nologo /v:m -for: - - - matrix: - only: - - configuration: Debug - build_script: - - CompileSharpmake.bat Sharpmake.sln Debug "Any CPU" - - - - matrix: - only: - - configuration: Release - build_script: - - CompileSharpmake.bat Sharpmake.sln Release "Any CPU" +test: + assemblies: + - 'Sharpmake.UnitTests\bin\*\Sharpmake.UnitTests.dll' after_test: - cmd: python regression_test.py - From bad9d70e5e5eb7158c27494ba84313fe759b05a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Parent?= Date: Sun, 26 Apr 2020 16:20:51 +0200 Subject: [PATCH 06/43] [Vcxproj] Linux support improvements - Fix library prefixing in additional dependencies - Replace hardcoded PlatformRemoteTool by an option to allow choosing g++ - Add CopySources option --- .../Linux/LinuxOptions.cs | 16 ++++++++ .../Linux/LinuxPlatform.Vcxproj.Template.cs | 10 ++--- .../Linux/LinuxPlatform.cs | 37 ++++++++++++++++++- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxOptions.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxOptions.cs index 6d09e5fd7..a72d655eb 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxOptions.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxOptions.cs @@ -20,6 +20,22 @@ public static partial class Linux { public static class Options { + public static class General + { + public enum CopySources + { + Enable, + [Default] + Disable + } + public enum PlatformRemoteTool + { + Gpp, //g++ + [Default] + Clang38 + } + } + public static class Compiler { public enum GenerateDebugInformation diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Vcxproj.Template.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Vcxproj.Template.cs index f267a5086..796599773 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Vcxproj.Template.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Vcxproj.Template.cs @@ -107,10 +107,10 @@ public sealed partial class LinuxPlatform [options.CustomBuildStepBeforeTargets] [options.CustomBuildStepAfterTargets] $(TargetDir) - clang++-3.8 - clang-3.8 - clang-3.8 - false + [options.RemoteCppCompileToolExe] + [options.RemoteCCompileToolExe] + [options.RemoteLdToolExe] + [options.CopySources] false [options.ProjectDirectory] @@ -130,7 +130,7 @@ public sealed partial class LinuxPlatform cd [relativeMasterBffPath] [conf.FastBuildCustomActionsBeforeBuildCommand] [fastBuildMakeCommandRebuild] -false +[options.CopySources] del ""[options.IntermediateDirectory]\*unity*.cpp"" >NUL 2>NUL del ""$(ProjectDir)[options.IntermediateDirectory]\*.obj"" >NUL 2>NUL del ""$(ProjectDir)[options.IntermediateDirectory]\*.a"" >NUL 2>NUL diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs index 96abd0968..671e41c20 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs @@ -14,7 +14,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using Sharpmake.Generators; using Sharpmake.Generators.FastBuild; @@ -112,6 +111,35 @@ public override void SetupPlatformTargetOptions(IGenerationContext context) context.CommandLineOptions["RandomizedBaseAddress"] = "/DYNAMICBASE"; } + public override void SetupSdkOptions(IGenerationContext context) + { + //Copy Sources. + // Enable Copy Sources="Yes" + // Disable Copy Sources="No" default + context.SelectOption + ( + Sharpmake.Options.Option(Options.General.CopySources.Enable, () => { context.Options["CopySources"] = "Yes"; }), + Sharpmake.Options.Option(Options.General.CopySources.Disable, () => { context.Options["CopySources"] = "No"; }) + ); + + //Remote Tool. + context.SelectOption + ( + Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Gpp, () => { context.Options["RemoteCppCompileToolExe"] = "g++"; }), + Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Clang38, () => { context.Options["RemoteCppCompileToolExe"] = "clang++-3.8"; }) + ); + context.SelectOption + ( + Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Gpp, () => { context.Options["RemoteCCompileToolExe"] = "g++"; }), + Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Clang38, () => { context.Options["RemoteCCompileToolExe"] = "clang-3.8"; }) + ); + context.SelectOption + ( + Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Gpp, () => { context.Options["RemoteLdToolExe"] = "g++"; }), + Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Clang38, () => { context.Options["RemoteLdToolExe"] = "clang-3.8"; }) + ); + } + public override void SelectCompilerOptions(IGenerationContext context) { var options = context.Options; @@ -263,6 +291,13 @@ public override void SelectCompilerOptions(IGenerationContext context) ); } + public override void SelectPlatformAdditionalDependenciesOptions(IGenerationContext context) + { + // the libs must be prefixed with -l: in the additional dependencies field in VS + var additionalDependencies = context.Options["AdditionalDependencies"].Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + context.Options["AdditionalDependencies"] = string.Join(";", additionalDependencies.Select(d => "-l:" + d)); + } + public override void GenerateProjectCompileVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) { generator.Write(_projectConfigurationsCompileTemplate); From 482670d4b53e2c5c6dac10d166097485380308b7 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Mon, 27 Apr 2020 11:51:46 +0200 Subject: [PATCH 07/43] Remove redundant attributes on configures in unit-test --- Sharpmake.UnitTests/PackageReferencesTest.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sharpmake.UnitTests/PackageReferencesTest.cs b/Sharpmake.UnitTests/PackageReferencesTest.cs index 788b1b3c3..c9c9a01b1 100644 --- a/Sharpmake.UnitTests/PackageReferencesTest.cs +++ b/Sharpmake.UnitTests/PackageReferencesTest.cs @@ -106,7 +106,6 @@ public class PrivateInheritedPackageReferencesProject : PublicBasePackageReferen { public PrivateInheritedPackageReferencesProject() { } - [Configure()] public override void ConfigureAll(Configuration conf, Target target) { base.ConfigureAll(conf, target); @@ -120,7 +119,6 @@ public class PublicInheritedPackageReferencesProject : PrivateBasePackageReferen { public PublicInheritedPackageReferencesProject() { } - [Configure()] public override void ConfigureAll(Configuration conf, Target target) { base.ConfigureAll(conf, target); From 7be92d210f0b32fa259c96fcc5a7b8423450ff37 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Mon, 27 Apr 2020 11:45:30 +0200 Subject: [PATCH 08/43] [Vcxproj|AndroidProj] Android support improvements - AndroidHome, NdkRoot, JavaHome, AntHome, can now be set as conf options, and/or as global settings. Note that if set in the conf, it will take precedence - AndroidAPILevel now support range [16, 30] - New utility methods in Options were added, to ease retrieving an option value in a range of configurations or dictionaries - API CHANGE: IGenerationContext doesn't allow the Options and CommandLineOptions setters anymore - Common code between Vcxproj and Androidproj generators has been moved to a new VsProjCommon class. Note that it's not an inheritance for now, to keep API breaking changes to a minimum - Androidproj generator now uses a GenerationContext, inheriting from the Vcxproj one until we can rename that... - The IVcxprojGenerationContext now keeps the list of options per configuration, so they can be queried by the platform modules - The list of options per configuration is generated sooner, so the generators can use them when writing global projet properties. This is used for instance to merge configuration options and write them once instead of duplicated. - Remove unused variable in the ProjectOptionsGenerator - IPlatformVcxproj now exposes a new callback that's called after the default project props have been imported - Add an option to control the verbosity of the msbuild logger when compiling android projects, by default set to low --- Sharpmake.Generators/FastBuild/Bff.cs | 12 +- Sharpmake.Generators/IGenerationContext.cs | 5 +- .../Sharpmake.Generators.csproj | 3 + .../VisualStudio/Androidproj.Template.cs | 14 +- .../VisualStudio/Androidproj.cs | 475 +++++++++--------- Sharpmake.Generators/VisualStudio/Csproj.cs | 1 + .../VisualStudio/IPlatformVcxproj.cs | 1 + .../VisualStudio/IVcxprojGenerationContext.cs | 1 + .../VisualStudio/ProjectOptionsGenerator.cs | 2 - Sharpmake.Generators/VisualStudio/Vcxproj.cs | 315 ++++-------- .../VisualStudio/VsProjCommon.Template.cs | 67 +++ .../VisualStudio/VsProjCommon.cs | 117 +++++ Sharpmake.Generators/VisualStudio/VsUtil.cs | 56 +++ .../AndroidPlatform.Vcxproj.Template.cs | 18 + .../Android/AndroidPlatform.cs | 97 +++- .../Android/GlobalSettings.cs | 46 ++ .../Sharpmake.CommonPlatforms/BasePlatform.cs | 4 + .../Sharpmake.CommonPlatforms.csproj | 1 + Sharpmake/Options.Android.cs | 91 +++- Sharpmake/Options.cs | 42 ++ 20 files changed, 873 insertions(+), 495 deletions(-) create mode 100644 Sharpmake.Generators/VisualStudio/VsProjCommon.Template.cs create mode 100644 Sharpmake.Generators/VisualStudio/VsProjCommon.cs create mode 100644 Sharpmake.Generators/VisualStudio/VsUtil.cs create mode 100644 Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/GlobalSettings.cs diff --git a/Sharpmake.Generators/FastBuild/Bff.cs b/Sharpmake.Generators/FastBuild/Bff.cs index 8f491af9d..6f5735ff9 100644 --- a/Sharpmake.Generators/FastBuild/Bff.cs +++ b/Sharpmake.Generators/FastBuild/Bff.cs @@ -836,7 +836,7 @@ List skipFiles List fastbuildEmbeddedResourceFilesList = new List(); var sourceFiles = confSubConfigs[tuple]; - foreach (Vcxproj.ProjectFile sourceFile in sourceFiles) + foreach (var sourceFile in sourceFiles) { string sourceFileName = CurrentBffPathKeyCombine(sourceFile.FileNameProjectRelative); @@ -1850,17 +1850,17 @@ out List filesInNonDefaultSections filesInNonDefaultSections = new List(); // Add source files - List allFiles = new List(); + var allFiles = new List(); Strings projectFiles = context.Project.GetSourceFilesForConfigurations(configurations); foreach (string file in projectFiles) { - Vcxproj.ProjectFile projectFile = new Vcxproj.ProjectFile(context, file); + var projectFile = new Vcxproj.ProjectFile(context, file); allFiles.Add(projectFile); } allFiles.Sort((l, r) => string.Compare(l.FileNameProjectRelative, r.FileNameProjectRelative, StringComparison.InvariantCulture)); - List sourceFiles = new List(); - foreach (Vcxproj.ProjectFile projectFile in allFiles) + var sourceFiles = new List(); + foreach (var projectFile in allFiles) { if (context.Project.SourceFilesCompileExtensions.Contains(projectFile.FileExtension) || (String.Compare(projectFile.FileExtension, ".rc", StringComparison.OrdinalIgnoreCase) == 0) || @@ -1868,7 +1868,7 @@ out List filesInNonDefaultSections sourceFiles.Add(projectFile); } - foreach (Vcxproj.ProjectFile file in sourceFiles) + foreach (var file in sourceFiles) { foreach (Project.Configuration conf in configurations) { diff --git a/Sharpmake.Generators/IGenerationContext.cs b/Sharpmake.Generators/IGenerationContext.cs index 87fdbaabf..74572a476 100644 --- a/Sharpmake.Generators/IGenerationContext.cs +++ b/Sharpmake.Generators/IGenerationContext.cs @@ -24,9 +24,8 @@ public interface IGenerationContext string ProjectDirectory { get; } DevEnv DevelopmentEnvironment { get; } - // The setter on those two should not be there. - Options.ExplicitOptions Options { get; set; } - IDictionary CommandLineOptions { get; set; } + Options.ExplicitOptions Options { get; } + IDictionary CommandLineOptions { get; } string ProjectDirectoryCapitalized { get; } string ProjectSourceCapitalized { get; } diff --git a/Sharpmake.Generators/Sharpmake.Generators.csproj b/Sharpmake.Generators/Sharpmake.Generators.csproj index e3993bd48..7a486e6a9 100644 --- a/Sharpmake.Generators/Sharpmake.Generators.csproj +++ b/Sharpmake.Generators/Sharpmake.Generators.csproj @@ -102,6 +102,9 @@ + + + diff --git a/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs b/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs index 7cd8eb93c..ab5a5238d 100644 --- a/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs +++ b/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs @@ -48,8 +48,11 @@ public static class Project [toolsVersion] 1.0 [projectName] - - + [androidTargetsPath] +"; + + public const string ImportAndroidDefaultProps = +@" "; // The output directory is converted to a rooted path by prefixing it with $(ProjectDir) to work around @@ -67,12 +70,13 @@ public static class Project public const string ProjectAfterConfigurationsGeneral = @" - - + "; public const string ProjectAfterImportedProps = -@" +@" + + "; public const string ProjectConfigurationBeginItemDefinition = diff --git a/Sharpmake.Generators/VisualStudio/Androidproj.cs b/Sharpmake.Generators/VisualStudio/Androidproj.cs index 3bb63a6e0..a567c940f 100644 --- a/Sharpmake.Generators/VisualStudio/Androidproj.cs +++ b/Sharpmake.Generators/VisualStudio/Androidproj.cs @@ -13,6 +13,7 @@ // limitations under the License. using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; @@ -20,14 +21,84 @@ namespace Sharpmake.Generators.VisualStudio { public partial class Androidproj : IProjectGenerator { - private AndroidPackageProject _Project; - private List _ProjectConfigurationList; - private string _ProjectDirectoryCapitalized; - //private string _ProjectSourceCapitalized; - private Project.Configuration _ProjectConfiguration; - private Builder _Builder; public const string ProjectExtension = ".androidproj"; + private class GenerationContext : IVcxprojGenerationContext + { + #region IVcxprojGenerationContext implementation + public Builder Builder { get; } + public Project Project { get; } + public Project.Configuration Configuration { get; internal set; } + public string ProjectDirectory { get; } + public DevEnv DevelopmentEnvironment => Configuration.Target.GetFragment(); + public Options.ExplicitOptions Options + { + get + { + Debug.Assert(_projectConfigurationOptions.ContainsKey(Configuration)); + return _projectConfigurationOptions[Configuration]; + } + } + public IDictionary CommandLineOptions { get; set; } + public string ProjectDirectoryCapitalized { get; } + public string ProjectSourceCapitalized { get; } + public bool PlainOutput { get; } + public void SelectOption(params Options.OptionAction[] options) + { + Sharpmake.Options.SelectOption(Configuration, options); + } + + public void SelectOptionWithFallback(Action fallbackAction, params Options.OptionAction[] options) + { + Sharpmake.Options.SelectOptionWithFallback(Configuration, fallbackAction, options); + } + + public string ProjectPath { get; } + public string ProjectFileName { get; } + public IReadOnlyList ProjectConfigurations { get; } + public IReadOnlyDictionary ProjectConfigurationOptions => _projectConfigurationOptions; + public DevEnvRange DevelopmentEnvironmentsRange { get; } + public IReadOnlyDictionary PresentPlatforms { get; } + public Resolver EnvironmentVariableResolver { get; internal set; } + #endregion + + private Dictionary _projectConfigurationOptions; + + public void SetProjectConfigurationOptions(Dictionary projectConfigurationOptions) + { + _projectConfigurationOptions = projectConfigurationOptions; + } + + internal AndroidPackageProject AndroidPackageProject { get; } + + public GenerationContext(Builder builder, string projectPath, Project project, IEnumerable projectConfigurations) + { + Builder = builder; + + FileInfo fileInfo = new FileInfo(projectPath); + ProjectPath = fileInfo.FullName; + ProjectDirectory = Path.GetDirectoryName(ProjectPath); + ProjectFileName = Path.GetFileName(ProjectPath); + Project = project; + AndroidPackageProject = (AndroidPackageProject)Project; + + ProjectDirectoryCapitalized = Util.GetCapitalizedPath(ProjectDirectory); + ProjectSourceCapitalized = Util.GetCapitalizedPath(Project.SourceRootPath); + + ProjectConfigurations = VsUtil.SortConfigurations(projectConfigurations, Path.Combine(ProjectDirectoryCapitalized, ProjectFileName + ProjectExtension)).ToArray(); + DevelopmentEnvironmentsRange = new DevEnvRange(ProjectConfigurations); + + PresentPlatforms = ProjectConfigurations.Select(conf => conf.Platform).Distinct().ToDictionary(p => p, p => PlatformRegistry.Get(p)); + } + + public void Reset() + { + CommandLineOptions = null; + Configuration = null; + EnvironmentVariableResolver = null; + } + } + public void Generate( Builder builder, Project project, @@ -36,225 +107,184 @@ public void Generate( List generatedFiles, List skipFiles) { - _Builder = builder; - - FileInfo fileInfo = new FileInfo(projectFile); - string projectPath = fileInfo.Directory.FullName; - string projectFileName = fileInfo.Name; - if (!(project is AndroidPackageProject)) throw new ArgumentException("Project is not a AndroidPackageProject"); - Generate((AndroidPackageProject)project, configurations, projectPath, projectFileName, generatedFiles, skipFiles); - - _Builder = null; + var context = new GenerationContext(builder, projectFile, project, configurations); + GenerateImpl(context, generatedFiles, skipFiles); } - private void Write(string value, TextWriter writer, Resolver resolver) + private void GenerateConfOptions(GenerationContext context) { - string resolvedValue = resolver.Resolve(value); - StringReader reader = new StringReader(resolvedValue); - string str = reader.ReadToEnd(); - writer.Write(str); - writer.Flush(); + // generate all configuration options once... + var projectOptionsGen = new ProjectOptionsGenerator(); + var projectConfigurationOptions = new Dictionary(); + context.SetProjectConfigurationOptions(projectConfigurationOptions); + foreach (Project.Configuration conf in context.ProjectConfigurations) + { + context.Configuration = conf; + + // set generator information + var platformVcxproj = context.PresentPlatforms[conf.Platform]; + var configurationTasks = PlatformRegistry.Get(conf.Platform); + conf.GeneratorSetGeneratedInformation( + platformVcxproj.ExecutableFileExtension, + platformVcxproj.PackageFileExtension, + configurationTasks.GetDefaultOutputExtension(Project.Configuration.OutputType.Dll), + platformVcxproj.ProgramDatabaseFileExtension); + + projectConfigurationOptions.Add(conf, new Options.ExplicitOptions()); + context.CommandLineOptions = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); + + projectOptionsGen.GenerateOptions(context); + GenerateOptions(context); + + context.Reset(); // just a safety, not necessary to clean up + } } - private void Generate( - AndroidPackageProject project, - List unsortedConfigurations, - string projectPath, - string projectFile, + private void GenerateImpl( + GenerationContext context, List generatedFiles, List skipFiles) { - // Need to sort by name and platform - List configurations = new List(); - configurations.AddRange(unsortedConfigurations.OrderBy(conf => conf.Name + conf.Platform)); - - // validate that 2 conf name in the same project don't have the same name - Dictionary configurationNameMapping = new Dictionary(); - string projectName = null; + GenerateConfOptions(context); - foreach (Project.Configuration conf in configurations) - { - if (projectName == null) - projectName = conf.ProjectName; - else if (projectName != conf.ProjectName) - throw new Error("Project configurations in the same project files must be the same: {0} != {1} in {2}", projectName, conf.ProjectName, projectFile); + var fileGenerator = new XmlFileGenerator(); - Project.Configuration otherConf; - - string projectUniqueName = conf.Name + Util.GetPlatformString(conf.Platform, conf.Project, conf.Target); - if (configurationNameMapping.TryGetValue(projectUniqueName, out otherConf)) - { - var differBy = Util.MakeDifferenceString(conf, otherConf); - throw new Error( - "Project {0} ({5} in {6}) has 2 configurations with the same name: \"{1}\" for {2} and {3}" - + Environment.NewLine + "Nb: ps3 and win32 cannot have same conf name: {4}", - project.Name, conf.Name, otherConf.Target, conf.Target, differBy, projectFile, projectPath); - } - - configurationNameMapping[projectUniqueName] = conf; + // xml begin header + string toolsVersion = context.DevelopmentEnvironmentsRange.MinDevEnv.GetVisualProjectToolsVersionString(); + using (fileGenerator.Declare("toolsVersion", toolsVersion)) + fileGenerator.Write(Template.Project.ProjectBegin); - // set generator information - switch (conf.Platform) - { - case Platform.android: - conf.GeneratorSetGeneratedInformation("elf", "elf", "so", "pdb"); - break; - default: - break; - } - } + VsProjCommon.WriteCustomProperties(context.Project.CustomProperties, fileGenerator); - Resolver resolver = new Resolver(); + VsProjCommon.WriteProjectConfigurationsDescription(context.ProjectConfigurations, fileGenerator); - _ProjectDirectoryCapitalized = Util.GetCapitalizedPath(projectPath); - //_ProjectSourceCapitalized = Util.GetCapitalizedPath(project.SourceRootPath); - _Project = project; - _ProjectConfigurationList = configurations; + // xml end header - MemoryStream memoryStream = new MemoryStream(); - StreamWriter writer = new StreamWriter(memoryStream); + string androidTargetsPath = Options.GetConfOption(context.ProjectConfigurations, rootpath: context.ProjectDirectoryCapitalized); - // xml begin header - DevEnvRange devEnvRange = new DevEnvRange(unsortedConfigurations); - using (resolver.NewScopedParameter("toolsVersion", devEnvRange.MinDevEnv.GetVisualProjectToolsVersionString())) + var firstConf = context.ProjectConfigurations.First(); + using (fileGenerator.Declare("projectName", firstConf.ProjectName)) + using (fileGenerator.Declare("guid", firstConf.ProjectGuid)) + using (fileGenerator.Declare("toolsVersion", toolsVersion)) + using (fileGenerator.Declare("androidTargetsPath", Util.EnsureTrailingSeparator(androidTargetsPath))) { - Write(Template.Project.ProjectBegin, writer, resolver); + fileGenerator.Write(Template.Project.ProjectDescription); } - Write(Template.Project.ProjectBeginConfigurationDescription, writer, resolver); - // xml header contain description of each target - foreach (Project.Configuration conf in _ProjectConfigurationList) - { - using (resolver.NewScopedParameter("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) - using (resolver.NewScopedParameter("conf", conf)) - { - Write(Template.Project.ProjectConfigurationDescription, writer, resolver); - } - } - Write(Template.Project.ProjectEndConfigurationDescription, writer, resolver); + fileGenerator.Write(VsProjCommon.Template.PropertyGroupEnd); - // xml end header - var firstConf = _ProjectConfigurationList.First(); - using (resolver.NewScopedParameter("projectName", projectName)) - using (resolver.NewScopedParameter("guid", firstConf.ProjectGuid)) - using (resolver.NewScopedParameter("toolsVersion", devEnvRange.MinDevEnv.GetVisualProjectToolsVersionString())) - { - Write(Template.Project.ProjectDescription, writer, resolver); - } + foreach (var platform in context.PresentPlatforms.Values) + platform.GeneratePlatformSpecificProjectDescription(context, fileGenerator); - // generate all configuration options once... - Dictionary options = new Dictionary(); - foreach (Project.Configuration conf in _ProjectConfigurationList) - { - _ProjectConfiguration = conf; - Options.ExplicitOptions option = GenerateOptions(project, projectPath, conf); - _ProjectConfiguration = null; - options.Add(conf, option); - } + fileGenerator.Write(Template.Project.ImportAndroidDefaultProps); + + foreach (var platform in context.PresentPlatforms.Values) + platform.GeneratePostDefaultPropsImport(context, fileGenerator); // configuration general - foreach (Project.Configuration conf in _ProjectConfigurationList) + foreach (Project.Configuration conf in context.ProjectConfigurations) { - using (resolver.NewScopedParameter("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) - using (resolver.NewScopedParameter("conf", conf)) - using (resolver.NewScopedParameter("options", options[conf])) + context.Configuration = conf; + + using (fileGenerator.Declare("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) + using (fileGenerator.Declare("conf", conf)) + using (fileGenerator.Declare("options", context.ProjectConfigurationOptions[conf])) { - Write(Template.Project.ProjectConfigurationsGeneral, writer, resolver); + fileGenerator.Write(Template.Project.ProjectConfigurationsGeneral); } } // .props files - Write(Template.Project.ProjectAfterConfigurationsGeneral, writer, resolver); - Write(Template.Project.ProjectAfterImportedProps, writer, resolver); + fileGenerator.Write(Template.Project.ProjectAfterConfigurationsGeneral); - string androidPackageDirectory = project.AntBuildRootDirectory; + VsProjCommon.WriteProjectCustomPropsFiles(context.Project.CustomPropsFiles, context.ProjectDirectoryCapitalized, fileGenerator); + VsProjCommon.WriteConfigurationsCustomPropsFiles(context.ProjectConfigurations, context.ProjectDirectoryCapitalized, fileGenerator); + + fileGenerator.Write(Template.Project.ProjectAfterImportedProps); + + string androidPackageDirectory = context.AndroidPackageProject.AntBuildRootDirectory; // configuration ItemDefinitionGroup - foreach (Project.Configuration conf in _ProjectConfigurationList) + foreach (Project.Configuration conf in context.ProjectConfigurations) { - using (resolver.NewScopedParameter("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) - using (resolver.NewScopedParameter("conf", conf)) - using (resolver.NewScopedParameter("options", options[conf])) - using (resolver.NewScopedParameter("androidPackageDirectory", androidPackageDirectory)) + context.Configuration = conf; + + using (fileGenerator.Declare("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) + using (fileGenerator.Declare("conf", conf)) + using (fileGenerator.Declare("options", context.ProjectConfigurationOptions[conf])) + using (fileGenerator.Declare("androidPackageDirectory", androidPackageDirectory)) { - Write(Template.Project.ProjectConfigurationBeginItemDefinition, writer, resolver); + fileGenerator.Write(Template.Project.ProjectConfigurationBeginItemDefinition); { - Write(Template.Project.AntPackage, writer, resolver); + fileGenerator.Write(Template.Project.AntPackage); } - Write(Template.Project.ProjectConfigurationEndItemDefinition, writer, resolver); + fileGenerator.Write(Template.Project.ProjectConfigurationEndItemDefinition); } } - GenerateFilesSection(project, writer, resolver, projectPath, projectFile, generatedFiles, skipFiles); - - GenerateProjectReferences(configurations, resolver, writer, options); + GenerateFilesSection(context, fileGenerator); // .targets - Write(Template.Project.ProjectTargets, writer, resolver); + fileGenerator.Write(Template.Project.ProjectTargets); + + GenerateProjectReferences(context, fileGenerator); - Write(Template.Project.ProjectEnd, writer, resolver); + // Environment variables + var environmentVariables = context.ProjectConfigurations.Select(conf => conf.Platform).Distinct().SelectMany(platform => context.PresentPlatforms[platform].GetEnvironmentVariables(context)); + VsProjCommon.WriteEnvironmentVariables(environmentVariables, fileGenerator); - // Write the project file - writer.Flush(); + fileGenerator.Write(Template.Project.ProjectEnd); // remove all line that contain RemoveLineTag - MemoryStream cleanMemoryStream = Util.RemoveLineTags(memoryStream, FileGeneratorUtilities.RemoveLineTag); + fileGenerator.RemoveTaggedLines(); + MemoryStream cleanMemoryStream = fileGenerator.ToMemoryStream(); - FileInfo projectFileInfo = new FileInfo(Path.Combine(projectPath, projectFile + ProjectExtension)); - if (_Builder.Context.WriteGeneratedFile(project.GetType(), projectFileInfo, cleanMemoryStream)) + FileInfo projectFileInfo = new FileInfo(context.ProjectPath + ProjectExtension); + if (context.Builder.Context.WriteGeneratedFile(context.Project.GetType(), projectFileInfo, cleanMemoryStream)) generatedFiles.Add(projectFileInfo.FullName); else skipFiles.Add(projectFileInfo.FullName); - - writer.Close(); - - _Project = null; } private void GenerateFilesSection( - AndroidPackageProject project, - StreamWriter writer, - Resolver resolver, - string projectPath, - string projectFileName, - List generatedFiles, - List skipFiles) + GenerationContext context, + IFileGenerator fileGenerator) { - Strings projectFiles = _Project.GetSourceFilesForConfigurations(_ProjectConfigurationList); + Strings projectFiles = context.Project.GetSourceFilesForConfigurations(context.ProjectConfigurations); // Add source files - List allFiles = new List(); - List includeFiles = new List(); - List sourceFiles = new List(); - List contentFiles = new List(); + var allFiles = new List(); + var includeFiles = new List(); + var sourceFiles = new List(); + var contentFiles = new List(); foreach (string file in projectFiles) { - ProjectFile projectFile = new ProjectFile(file, _ProjectDirectoryCapitalized, _Project.SourceRootPath); + var projectFile = new Vcxproj.ProjectFile(context, file); allFiles.Add(projectFile); } - allFiles.Sort((ProjectFile l, ProjectFile r) => { return string.Compare(l.FileNameProjectRelative, r.FileNameProjectRelative, StringComparison.OrdinalIgnoreCase); }); + allFiles.Sort((l, r) => { return string.Compare(l.FileNameProjectRelative, r.FileNameProjectRelative, StringComparison.InvariantCultureIgnoreCase); }); // type -> files - var customSourceFiles = new Dictionary>(); - foreach (ProjectFile projectFile in allFiles) + var customSourceFiles = new Dictionary>(); + foreach (var projectFile in allFiles) { string type = null; - if (_Project.ExtensionBuildTools.TryGetValue(projectFile.FileExtension, out type)) + if (context.Project.ExtensionBuildTools.TryGetValue(projectFile.FileExtension, out type)) { - List files = null; + List files = null; if (!customSourceFiles.TryGetValue(type, out files)) { - files = new List(); + files = new List(); customSourceFiles[type] = files; } files.Add(projectFile); } - else if (_Project.SourceFilesCompileExtensions.Contains(projectFile.FileExtension) || + else if (context.Project.SourceFilesCompileExtensions.Contains(projectFile.FileExtension) || (String.Compare(projectFile.FileExtension, ".rc", StringComparison.OrdinalIgnoreCase) == 0)) { sourceFiles.Add(projectFile); @@ -270,36 +300,36 @@ private void GenerateFilesSection( } // Write header files - Write(Template.Project.ProjectFilesBegin, writer, resolver); - foreach (ProjectFile file in includeFiles) + fileGenerator.Write(Template.Project.ProjectFilesBegin); + foreach (var file in includeFiles) { - using (resolver.NewScopedParameter("file", file)) - Write(Template.Project.ProjectFilesHeader, writer, resolver); + using (fileGenerator.Declare("file", file)) + fileGenerator.Write(Template.Project.ProjectFilesHeader); } - Write(Template.Project.ProjectFilesEnd, writer, resolver); + fileGenerator.Write(Template.Project.ProjectFilesEnd); // Write content files - Write(Template.Project.ProjectFilesBegin, writer, resolver); - foreach (ProjectFile file in contentFiles) + fileGenerator.Write(Template.Project.ProjectFilesBegin); + foreach (var file in contentFiles) { - using (resolver.NewScopedParameter("file", file)) - Write(Template.Project.ContentSimple, writer, resolver); + using (fileGenerator.Declare("file", file)) + fileGenerator.Write(Template.Project.ContentSimple); } - Write(Template.Project.ProjectFilesEnd, writer, resolver); + fileGenerator.Write(Template.Project.ProjectFilesEnd); // Write Android project files - Write(Template.Project.ItemGroupBegin, writer, resolver); + fileGenerator.Write(Template.Project.ItemGroupBegin); - using (resolver.NewScopedParameter("antBuildXml", project.AntBuildXml)) - using (resolver.NewScopedParameter("antProjectPropertiesFile", project.AntProjectPropertiesFile)) - using (resolver.NewScopedParameter("androidManifest", project.AndroidManifest)) + using (fileGenerator.Declare("antBuildXml", context.AndroidPackageProject.AntBuildXml)) + using (fileGenerator.Declare("antProjectPropertiesFile", context.AndroidPackageProject.AntProjectPropertiesFile)) + using (fileGenerator.Declare("androidManifest", context.AndroidPackageProject.AndroidManifest)) { - Write(Template.Project.AntBuildXml, writer, resolver); - Write(Template.Project.AndroidManifest, writer, resolver); - Write(Template.Project.AntProjectPropertiesFile, writer, resolver); + fileGenerator.Write(Template.Project.AntBuildXml); + fileGenerator.Write(Template.Project.AndroidManifest); + fileGenerator.Write(Template.Project.AntProjectPropertiesFile); } - Write(Template.Project.ItemGroupEnd, writer, resolver); + fileGenerator.Write(Template.Project.ItemGroupEnd); } private struct ProjectDependencyInfo @@ -309,53 +339,54 @@ private struct ProjectDependencyInfo } private void GenerateProjectReferences( - IEnumerable configurations, - Resolver resolver, - StreamWriter writer, - Dictionary optionsDictionary) + GenerationContext context, + IFileGenerator fileGenerator) { - UniqueList dependencies = new UniqueList(); - foreach (var c in configurations) + var dependencies = new UniqueList(); + foreach (var c in context.ProjectConfigurations) { foreach (var d in c.ConfigurationDependencies) { + // Ignore projects marked as Export + if (d.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Export) + continue; + ProjectDependencyInfo depInfo; depInfo.ProjectFullFileNameWithExtension = d.ProjectFullFileNameWithExtension; - depInfo.ProjectGuid = d.ProjectGuid; + + if (d.Project.SharpmakeProjectType != Project.ProjectTypeAttribute.Compile) + depInfo.ProjectGuid = d.ProjectGuid; + else + throw new NotImplementedException("Sharpmake.Compile not supported as a dependency by this generator."); dependencies.Add(depInfo); } } if (dependencies.Count > 0) { - Write(Template.Project.ItemGroupBegin, writer, resolver); - var conf = configurations.ToList().First(); + fileGenerator.Write(Template.Project.ItemGroupBegin); foreach (var d in dependencies) { - string include = Util.PathGetRelative(conf.ProjectPath, d.ProjectFullFileNameWithExtension); - using (resolver.NewScopedParameter("include", include)) - using (resolver.NewScopedParameter("projectGUID", d.ProjectGuid)) + string include = Util.PathGetRelative(context.ProjectDirectory, d.ProjectFullFileNameWithExtension); + using (fileGenerator.Declare("include", include)) + using (fileGenerator.Declare("projectGUID", d.ProjectGuid)) { - Write(Template.Project.ProjectReference, writer, resolver); + fileGenerator.Write(Template.Project.ProjectReference); } } - Write(Template.Project.ItemGroupEnd, writer, resolver); + fileGenerator.Write(Template.Project.ItemGroupEnd); } } - private void SelectOption(params Options.OptionAction[] options) - { - Options.SelectOption(_ProjectConfiguration, options); - } - - private Options.ExplicitOptions GenerateOptions(AndroidPackageProject project, string projectPath, Project.Configuration conf) + private void GenerateOptions(GenerationContext context) { - Options.ExplicitOptions options = new Options.ExplicitOptions(); + var options = context.Options; + var conf = context.Configuration; options["OutputFile"] = FileGeneratorUtilities.RemoveLineTag; - if (_Project.AppLibType != null) + if (context.AndroidPackageProject.AppLibType != null) { - Project.Configuration appLibConf = conf.ConfigurationDependencies.FirstOrDefault(confDep => (confDep.Project.GetType() == _Project.AppLibType)); + Project.Configuration appLibConf = conf.ConfigurationDependencies.FirstOrDefault(confDep => (confDep.Project.GetType() == context.AndroidPackageProject.AppLibType)); if (appLibConf != null) { // The lib name to first load from an AndroidActivity must be a dynamic library. @@ -366,71 +397,19 @@ private Options.ExplicitOptions GenerateOptions(AndroidPackageProject project, s } else { - throw new Error("Missing dependency of type \"{0}\" in configuration \"{1}\" dependencies.", _Project.AppLibType.ToNiceTypeName(), conf); + throw new Error("Missing dependency of type \"{0}\" in configuration \"{1}\" dependencies.", context.AndroidPackageProject.AppLibType.ToNiceTypeName(), conf); } } - - //Options.Vc.General.UseDebugLibraries. - // Disable WarnAsError="false" - // Enable WarnAsError="true" /WX - SelectOption - ( - Options.Option(Options.Vc.General.UseDebugLibraries.Disabled, () => { options["UseDebugLibraries"] = "false"; }), - Options.Option(Options.Vc.General.UseDebugLibraries.Enabled, () => { options["UseDebugLibraries"] = "true"; }) - ); - - SelectOption - ( - Options.Option(Options.Android.General.AndroidAPILevel.Default, () => { options["AndroidAPILevel"] = FileGeneratorUtilities.RemoveLineTag; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android19, () => { options["AndroidAPILevel"] = "android-19"; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android21, () => { options["AndroidAPILevel"] = "android-21"; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android22, () => { options["AndroidAPILevel"] = "android-22"; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android23, () => { options["AndroidAPILevel"] = "android-23"; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android24, () => { options["AndroidAPILevel"] = "android-24"; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android25, () => { options["AndroidAPILevel"] = "android-25"; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android26, () => { options["AndroidAPILevel"] = "android-26"; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android27, () => { options["AndroidAPILevel"] = "android-27"; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android28, () => { options["AndroidAPILevel"] = "android-28"; }) - ); - //OutputDirectory // The debugger need a rooted path to work properly. // So we root the relative output directory to $(ProjectDir) to work around this limitation. - // Hopefully in a futur version of the cross platform tools will be able to remove this hack. - string outputDirectoryRelative = Util.PathGetRelative(projectPath, conf.TargetPath); + // Hopefully in a future version of the cross platform tools will be able to remove this hack. + string outputDirectoryRelative = Util.PathGetRelative(context.ProjectDirectoryCapitalized, conf.TargetPath); options["OutputDirectory"] = outputDirectoryRelative; //IntermediateDirectory - string intermediateDirectoryRelative = Util.PathGetRelative(projectPath, conf.IntermediatePath); + string intermediateDirectoryRelative = Util.PathGetRelative(context.ProjectDirectoryCapitalized, conf.IntermediatePath); options["IntermediateDirectory"] = intermediateDirectoryRelative; - - return options; - } - - public class ProjectFile - { - public string FileName; - public string FileNameProjectRelative; - public string FileNameSourceRelative; - public string FileExtension; - - public ProjectFile(string fileName, string projectDirectoryCapitalized, string sourceRootPath) - { - FileName = Project.GetCapitalizedFile(fileName); - if (FileName == null) - FileName = fileName; - - FileNameProjectRelative = Util.PathGetRelative(projectDirectoryCapitalized, FileName, true); - - FileNameSourceRelative = Util.PathGetRelative(sourceRootPath, FileName, true); - - FileExtension = Path.GetExtension(FileName); - } - - public override string ToString() - { - return FileName; - } } } } diff --git a/Sharpmake.Generators/VisualStudio/Csproj.cs b/Sharpmake.Generators/VisualStudio/Csproj.cs index 555d8e01b..737d76332 100644 --- a/Sharpmake.Generators/VisualStudio/Csproj.cs +++ b/Sharpmake.Generators/VisualStudio/Csproj.cs @@ -1399,6 +1399,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) { if (customProperties.Any()) diff --git a/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs b/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs index cdfba9d2e..0a000012b 100644 --- a/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs @@ -81,6 +81,7 @@ public interface IPlatformVcxproj void GeneratePlatformSpecificProjectDescription(IVcxprojGenerationContext context, IFileGenerator generator); void GenerateProjectPlatformSdkDirectoryDescription(IVcxprojGenerationContext context, IFileGenerator generator); + void GeneratePostDefaultPropsImport(IVcxprojGenerationContext context, IFileGenerator generator); void GenerateProjectConfigurationGeneral(IVcxprojGenerationContext context, IFileGenerator generator); void GenerateProjectConfigurationGeneral2(IVcxprojGenerationContext context, IFileGenerator generator); // TODO: Merge with the above function and edit the reference projects. void GenerateProjectConfigurationFastBuildMakeFile(IVcxprojGenerationContext context, IFileGenerator generator); diff --git a/Sharpmake.Generators/VisualStudio/IVcxprojGenerationContext.cs b/Sharpmake.Generators/VisualStudio/IVcxprojGenerationContext.cs index 322302a53..883853d60 100644 --- a/Sharpmake.Generators/VisualStudio/IVcxprojGenerationContext.cs +++ b/Sharpmake.Generators/VisualStudio/IVcxprojGenerationContext.cs @@ -20,6 +20,7 @@ public interface IVcxprojGenerationContext : IGenerationContext string ProjectPath { get; } string ProjectFileName { get; } IReadOnlyList ProjectConfigurations { get; } + IReadOnlyDictionary ProjectConfigurationOptions { get; } DevEnvRange DevelopmentEnvironmentsRange { get; } IReadOnlyDictionary PresentPlatforms { get; } diff --git a/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs b/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs index 128ae80ea..699cc1b0b 100644 --- a/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs +++ b/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs @@ -112,8 +112,6 @@ internal void GenerateOptions(IGenerationContext context, ProjectOptionGeneratio private void GenerateGeneralOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) { - DevEnv visualVersion = context.Configuration.Target.GetFragment(); - // Default defines, includes, libraries... context.Options.ExplicitDefines.AddRange(optionsContext.PlatformVcxproj.GetImplicitlyDefinedSymbols(context)); diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.cs index 817678cf4..4494c90e3 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.cs @@ -36,7 +36,7 @@ public enum BuildStep private class GenerationContext : IVcxprojGenerationContext { - private Options.ExplicitOptions _options; + private Dictionary _projectConfigurationOptions; private IDictionary _cmdLineOptions; private Project.Configuration _configuration; private Resolver _envVarResolver; @@ -62,18 +62,22 @@ public Project.Configuration Configuration } } public IReadOnlyList ProjectConfigurations { get; } + + public IReadOnlyDictionary ProjectConfigurationOptions => _projectConfigurationOptions; + + public void SetProjectConfigurationOptions(Dictionary projectConfigurationOptions) + { + _projectConfigurationOptions = projectConfigurationOptions; + } + public DevEnv DevelopmentEnvironment => Configuration.Target.GetFragment(); public DevEnvRange DevelopmentEnvironmentsRange { get; } public Options.ExplicitOptions Options { get { - Debug.Assert(_options != null); - return _options; - } - set - { - _options = value; + Debug.Assert(_projectConfigurationOptions.ContainsKey(Configuration)); + return _projectConfigurationOptions[Configuration]; } } public IDictionary CommandLineOptions @@ -115,15 +119,14 @@ public GenerationContext(Builder builder, string projectPath, Project project, I ProjectDirectoryCapitalized = Util.GetCapitalizedPath(ProjectDirectory); ProjectSourceCapitalized = Util.GetCapitalizedPath(Project.SourceRootPath); - ProjectConfigurations = SortConfigurations(projectConfigurations).ToArray(); - DevelopmentEnvironmentsRange = new DevEnvRange(projectConfigurations); + ProjectConfigurations = VsUtil.SortConfigurations(projectConfigurations, Path.Combine(ProjectDirectoryCapitalized, ProjectFileName + ProjectExtension)).ToArray(); + DevelopmentEnvironmentsRange = new DevEnvRange(ProjectConfigurations); - PresentPlatforms = projectConfigurations.Select(conf => conf.Platform).Distinct().ToDictionary(p => p, p => PlatformRegistry.Get(p)); + PresentPlatforms = ProjectConfigurations.Select(conf => conf.Platform).Distinct().ToDictionary(p => p, p => PlatformRegistry.Get(p)); } public void Reset() { - Options = null; CommandLineOptions = null; Configuration = null; EnvironmentVariableResolver = null; @@ -138,39 +141,6 @@ public void SelectOptionWithFallback(Action fallbackAction, params Options.Optio { Sharpmake.Options.SelectOptionWithFallback(Configuration, fallbackAction, options); } - - private IEnumerable SortConfigurations(IEnumerable unsortedConfigurations) - { - // Need to sort by name and platform - var configurations = new List(); - configurations.AddRange(unsortedConfigurations.OrderBy(conf => conf.Name + Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))); - - // validate that 2 conf name in the same project don't have the same name - var configurationNameMapping = new Dictionary(); - - foreach (Project.Configuration conf in configurations) - { - var projectUniqueName = conf.Name + Util.GetPlatformString(conf.Platform, conf.Project, conf.Target); - - Project.Configuration previousConf; - if (configurationNameMapping.TryGetValue(projectUniqueName, out previousConf)) - { - throw new Error( - "Project '{0}' contains distinct configurations with the same name, please add something to distinguish them:\n- {1}", - Path.Combine(ProjectDirectoryCapitalized, ProjectFileName + ProjectExtension), - string.Join( - Environment.NewLine + "- ", - configurations.Select( - pc => pc.Name + '|' + Util.GetPlatformString(pc.Platform, pc.Project, pc.Target) + $" => '{pc.Target.GetTargetString()}'" - ).OrderBy(name => name) - ) - ); - } - configurationNameMapping[projectUniqueName] = conf; - } - - return configurations; - } } public void Generate(Builder builder, Project project, List configurations, string projectFile, List generatedFiles, List skipFiles) @@ -236,16 +206,6 @@ public static Dictionary CombineCustomFileB return steps; } - /// - /// Generate a pseudo Guid base on relative path from the Project CsPath to the generated files - /// Need to do it that way because many vcproj may be generated from the same Project. - /// - private string GetProjectFileGuid(string outputProjectFile, Project project) - { - string reletiveToCsProjectFile = Util.PathGetRelative(project.SharpmakeCsPath, outputProjectFile); - return Util.BuildGuid(reletiveToCsProjectFile).ToString().ToUpper(); - } - private static string GetVCTargetsPathOverride(DevEnv devEnv) { switch (devEnv) @@ -340,21 +300,17 @@ private void WriteVcOverrides(GenerationContext context, FileGenerator fileGener } } - private void GenerateImpl(GenerationContext context, IList generatedFiles, IList skipFiles) + private void GenerateConfOptions(GenerationContext context) { - FileName = context.ProjectPath; - - // set generator information - string projectName = null; - foreach (var conf in context.ProjectConfigurations) + // generate all configuration options once... + var projectOptionsGen = new ProjectOptionsGenerator(); + var projectConfigurationOptions = new Dictionary(); + context.SetProjectConfigurationOptions(projectConfigurationOptions); + foreach (Project.Configuration conf in context.ProjectConfigurations) { - // Get the name of the project by reading configurations. Make sure that all - // configurations use the same name! - if (projectName == null) - projectName = conf.ProjectName; - else if (projectName != conf.ProjectName) - throw new Error("Project configurations in the same project files must be the same: {0} != {1} in {2}", projectName, conf.ProjectName, context.ProjectFileName); + context.Configuration = conf; + // set generator information var platformVcxproj = context.PresentPlatforms[conf.Platform]; var configurationTasks = PlatformRegistry.Get(conf.Platform); conf.GeneratorSetGeneratedInformation( @@ -362,7 +318,23 @@ private void GenerateImpl(GenerationContext context, IList generatedFile platformVcxproj.PackageFileExtension, configurationTasks.GetDefaultOutputExtension(Project.Configuration.OutputType.Dll), platformVcxproj.ProgramDatabaseFileExtension); + + projectConfigurationOptions.Add(conf, new Options.ExplicitOptions()); + context.CommandLineOptions = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); + + projectOptionsGen.GenerateOptions(context); + FillIncludeDirectoriesOptions(context); + FillLibrariesOptions(context); + + context.Reset(); // just a safety, not necessary to clean up } + } + + private void GenerateImpl(GenerationContext context, IList generatedFiles, IList skipFiles) + { + FileName = context.ProjectPath; + + GenerateConfOptions(context); // source control string sccProjectName = FileGeneratorUtilities.RemoveLineTag; @@ -377,52 +349,30 @@ private void GenerateImpl(GenerationContext context, IList generatedFile var fileGenerator = new XmlFileGenerator(); - var firstConf = context.ProjectConfigurations.First(); - // xml begin header using (fileGenerator.Declare("toolsVersion", context.DevelopmentEnvironmentsRange.MinDevEnv.GetVisualProjectToolsVersionString())) { fileGenerator.Write(Template.Project.ProjectBegin); } - WriteCustomProperties(context, fileGenerator); + VsProjCommon.WriteCustomProperties(context.Project.CustomProperties, fileGenerator); foreach (var platformVcxproj in context.PresentPlatforms.Values) platformVcxproj.GenerateSdkVcxproj(context, fileGenerator); + VsProjCommon.WriteProjectConfigurationsDescription(context.ProjectConfigurations, fileGenerator); + bool hasFastBuildConfig = false; bool hasNonFastBuildConfig = false; - - fileGenerator.Write(Template.Project.ProjectBeginConfigurationDescription); - // xml header contain description of each target - var platformNames = new Strings(); - var configNames = new Strings(); foreach (var conf in context.ProjectConfigurations) { - var platformName = Util.GetPlatformString(conf.Platform, conf.Project, conf.Target); - platformNames.Add(platformName); - configNames.Add(conf.Name); - if (conf.IsFastBuild) hasFastBuildConfig = true; else hasNonFastBuildConfig = true; } - // write all combinations to avoid "Incomplete Configuration" VS warning - foreach (var configName in configNames.SortedValues) - { - foreach (var platformName in platformNames.SortedValues) - { - using (fileGenerator.Declare("platformName", platformName)) - using (fileGenerator.Declare("configName", configName)) - { - fileGenerator.Write(Template.Project.ProjectConfigurationDescription); - } - } - } - - fileGenerator.Write(Template.Project.ProjectEndConfigurationDescription); + var firstConf = context.ProjectConfigurations.First(); //checking only the first one, having one with CLR support and others without would be an error bool clrSupport = Util.IsDotNet(firstConf); @@ -436,7 +386,7 @@ private void GenerateImpl(GenerationContext context, IList generatedFile targetFrameworkString = Util.GetDotNetTargetString(firstConf.Target.GetFragment()); } - using (fileGenerator.Declare("projectName", projectName)) + using (fileGenerator.Declare("projectName", firstConf.ProjectName)) using (fileGenerator.Declare("guid", firstConf.ProjectGuid)) using (fileGenerator.Declare("sccProjectName", sccProjectName)) using (fileGenerator.Declare("sccLocalPath", sccLocalPath)) @@ -460,23 +410,8 @@ private void GenerateImpl(GenerationContext context, IList generatedFile fileGenerator.Write(Template.Project.ImportCppDefaultProps); - // generate all configuration options onces... - Dictionary options = new Dictionary(); - ProjectOptionsGenerator projectOptionsGen = new ProjectOptionsGenerator(); - foreach (Project.Configuration conf in context.ProjectConfigurations) - { - context.Options = new Options.ExplicitOptions(); - context.CommandLineOptions = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); - - context.Configuration = conf; - projectOptionsGen.GenerateOptions(context); - FillIncludeDirectoriesOptions(context); - FillLibrariesOptions(context); - - options.Add(conf, context.Options); - - context.Reset(); // just a safety, not necessary to clean up - } + foreach (var platform in context.PresentPlatforms.Values) + platform.GeneratePostDefaultPropsImport(context, fileGenerator); // user file string projectFilePath = FileName + ProjectExtension; @@ -490,7 +425,7 @@ private void GenerateImpl(GenerationContext context, IList generatedFile using (fileGenerator.Declare("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) using (fileGenerator.Declare("conf", conf)) - using (fileGenerator.Declare("options", options[conf])) + using (fileGenerator.Declare("options", context.ProjectConfigurationOptions[conf])) using (fileGenerator.Declare("clrSupport", (conf.IsFastBuild || !clrSupport) ? FileGeneratorUtilities.RemoveLineTag : clrSupport.ToString().ToLower())) { var platformVcxproj = context.PresentPlatforms[conf.Platform]; @@ -501,38 +436,10 @@ private void GenerateImpl(GenerationContext context, IList generatedFile // .props files fileGenerator.Write(Template.Project.ProjectAfterConfigurationsGeneral); if (context.Project.ContainsASM) - { fileGenerator.Write(Template.Project.ProjectImportedMasmProps); - } - foreach (string propsFile in context.Project.CustomPropsFiles) - { - string capitalizedFile = Project.GetCapitalizedFile(propsFile) ?? propsFile; - - string relativeFile = Util.PathGetRelative(context.ProjectDirectoryCapitalized, capitalizedFile); - using (fileGenerator.Declare("importedPropsFile", relativeFile)) - { - fileGenerator.Write(Template.Project.ProjectImportedProps); - } - } - // configuration .props files - foreach (Project.Configuration conf in context.ProjectConfigurations) - { - using (fileGenerator.Declare("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) - using (fileGenerator.Declare("conf", conf)) - { - foreach (string propsFile in conf.CustomPropsFiles) - { - string capitalizedFile = Project.GetCapitalizedFile(propsFile) ?? propsFile; - - string relativeFile = Util.PathGetRelative(context.ProjectDirectoryCapitalized, capitalizedFile); - using (fileGenerator.Declare("importedPropsFile", relativeFile)) - { - fileGenerator.Write(Template.Project.ProjectConfigurationImportedProps); - } - } - } - } + VsProjCommon.WriteProjectCustomPropsFiles(context.Project.CustomPropsFiles, context.ProjectDirectoryCapitalized, fileGenerator); + VsProjCommon.WriteConfigurationsCustomPropsFiles(context.ProjectConfigurations, context.ProjectDirectoryCapitalized, fileGenerator); fileGenerator.Write(Template.Project.ProjectImportedPropsEnd); fileGenerator.Write(Template.Project.ProjectAfterConfigurationsGeneralImportPropertySheets); @@ -548,7 +455,7 @@ private void GenerateImpl(GenerationContext context, IList generatedFile using (fileGenerator.Declare("project", context.Project)) using (fileGenerator.Declare("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) using (fileGenerator.Declare("conf", conf)) - using (fileGenerator.Declare("options", options[conf])) + using (fileGenerator.Declare("options", context.ProjectConfigurationOptions[conf])) using (fileGenerator.Declare("target", conf.Target)) { var platformVcxproj = context.PresentPlatforms[conf.Platform]; @@ -649,7 +556,7 @@ private void GenerateImpl(GenerationContext context, IList generatedFile using (fileGenerator.Declare("conf", conf)) using (fileGenerator.Declare("project", conf.Project)) using (fileGenerator.Declare("target", conf.Target)) - using (fileGenerator.Declare("options", options[conf])) + using (fileGenerator.Declare("options", context.ProjectConfigurationOptions[conf])) using (fileGenerator.Declare("clrSupport", !clrSupport ? FileGeneratorUtilities.RemoveLineTag : clrSupport.ToString().ToLower())) { fileGenerator.Write(Template.Project.ProjectConfigurationBeginItemDefinition); @@ -694,7 +601,7 @@ private void GenerateImpl(GenerationContext context, IList generatedFile // source file requires to be remove from the projects, so that not 2 same cpp file be in 2 different project. // TODO: make a better check if (hasNonFastBuildConfig || !context.Project.StripFastBuildSourceFiles || context.ProjectConfigurations.Any(conf => !conf.StripFastBuildSourceFiles)) - GenerateFilesSection(context, options, fileGenerator, generatedFiles, skipFiles); + GenerateFilesSection(context, fileGenerator, generatedFiles, skipFiles); else if (hasFastBuildConfig) GenerateBffFilesSection(context, fileGenerator); @@ -742,21 +649,11 @@ private void GenerateImpl(GenerationContext context, IList generatedFile // 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. // Nevertheless, non-fastbuild dependencies (such as C# projects) must be written. - GenerateProjectReferences(context, fileGenerator, options, hasFastBuildConfig); + GenerateProjectReferences(context, fileGenerator, hasFastBuildConfig); // Environment variables var environmentVariables = context.ProjectConfigurations.Select(conf => conf.Platform).Distinct().SelectMany(platform => context.PresentPlatforms[platform].GetEnvironmentVariables(context)); - if (environmentVariables.Any()) - { - fileGenerator.Write(Template.Project.ItemGroupBegin); - foreach (var environmentTuple in environmentVariables) - { - using (fileGenerator.Declare("environmentVariableName", environmentTuple.Identifier)) - using (fileGenerator.Declare("environmentVariableValue", environmentTuple.Value)) - fileGenerator.Write(Template.Project.ProjectBuildMacroEnvironmentVariable); - } - fileGenerator.Write(Template.Project.ItemGroupEnd); - } + VsProjCommon.WriteEnvironmentVariables(environmentVariables, fileGenerator); // Generate vcxproj configuration to run after a deployment from the PC if (context.Project.UseRunFromPcDeployment) @@ -909,21 +806,6 @@ Strings ignoreSpecificLibraryNames platformVcxproj.SelectPlatformAdditionalDependenciesOptions(context); } - private void WriteCustomProperties(IVcxprojGenerationContext context, IFileGenerator fileGenerator) - { - if (context.Project.CustomProperties.Keys.Count == 0) - return; - - fileGenerator.Write(Template.Project.PropertyGroupStart); - foreach (var key in context.Project.CustomProperties.Keys) - { - using (fileGenerator.Declare("custompropertyname", key)) - using (fileGenerator.Declare("custompropertyvalue", context.Project.CustomProperties[key])) - fileGenerator.Write(Template.Project.CustomProperty); - } - fileGenerator.Write(Template.Project.PropertyGroupEnd); - } - private struct ProjectDependencyInfo { public string ProjectFullFileNameWithExtension; @@ -942,7 +824,7 @@ private string ReadGuidFromProjectFile(Project.Configuration dependency) private void GenerateProjectReferences( IVcxprojGenerationContext context, IFileGenerator fileGenerator, - IDictionary optionsDictionary, bool fastbuildOnly) + bool fastbuildOnly) { var firstConf = context.ProjectConfigurations.First(); @@ -1136,10 +1018,10 @@ private void GenerateProjectReferences( } } - Options.ExplicitOptions options = optionsDictionary[firstConf]; + Options.ExplicitOptions options = context.ProjectConfigurationOptions[firstConf]; foreach (var dependencyInfo in dependencies) { - string include = Util.PathGetRelative(firstConf.ProjectPath, dependencyInfo.ProjectFullFileNameWithExtension); + string include = Util.PathGetRelative(context.ProjectDirectory, dependencyInfo.ProjectFullFileNameWithExtension); string backupUseLibraryDependencyInputs = options["UseLibraryDependencyInputs"]; if (dependencyInfo.ContainsASM) @@ -1236,7 +1118,7 @@ private void GenerateBffFilesSection(IVcxprojGenerationContext context, IFileGen private void GenerateFiltersFile( IVcxprojGenerationContext context, string filtersFileName, - IList>> allFileLists, + IList>> allFileLists, string relativeCopyDependenciesFileName, Resolver resolver, IList generatedFiles, @@ -1254,14 +1136,14 @@ IList skipFiles foreach (var entry in allFileLists) { string type = entry.Item1; - List files = entry.Item2; + var files = entry.Item2; if (files.Count != 0) { using (fileGenerator.Declare("type", type)) { // write include... fileGenerator.Write(Vcxproj.Template.Project.ItemGroupBegin); - foreach (ProjectFile file in files) + foreach (var file in files) { using (fileGenerator.Declare("file", file)) { @@ -1340,7 +1222,6 @@ IList skipFiles private void GenerateFilesSection( IVcxprojGenerationContext context, - Dictionary options, IFileGenerator fileGenerator, IList generatedFiles, IList skipFiles @@ -1353,35 +1234,35 @@ IList skipFiles Strings projectFiles = context.Project.GetSourceFilesForConfigurations(context.ProjectConfigurations); // Add source files - List allFiles = new List(); - List includeFiles = new List(); - List sourceFiles = new List(); - List NatvisFiles = new List(); - List PRIFiles = new List(); - List NoneFiles = new List(); - List XResourcesReswFiles = new List(); - List XResourcesImgFiles = new List(); - List customBuildFiles = new List(); + var allFiles = new List(); + var includeFiles = new List(); + var sourceFiles = new List(); + var NatvisFiles = new List(); + var PRIFiles = new List(); + var NoneFiles = new List(); + var XResourcesReswFiles = new List(); + var XResourcesImgFiles = new List(); + var customBuildFiles = new List(); foreach (string file in context.Project.NatvisFiles) { - ProjectFile natvisFile = new ProjectFile(context, file); + var natvisFile = new ProjectFile(context, file); NatvisFiles.Add(natvisFile); } foreach (string file in context.Project.NoneFiles) { - ProjectFile priFile = new ProjectFile(context, file); + var priFile = new ProjectFile(context, file); NoneFiles.Add(priFile); } foreach (string file in projectFiles) { - ProjectFile projectFile = new ProjectFile(context, file); + var projectFile = new ProjectFile(context, file); allFiles.Add(projectFile); } - allFiles.Sort((ProjectFile l, ProjectFile r) => { return string.Compare(l.FileNameProjectRelative, r.FileNameProjectRelative, StringComparison.InvariantCulture); }); + allFiles.Sort((l, r) => { return string.Compare(l.FileNameProjectRelative, r.FileNameProjectRelative, StringComparison.InvariantCultureIgnoreCase); }); // Gather files with custom build steps. var configurationCustomFileBuildSteps = new Dictionary>(); @@ -1403,7 +1284,7 @@ IList skipFiles // type -> files var customSourceFiles = new Dictionary>(); - foreach (ProjectFile projectFile in allFiles) + foreach (var projectFile in allFiles) { string type = null; if (context.Project.ExtensionBuildTools.TryGetValue(projectFile.FileExtension, out type)) @@ -1438,7 +1319,7 @@ IList skipFiles if (hasCustomBuildForAllIncludes) { - foreach (ProjectFile file in includeFiles) + foreach (var file in includeFiles) { using (fileGenerator.Declare("file", file.FileNameProjectRelative)) using (fileGenerator.Declare("filetype", FileGeneratorUtilities.RemoveLineTag)) @@ -1470,7 +1351,7 @@ IList skipFiles } else { - foreach (ProjectFile file in includeFiles) + foreach (var file in includeFiles) { using (fileGenerator.Declare("file", file)) fileGenerator.Write(Template.Project.ProjectFilesHeader); @@ -1483,7 +1364,7 @@ IList skipFiles // Write custom build steps fileGenerator.Write(Template.Project.ProjectFilesBegin); - foreach (ProjectFile file in customBuildFiles) + foreach (var file in customBuildFiles) { using (fileGenerator.Declare("file", file.FileNameProjectRelative)) using (fileGenerator.Declare("filetype", FileGeneratorUtilities.RemoveLineTag)) @@ -1521,7 +1402,7 @@ IList skipFiles if (context.Project.NatvisFiles.Count > 0 && context.ProjectConfigurations.Any(conf => conf.Target.HaveFragment() && conf.Target.GetFragment() >= DevEnv.vs2015)) { fileGenerator.Write(Template.Project.ProjectFilesBegin); - foreach (ProjectFile file in NatvisFiles) + foreach (var file in NatvisFiles) { using (fileGenerator.Declare("file", file)) fileGenerator.Write(Template.Project.ProjectFilesNatvis); @@ -1536,7 +1417,7 @@ IList skipFiles fileGenerator.Write(Template.Project.ProjectFilesBegin); foreach (string file in context.Project.PRIFiles.SortedValues) { - ProjectFile priFile = new ProjectFile(context, file); + var priFile = new ProjectFile(context, file); PRIFiles.Add(priFile); writtenPRIFiles.Add(priFile.FileNameProjectRelative); using (fileGenerator.Declare("file", priFile)) @@ -1551,7 +1432,7 @@ IList skipFiles fileGenerator.Write(Template.Project.ProjectFilesBegin); foreach (string file in context.Project.NoneFiles) { - ProjectFile projectFile = new ProjectFile(context, file); + var projectFile = new ProjectFile(context, file); using (fileGenerator.Declare("file", projectFile)) fileGenerator.Write(Template.Project.ProjectFilesNone); } @@ -1566,7 +1447,7 @@ IList skipFiles foreach (var tuple in customPlatformFiles) { string type = tuple.Item1; - List files = tuple.Item2; + var files = tuple.Item2; customSourceFiles.GetValueOrAdd(type, new List()).AddRange(files); } } @@ -1574,14 +1455,14 @@ IList skipFiles fileGenerator.Write(Template.Project.ProjectFilesBegin); // Validation map - List> configurationCompiledFiles = new List>(); + var configurationCompiledFiles = new List>(); foreach (Project.Configuration conf in context.ProjectConfigurations) configurationCompiledFiles.Add(new List()); bool hasCustomBuildForAllSources = context.ProjectConfigurations.First().CustomBuildForAllSources != null; if (hasCustomBuildForAllSources) { - foreach (ProjectFile file in sourceFiles) + foreach (var file in sourceFiles) { using (fileGenerator.Declare("file", file.FileNameProjectRelative)) using (fileGenerator.Declare("filetype", FileGeneratorUtilities.RemoveLineTag)) @@ -1614,7 +1495,7 @@ IList skipFiles else { // Write source files - foreach (ProjectFile file in sourceFiles) + foreach (var file in sourceFiles) { using (fileGenerator.Declare("file", file)) using (fileGenerator.Declare("filetype", FileGeneratorUtilities.RemoveLineTag)) @@ -1632,7 +1513,7 @@ IList skipFiles for (int i = 0; i < context.ProjectConfigurations.Count; ++i) { Project.Configuration conf = context.ProjectConfigurations[i]; - List compiledFiles = configurationCompiledFiles[i]; + var compiledFiles = configurationCompiledFiles[i]; bool hasPrecomp = !string.IsNullOrEmpty(conf.PrecompSource) && !string.IsNullOrEmpty(conf.PrecompHeader); bool isPrecompSource = !string.IsNullOrEmpty(conf.PrecompSource) && file.FileName.EndsWith(conf.PrecompSource, StringComparison.OrdinalIgnoreCase); @@ -1751,7 +1632,7 @@ IList skipFiles // in case we are using the LLVM toolchain, the PCH was added // as force include globally for the conf, so we need // to use the forced include vanilla list that we prepared - var optionsForConf = options[conf]; + var optionsForConf = context.ProjectConfigurationOptions[conf]; if (optionsForConf.ContainsKey("ForcedIncludeFilesVanilla")) { // Note: faster to test that the options array has the @@ -1820,7 +1701,7 @@ IList skipFiles fileGenerator.Write(Template.Project.ProjectFilesBegin); using (fileGenerator.Declare("type", typeName)) { - List files = customSourceFiles[typeName]; + var files = customSourceFiles[typeName]; foreach (var file in files) { using (fileGenerator.Declare("file", file)) @@ -1834,7 +1715,7 @@ IList skipFiles using (fileGenerator.Declare("conf", conf)) using (fileGenerator.Declare("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) { - List compiledFiles = configurationCompiledFiles[i]; + var compiledFiles = configurationCompiledFiles[i]; bool isExcludeFromBuild = conf.ResolvedSourceFilesBuildExclude.Contains(file.FileName); if (isExcludeFromBuild) { @@ -1929,9 +1810,9 @@ IList skipFiles for (int i = 0; i < context.ProjectConfigurations.Count; ++i) { Project.Configuration conf = context.ProjectConfigurations[i]; - List compiledFiles = configurationCompiledFiles[i]; + var compiledFiles = configurationCompiledFiles[i]; - compiledFiles.Sort((ProjectFile l, ProjectFile r) => { return String.Compare(l.FileNameWithoutExtension, r.FileNameWithoutExtension, StringComparison.OrdinalIgnoreCase); }); + compiledFiles.Sort((l, r) => { return String.Compare(l.FileNameWithoutExtension, r.FileNameWithoutExtension, StringComparison.OrdinalIgnoreCase); }); for (int j = 0; j < compiledFiles.Count - 1; ++j) { @@ -1960,20 +1841,20 @@ IList skipFiles GenerateBffFilesSection(context, fileGenerator); var allFileLists = new List>>(); - allFileLists.Add(new Tuple>(hasCustomBuildForAllSources ? "CustomBuild" : "ClCompile", sourceFiles)); - allFileLists.Add(new Tuple>("PRIResource", XResourcesReswFiles)); - allFileLists.Add(new Tuple>("Image", XResourcesImgFiles)); - allFileLists.Add(new Tuple>(hasCustomBuildForAllIncludes ? "CustomBuild" : "ClInclude", includeFiles)); - allFileLists.Add(new Tuple>("CustomBuild", customBuildFiles)); + allFileLists.Add(Tuple.Create(hasCustomBuildForAllSources ? "CustomBuild" : "ClCompile", sourceFiles)); + allFileLists.Add(Tuple.Create("PRIResource", XResourcesReswFiles)); + allFileLists.Add(Tuple.Create("Image", XResourcesImgFiles)); + allFileLists.Add(Tuple.Create(hasCustomBuildForAllIncludes ? "CustomBuild" : "ClInclude", includeFiles)); + allFileLists.Add(Tuple.Create("CustomBuild", customBuildFiles)); if (NatvisFiles.Count > 0) - allFileLists.Add(new Tuple>("Natvis", NatvisFiles)); + allFileLists.Add(Tuple.Create("Natvis", NatvisFiles)); if (PRIFiles.Count > 0) - allFileLists.Add(new Tuple>("PRIResource", PRIFiles)); + allFileLists.Add(Tuple.Create("PRIResource", PRIFiles)); if (NoneFiles.Count > 0) - allFileLists.Add(new Tuple>("None", NoneFiles)); + allFileLists.Add(Tuple.Create("None", NoneFiles)); foreach (var entry in customSourceFiles) { - allFileLists.Add(new Tuple>(entry.Key, entry.Value)); + allFileLists.Add(Tuple.Create(entry.Key, entry.Value)); } bool skipFilterGeneration = context.ProjectConfigurations.Any(conf => conf.SkipFilterGeneration); diff --git a/Sharpmake.Generators/VisualStudio/VsProjCommon.Template.cs b/Sharpmake.Generators/VisualStudio/VsProjCommon.Template.cs new file mode 100644 index 000000000..2e6056e46 --- /dev/null +++ b/Sharpmake.Generators/VisualStudio/VsProjCommon.Template.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sharpmake.Generators.VisualStudio +{ + internal static partial class VsProjCommon + { + public static class Template + { + public static string PropertyGroupStart = + @" +"; + + public static string PropertyGroupEnd = + @" +"; + + public static string ItemGroupBegin = + @" +"; + + public static string ItemGroupEnd = + @" +"; + + public static string CustomProperty = + @" <[custompropertyname]>[custompropertyvalue] +"; + + public static class Project + { + public static string ProjectBeginConfigurationDescription = + @" +"; + + public static string ProjectEndConfigurationDescription = + @" +"; + + public static string ProjectConfigurationDescription = + @" + [configName] + [platformName] + +"; + + public static string ProjectImportProps = + @" +"; + + public static string ProjectConfigurationImportProps = + @" +"; + + public static string ProjectBuildMacroEnvironmentVariable = + @" + [environmentVariableValue] + true + +"; + } + } + } +} diff --git a/Sharpmake.Generators/VisualStudio/VsProjCommon.cs b/Sharpmake.Generators/VisualStudio/VsProjCommon.cs new file mode 100644 index 000000000..bec9ba273 --- /dev/null +++ b/Sharpmake.Generators/VisualStudio/VsProjCommon.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sharpmake.Generators.VisualStudio +{ + internal static partial class VsProjCommon + { + public static void WriteCustomProperties(Dictionary customProperties, IFileGenerator fileGenerator) + { + if (customProperties.Count == 0) + return; + + fileGenerator.Write(Template.PropertyGroupStart); + foreach (var kvp in customProperties) + { + using (fileGenerator.Declare("custompropertyname", kvp.Key)) + using (fileGenerator.Declare("custompropertyvalue", kvp.Value)) + fileGenerator.Write(Template.CustomProperty); + } + fileGenerator.Write(Template.PropertyGroupEnd); + } + + public static void WriteProjectConfigurationsDescription(IEnumerable configurations, IFileGenerator fileGenerator) + { + fileGenerator.Write(Template.Project.ProjectBeginConfigurationDescription); + + var platformNames = new Strings(); + var configNames = new Strings(); + foreach (var conf in configurations) + { + var platformName = Util.GetPlatformString(conf.Platform, conf.Project, conf.Target); + platformNames.Add(platformName); + configNames.Add(conf.Name); + } + + // write all combinations to avoid "Incomplete Configuration" VS warning + foreach (var configName in configNames.SortedValues) + { + foreach (var platformName in platformNames.SortedValues) + { + using (fileGenerator.Declare("platformName", platformName)) + using (fileGenerator.Declare("configName", configName)) + { + fileGenerator.Write(Template.Project.ProjectConfigurationDescription); + } + } + } + + fileGenerator.Write(Template.Project.ProjectEndConfigurationDescription); + } + + public static void WriteProjectCustomPropsFiles( + IEnumerable customProps, + string projectDirectoryCapitalized, + IFileGenerator fileGenerator + ) + { + foreach (string propsFile in customProps) + { + string capitalizedFile = Project.GetCapitalizedFile(propsFile) ?? propsFile; + + string relativeFile = Util.PathGetRelative(projectDirectoryCapitalized, capitalizedFile); + using (fileGenerator.Declare("importedPropsFile", relativeFile)) + { + fileGenerator.Write(Template.Project.ProjectImportProps); + } + } + } + + public static void WriteConfigurationsCustomPropsFiles( + IEnumerable configurations, + string projectDirectoryCapitalized, + IFileGenerator fileGenerator + ) + { + foreach (Project.Configuration conf in configurations) + { + using (fileGenerator.Declare("platformName", Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))) + using (fileGenerator.Declare("conf", conf)) + { + foreach (string propsFile in conf.CustomPropsFiles) + { + string capitalizedFile = Project.GetCapitalizedFile(propsFile) ?? propsFile; + + string relativeFile = Util.PathGetRelative(projectDirectoryCapitalized, capitalizedFile); + using (fileGenerator.Declare("importedPropsFile", relativeFile)) + { + fileGenerator.Write(Template.Project.ProjectConfigurationImportProps); + } + } + } + } + } + + public static void WriteEnvironmentVariables( + IEnumerable environmentVariables, + IFileGenerator fileGenerator + ) + { + if (!environmentVariables.Any()) + return; + + fileGenerator.Write(Template.ItemGroupBegin); + foreach (var environmentTuple in environmentVariables) + { + using (fileGenerator.Declare("environmentVariableName", environmentTuple.Identifier)) + using (fileGenerator.Declare("environmentVariableValue", environmentTuple.Value)) + fileGenerator.Write(Template.Project.ProjectBuildMacroEnvironmentVariable); + } + fileGenerator.Write(Template.ItemGroupEnd); + } + } +} diff --git a/Sharpmake.Generators/VisualStudio/VsUtil.cs b/Sharpmake.Generators/VisualStudio/VsUtil.cs new file mode 100644 index 000000000..12b360910 --- /dev/null +++ b/Sharpmake.Generators/VisualStudio/VsUtil.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sharpmake.Generators.VisualStudio +{ + internal static class VsUtil + { + public static IEnumerable SortConfigurations( + IEnumerable unsortedConfigurations, + string projectFileFullPath + ) + { + // Need to sort by name and platform + var configurations = new List(); + configurations.AddRange(unsortedConfigurations.OrderBy(conf => conf.Name + Util.GetPlatformString(conf.Platform, conf.Project, conf.Target))); + + // Make sure that all configurations use the same project name, + // and validate that 2 conf in the same project have a distinct tuple name + platform + var configurationNameMapping = new Dictionary(); + + string projectName = null; + + foreach (Project.Configuration conf in configurations) + { + if (projectName == null) + projectName = conf.ProjectName; + else if (projectName != conf.ProjectName) + throw new Error("Project configurations in the same project files must be the same: {0} != {1} in {2}", projectName, conf.ProjectName, projectFileFullPath); + + var projectUniqueName = conf.Name + Util.GetPlatformString(conf.Platform, conf.Project, conf.Target); + + Project.Configuration previousConf; + if (configurationNameMapping.TryGetValue(projectUniqueName, out previousConf)) + { + throw new Error( + "Project '{0}' contains distinct configurations with the same name, please add something to distinguish them:\n- {1}", + projectFileFullPath, + string.Join( + Environment.NewLine + "- ", + configurations.Select( + pc => pc.Name + '|' + Util.GetPlatformString(pc.Platform, pc.Project, pc.Target) + $" => '{pc.Target.GetTargetString()}'" + ).OrderBy(name => name) + ) + ); + } + configurationNameMapping[projectUniqueName] = conf; + } + + return configurations; + } + } +} diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs index 1070f9066..f434d9a62 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs @@ -24,6 +24,23 @@ public sealed partial class AndroidPlatform private const string _projectDescriptionPlatformSpecific = @" Android [applicationTypeRevision] + [androidHome] + [antHome] + [javaHome] + [ndkRoot] +"; + + private const string _projectImportAppTypeProps = + @" + +"; + + // Workaround for app type props not overridable Microsoft.Cpp.Default.props + private const string _postImportAppTypeProps = + @" + <_ApplicationTypeDefaultPropsFound>true + <_ApplicationTypeRevisionDefaultPropsFound>true + "; private const string _projectConfigurationsGeneralTemplate = @@ -34,6 +51,7 @@ public sealed partial class AndroidPlatform [options.UseOfStl] [options.ThumbMode] [options.AndroidAPILevel] + [options.ShowAndroidPathsVerbosity] "; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index 6cccb576e..5437cafef 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -22,7 +22,9 @@ namespace Sharpmake { public static partial class Android { - [PlatformImplementation(Platform.android, + public const Platform SharpmakePlatform = Platform.android; + + [PlatformImplementation(SharpmakePlatform, typeof(IPlatformDescriptor), typeof(IPlatformVcxproj), typeof(Project.Configuration.IConfigurationTasks))] @@ -110,13 +112,79 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati string applicationTypeRevision = (context.DevelopmentEnvironmentsRange.MinDevEnv == DevEnv.vs2017 || context.DevelopmentEnvironmentsRange.MinDevEnv == DevEnv.vs2019) ? "3.0" : "2.0"; using (generator.Declare("applicationTypeRevision", applicationTypeRevision)) + using (generator.Declare("androidHome", Options.GetOptionValue("androidHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("antHome", Options.GetOptionValue("antHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("javaHome", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("ndkRoot", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) { generator.Write(_projectDescriptionPlatformSpecific); } + string msBuildPathOverrides = string.Empty; + + // MSBuild override when mixing devenvs in the same vcxproj is not supported, + // but before throwing an exception check if we have some override + for (DevEnv devEnv = context.DevelopmentEnvironmentsRange.MinDevEnv; devEnv <= context.DevelopmentEnvironmentsRange.MaxDevEnv; devEnv = (DevEnv)((int)devEnv << 1)) + { + switch (devEnv) + { + case DevEnv.vs2019: + { + // Note1: _PlatformFolder override is deprecated starting with vs2019, so we write AdditionalVCTargetsPath instead + // Note2: MSBuildGlobalSettings.SetCppPlatformFolder for vs2019 is no more the valid way to handle it. Older buildtools packages can anyway contain it, and need upgrade. + + if (!string.IsNullOrEmpty(MSBuildGlobalSettings.GetCppPlatformFolder(devEnv, SharpmakePlatform))) + throw new Error("SetCppPlatformFolder is not supported by VS2019 correctly: use of MSBuildGlobalSettings.SetCppPlatformFolder should be replaced by use of MSBuildGlobalSettings.SetAdditionalVCTargetsPath."); + + // vs2019 use AdditionalVCTargetsPath + string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform); + if (!string.IsNullOrEmpty(additionalVCTargetsPath)) + { + using (generator.Declare("additionalVCTargetsPath", Util.EnsureTrailingSeparator(additionalVCTargetsPath))) + msBuildPathOverrides += generator.Resolver.Resolve(Vcxproj.Template.Project.AdditionalVCTargetsPath); + } + } + break; + } + } + + if (!string.IsNullOrEmpty(msBuildPathOverrides)) + { + if (context.DevelopmentEnvironmentsRange.MinDevEnv != context.DevelopmentEnvironmentsRange.MaxDevEnv) + throw new Error("Different vs versions not supported in the same vcxproj"); + + generator.WriteVerbatim(msBuildPathOverrides); + } + generator.Write(Vcxproj.Template.Project.ProjectDescriptionEnd); } + private bool _importAppTypesOverrides = false; + public override void GenerateProjectPlatformSdkDirectoryDescription(IVcxprojGenerationContext context, IFileGenerator generator) + { + base.GenerateProjectPlatformSdkDirectoryDescription(context, generator); + + // in case we've set an additional vc targets path, import the props from there instead + var devEnv = context.DevelopmentEnvironmentsRange.MinDevEnv; + if (context.DevelopmentEnvironmentsRange.MinDevEnv == DevEnv.vs2019) + { + string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform); + if (!string.IsNullOrEmpty(additionalVCTargetsPath)) + { + _importAppTypesOverrides = true; + generator.WriteVerbatim(_projectImportAppTypeProps); + } + } + } + + public override void GeneratePostDefaultPropsImport(IVcxprojGenerationContext context, IFileGenerator generator) + { + base.GeneratePostDefaultPropsImport(context, generator); + + if (_importAppTypesOverrides) + generator.WriteVerbatim(_postImportAppTypeProps); + } + public override void GenerateProjectCompileVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) { generator.Write(_projectConfigurationsCompileTemplate); @@ -142,6 +210,18 @@ protected override string GetProjectStaticLinkVcxprojTemplate() return _projectConfigurationsStaticLinkTemplate; } + public override void SetupSdkOptions(IGenerationContext context) + { + base.SetupSdkOptions(context); + var conf = context.Configuration; + var options = context.Options; + + options["androidHome"] = Options.PathOption.Get(conf, GlobalSettings.AndroidHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); + options["antHome"] = Options.PathOption.Get (conf, GlobalSettings.AntHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); + options["javaHome"] = Options.PathOption.Get (conf, GlobalSettings.JavaHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); + options["ndkRoot"] = Options.PathOption.Get (conf, GlobalSettings.NdkRoot ?? RemoveLineTag, context.ProjectDirectoryCapitalized); + } + public override void SelectCompilerOptions(IGenerationContext context) { var options = context.Options; @@ -150,10 +230,21 @@ public override void SelectCompilerOptions(IGenerationContext context) // Although we add options to cmdLineOptions, FastBuild isn't supported yet for Android projects. + context.SelectOption + ( + Options.Option(Options.Android.General.ShowAndroidPathsVerbosity.High, () => { options["ShowAndroidPathsVerbosity"] = "High"; }), + Options.Option(Options.Android.General.ShowAndroidPathsVerbosity.Normal, () => { options["ShowAndroidPathsVerbosity"] = "Normal"; }), + Options.Option(Options.Android.General.ShowAndroidPathsVerbosity.Low, () => { options["ShowAndroidPathsVerbosity"] = "Low"; }) + ); + context.SelectOption ( Options.Option(Options.Android.General.AndroidAPILevel.Default, () => { options["AndroidAPILevel"] = RemoveLineTag; }), + Options.Option(Options.Android.General.AndroidAPILevel.Android16, () => { options["AndroidAPILevel"] = "android-16"; }), + Options.Option(Options.Android.General.AndroidAPILevel.Android17, () => { options["AndroidAPILevel"] = "android-17"; }), + Options.Option(Options.Android.General.AndroidAPILevel.Android18, () => { options["AndroidAPILevel"] = "android-18"; }), Options.Option(Options.Android.General.AndroidAPILevel.Android19, () => { options["AndroidAPILevel"] = "android-19"; }), + Options.Option(Options.Android.General.AndroidAPILevel.Android20, () => { options["AndroidAPILevel"] = "android-20"; }), Options.Option(Options.Android.General.AndroidAPILevel.Android21, () => { options["AndroidAPILevel"] = "android-21"; }), Options.Option(Options.Android.General.AndroidAPILevel.Android22, () => { options["AndroidAPILevel"] = "android-22"; }), Options.Option(Options.Android.General.AndroidAPILevel.Android23, () => { options["AndroidAPILevel"] = "android-23"; }), @@ -161,7 +252,9 @@ public override void SelectCompilerOptions(IGenerationContext context) Options.Option(Options.Android.General.AndroidAPILevel.Android25, () => { options["AndroidAPILevel"] = "android-25"; }), Options.Option(Options.Android.General.AndroidAPILevel.Android26, () => { options["AndroidAPILevel"] = "android-26"; }), Options.Option(Options.Android.General.AndroidAPILevel.Android27, () => { options["AndroidAPILevel"] = "android-27"; }), - Options.Option(Options.Android.General.AndroidAPILevel.Android28, () => { options["AndroidAPILevel"] = "android-28"; }) + Options.Option(Options.Android.General.AndroidAPILevel.Android28, () => { options["AndroidAPILevel"] = "android-28"; }), + Options.Option(Options.Android.General.AndroidAPILevel.Android29, () => { options["AndroidAPILevel"] = "android-29"; }), + Options.Option(Options.Android.General.AndroidAPILevel.Android30, () => { options["AndroidAPILevel"] = "android-30"; }) ); context.SelectOption diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/GlobalSettings.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/GlobalSettings.cs new file mode 100644 index 000000000..6c4d14eed --- /dev/null +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/GlobalSettings.cs @@ -0,0 +1,46 @@ +// Copyright (c) 2017 Ubisoft Entertainment +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Collections.Generic; + +namespace Sharpmake +{ + public static partial class Android + { + public static class GlobalSettings + { + /// + /// Android SDK path + /// + public static string AndroidHome { get; set; } + + /// + /// Android NDK path + /// + public static string NdkRoot { get; set; } + + /// + /// Java SE Development Kit path + /// + public static string JavaHome { get; set; } + + /// + /// Apache Ant path + /// + public static string AntHome { get; set; } + } + } +} diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs index 4a16a5187..9afaf57eb 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs @@ -327,6 +327,10 @@ public virtual void GenerateProjectPlatformSdkDirectoryDescription(IVcxprojGener WriteWindowsKitsOverrides(context, generator); } + public virtual void GeneratePostDefaultPropsImport(IVcxprojGenerationContext context, IFileGenerator generator) + { + } + public virtual void GenerateProjectConfigurationGeneral(IVcxprojGenerationContext context, IFileGenerator generator) { generator.Write(_projectConfigurationsGeneral); diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj index 6747e620b..005575dc9 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj @@ -56,6 +56,7 @@ + diff --git a/Sharpmake/Options.Android.cs b/Sharpmake/Options.Android.cs index 327577d8f..ac798dffa 100644 --- a/Sharpmake/Options.Android.cs +++ b/Sharpmake/Options.Android.cs @@ -14,27 +14,94 @@ namespace Sharpmake { - using System; - public static partial class Options { - public static class Android + public static class Android // TODO: move this to the CommonPlatforms module { public static class General { + /// + /// Android SDK path + /// If unset, will use Android.GlobalSettings.AndroidHome + /// + public class AndroidHome : PathOption + { + public AndroidHome(string path) + : base(path) { } + } + + /// + /// Android NDK path + /// If unset, will use Android.GlobalSettings.NdkRoot + /// + public class NdkRoot : PathOption + { + public NdkRoot(string path) + : base(path) { } + } + + /// + /// Java SE Development Kit path + /// If unset, will use Android.GlobalSettings.JavaHome + /// + public class JavaHome : PathOption + { + public JavaHome(string path) + : base(path) { } + } + + /// + /// Apache Ant path + /// If unset, will use Android.GlobalSettings.AntHome + /// + public class AntHome : PathOption + { + public AntHome(string path) + : base(path) { } + } + + /// + /// Path to the AndroidProj MSBuild files + /// Expected to contain the files found in MSBuild\Microsoft\MDD\Android\V150 + /// If unset, line won't be written + /// + public class AndroidTargetsPath : PathOption + { + public AndroidTargetsPath(string path) + : base(path) { } + } + + /// + /// Verbosity of the tasks (vcxproj only) + /// At the time of this writing, this only control if on build env variables values are printed + /// + public enum ShowAndroidPathsVerbosity + { + High, + Normal, + [Default] + Low + } + public enum AndroidAPILevel { [Default] Default, - Android19, - Android21, - Android22, - Android23, - Android24, - Android25, - Android26, - Android27, - Android28, + Android16, // Jelly Bean 4.1.x + Android17, // Jelly Bean 4.2.x + Android18, // Jelly Bean 4.3.x + Android19, // KitKat 4.4 - 4.4.4 + Android20, // Does it really exist? + Android21, // Lollipop 5.0 - 5.0.2 + Android22, // Lollipop 5.1 + Android23, // Marshmallow 6.0 + Android24, // Nougat 7.0 + Android25, // Nougat 7.1 + Android26, // Oreo 8.0.0 + Android27, // Oreo 8.1.0 + Android28, // Pie 9.0 + Android29, // Android 10 + Android30, // Android 11 } public enum PlatformToolset diff --git a/Sharpmake/Options.cs b/Sharpmake/Options.cs index e6b36278e..dec1b648f 100644 --- a/Sharpmake/Options.cs +++ b/Sharpmake/Options.cs @@ -14,6 +14,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Reflection; namespace Sharpmake @@ -128,6 +129,47 @@ public class ExplicitOptions : Dictionary public Strings ExplicitDefines = new Strings(); } + /// + /// This method will retrieve a path option from all the configurations, ensuring it has the same value. + /// If none of the configurations have the option, it will return the fallback value + /// + /// The type of the option to lookup in the configurations. + /// The list of configurations to look into. + /// Optional: Fallback value to return in case none of the configurations have the option. + /// Optional: The rootpath to convert the path relative to. + /// + public static string GetConfOption(IEnumerable configurations, string fallback = RemoveLineTag, string rootpath = null) + where T : PathOption + { + var values = configurations.Select(conf => PathOption.Get(conf, fallback, rootpath)).Distinct().ToList(); + if (values.Count != 1) + throw new Error(nameof(T) + " has conflicting values in the configurations, they must all have the same"); + + return values.First(); + } + + /// + /// This method will retrieve the values associated to a key in an enumerable of dictionaries, + /// ensuring that the value is identical in all of them, or doesn't exist at all. + /// If none of the dictionaries contain the key, it will return the fallback value + /// + /// The list of dictionaries to look into. + /// The list of dictionaries to look into. + /// Optional: Fallback value to return in case none of the dictionaries have the key. + /// + public static string GetOptionValue(string key, IEnumerable> dictionaries, string fallback = RemoveLineTag) + { + var values = dictionaries.Select(dict => { + string value; + return dict.TryGetValue(key, out value) ? value : fallback; + }).Distinct().ToList(); + + if (values.Count != 1) + throw new Error($"Found conflicting values for '{key}' in the dictionaries, they must all have the same value"); + + return values.First(); + } + #region Private [System.AttributeUsage(AttributeTargets.Field)] From f1894e203847bd1a14931af8e10c3098630e0f7b Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Mon, 27 Apr 2020 17:08:09 +0200 Subject: [PATCH 09/43] Fix default values in string options, they need to be public as well as static --- Sharpmake/Options.CSharp.cs | 1 - Sharpmake/Options.cs | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Sharpmake/Options.CSharp.cs b/Sharpmake/Options.CSharp.cs index aa1d1a9b6..6cf5db34f 100644 --- a/Sharpmake/Options.CSharp.cs +++ b/Sharpmake/Options.CSharp.cs @@ -197,7 +197,6 @@ public ApplicationRevision(string revision) : base(revision) { } public class ApplicationVersion : StringOption { - public static readonly string Default = "1.0.0.%2a"; public ApplicationVersion(string version) : base(version) { } } diff --git a/Sharpmake/Options.cs b/Sharpmake/Options.cs index dec1b648f..7a4c65728 100644 --- a/Sharpmake/Options.cs +++ b/Sharpmake/Options.cs @@ -31,6 +31,11 @@ public enum DefaultTarget All = Debug | Release } + /// + /// Used to hold an option that has a string value + /// A default value can be set by adding a `public static readonly string Default` field, ex: + /// public static readonly string Default = "3.0"; + /// public abstract class StringOption { public static string Get(Project.Configuration conf) @@ -39,7 +44,7 @@ public static string Get(Project.Configuration conf) var option = Options.GetObject(conf); if (option == null) { - var defaultValue = typeof(T).GetField("Default", BindingFlags.Static); + var defaultValue = typeof(T).GetField("Default", BindingFlags.Public | BindingFlags.Static); return defaultValue != null ? (defaultValue.GetValue(null) as string) : RemoveLineTag; } return option.Value; From fab5f2d2bae92847b7e5eb80c5fd92be0a63348e Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Mon, 27 Apr 2020 17:10:02 +0200 Subject: [PATCH 10/43] Fix NDKRoot option --- .../Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index 5437cafef..a1a95be72 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -115,7 +115,7 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati using (generator.Declare("androidHome", Options.GetOptionValue("androidHome", context.ProjectConfigurationOptions.Values))) using (generator.Declare("antHome", Options.GetOptionValue("antHome", context.ProjectConfigurationOptions.Values))) using (generator.Declare("javaHome", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("ndkRoot", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("ndkRoot", Options.GetOptionValue("ndkRoot", context.ProjectConfigurationOptions.Values))) { generator.Write(_projectDescriptionPlatformSpecific); } From a151600a7204470d4c2c2c6c27394e11bc3bb07a Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Mon, 27 Apr 2020 17:10:58 +0200 Subject: [PATCH 11/43] [Vcproj][Android] Make ApplicationTypeRevision an option --- .../Android/AndroidPlatform.cs | 14 +++++++------- Sharpmake/Options.Android.cs | 12 ++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index a1a95be72..c67a2c1fe 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -109,13 +109,11 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati { generator.Write(_projectStartPlatformConditional); - string applicationTypeRevision = (context.DevelopmentEnvironmentsRange.MinDevEnv == DevEnv.vs2017 || context.DevelopmentEnvironmentsRange.MinDevEnv == DevEnv.vs2019) ? "3.0" : "2.0"; - - using (generator.Declare("applicationTypeRevision", applicationTypeRevision)) - using (generator.Declare("androidHome", Options.GetOptionValue("androidHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("antHome", Options.GetOptionValue("antHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("javaHome", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("ndkRoot", Options.GetOptionValue("ndkRoot", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("applicationTypeRevision", Options.GetOptionValue("applicationTypeRevision", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("androidHome", Options.GetOptionValue("androidHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("antHome", Options.GetOptionValue("antHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("javaHome", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("ndkRoot", Options.GetOptionValue("ndkRoot", context.ProjectConfigurationOptions.Values))) { generator.Write(_projectDescriptionPlatformSpecific); } @@ -220,6 +218,8 @@ public override void SetupSdkOptions(IGenerationContext context) options["antHome"] = Options.PathOption.Get (conf, GlobalSettings.AntHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); options["javaHome"] = Options.PathOption.Get (conf, GlobalSettings.JavaHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); options["ndkRoot"] = Options.PathOption.Get (conf, GlobalSettings.NdkRoot ?? RemoveLineTag, context.ProjectDirectoryCapitalized); + + options["applicationTypeRevision"] = Options.StringOption.Get(conf); } public override void SelectCompilerOptions(IGenerationContext context) diff --git a/Sharpmake/Options.Android.cs b/Sharpmake/Options.Android.cs index ac798dffa..a8284e379 100644 --- a/Sharpmake/Options.Android.cs +++ b/Sharpmake/Options.Android.cs @@ -71,6 +71,18 @@ public AndroidTargetsPath(string path) : base(path) { } } + /// + /// Application Type Revision + /// This must be a valid version string, of the form major.minor[.build[.revision]]. + /// Examples: 1.0, 10.0.0.0 + /// + public class ApplicationTypeRevision : StringOption + { + public static readonly string Default = "3.0"; + public ApplicationTypeRevision(string revision) + : base(revision) { } + } + /// /// Verbosity of the tasks (vcxproj only) /// At the time of this writing, this only control if on build env variables values are printed From b7c6dd3b9108d24338f15e0ccca1a7c6f3aaa276 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 28 Apr 2020 18:52:51 +0200 Subject: [PATCH 12/43] [Android] Fix the post import section, was written more than necessary --- .../Android/AndroidPlatform.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index c67a2c1fe..3086015dc 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -157,7 +157,6 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati generator.Write(Vcxproj.Template.Project.ProjectDescriptionEnd); } - private bool _importAppTypesOverrides = false; public override void GenerateProjectPlatformSdkDirectoryDescription(IVcxprojGenerationContext context, IFileGenerator generator) { base.GenerateProjectPlatformSdkDirectoryDescription(context, generator); @@ -168,10 +167,7 @@ public override void GenerateProjectPlatformSdkDirectoryDescription(IVcxprojGene { string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform); if (!string.IsNullOrEmpty(additionalVCTargetsPath)) - { - _importAppTypesOverrides = true; generator.WriteVerbatim(_projectImportAppTypeProps); - } } } @@ -179,8 +175,13 @@ public override void GeneratePostDefaultPropsImport(IVcxprojGenerationContext co { base.GeneratePostDefaultPropsImport(context, generator); - if (_importAppTypesOverrides) - generator.WriteVerbatim(_postImportAppTypeProps); + // in case we've set an additional vc targets path, import the props from there instead + var devEnv = context.DevelopmentEnvironmentsRange.MinDevEnv; + if (context.DevelopmentEnvironmentsRange.MinDevEnv == DevEnv.vs2019) + { + if (!string.IsNullOrEmpty(MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform))) + generator.WriteVerbatim(_postImportAppTypeProps); + } } public override void GenerateProjectCompileVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) From f1d743409df3b66f5bb65d9e7fb9d95c9ad1648b Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 28 Apr 2020 18:53:44 +0200 Subject: [PATCH 13/43] [Android] Implement clang 3.6 as an option, in case we use AppTypeRevision 1.0, and add the revisions supported by each entry as a comment --- .../Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs | 1 + Sharpmake/Options.Android.cs | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index 3086015dc..c0abd5017 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -261,6 +261,7 @@ public override void SelectCompilerOptions(IGenerationContext context) context.SelectOption ( Options.Option(Options.Android.General.PlatformToolset.Default, () => { options["PlatformToolset"] = RemoveLineTag; }), + Options.Option(Options.Android.General.PlatformToolset.Clang_3_6, () => { options["PlatformToolset"] = "Clang_3_6"; }), Options.Option(Options.Android.General.PlatformToolset.Clang_3_8, () => { options["PlatformToolset"] = "Clang_3_8"; }), Options.Option(Options.Android.General.PlatformToolset.Clang_5_0, () => { options["PlatformToolset"] = "Clang_5_0"; }), Options.Option(Options.Android.General.PlatformToolset.Gcc_4_9, () => { options["PlatformToolset"] = "Gcc_4_9"; }) diff --git a/Sharpmake/Options.Android.cs b/Sharpmake/Options.Android.cs index a8284e379..080ecbe7f 100644 --- a/Sharpmake/Options.Android.cs +++ b/Sharpmake/Options.Android.cs @@ -121,11 +121,13 @@ public enum PlatformToolset [Default] Default, [DevEnvVersion(minimum = DevEnv.vs2015)] - Clang_3_8, + Clang_3_6, // needs ApplicationTypeRevision 1.0 [DevEnvVersion(minimum = DevEnv.vs2015)] - Clang_5_0, + Clang_3_8, // needs ApplicationTypeRevision 2.0 or 3.0 [DevEnvVersion(minimum = DevEnv.vs2015)] - Gcc_4_9 + Clang_5_0, // needs ApplicationTypeRevision 3.0 + [DevEnvVersion(minimum = DevEnv.vs2015)] + Gcc_4_9 // needs ApplicationTypeRevision 1.0 or 2.0 or 3.0 } // This is applicable for arm architecture only From 1ee5d5b45a10184ba7dd308a0094f625ae87f1e6 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 28 Apr 2020 18:54:10 +0200 Subject: [PATCH 14/43] Remove restriction of devenv on SetAdditionalVCTargetsPath --- Sharpmake/MSBuildGlobalSettings.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Sharpmake/MSBuildGlobalSettings.cs b/Sharpmake/MSBuildGlobalSettings.cs index f2c13708e..1831e6c4f 100644 --- a/Sharpmake/MSBuildGlobalSettings.cs +++ b/Sharpmake/MSBuildGlobalSettings.cs @@ -120,9 +120,6 @@ public static void SetAdditionalVCTargetsPath(DevEnv devEnv, Platform platform, /// public static void SetAdditionalVCTargetsPath(DevEnv devEnv, string platform, string value) { - if (devEnv != DevEnv.vs2019) - throw new Error("Overriding AdditionalVCTargetsPath is not available before VS2019"); - var key = Tuple.Create(devEnv, platform); if (!string.Equals(s_additionalVCTargetsPath.GetOrAdd(key, value), value)) throw new Error("You can't register more than once an additional VC target path for a specific combinaison. Key already registered: " + key); From bd5d550ab3bab86cf80f37ee0be1ce0c88af97f7 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 28 Apr 2020 18:54:42 +0200 Subject: [PATCH 15/43] [Android] Implement toolchain and MSBuild files redirection with vs2017 --- .../AndroidPlatform.Vcxproj.Template.cs | 5 +++ .../Android/AndroidPlatform.cs | 35 +++++++++++++------ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs index f434d9a62..f50d2cdaf 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs @@ -30,6 +30,10 @@ public sealed partial class AndroidPlatform [ndkRoot] "; + private const string _projectPlatformDefaultPropsPath = + @" <_PlatformDefaultPropsPath>$(AdditionalVCTargetsPath)Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Platforms\$(Platform)\Platform.Default.props +"; + private const string _projectImportAppTypeProps = @" @@ -38,6 +42,7 @@ public sealed partial class AndroidPlatform // Workaround for app type props not overridable Microsoft.Cpp.Default.props private const string _postImportAppTypeProps = @" + <_PlatformFolder>[platformFolderOverride] <_ApplicationTypeDefaultPropsFound>true <_ApplicationTypeRevisionDefaultPropsFound>true diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index c0abd5017..20e2c6682 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -126,20 +126,24 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati { switch (devEnv) { + case DevEnv.vs2017: case DevEnv.vs2019: { - // Note1: _PlatformFolder override is deprecated starting with vs2019, so we write AdditionalVCTargetsPath instead - // Note2: MSBuildGlobalSettings.SetCppPlatformFolder for vs2019 is no more the valid way to handle it. Older buildtools packages can anyway contain it, and need upgrade. - + // _PlatformFolder override is not enough for android, we need to write AdditionalVCTargetsPath instead + // Note that AdditionalVCTargetsPath is not officially supported by vs2017, but we use it for convenience and consistency if (!string.IsNullOrEmpty(MSBuildGlobalSettings.GetCppPlatformFolder(devEnv, SharpmakePlatform))) - throw new Error("SetCppPlatformFolder is not supported by VS2019 correctly: use of MSBuildGlobalSettings.SetCppPlatformFolder should be replaced by use of MSBuildGlobalSettings.SetAdditionalVCTargetsPath."); + throw new Error("SetCppPlatformFolder is not supported by AndroidPlatform correctly: use of MSBuildGlobalSettings.SetCppPlatformFolder should be replaced by use of MSBuildGlobalSettings.SetAdditionalVCTargetsPath."); - // vs2019 use AdditionalVCTargetsPath string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform); if (!string.IsNullOrEmpty(additionalVCTargetsPath)) { using (generator.Declare("additionalVCTargetsPath", Util.EnsureTrailingSeparator(additionalVCTargetsPath))) msBuildPathOverrides += generator.Resolver.Resolve(Vcxproj.Template.Project.AdditionalVCTargetsPath); + + // with vs2017, we need to set the _PlatformDefaultPropsPath property + // otherwise the Microsoft.Cpp.Default.props won't be able to find the default platform props correctly + if (devEnv == DevEnv.vs2017) + msBuildPathOverrides += _projectPlatformDefaultPropsPath; } } break; @@ -161,13 +165,15 @@ public override void GenerateProjectPlatformSdkDirectoryDescription(IVcxprojGene { base.GenerateProjectPlatformSdkDirectoryDescription(context, generator); - // in case we've set an additional vc targets path, import the props from there instead var devEnv = context.DevelopmentEnvironmentsRange.MinDevEnv; - if (context.DevelopmentEnvironmentsRange.MinDevEnv == DevEnv.vs2019) + if (devEnv == DevEnv.vs2017 || devEnv == DevEnv.vs2019) { string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform); if (!string.IsNullOrEmpty(additionalVCTargetsPath)) + { + // in case we've written an additional vc targets path, we need to set a couple of properties to avoid a warning generator.WriteVerbatim(_projectImportAppTypeProps); + } } } @@ -175,12 +181,21 @@ public override void GeneratePostDefaultPropsImport(IVcxprojGenerationContext co { base.GeneratePostDefaultPropsImport(context, generator); - // in case we've set an additional vc targets path, import the props from there instead + // in case we've set an additional vc targets path, we need to do some cleanups var devEnv = context.DevelopmentEnvironmentsRange.MinDevEnv; - if (context.DevelopmentEnvironmentsRange.MinDevEnv == DevEnv.vs2019) + if (devEnv == DevEnv.vs2017 || devEnv == DevEnv.vs2019) { if (!string.IsNullOrEmpty(MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform))) - generator.WriteVerbatim(_postImportAppTypeProps); + { + // with vs2017, we also need to set the _PlatformFolder correctly since it won't have + // the correct value after the Microsoft.Cpp.Default.props import + string platformFolderOverride = RemoveLineTag; + if (devEnv == DevEnv.vs2017) + platformFolderOverride = @"$(AdditionalVCTargetsPath)Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Platforms\$(Platform)\"; + + using (generator.Declare("platformFolderOverride", platformFolderOverride)) + generator.Write(_postImportAppTypeProps); + } } } From 972b9e9437f16954a748538b02b4b49d86fab6fb Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 28 Apr 2020 19:27:34 +0200 Subject: [PATCH 16/43] Formatting and license headers. --- .../VisualStudio/VsProjCommon.Template.cs | 16 +++++++++++++++- .../VisualStudio/VsProjCommon.cs | 16 +++++++++++++++- Sharpmake.Generators/VisualStudio/VsUtil.cs | 16 +++++++++++++++- .../Android/AndroidPlatform.cs | 14 +++++++------- Sharpmake/Options.cs | 5 +++-- 5 files changed, 55 insertions(+), 12 deletions(-) diff --git a/Sharpmake.Generators/VisualStudio/VsProjCommon.Template.cs b/Sharpmake.Generators/VisualStudio/VsProjCommon.Template.cs index 2e6056e46..537141a9d 100644 --- a/Sharpmake.Generators/VisualStudio/VsProjCommon.Template.cs +++ b/Sharpmake.Generators/VisualStudio/VsProjCommon.Template.cs @@ -1,4 +1,18 @@ -using System; +// Copyright (c) 2017 Ubisoft Entertainment +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/Sharpmake.Generators/VisualStudio/VsProjCommon.cs b/Sharpmake.Generators/VisualStudio/VsProjCommon.cs index bec9ba273..3afcf3edb 100644 --- a/Sharpmake.Generators/VisualStudio/VsProjCommon.cs +++ b/Sharpmake.Generators/VisualStudio/VsProjCommon.cs @@ -1,4 +1,18 @@ -using System; +// Copyright (c) 2017 Ubisoft Entertainment +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/Sharpmake.Generators/VisualStudio/VsUtil.cs b/Sharpmake.Generators/VisualStudio/VsUtil.cs index 12b360910..6ec2ba595 100644 --- a/Sharpmake.Generators/VisualStudio/VsUtil.cs +++ b/Sharpmake.Generators/VisualStudio/VsUtil.cs @@ -1,4 +1,18 @@ -using System; +// Copyright (c) 2017 Ubisoft Entertainment +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index 20e2c6682..8fbeb6bd9 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -110,10 +110,10 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati generator.Write(_projectStartPlatformConditional); using (generator.Declare("applicationTypeRevision", Options.GetOptionValue("applicationTypeRevision", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("androidHome", Options.GetOptionValue("androidHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("antHome", Options.GetOptionValue("antHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("javaHome", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("ndkRoot", Options.GetOptionValue("ndkRoot", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("androidHome", Options.GetOptionValue("androidHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("antHome", Options.GetOptionValue("antHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("javaHome", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("ndkRoot", Options.GetOptionValue("ndkRoot", context.ProjectConfigurationOptions.Values))) { generator.Write(_projectDescriptionPlatformSpecific); } @@ -231,9 +231,9 @@ public override void SetupSdkOptions(IGenerationContext context) var options = context.Options; options["androidHome"] = Options.PathOption.Get(conf, GlobalSettings.AndroidHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); - options["antHome"] = Options.PathOption.Get (conf, GlobalSettings.AntHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); - options["javaHome"] = Options.PathOption.Get (conf, GlobalSettings.JavaHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); - options["ndkRoot"] = Options.PathOption.Get (conf, GlobalSettings.NdkRoot ?? RemoveLineTag, context.ProjectDirectoryCapitalized); + options["antHome"] = Options.PathOption.Get(conf, GlobalSettings.AntHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); + options["javaHome"] = Options.PathOption.Get(conf, GlobalSettings.JavaHome ?? RemoveLineTag, context.ProjectDirectoryCapitalized); + options["ndkRoot"] = Options.PathOption.Get(conf, GlobalSettings.NdkRoot ?? RemoveLineTag, context.ProjectDirectoryCapitalized); options["applicationTypeRevision"] = Options.StringOption.Get(conf); } diff --git a/Sharpmake/Options.cs b/Sharpmake/Options.cs index 7a4c65728..b744f5ef1 100644 --- a/Sharpmake/Options.cs +++ b/Sharpmake/Options.cs @@ -162,9 +162,10 @@ public static string GetConfOption(IEnumerable configu /// The list of dictionaries to look into. /// Optional: Fallback value to return in case none of the dictionaries have the key. /// - public static string GetOptionValue(string key, IEnumerable> dictionaries, string fallback = RemoveLineTag) + public static string GetOptionValue(string key, IEnumerable> dictionaries, string fallback = RemoveLineTag) { - var values = dictionaries.Select(dict => { + var values = dictionaries.Select(dict => + { string value; return dict.TryGetValue(key, out value) ? value : fallback; }).Distinct().ToList(); From 9eda732d827ec9fe343c7286c1c5ced8daad377c Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 28 Apr 2020 21:44:39 +0200 Subject: [PATCH 17/43] [Androidproj] Implement ShowAndroidPathVerbosity option --- Sharpmake.Generators/VisualStudio/Androidproj.Template.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs b/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs index ab5a5238d..3bb04ecf6 100644 --- a/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs +++ b/Sharpmake.Generators/VisualStudio/Androidproj.Template.cs @@ -65,6 +65,7 @@ public static class Project $(ProjectDir)[options.OutputDirectory]\ [options.IntermediateDirectory]\ [options.OutputFile] + [options.ShowAndroidPathsVerbosity] "; From 9d4b19529ed0a13e8a834a2c21be1951498444ca Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 28 Apr 2020 21:46:47 +0200 Subject: [PATCH 18/43] [Android] Add a Default option in ShowAndroidPathsVerbosity, which will use whatever msbuild has as default, and use it as default --- .../Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs | 1 + Sharpmake/Options.Android.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index 8fbeb6bd9..0e8525cd7 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -248,6 +248,7 @@ public override void SelectCompilerOptions(IGenerationContext context) context.SelectOption ( + Options.Option(Options.Android.General.ShowAndroidPathsVerbosity.Default, () => { options["ShowAndroidPathsVerbosity"] = RemoveLineTag; }), Options.Option(Options.Android.General.ShowAndroidPathsVerbosity.High, () => { options["ShowAndroidPathsVerbosity"] = "High"; }), Options.Option(Options.Android.General.ShowAndroidPathsVerbosity.Normal, () => { options["ShowAndroidPathsVerbosity"] = "Normal"; }), Options.Option(Options.Android.General.ShowAndroidPathsVerbosity.Low, () => { options["ShowAndroidPathsVerbosity"] = "Low"; }) diff --git a/Sharpmake/Options.Android.cs b/Sharpmake/Options.Android.cs index 080ecbe7f..e5151b007 100644 --- a/Sharpmake/Options.Android.cs +++ b/Sharpmake/Options.Android.cs @@ -89,9 +89,10 @@ public ApplicationTypeRevision(string revision) /// public enum ShowAndroidPathsVerbosity { + [Default] + Default, High, Normal, - [Default] Low } From 6d738ee8811035a32192fe7e6847942d0b91f393 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Wed, 29 Apr 2020 21:18:00 +0200 Subject: [PATCH 19/43] [Android] Change the way we do the override of MSBuild files with vs2017, in some cases the files from the local VS install were still used --- .../AndroidPlatform.Vcxproj.Template.cs | 7 +-- .../Android/AndroidPlatform.cs | 53 ++++++++++--------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs index f50d2cdaf..164590324 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.Vcxproj.Template.cs @@ -22,7 +22,7 @@ public sealed partial class AndroidPlatform "; private const string _projectDescriptionPlatformSpecific = -@" Android +@" [applicationType] [applicationTypeRevision] [androidHome] [antHome] @@ -31,7 +31,9 @@ public sealed partial class AndroidPlatform "; private const string _projectPlatformDefaultPropsPath = - @" <_PlatformDefaultPropsPath>$(AdditionalVCTargetsPath)Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Platforms\$(Platform)\Platform.Default.props + @" <_PlatformFolder>$(AdditionalVCTargetsPath)Application Type\Android\[applicationTypeRevision]\Platforms\$(Platform)\ + <_ApplicationTypeDefaultPropsPath>$(AdditionalVCTargetsPath)Application Type\Android\Default.props + <_ApplicationTypeRevisionDefaultPropsPath>$(AdditionalVCTargetsPath)Application Type\Android\[applicationTypeRevision]\Default.props "; private const string _projectImportAppTypeProps = @@ -42,7 +44,6 @@ public sealed partial class AndroidPlatform // Workaround for app type props not overridable Microsoft.Cpp.Default.props private const string _postImportAppTypeProps = @" - <_PlatformFolder>[platformFolderOverride] <_ApplicationTypeDefaultPropsFound>true <_ApplicationTypeRevisionDefaultPropsFound>true diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index 0e8525cd7..008ec561b 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -109,14 +109,8 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati { generator.Write(_projectStartPlatformConditional); - using (generator.Declare("applicationTypeRevision", Options.GetOptionValue("applicationTypeRevision", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("androidHome", Options.GetOptionValue("androidHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("antHome", Options.GetOptionValue("antHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("javaHome", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) - using (generator.Declare("ndkRoot", Options.GetOptionValue("ndkRoot", context.ProjectConfigurationOptions.Values))) - { - generator.Write(_projectDescriptionPlatformSpecific); - } + string applicationType = "Android"; + string applicationTypeRevision = Options.GetOptionValue("applicationTypeRevision", context.ProjectConfigurationOptions.Values); string msBuildPathOverrides = string.Empty; @@ -129,8 +123,8 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati case DevEnv.vs2017: case DevEnv.vs2019: { - // _PlatformFolder override is not enough for android, we need to write AdditionalVCTargetsPath instead - // Note that AdditionalVCTargetsPath is not officially supported by vs2017, but we use it for convenience and consistency + // _PlatformFolder override is not enough for android, we need to know the AdditionalVCTargetsPath + // Note that AdditionalVCTargetsPath is not officially supported by vs2017, but we use the variable anyway for convenience and consistency if (!string.IsNullOrEmpty(MSBuildGlobalSettings.GetCppPlatformFolder(devEnv, SharpmakePlatform))) throw new Error("SetCppPlatformFolder is not supported by AndroidPlatform correctly: use of MSBuildGlobalSettings.SetCppPlatformFolder should be replaced by use of MSBuildGlobalSettings.SetAdditionalVCTargetsPath."); @@ -143,13 +137,32 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati // with vs2017, we need to set the _PlatformDefaultPropsPath property // otherwise the Microsoft.Cpp.Default.props won't be able to find the default platform props correctly if (devEnv == DevEnv.vs2017) - msBuildPathOverrides += _projectPlatformDefaultPropsPath; + { + using (generator.Declare("applicationTypeRevision", applicationTypeRevision)) + msBuildPathOverrides += generator.Resolver.Resolve(_projectPlatformDefaultPropsPath); + + // application type and revisions need to be cleared otherwise + // the inclusion of the cpp default props will use the files from + // the local vs installation and not the redirected one.. + applicationType = RemoveLineTag; + applicationTypeRevision = RemoveLineTag; + } } } break; } } + using (generator.Declare("applicationType", applicationType)) + using (generator.Declare("applicationTypeRevision", applicationTypeRevision)) + using (generator.Declare("androidHome", Options.GetOptionValue("androidHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("antHome", Options.GetOptionValue("antHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("javaHome", Options.GetOptionValue("javaHome", context.ProjectConfigurationOptions.Values))) + using (generator.Declare("ndkRoot", Options.GetOptionValue("ndkRoot", context.ProjectConfigurationOptions.Values))) + { + generator.Write(_projectDescriptionPlatformSpecific); + } + if (!string.IsNullOrEmpty(msBuildPathOverrides)) { if (context.DevelopmentEnvironmentsRange.MinDevEnv != context.DevelopmentEnvironmentsRange.MaxDevEnv) @@ -166,14 +179,11 @@ public override void GenerateProjectPlatformSdkDirectoryDescription(IVcxprojGene base.GenerateProjectPlatformSdkDirectoryDescription(context, generator); var devEnv = context.DevelopmentEnvironmentsRange.MinDevEnv; - if (devEnv == DevEnv.vs2017 || devEnv == DevEnv.vs2019) + if (devEnv == DevEnv.vs2019) { string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform); if (!string.IsNullOrEmpty(additionalVCTargetsPath)) - { - // in case we've written an additional vc targets path, we need to set a couple of properties to avoid a warning generator.WriteVerbatim(_projectImportAppTypeProps); - } } } @@ -181,21 +191,12 @@ public override void GeneratePostDefaultPropsImport(IVcxprojGenerationContext co { base.GeneratePostDefaultPropsImport(context, generator); - // in case we've set an additional vc targets path, we need to do some cleanups var devEnv = context.DevelopmentEnvironmentsRange.MinDevEnv; if (devEnv == DevEnv.vs2017 || devEnv == DevEnv.vs2019) { + // in case we've written an additional vc targets path, we need to set a couple of properties to avoid a warning if (!string.IsNullOrEmpty(MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform))) - { - // with vs2017, we also need to set the _PlatformFolder correctly since it won't have - // the correct value after the Microsoft.Cpp.Default.props import - string platformFolderOverride = RemoveLineTag; - if (devEnv == DevEnv.vs2017) - platformFolderOverride = @"$(AdditionalVCTargetsPath)Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Platforms\$(Platform)\"; - - using (generator.Declare("platformFolderOverride", platformFolderOverride)) - generator.Write(_postImportAppTypeProps); - } + generator.WriteVerbatim(_postImportAppTypeProps); } } From 193e64505800dc50a5c91b11b63a1e48cd0fc2da Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Thu, 30 Apr 2020 11:12:00 +0200 Subject: [PATCH 20/43] [Android] Add "Latest" to the AndroidAPILevel option, that will allow sharpmake to auto-detect and set the latest api level found Note that the SDK and/or NDK path must have been set for it to work. If none is found, it will reset to default. --- .../Android/AndroidPlatform.cs | 25 ++++++- .../Sharpmake.CommonPlatforms/Android/Util.cs | 66 +++++++++++++++++++ .../Sharpmake.CommonPlatforms.csproj | 1 + Sharpmake/Options.Android.cs | 1 + 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/Util.cs diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index 008ec561b..f8b505be6 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -14,6 +14,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using Sharpmake.Generators; using Sharpmake.Generators.VisualStudio; @@ -131,7 +132,7 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, SharpmakePlatform); if (!string.IsNullOrEmpty(additionalVCTargetsPath)) { - using (generator.Declare("additionalVCTargetsPath", Util.EnsureTrailingSeparator(additionalVCTargetsPath))) + using (generator.Declare("additionalVCTargetsPath", Sharpmake.Util.EnsureTrailingSeparator(additionalVCTargetsPath))) msBuildPathOverrides += generator.Resolver.Resolve(Vcxproj.Template.Project.AdditionalVCTargetsPath); // with vs2017, we need to set the _PlatformDefaultPropsPath property @@ -257,6 +258,28 @@ public override void SelectCompilerOptions(IGenerationContext context) context.SelectOption ( + Options.Option(Options.Android.General.AndroidAPILevel.Latest, () => { + string lookupDirectory; + if (context.Project is AndroidPackageProject) + { + // for the packaging projects, we look in the SDK + lookupDirectory = options["androidHome"]; + } + else + { + // otherwise, look in the NDK + lookupDirectory = options["ndkRoot"]; + } + + string androidApiLevel = RemoveLineTag; + if (lookupDirectory != RemoveLineTag) + { + string latestApiLevel = Util.FindLatestApiLevelInDirectory(Path.Combine(lookupDirectory, "platforms")); + if (!string.IsNullOrEmpty(latestApiLevel)) + androidApiLevel = latestApiLevel; + } + options["AndroidAPILevel"] = androidApiLevel; + }), Options.Option(Options.Android.General.AndroidAPILevel.Default, () => { options["AndroidAPILevel"] = RemoveLineTag; }), Options.Option(Options.Android.General.AndroidAPILevel.Android16, () => { options["AndroidAPILevel"] = "android-16"; }), Options.Option(Options.Android.General.AndroidAPILevel.Android17, () => { options["AndroidAPILevel"] = "android-17"; }), diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/Util.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/Util.cs new file mode 100644 index 000000000..8fc19d458 --- /dev/null +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/Util.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2017 Ubisoft Entertainment +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +using System.IO; +using System.Linq; + +namespace Sharpmake +{ + public static partial class Android + { + internal static class Util + { + // will find folders named after the platform api level, + // following this pattern: android-XX, with XX being 2 digits + public static string FindLatestApiLevelInDirectory(string directory) + { + string latestDirectory = null; + if (Directory.Exists(directory)) + { + var androidDirectories = Sharpmake.Util.DirectoryGetDirectories(directory); + int latestValue = 0; + foreach (var folderName in androidDirectories.Select(Path.GetFileName)) + { + int current = 0; + if (TryParseAndroidApiValue(folderName, out current)) + { + if (current > latestValue) + { + latestValue = current; + latestDirectory = folderName; + } + } + } + } + + return latestDirectory; + } + + public static bool TryParseAndroidApiValue(string apiString, out int apiValue) + { + apiValue = 0; + if (string.IsNullOrWhiteSpace(apiString)) + return false; + + const int devKitEditionTargetExpectedLength = 10; + if (apiString.Length != devKitEditionTargetExpectedLength) + return false; + + // skip 'android-' + string valueString = apiString.Substring(8); + + return int.TryParse(valueString, out apiValue); + } + } + } +} diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj index 005575dc9..4778bad45 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj @@ -57,6 +57,7 @@ + diff --git a/Sharpmake/Options.Android.cs b/Sharpmake/Options.Android.cs index e5151b007..145cda361 100644 --- a/Sharpmake/Options.Android.cs +++ b/Sharpmake/Options.Android.cs @@ -100,6 +100,7 @@ public enum AndroidAPILevel { [Default] Default, + Latest, // sharpmake will try and auto-detect the latest installed, or fallback to default: note that the SDK/NDK paths are needed Android16, // Jelly Bean 4.1.x Android17, // Jelly Bean 4.2.x Android18, // Jelly Bean 4.3.x From 7d1091a23822edc6de42194f7acae210a1010c25 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Thu, 30 Apr 2020 13:11:09 +0200 Subject: [PATCH 21/43] [Android] Change default Stl lib to libc++_shared https://developer.android.com/ndk/guides/standalone_toolchain#c_stl_support --- Sharpmake/Options.Android.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sharpmake/Options.Android.cs b/Sharpmake/Options.Android.cs index 145cda361..e43c15da8 100644 --- a/Sharpmake/Options.Android.cs +++ b/Sharpmake/Options.Android.cs @@ -144,7 +144,6 @@ public enum ThumbMode public enum UseOfStl { - [Default] Default, System, GAbiPP_Static, @@ -154,6 +153,7 @@ public enum UseOfStl GnuStl_Static, GnuStl_Shared, LibCpp_Static, + [Default] LibCpp_Shared } From 37203f7d82243eb55795521251e63997e0a17a0d Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Thu, 30 Apr 2020 13:13:01 +0200 Subject: [PATCH 22/43] - Add a HasPrecomp method in IPlatformVcxproj, since not all platforms need to have a PrecompSource to activate pch - Implement it on android so it doesn't check PrecompSource --- Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs | 2 ++ .../VisualStudio/ProjectOptionsGenerator.cs | 2 +- Sharpmake.Generators/VisualStudio/Vcxproj.cs | 10 ++++++---- .../Android/AndroidPlatform.cs | 5 +++++ .../Sharpmake.CommonPlatforms/BasePlatform.cs | 6 ++++++ 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs b/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs index 0a000012b..2d66fd6a9 100644 --- a/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs @@ -71,6 +71,8 @@ public interface IPlatformVcxproj void SelectApplicationFormatOptions(IGenerationContext context); void SelectBuildType(IGenerationContext context); + bool HasPrecomp(IGenerationContext context); + void GenerateSdkVcxproj(IVcxprojGenerationContext context, IFileGenerator generator); void GenerateMakefileConfigurationVcxproj(IVcxprojGenerationContext context, IFileGenerator generator); void GenerateProjectCompileVcxproj(IVcxprojGenerationContext context, IFileGenerator generator); diff --git a/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs b/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs index 699cc1b0b..747cddd21 100644 --- a/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs +++ b/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs @@ -1137,7 +1137,7 @@ private static void SelectPlatformToolsetOption(IGenerationContext context, Proj private static void SelectPrecompiledHeaderOption(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) { - if (string.IsNullOrEmpty(context.Configuration.PrecompHeader) || string.IsNullOrEmpty(context.Configuration.PrecompSource)) + if (!optionsContext.PlatformVcxproj.HasPrecomp(context)) { context.Options["UsePrecompiledHeader"] = "NotUsing"; context.Options["PrecompiledHeaderThrough"] = FileGeneratorUtilities.RemoveLineTag; diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.cs index 4494c90e3..585d0a1de 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.cs @@ -1221,7 +1221,7 @@ IList skipFiles } private void GenerateFilesSection( - IVcxprojGenerationContext context, + GenerationContext context, IFileGenerator fileGenerator, IList generatedFiles, IList skipFiles @@ -1513,9 +1513,12 @@ IList skipFiles for (int i = 0; i < context.ProjectConfigurations.Count; ++i) { Project.Configuration conf = context.ProjectConfigurations[i]; + context.Configuration = conf; + var platformVcxproj = context.PresentPlatforms[conf.Platform]; + var compiledFiles = configurationCompiledFiles[i]; - bool hasPrecomp = !string.IsNullOrEmpty(conf.PrecompSource) && !string.IsNullOrEmpty(conf.PrecompHeader); + bool hasPrecomp = platformVcxproj.HasPrecomp(context); bool isPrecompSource = !string.IsNullOrEmpty(conf.PrecompSource) && file.FileName.EndsWith(conf.PrecompSource, StringComparison.OrdinalIgnoreCase); bool isDontUsePrecomp = conf.PrecompSourceExclude.Contains(file.FileName) || conf.PrecompSourceExcludeFolders.Any(folder => file.FileName.StartsWith(folder, StringComparison.OrdinalIgnoreCase)) || @@ -1534,7 +1537,6 @@ IList skipFiles bool objsInSubdirectories = conf.ObjectFileName != null && !isResource; bool isExcludeFromGenerateXmlDocumentation = conf.ResolvedSourceFilesGenerateXmlDocumentationExclude.Contains(file.FileName); - var platformVcxproj = context.PresentPlatforms[conf.Platform]; if (isPrecompSource && platformVcxproj.ExcludesPrecompiledHeadersFromBuild) isExcludeFromBuild = true; if (!isExcludeFromBuild && !isResource) @@ -1542,7 +1544,7 @@ IList skipFiles if (isCompileAsCLRFile || consumeWinRTExtensions || excludeWinRTExtensions) isDontUsePrecomp = true; - if (String.Compare(file.FileExtension, ".c", StringComparison.OrdinalIgnoreCase) == 0) + if (string.Compare(file.FileExtension, ".c", StringComparison.OrdinalIgnoreCase) == 0) isDontUsePrecomp = true; string exceptionSetting = null; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index f8b505be6..6cb3ad07d 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -507,6 +507,11 @@ public override IEnumerable GetLibraryPaths(IGenerationContext context) return dirs; } + public override bool HasPrecomp(IGenerationContext context) + { + return !string.IsNullOrEmpty(context.Configuration.PrecompHeader); + } + #endregion // IPlatformVcxproj implementation } } diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs index 9afaf57eb..d097d742d 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs @@ -201,6 +201,12 @@ public virtual void SelectBuildType(IGenerationContext context) { } + public virtual bool HasPrecomp(IGenerationContext context) + { + Project.Configuration conf = context.Configuration; + return !string.IsNullOrEmpty(conf.PrecompSource) && !string.IsNullOrEmpty(conf.PrecompHeader); + } + public virtual void GenerateSdkVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) { } From 0d8c0a0be4743bd285fad3d84e7e92ce1a82c9ad Mon Sep 17 00:00:00 2001 From: Christian Corsano Date: Sat, 2 May 2020 12:43:30 +0200 Subject: [PATCH 23/43] Make sure JSON float serialization is culture invariant --- Sharpmake.UnitTests/JsonSerializerTest.cs | 13 +++++++++++++ Sharpmake/Util.cs | 22 ++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Sharpmake.UnitTests/JsonSerializerTest.cs b/Sharpmake.UnitTests/JsonSerializerTest.cs index a89822ba7..500ed373a 100644 --- a/Sharpmake.UnitTests/JsonSerializerTest.cs +++ b/Sharpmake.UnitTests/JsonSerializerTest.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using NUnit.Framework; +using System.Globalization; namespace Sharpmake.UnitTests { @@ -107,6 +108,18 @@ public void SerializeNegativeDouble() Assert.That(_writer.ToString(), Is.EqualTo("-13.37")); } + [Test] + public void FloatSerializationIsNotCultureDependent() + { + // Change culture to a non-json compatible format + CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("da-DK"); + // As illustration + Assert.That((-13.37).ToString(), Is.EqualTo("-13,37")); + + _serializer.Serialize(-13.37); + Assert.That(_writer.ToString(), Is.EqualTo("-13.37")); + } + [Test] public void SerializeTrue() { diff --git a/Sharpmake/Util.cs b/Sharpmake/Util.cs index c59585af5..dc304c282 100644 --- a/Sharpmake/Util.cs +++ b/Sharpmake/Util.cs @@ -16,6 +16,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -1473,10 +1474,14 @@ public static string EscapeJson(string value, bool quote = false, string nullVal return sb.ToString(); } - private static bool IsNumber(object o) + private static bool IsFloat(object o) { - return o is float || o is double || o is decimal || - o is sbyte || o is short || o is int || o is long || + return o is float || o is double || o is decimal; + } + + private static bool IsInteger(object o) + { + return o is sbyte || o is short || o is int || o is long || o is byte || o is ushort || o is uint || o is ulong; } @@ -1522,7 +1527,16 @@ public void Serialize(object value) { SerializeArray((IEnumerable)value); } - else if (value is bool || IsNumber(value)) + else if (value is bool) + { + _writer.Write(value.ToString().ToLower()); + } + else if (IsFloat(value)) + { + // This *should* be safe without Escaping + _writer.Write(Convert.ToDouble(value).ToString(CultureInfo.InvariantCulture)); + } + else if (IsInteger(value)) { // This *should* be safe without Escaping _writer.Write(EscapeJson(value.ToString().ToLower())); From c5962a5c40609c55e2950f09be94b82afa0811c6 Mon Sep 17 00:00:00 2001 From: guiguibubu Date: Sun, 10 May 2020 16:26:35 -0400 Subject: [PATCH 24/43] Suppress Pause in scripts for both Platforms (risky for CI) --- bootstrap.bat | 1 - 1 file changed, 1 deletion(-) diff --git a/bootstrap.bat b/bootstrap.bat index aa18f3f07..ab1013e02 100644 --- a/bootstrap.bat +++ b/bootstrap.bat @@ -30,7 +30,6 @@ goto end :error COLOR 4F echo Bootstrap failed^! -pause set ERROR_CODE=1 goto end From 7bc09506e01aff0658479b12c8e95f87c00b04be Mon Sep 17 00:00:00 2001 From: guiguibubu Date: Sat, 9 May 2020 17:13:21 -0400 Subject: [PATCH 25/43] Add Compile Sharpmake script for MacOS - adapt Bootstrapper by calling CompileSharpmake script - make Compile script as executable - adapt CI with new script for MacOS --- .appveyor.yml | 2 +- CompileSharpmake.sh | 40 +++++++++++++++++++++++++++++++++++++++ bootstrap.sh | 46 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 78 insertions(+), 10 deletions(-) create mode 100755 CompileSharpmake.sh diff --git a/.appveyor.yml b/.appveyor.yml index a4975721f..7574a455f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -21,7 +21,7 @@ before_build: build_script: - cmd: CompileSharpmake.bat Sharpmake.sln "%CONFIGURATION%" "%PLATFORM%" - - sh: msbuild -t:build -restore Sharpmake.sln /p:Configuration=\"$CONFIGURATION\" /p:Platform=\"$PLATFORM\" /nologo /v:m + - sh: ./CompileSharpmake.sh Sharpmake.sln "${CONFIGURATION}" "${PLATFORM}" test: assemblies: diff --git a/CompileSharpmake.sh b/CompileSharpmake.sh new file mode 100755 index 000000000..2420ff9a0 --- /dev/null +++ b/CompileSharpmake.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# Script arguments: +# $1: Project/Solution to build +# $2: Target(Normally should be Debug or Release) +# $3: Platform(Normally should be "Any CPU" for sln and AnyCPU for a csproj) +# if none are passed, defaults to building Sharpmake.sln in Debug|Any CPU + +function BuildSharpmake { + solutionPath=$1 + configuration=$2 + platform=$3 + echo Compiling $solutionPath in "${configuration}|${platform}"... + MSBUILD_CMD="msbuild -t:build -restore \"${solutionPath}\" /nologo /v:m /p:Configuration=${configuration} /p:Platform=\"${platform}\"" + echo $MSBUILD_CMD + eval $MSBUILD_CMD + if [ $? -ne 0 ]; then + echo ERROR: Failed to compile $solutionPath in "${configuration}|${platform}". + exit 1 + fi +} + +# fail immediately if anything goes wrong +set -e + +pushd $(dirname $0) > /dev/null +CURRENT_DIR=$(pwd) +popd > /dev/null + +which msbuild > /dev/null +MSBUILD_FOUND=$? +if [ $MSBUILD_FOUND -ne 0 ]; then + echo "MSBuild not found" + exit $MSBUILD_FOUND +fi + +SOLUTION_PATH=${1:-"${CURRENT_DIR}/Sharpmake.sln"} +CONFIGURATION=${2:-"Debug"} +PLATFORM=${3:-"Any CPU"} + +BuildSharpmake "$SOLUTION_PATH" "$CONFIGURATION" "$PLATFORM" diff --git a/bootstrap.sh b/bootstrap.sh index f7fd65d7d..210829ac4 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,26 +1,54 @@ #!/bin/sh +function success { + echo Bootstrap succeeded \! + exit 0 +} + +function error { + echo Bootstrap failed \! + exit 1 +} + # fail immediately if anything goes wrong set -e +pushd $(dirname $0) > /dev/null +CURRENT_DIR=$(pwd) +popd > /dev/null + +which msbuild > /dev/null +MSBUILD_FOUND=$? +if [ $MSBUILD_FOUND -ne 0 ]; then + echo "MSBuild not found" + error +fi + # workaround for https://github.com/mono/mono/issues/6752 TERM=xterm -# TODO: Test mono and msbuild existence -SHARPMAKE_EXECUTABLE=$PWD/bin/debug/Sharpmake.Application.exe - -SM_CMD="msbuild -t:build -restore /p:Configuration=Debug /p:Platform="AnyCPU" /v:m Sharpmake.Application/Sharpmake.Application.csproj" -echo "Building Sharpmake..." -echo $SM_CMD -eval $SM_CMD +SHARPMAKE_EXECUTABLE=$CURRENT_DIR/bin/debug/Sharpmake.Application.exe +$CURRENT_DIR/CompileSharpmake.sh Sharpmake.Application/Sharpmake.Application.csproj Debug AnyCPU if [ $? -ne 0 ]; then echo "The build has failed." if [ -f $SHARPMAKE_EXECUTABLE ]; then - echo "A previously built sharpmake exe was found at '$SHARPMAKE_EXECUTABLE', it will be reused." + echo "A previously built sharpmake exe was found at '${SHARPMAKE_EXECUTABLE}', it will be reused." fi fi +which mono > /dev/null +MONO_FOUND=$? +if [ $MONO_FOUND -ne 0 ]; then + echo "Mono not found" + error +fi + +SHARPMAKE_MAIN=${1:-"$CURRENT_DIR/Sharpmake.Main.sharpmake.cs"} + echo "Generating Sharpmake solution..." -mono --debug $SHARPMAKE_EXECUTABLE "/sources(\"Sharpmake.Main.sharpmake.cs\")" /verbose +SM_CMD="mono --debug \"${SHARPMAKE_EXECUTABLE}\" \"/sources(\\\"${SHARPMAKE_MAIN}\\\")\" /verbose" +echo $SM_CMD +eval $SM_CMD || error +success From 7465fdf42cb3558ca2a093457991609b0bd0d87c Mon Sep 17 00:00:00 2001 From: Colin Brady Date: Thu, 14 May 2020 07:52:24 -0400 Subject: [PATCH 26/43] Fixed discrepancy in how Sharpmake determines which projects to build between single and multithreaded modes (#76) This led to cases where certain necessary projects were not being generated in multithreaded mode, leading to build failures _buildScheduledType now acts as an accumulator of all project types to be generated, the contents of which is then added to Arguments.TypesToGenerate at the end of BuildProjectAndSolution Co-authored-by: Colin Brady --- Sharpmake/Builder.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Sharpmake/Builder.cs b/Sharpmake/Builder.cs index b7c1cba4f..51bce0d79 100644 --- a/Sharpmake/Builder.cs +++ b/Sharpmake/Builder.cs @@ -279,15 +279,12 @@ public void BuildProjectAndSolution() foreach (Type projectDependenciesType in projectDependenciesTypes) { - if (!Arguments.TypesToGenerate.Contains(projectDependenciesType)) - Arguments.TypesToGenerate.Add(projectDependenciesType); + _buildScheduledType.Add(projectDependenciesType); } } } else { - _buildScheduledType.UnionWith(Arguments.TypesToGenerate); - foreach (Type type in Arguments.TypesToGenerate) { _tasks.AddTask(BuildProjectAndSolutionTask, type, type.BaseType == typeof(Project) ? ThreadPool.Priority.Low : ThreadPool.Priority.High); @@ -295,6 +292,8 @@ public void BuildProjectAndSolution() _tasks.Wait(); } + + Arguments.TypesToGenerate.AddRange(_buildScheduledType); } } From b446d69f64ba6380e5745e6a61c37793930ec731 Mon Sep 17 00:00:00 2001 From: David Knott Date: Thu, 14 May 2020 18:42:57 -0400 Subject: [PATCH 27/43] Add support for Windows SDK 10.0.19041.0 --- Sharpmake/ExtensionMethods.cs | 1 + Sharpmake/Options.Vc.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Sharpmake/ExtensionMethods.cs b/Sharpmake/ExtensionMethods.cs index 00412a35c..e83f57dd4 100644 --- a/Sharpmake/ExtensionMethods.cs +++ b/Sharpmake/ExtensionMethods.cs @@ -610,6 +610,7 @@ public static string ToVersionString(this Options.Vc.General.WindowsTargetPlatfo case Options.Vc.General.WindowsTargetPlatformVersion.v10_0_17134_0: return "10.0.17134.0"; case Options.Vc.General.WindowsTargetPlatformVersion.v10_0_17763_0: return "10.0.17763.0"; case Options.Vc.General.WindowsTargetPlatformVersion.v10_0_18362_0: return "10.0.18362.0"; + case Options.Vc.General.WindowsTargetPlatformVersion.v10_0_19041_0: return "10.0.19041.0"; case Options.Vc.General.WindowsTargetPlatformVersion.Latest: return "$(LatestTargetPlatformVersion)"; default: throw new ArgumentOutOfRangeException(windowsTargetPlatformVersion.ToString()); diff --git a/Sharpmake/Options.Vc.cs b/Sharpmake/Options.Vc.cs index 9acc73393..953fbeecc 100644 --- a/Sharpmake/Options.Vc.cs +++ b/Sharpmake/Options.Vc.cs @@ -64,6 +64,7 @@ public enum WindowsTargetPlatformVersion v10_0_17134_0, // 1803, April 2018 Update v10_0_17763_0, // 1809, October 2018 Update v10_0_18362_0, // 1903, May 2019 Update + v10_0_19041_0, // 2004, May 2020 Update Latest, // latest available in host machine } From 8c5605ff55c701cea7b7731b6336194eec103a8b Mon Sep 17 00:00:00 2001 From: Benjamin Couratin Date: Fri, 15 May 2020 09:44:44 +0000 Subject: [PATCH 28/43] Add new utility extension method `GetVisualStudioVCRedistVersion` --- Sharpmake/ExtensionMethods.cs | 45 ++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/Sharpmake/ExtensionMethods.cs b/Sharpmake/ExtensionMethods.cs index e83f57dd4..4e3b010be 100644 --- a/Sharpmake/ExtensionMethods.cs +++ b/Sharpmake/ExtensionMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Ubisoft Entertainment +// Copyright (c) 2017 Ubisoft Entertainment // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -346,6 +346,49 @@ public static Version GetVisualStudioVCToolsVersion(this DevEnv visualVersion) return version; } + private static string GetDefaultRedistVersion(this DevEnv visualVersion) + { + switch (visualVersion) + { + case DevEnv.vs2017: + return "14.16.27012"; + case DevEnv.vs2019: + return "14.24.28127"; + default: + throw new Error("DevEnv " + visualVersion + " not recognized for default compiler version"); + } + } + + private static readonly ConcurrentDictionary s_visualStudioVCRedistVersionCache = new ConcurrentDictionary(); + public static Version GetVisualStudioVCRedistVersion(this DevEnv visualVersion) + { + Version version = s_visualStudioVCRedistVersionCache.GetOrAdd(visualVersion, devEnv => + { + string vsDir = visualVersion.GetVisualStudioDir(); + switch (visualVersion) + { + case DevEnv.vs2017: + case DevEnv.vs2019: + string versionString = visualVersion.GetDefaultRedistVersion(); // default fallback + try + { + string toolchainFile = Path.Combine(vsDir, "VC", "Auxiliary", "Build", "Microsoft.VCRedistVersion.default.txt"); + if (File.Exists(toolchainFile)) + { + using (StreamReader file = new StreamReader(toolchainFile)) + versionString = file.ReadLine().Trim(); + } + } + catch { } + + return new Version(versionString); + } + throw new ArgumentOutOfRangeException("VS version not recognized " + visualVersion); + }); + + return version; + } + public static string GetVisualStudioBinPath(this DevEnv visualVersion, Platform platform) { switch (visualVersion) From 9650cca158dcff1e11585d183b6e9c79366167fe Mon Sep 17 00:00:00 2001 From: guiguibubu Date: Sat, 16 May 2020 11:48:51 -0400 Subject: [PATCH 29/43] Replace hard coded "REMOVE_LINE_TAG" by the FileGeneratorUtility one --- Sharpmake.Generators/Apple/XCodeProj.cs | 2 +- Sharpmake.Generators/Generic/MakeProject.cs | 2 +- Sharpmake.Generators/VisualStudio/Csproj.cs | 2 +- Sharpmake.Generators/VisualStudio/ProjectJson.cs | 2 +- Sharpmake.Generators/VisualStudio/UserFile.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sharpmake.Generators/Apple/XCodeProj.cs b/Sharpmake.Generators/Apple/XCodeProj.cs index 04ae5f8a6..99f8a3995 100644 --- a/Sharpmake.Generators/Apple/XCodeProj.cs +++ b/Sharpmake.Generators/Apple/XCodeProj.cs @@ -32,7 +32,7 @@ public partial class XCodeProj : IProjectGenerator private const int ProjectArchiveVersion = 1; private const int ProjectObjectVersion = 46; - public const string RemoveLineTag = "REMOVE_LINE_TAG"; + public const string RemoveLineTag = FileGeneratorUtilities.RemoveLineTag; public static readonly char FolderSeparator; diff --git a/Sharpmake.Generators/Generic/MakeProject.cs b/Sharpmake.Generators/Generic/MakeProject.cs index 3904e03b9..349f50547 100644 --- a/Sharpmake.Generators/Generic/MakeProject.cs +++ b/Sharpmake.Generators/Generic/MakeProject.cs @@ -20,7 +20,7 @@ namespace Sharpmake.Generators.Generic public partial class MakeProject : IProjectGenerator { private const string _makefileExtension = ".mk"; - private const string RemoveLineTag = "REMOVE_LINE_TAG"; + private const string RemoveLineTag = FileGeneratorUtilities.RemoveLineTag; private Builder _builder; diff --git a/Sharpmake.Generators/VisualStudio/Csproj.cs b/Sharpmake.Generators/VisualStudio/Csproj.cs index 737d76332..8aad1de8b 100644 --- a/Sharpmake.Generators/VisualStudio/Csproj.cs +++ b/Sharpmake.Generators/VisualStudio/Csproj.cs @@ -872,7 +872,7 @@ public void Generate(Builder builder, Project project, List Path.Combine(_projectPath, "project.json"); public string ProjectJsonLockPath => Path.Combine(_projectPath, "project.lock.json"); - public const string RemoveLineTag = "REMOVE_LINE_TAG"; + public const string RemoveLineTag = FileGeneratorUtilities.RemoveLineTag; public void Generate(Builder builder, CSharpProject project, List configurations, string projectPath, List generatedFiles, List skipFiles) { diff --git a/Sharpmake.Generators/VisualStudio/UserFile.cs b/Sharpmake.Generators/VisualStudio/UserFile.cs index 3477f086e..1c1f7a11f 100644 --- a/Sharpmake.Generators/VisualStudio/UserFile.cs +++ b/Sharpmake.Generators/VisualStudio/UserFile.cs @@ -18,7 +18,7 @@ namespace Sharpmake.Generators.VisualStudio { public abstract class UserFileBase { - protected const string RemoveLineTag = "REMOVE_LINE_TAG"; + protected const string RemoveLineTag = FileGeneratorUtilities.RemoveLineTag; protected const string UserFileExtension = ".user"; private readonly string _userFilePath; From f453c3595c6bb4a28c12bc3a0d31489ec8bf6907 Mon Sep 17 00:00:00 2001 From: Benoit Rousseau Date: Mon, 4 May 2020 11:34:57 +0200 Subject: [PATCH 30/43] Adds support for whole archive in Linux. * Adds support for --whole-archive and --no-whole-archive. --- .../Sharpmake.CommonPlatforms/Linux/LinuxOptions.cs | 7 +++++++ .../Linux/LinuxPlatform.Bff.Template.cs | 6 +++++- .../Linux/LinuxPlatform.Vcxproj.Template.cs | 1 + .../Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs | 6 ++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxOptions.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxOptions.cs index a72d655eb..c733a2e81 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxOptions.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxOptions.cs @@ -205,6 +205,13 @@ public enum UseThinArchives [Default] Disable } + + public enum WholeArchive + { + Enable, + [Default] + Disable + } } } } diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Bff.Template.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Bff.Template.cs index f2c4e45f9..87182b277 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Bff.Template.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Bff.Template.cs @@ -19,7 +19,11 @@ public static partial class Linux public sealed partial class LinuxPlatform { public const string _linkerOptionsTemplate = @" - .LinkerOptions = '-o ""%2"" ""%1""[sharedOption]' + .LinkerOptions = '-o ""%2""' + + ' [cmdLineOptions.WholeArchiveBegin]' + + ' ""%1""' + + ' [cmdLineOptions.WholeArchiveEnd]' + + ' [sharedOption]' // Library Search Path // --------------------------- + ' [cmdLineOptions.AdditionalLibraryDirectories]' diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Vcxproj.Template.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Vcxproj.Template.cs index 796599773..0fdfc0302 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Vcxproj.Template.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.Vcxproj.Template.cs @@ -76,6 +76,7 @@ public sealed partial class LinuxPlatform [options.EditAndContinue] [options.InfoStripping] [options.DataStripping] + [options.WholeArchive] [options.DuplicateStripping] [options.Addressing] diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs index 671e41c20..62322ef7a 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs @@ -289,6 +289,12 @@ public override void SelectCompilerOptions(IGenerationContext context) Sharpmake.Options.Option(Options.Linker.UseThinArchives.Enable, () => { options["UseThinArchives"] = "true"; cmdLineOptions["UseThinArchives"] = "T"; }), Sharpmake.Options.Option(Options.Linker.UseThinArchives.Disable, () => { options["UseThinArchives"] = "false"; cmdLineOptions["UseThinArchives"] = ""; }) ); + + context.SelectOption + ( + Sharpmake.Options.Option(Options.Linker.WholeArchive.Enable, () => { options["WholeArchive"] = "true"; cmdLineOptions["WholeArchiveBegin"] = "--whole-archive"; cmdLineOptions["WholeArchiveEnd"] = "--no-whole-archive"; }), + Sharpmake.Options.Option(Options.Linker.WholeArchive.Disable, () => { options["WholeArchive"] = "false"; cmdLineOptions["WholeArchiveBegin"] = FileGeneratorUtilities.RemoveLineTag; cmdLineOptions["WholeArchiveEnd"] = FileGeneratorUtilities.RemoveLineTag; }) + ); } public override void SelectPlatformAdditionalDependenciesOptions(IGenerationContext context) From 49559e4f286e8ea97994f25c95ffd486cf9143bd Mon Sep 17 00:00:00 2001 From: Benoit Rousseau Date: Mon, 4 May 2020 11:52:13 +0200 Subject: [PATCH 31/43] Add a conf option to allow the generator to output full paths instead of relative paths. For now only used by the csproj generator, for output and int paths. --- Sharpmake.Generators/VisualStudio/Csproj.cs | 6 +++--- Sharpmake/Project.Configuration.cs | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Sharpmake.Generators/VisualStudio/Csproj.cs b/Sharpmake.Generators/VisualStudio/Csproj.cs index 8aad1de8b..7032163eb 100644 --- a/Sharpmake.Generators/VisualStudio/Csproj.cs +++ b/Sharpmake.Generators/VisualStudio/Csproj.cs @@ -2856,13 +2856,13 @@ private Options.ExplicitOptions GenerateOptions(CSharpProject project, Project.C break; } - string outputDirectoryRelative = Util.PathGetRelative(_projectPath, conf.TargetPath); - string outputLibDirectoryRelative = Util.PathGetRelative(_projectPath, conf.TargetLibraryPath); + string outputDirectoryRelative = conf.PreferRelativePaths ? Util.PathGetRelative(_projectPath, conf.TargetPath) : Util.PathGetAbsolute(_projectPath, conf.TargetPath); + string outputLibDirectoryRelative = conf.PreferRelativePaths ? Util.PathGetRelative(_projectPath, conf.TargetLibraryPath) : Util.PathGetAbsolute(_projectPath, conf.TargetLibraryPath); options["OutputDirectory"] = conf.Output == Project.Configuration.OutputType.Lib ? outputLibDirectoryRelative : outputDirectoryRelative; //IntermediateDirectory - string intermediateDirectory = Util.PathGetRelative(_projectPath, conf.IntermediatePath); + string intermediateDirectory = conf.PreferRelativePaths ? Util.PathGetRelative(_projectPath, conf.IntermediatePath) : Util.PathGetAbsolute(_projectPath, conf.IntermediatePath); options["IntermediateDirectory"] = intermediateDirectory; //BaseIntermediateOutputPath diff --git a/Sharpmake/Project.Configuration.cs b/Sharpmake/Project.Configuration.cs index 410a7e69c..1da1617e7 100644 --- a/Sharpmake/Project.Configuration.cs +++ b/Sharpmake/Project.Configuration.cs @@ -2166,6 +2166,11 @@ public void GeneratorSetGeneratedInformation(string executableExtension, string public Strings PRIFilesExtensions = new Strings(); + /// + /// Generate relative paths in places where it would be otherwise beneficial to use absolute paths. + /// + public bool PreferRelativePaths = true; + internal override void Construct(object owner, ITarget target) { base.Construct(owner, target); From 777ee30ba2c25af99d0cae8c2e28e576347e4220 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 5 May 2020 11:38:24 +0200 Subject: [PATCH 32/43] Fix generation of vs2019 when additionalVCTargetsPath is null --- .../Sharpmake.CommonPlatforms/Windows/Win64Platform.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs index 1d7552864..28a626647 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs @@ -459,10 +459,14 @@ public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerati if (!string.IsNullOrEmpty(MSBuildGlobalSettings.GetCppPlatformFolder(uniqueDevEnv, Platform.win64))) throw new Error("SetCppPlatformFolder is not supported by VS2019 correctly: use of MSBuildGlobalSettings.SetCppPlatformFolder should be replaced by use of MSBuildGlobalSettings.SetAdditionalVCTargetsPath."); + // vs2019 use AdditionalVCTargetsPath string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(uniqueDevEnv, Platform.win64); - using (generator.Declare("additionalVCTargetsPath", Util.EnsureTrailingSeparator(additionalVCTargetsPath))) // the path shall end with a "\" - generator.Write(Vcxproj.Template.Project.AdditionalVCTargetsPath); + if (!string.IsNullOrEmpty(additionalVCTargetsPath)) + { + using (generator.Declare("additionalVCTargetsPath", Util.EnsureTrailingSeparator(additionalVCTargetsPath))) // the path shall end with a "\" + generator.Write(Vcxproj.Template.Project.AdditionalVCTargetsPath); + } } break; default: From f87609bb541a09b1be88e1ac6e0ea3e82e24d917 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Wed, 6 May 2020 10:49:58 +0200 Subject: [PATCH 33/43] Create a base class for Apple platforms, and add iOS --- .../Apple/BaseApplePlatform.cs | 94 +++++++++++++++++++ .../Apple/MacOsPlatform.cs | 75 +-------------- .../Apple/iOsPlatform.cs | 29 ++++++ .../Sharpmake.CommonPlatforms.csproj | 2 + 4 files changed, 130 insertions(+), 70 deletions(-) create mode 100644 Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs create mode 100644 Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/iOsPlatform.cs diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs new file mode 100644 index 000000000..ebff956ea --- /dev/null +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs @@ -0,0 +1,94 @@ +// Copyright (c) 2017 Ubisoft Entertainment +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.IO; +using Sharpmake.Generators; +using Sharpmake.Generators.FastBuild; + +namespace Sharpmake +{ + public abstract partial class BaseApplePlatform + : IPlatformDescriptor, Project.Configuration.IConfigurationTasks + { + #region IPlatformDescriptor + public abstract string SimplePlatformString { get; } + public bool IsMicrosoftPlatform => false; + public bool IsUsingClang => true; + public bool HasDotNetSupport => false; // maybe? (.NET Core) + public bool HasSharedLibrarySupport => true; + public bool HasPrecompiledHeaderSupport => true; + + public bool IsPcPlatform => false; // LCTODO: ditch since it's obsolete + + public EnvironmentVariableResolver GetPlatformEnvironmentResolver(params VariableAssignment[] variables) + { + return new EnvironmentVariableResolver(variables); + } + + public string GetPlatformString(ITarget target) => SimplePlatformString; + #endregion + + #region IConfigurationTasks + public string GetDefaultOutputExtension(Project.Configuration.OutputType outputType) + { + switch (outputType) + { + // Using the Unix extensions since Darwin is a Unix implementation and the + // executables Mac users interact with are actually bundles. If this causes + // issues, see if using .app for executables and .dylib/.framework for + // libraries work better. iOS is Darwin/Cocoa so assuming that the same goes + // for it. + case Project.Configuration.OutputType.Exe: + case Project.Configuration.OutputType.IosApp: + case Project.Configuration.OutputType.IosTestBundle: + return string.Empty; + case Project.Configuration.OutputType.Lib: + return "a"; + case Project.Configuration.OutputType.Dll: + return "so"; + + // .NET remains the same on all platforms. (Mono loads .exe and .dll regardless + // of platforms, and I assume the same about .NET Core.) + case Project.Configuration.OutputType.DotNetConsoleApp: + case Project.Configuration.OutputType.DotNetWindowsApp: + return "exe"; + case Project.Configuration.OutputType.DotNetClassLibrary: + return "dll"; + + case Project.Configuration.OutputType.None: + return string.Empty; + default: + return outputType.ToString().ToLower(); + } + } + + public IEnumerable GetPlatformLibraryPaths(Project.Configuration configuration) + { + yield break; + } + + public void SetupDynamicLibraryPaths(Project.Configuration configuration, DependencySetting dependencySetting, Project.Configuration dependency) + { + DefaultPlatform.SetupLibraryPaths(configuration, dependencySetting, dependency); + } + + public void SetupStaticLibraryPaths(Project.Configuration configuration, DependencySetting dependencySetting, Project.Configuration dependency) + { + DefaultPlatform.SetupLibraryPaths(configuration, dependencySetting, dependency); + } + #endregion + } +} diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacOsPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacOsPlatform.cs index 5e46c8d6e..20171a586 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacOsPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacOsPlatform.cs @@ -12,83 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.Collections.Generic; - namespace Sharpmake { - public static class Apple + public static partial class Apple { - [PlatformImplementation(Platform.mac, + [PlatformImplementation(SharpmakePlatform, typeof(IPlatformDescriptor), typeof(Project.Configuration.IConfigurationTasks))] - public sealed class MacOsPlatform : IPlatformDescriptor, Project.Configuration.IConfigurationTasks + public sealed class MacOsPlatform : BaseApplePlatform { - #region IPlatformDescriptor implementation. - public string SimplePlatformString => "Mac"; - public string GetPlatformString(ITarget target) { return SimplePlatformString; } - - public bool IsMicrosoftPlatform => false; - public bool IsPcPlatform => true; - public bool IsUsingClang => true; - public bool HasDotNetSupport => false; // maybe? (.NET Core) - public bool HasSharedLibrarySupport => true; - public bool HasPrecompiledHeaderSupport => true; - - public EnvironmentVariableResolver GetPlatformEnvironmentResolver(params VariableAssignment[] variables) - { - return new EnvironmentVariableResolver(variables); - } - #endregion - - #region Project.Configuration.IConfigurationTasks implementation. - public void SetupDynamicLibraryPaths(Project.Configuration configuration, DependencySetting dependencySetting, Project.Configuration dependency) - { - DefaultPlatform.SetupLibraryPaths(configuration, dependencySetting, dependency); - } - - public void SetupStaticLibraryPaths(Project.Configuration configuration, DependencySetting dependencySetting, Project.Configuration dependency) - { - DefaultPlatform.SetupLibraryPaths(configuration, dependencySetting, dependency); - } - - public string GetDefaultOutputExtension(Project.Configuration.OutputType outputType) - { - switch (outputType) - { - // Using the Unix extensions since Darwin is a Unix implementation and the - // executables Mac users interact with are actually bundles. If this causes - // issues, see if using .app for executables and .dylib/.framework for - // libraries work better. iOS is Darwin/Cocoa so assuming that the same goes - // for it. - case Project.Configuration.OutputType.Exe: - case Project.Configuration.OutputType.IosApp: - case Project.Configuration.OutputType.IosTestBundle: - return string.Empty; - case Project.Configuration.OutputType.Lib: - return "a"; - case Project.Configuration.OutputType.Dll: - return "so"; - - // .NET remains the same on all platforms. (Mono loads .exe and .dll regardless - // of platforms, and I assume the same about .NET Core.) - case Project.Configuration.OutputType.DotNetConsoleApp: - case Project.Configuration.OutputType.DotNetWindowsApp: - return "exe"; - case Project.Configuration.OutputType.DotNetClassLibrary: - return "dll"; - - case Project.Configuration.OutputType.None: - return string.Empty; - default: - return outputType.ToString().ToLower(); - } - } + public const Platform SharpmakePlatform = Platform.mac; - public IEnumerable GetPlatformLibraryPaths(Project.Configuration configuration) - { - yield break; - } - #endregion + public override string SimplePlatformString => "Mac"; } } } diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/iOsPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/iOsPlatform.cs new file mode 100644 index 000000000..09a982fc5 --- /dev/null +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/iOsPlatform.cs @@ -0,0 +1,29 @@ +// Copyright (c) 2017 Ubisoft Entertainment +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Sharpmake +{ + public static partial class Apple + { + [PlatformImplementation(SharpmakePlatform, + typeof(IPlatformDescriptor), + typeof(Project.Configuration.IConfigurationTasks))] + public sealed class iOsPlatform : BaseApplePlatform + { + public const Platform SharpmakePlatform = Platform.ios; + + public override string SimplePlatformString => "iOS"; + } + } +} diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj index 4778bad45..a192dcba8 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Sharpmake.CommonPlatforms.csproj @@ -58,7 +58,9 @@ + + From c9482a4511b6e0022f2414b0f2f5c529acb04fcd Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Wed, 6 May 2020 14:39:15 +0200 Subject: [PATCH 34/43] [Vcxproj|Linux] Fix LocalRemoteCopySources tag, should write true/false instead of Yes/No --- .../Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs index 62322ef7a..5c7cc509f 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs @@ -113,16 +113,12 @@ public override void SetupPlatformTargetOptions(IGenerationContext context) public override void SetupSdkOptions(IGenerationContext context) { - //Copy Sources. - // Enable Copy Sources="Yes" - // Disable Copy Sources="No" default context.SelectOption ( - Sharpmake.Options.Option(Options.General.CopySources.Enable, () => { context.Options["CopySources"] = "Yes"; }), - Sharpmake.Options.Option(Options.General.CopySources.Disable, () => { context.Options["CopySources"] = "No"; }) + Sharpmake.Options.Option(Options.General.CopySources.Enable, () => { context.Options["CopySources"] = "true"; }), + Sharpmake.Options.Option(Options.General.CopySources.Disable, () => { context.Options["CopySources"] = "false"; }) ); - //Remote Tool. context.SelectOption ( Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Gpp, () => { context.Options["RemoteCppCompileToolExe"] = "g++"; }), From afb4136080406e336550737387be094072860f8d Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Wed, 13 May 2020 10:40:37 +0200 Subject: [PATCH 35/43] Prevent writing empty sections in win64 vcxproj when toolchains are not overriden --- .../Windows/ClangForWindowsSettings.cs | 15 +++- .../Windows/Win64Platform.cs | 83 ++++++++++--------- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/ClangForWindowsSettings.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/ClangForWindowsSettings.cs index bde6853e5..7561ce752 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/ClangForWindowsSettings.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/ClangForWindowsSettings.cs @@ -80,6 +80,13 @@ public static string ClangVersion } public static void WriteLLVMOverrides(IVcxprojGenerationContext context, IFileGenerator generator) + { + string llvmOverrideSection = GetLLVMOverridesSection(context, generator.Resolver); + if (!string.IsNullOrEmpty(llvmOverrideSection)) + generator.Write(llvmOverrideSection); + } + + internal static string GetLLVMOverridesSection(IVcxprojGenerationContext context, Resolver resolver) { if (Settings.OverridenLLVMInstallDir) { @@ -87,11 +94,13 @@ public static void WriteLLVMOverrides(IVcxprojGenerationContext context, IFileGe if (hasClangConfiguration) { - using (generator.Declare("custompropertyname", "LLVMInstallDir")) - using (generator.Declare("custompropertyvalue", Settings.LLVMInstallDir.TrimEnd(Util._pathSeparators))) // trailing separator will be added by LLVM.Cpp.Common.props - generator.Write(Vcxproj.Template.Project.CustomProperty); + using (resolver.NewScopedParameter("custompropertyname", "LLVMInstallDir")) + using (resolver.NewScopedParameter("custompropertyvalue", Settings.LLVMInstallDir.TrimEnd(Util._pathSeparators))) // trailing separator will be added by LLVM.Cpp.Common.props + return resolver.Resolve(Vcxproj.Template.Project.CustomProperty); } } + + return null; } } } diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs index 28a626647..96726c0e6 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs @@ -428,53 +428,62 @@ protected override IEnumerable GetPlatformIncludePathsWithPre public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerationContext context, IFileGenerator generator) { - if (!ClangForWindows.Settings.OverridenLLVMInstallDir) - return; + string propertyGroups = string.Empty; - if (context.DevelopmentEnvironmentsRange.MinDevEnv != context.DevelopmentEnvironmentsRange.MaxDevEnv) - throw new Error("Different vs versions not supported in the same vcxproj"); - DevEnv uniqueDevEnv = context.DevelopmentEnvironmentsRange.MinDevEnv; - - using (generator.Declare("platformName", SimplePlatformString)) + // MSBuild override when mixing devenvs in the same vcxproj is not supported, + // but before throwing an exception check if we have some override + for (DevEnv devEnv = context.DevelopmentEnvironmentsRange.MinDevEnv; devEnv <= context.DevelopmentEnvironmentsRange.MaxDevEnv; devEnv = (DevEnv)((int)devEnv << 1)) { - generator.Write(Vcxproj.Template.Project.ProjectDescriptionStartPlatformConditional); + switch (devEnv) { - switch (uniqueDevEnv) - { - case DevEnv.vs2017: + case DevEnv.vs2017: + { + string platformFolder = MSBuildGlobalSettings.GetCppPlatformFolder(context.DevelopmentEnvironmentsRange.MinDevEnv, Platform.win64); + if (!string.IsNullOrEmpty(platformFolder)) { - string platformFolder = MSBuildGlobalSettings.GetCppPlatformFolder(context.DevelopmentEnvironmentsRange.MinDevEnv, Platform.win64); - if (!string.IsNullOrEmpty(platformFolder)) - { - using (generator.Declare("platformFolder", Util.EnsureTrailingSeparator(platformFolder))) // _PlatformFolder require the path to end with a "\" - generator.Write(Vcxproj.Template.Project.PlatformFolderOverride); - } + using (generator.Declare("platformFolder", Util.EnsureTrailingSeparator(platformFolder))) // _PlatformFolder require the path to end with a "\" + propertyGroups += generator.Resolver.Resolve(Vcxproj.Template.Project.PlatformFolderOverride); } - break; - case DevEnv.vs2019: - { - // Note1: _PlatformFolder override is deprecated starting with vs2019, so we write AdditionalVCTargetsPath instead - // Note2: MSBuildGlobalSettings.SetCppPlatformFolder for vs2019 is no more the valid way to handle it. Older buildtools packages can anyway contain it, and need upgrade. + } + break; + case DevEnv.vs2019: + { + // Note1: _PlatformFolder override is deprecated starting with vs2019, so we write AdditionalVCTargetsPath instead + // Note2: MSBuildGlobalSettings.SetCppPlatformFolder for vs2019 is no more the valid way to handle it. Older buildtools packages can anyway contain it, and need upgrade. - if (!string.IsNullOrEmpty(MSBuildGlobalSettings.GetCppPlatformFolder(uniqueDevEnv, Platform.win64))) - throw new Error("SetCppPlatformFolder is not supported by VS2019 correctly: use of MSBuildGlobalSettings.SetCppPlatformFolder should be replaced by use of MSBuildGlobalSettings.SetAdditionalVCTargetsPath."); + if (!string.IsNullOrEmpty(MSBuildGlobalSettings.GetCppPlatformFolder(devEnv, Platform.win64))) + throw new Error("SetCppPlatformFolder is not supported by VS2019 correctly: use of MSBuildGlobalSettings.SetCppPlatformFolder should be replaced by use of MSBuildGlobalSettings.SetAdditionalVCTargetsPath."); - // vs2019 use AdditionalVCTargetsPath - string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(uniqueDevEnv, Platform.win64); - if (!string.IsNullOrEmpty(additionalVCTargetsPath)) - { - using (generator.Declare("additionalVCTargetsPath", Util.EnsureTrailingSeparator(additionalVCTargetsPath))) // the path shall end with a "\" - generator.Write(Vcxproj.Template.Project.AdditionalVCTargetsPath); - } + // vs2019 use AdditionalVCTargetsPath + string additionalVCTargetsPath = MSBuildGlobalSettings.GetAdditionalVCTargetsPath(devEnv, Platform.win64); + if (!string.IsNullOrEmpty(additionalVCTargetsPath)) + { + using (generator.Declare("additionalVCTargetsPath", Util.EnsureTrailingSeparator(additionalVCTargetsPath))) // the path shall end with a "\" + propertyGroups += generator.Resolver.Resolve(Vcxproj.Template.Project.AdditionalVCTargetsPath); } - break; - default: - throw new Error(uniqueDevEnv + " is not supported."); - } - ClangForWindows.WriteLLVMOverrides(context, generator); + } + break; + default: + throw new Error(devEnv + " is not supported."); + } + } + + string llvmOverrideSection = ClangForWindows.GetLLVMOverridesSection(context, generator.Resolver); + if (!string.IsNullOrEmpty(llvmOverrideSection)) + propertyGroups += llvmOverrideSection; + + if (!string.IsNullOrEmpty(propertyGroups)) + { + if (context.DevelopmentEnvironmentsRange.MinDevEnv != context.DevelopmentEnvironmentsRange.MaxDevEnv) + throw new Error("Different vs versions not supported in the same vcxproj"); + + using (generator.Declare("platformName", SimplePlatformString)) + { + generator.Write(Vcxproj.Template.Project.ProjectDescriptionStartPlatformConditional); + generator.WriteVerbatim(propertyGroups); + generator.Write(Vcxproj.Template.Project.PropertyGroupEnd); } - generator.Write(Vcxproj.Template.Project.PropertyGroupEnd); } } #endregion From 3719af24053c461d5cb9f049a7af358dbf910529 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Thu, 14 May 2020 13:02:25 +0200 Subject: [PATCH 36/43] - Fix hardcoded .dll extension, since it depends on the platform, we query it - Fix target depends path --- Sharpmake/Project.Configuration.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Sharpmake/Project.Configuration.cs b/Sharpmake/Project.Configuration.cs index 1da1617e7..4e23045b8 100644 --- a/Sharpmake/Project.Configuration.cs +++ b/Sharpmake/Project.Configuration.cs @@ -2860,10 +2860,12 @@ internal void Link(Builder builder) break; case OutputType.Dll: { + var configTasks = PlatformRegistry.Get(dependency.Platform); + if (dependency.ExportDllSymbols && (isImmediate || hasPublicPathToRoot || !goesThroughDLL)) { if (explicitDependenciesGlobal || !compile || (IsFastBuild && Util.IsDotNet(dependency))) - PlatformRegistry.Get(dependency.Platform).SetupDynamicLibraryPaths(this, dependencySetting, dependency); + configTasks.SetupDynamicLibraryPaths(this, dependencySetting, dependency); if (dependencySetting.HasFlag(DependencySetting.LibraryFiles)) ConfigurationDependencies.Add(dependency); if (dependencySetting.HasFlag(DependencySetting.ForceUsingAssembly)) @@ -2884,6 +2886,8 @@ internal void Link(Builder builder) dependencySetting.HasFlag(DependencySetting.ForceUsingAssembly)) AdditionalUsingDirectories.Add(dependency.TargetPath); + string platformDllExtension = "." + configTasks.GetDefaultOutputExtension(OutputType.Dll); + string dependencyDllFullPath = Path.Combine(dependency.TargetPath, dependency.TargetFileFullName + platformDllExtension); if ((Output == OutputType.Exe || ExecuteTargetCopy) && dependencySetting.HasFlag(DependencySetting.LibraryFiles) && dependency.TargetPath != TargetPath) @@ -2891,7 +2895,7 @@ internal void Link(Builder builder) // If using OnlyBuildOrder, ExecuteTargetCopy must be set to enable the copy. if (dependencySetting != DependencySetting.OnlyBuildOrder || ExecuteTargetCopy) { - _resolvedTargetCopyFiles.Add(Path.Combine(dependency.TargetPath, dependency.TargetFileFullName + ".dll")); + _resolvedTargetCopyFiles.Add(dependencyDllFullPath); // Add PDBs only if they exist and the dependency is not an [export] project if (!isExport && Sharpmake.Options.GetObject(dependency) != Sharpmake.Options.Vc.Linker.GenerateDebugInformation.Disable) { @@ -2906,7 +2910,7 @@ internal void Link(Builder builder) _resolvedEventCustomPreBuildExe.AddRange(dependency.EventCustomPreBuildExe); _resolvedEventCustomPostBuildExe.AddRange(dependency.EventCustomPostBuildExe); } - _resolvedTargetDependsFiles.Add(Path.Combine(TargetPath, dependency.TargetFileFullName + ".dll")); + _resolvedTargetDependsFiles.Add(dependencyDllFullPath); // If this is not a .Net project, no .Net dependencies are needed if (Util.IsDotNet(this)) From dbb59b743386c8e6186f0ac5cb9b9e508c27839e Mon Sep 17 00:00:00 2001 From: Benoit Rousseau Date: Wed, 21 Nov 2018 16:50:49 -0500 Subject: [PATCH 37/43] Changes the behavior of DependencySetting.OnlyBuildOrder to add the target as a vcxproj project reference, or a prebuild dependency in FastBuild. --- .../FastBuild/Bff.Template.cs | 1 + Sharpmake.Generators/FastBuild/Bff.Util.cs | 30 +++++++++++++++++++ Sharpmake.Generators/FastBuild/Bff.cs | 19 ++++++++++++ Sharpmake.Generators/VisualStudio/Vcxproj.cs | 5 +++- Sharpmake/Project.Configuration.cs | 10 ++++++- 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Sharpmake.Generators/FastBuild/Bff.Template.cs b/Sharpmake.Generators/FastBuild/Bff.Template.cs index bb92ae6e9..c11ebb05f 100644 --- a/Sharpmake.Generators/FastBuild/Bff.Template.cs +++ b/Sharpmake.Generators/FastBuild/Bff.Template.cs @@ -457,6 +457,7 @@ public static class ConfigurationFile [fastBuildUsingPlatformConfig] .Intermediate = '[cmdLineOptions.IntermediateDirectory]\' .Libraries = [fastBuildProjectDependencies] + .PreBuildDependencies = [fastBuildBuildOnlyDependencies] .LinkerAssemblyResources = { [fastBuildObjectListEmbeddedResources] } .LinkerOutput = '[fastBuildLinkerOutputFile]' .LinkerLinkObjects = [fastBuildLinkerLinkObjects] diff --git a/Sharpmake.Generators/FastBuild/Bff.Util.cs b/Sharpmake.Generators/FastBuild/Bff.Util.cs index 0da4a1065..9850511ef 100644 --- a/Sharpmake.Generators/FastBuild/Bff.Util.cs +++ b/Sharpmake.Generators/FastBuild/Bff.Util.cs @@ -533,6 +533,36 @@ private static void GetOrderedFlattenedProjectDependenciesInternal(Project.Confi } } + internal static UniqueList GetOrderedFlattenedBuildOnlyDependencies(Project.Configuration conf) + { + var dependencies = new UniqueList(); + GetOrderedFlattenedBuildOnlyDependenciesInternal(conf, dependencies); + return dependencies; + } + + private static void GetOrderedFlattenedBuildOnlyDependenciesInternal(Project.Configuration conf, UniqueList dependencies) + { + if (!conf.IsFastBuild) + return; + + IEnumerable confDependencies = conf.BuildOrderDependencies; + + if (confDependencies.Contains(conf)) + throw new Error("Cyclic dependency detected in project " + conf); + + UniqueList tmpDeps = new UniqueList(); + foreach (var dep in confDependencies) + { + GetOrderedFlattenedBuildOnlyDependenciesInternal(dep, tmpDeps); + tmpDeps.Add(dep); + } + foreach (var dep in tmpDeps) + { + if (dep.IsFastBuild && confDependencies.Contains(dep) && (conf != dep)) + dependencies.Add(dep); + } + } + public static string FBuildCollectionFormat(Strings collection, int spaceLength, Strings includedExtensions = null) { // Select items. diff --git a/Sharpmake.Generators/FastBuild/Bff.cs b/Sharpmake.Generators/FastBuild/Bff.cs index 6f5735ff9..c67e8cda9 100644 --- a/Sharpmake.Generators/FastBuild/Bff.cs +++ b/Sharpmake.Generators/FastBuild/Bff.cs @@ -377,6 +377,7 @@ List skipFiles string fastBuildOutputFileShortName = GetShortProjectName(project, conf); var fastBuildProjectDependencies = new List(); + var fastBuildBuildOnlyDependencies = new List(); var fastBuildProjectExeUtilityDependencyList = new List(); bool mustGenerateLibrary = confSubConfigs.Count > 1 && !useObjectLists && isLastSubConfig && isOutputTypeLib; @@ -409,6 +410,23 @@ List skipFiles fastBuildProjectExeUtilityDependencyList.Add(GetShortProjectName(depProjConfig.Project, depProjConfig)); } } + + orderedProjectDeps = UtilityMethods.GetOrderedFlattenedBuildOnlyDependencies(conf); + foreach (var depProjConfig in orderedProjectDeps) + { + if (depProjConfig.Project == project) + throw new Error("Sharpmake-FastBuild : Project dependencies refers to itself."); + + bool isExport = depProjConfig.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Export; + if (isExport) + continue; + + if (depProjConfig.Output != Project.Configuration.OutputType.Exe && + depProjConfig.Output != Project.Configuration.OutputType.Utility) + { + fastBuildBuildOnlyDependencies.Add(GetShortProjectName(depProjConfig.Project, depProjConfig)); + } + } } string librarianAdditionalInputs = FileGeneratorUtilities.RemoveLineTag; @@ -936,6 +954,7 @@ List skipFiles using (bffGenerator.Declare("fastBuildEmbeddedResources", fastBuildEmbeddedResources)) using (bffGenerator.Declare("fastBuildPrecompiledSourceFile", fastBuildPrecompiledSourceFile)) using (bffGenerator.Declare("fastBuildProjectDependencies", UtilityMethods.FBuildFormatList(fastBuildProjectDependencies, 30))) + using (bffGenerator.Declare("fastBuildBuildOnlyDependencies", UtilityMethods.FBuildFormatList(fastBuildBuildOnlyDependencies, 30))) using (bffGenerator.Declare("fastBuildPreBuildTargets", UtilityMethods.FBuildFormatList(fastBuildPreBuildDependencies.ToList(), 28))) using (bffGenerator.Declare("fastBuildObjectListEmbeddedResources", fastBuildObjectListEmbeddedResources)) using (bffGenerator.Declare("fastBuildCompilerPCHOptions", fastBuildCompilerPCHOptions)) diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.cs index 585d0a1de..9597f83b3 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.cs @@ -991,7 +991,10 @@ private void GenerateProjectReferences( var dependencies = new UniqueList(); foreach (var configuration in context.ProjectConfigurations) { - foreach (var configurationDependency in configuration.ConfigurationDependencies) + var configDeps = new UniqueList(); + configDeps.AddRange(configuration.ConfigurationDependencies); + configDeps.AddRange(configuration.BuildOrderDependencies); + foreach (var configurationDependency in configDeps) { // Ignore projects marked as Export if (configurationDependency.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Export) diff --git a/Sharpmake/Project.Configuration.cs b/Sharpmake/Project.Configuration.cs index 4e23045b8..6fc03d353 100644 --- a/Sharpmake/Project.Configuration.cs +++ b/Sharpmake/Project.Configuration.cs @@ -1113,6 +1113,7 @@ public void AddDependencyBuiltTargetLibraryFile(string libraryFile, int orderNum public UniqueList ConfigurationDependencies = new UniqueList(); public UniqueList ForceUsingDependencies = new UniqueList(); public UniqueList GenericBuildDependencies = new UniqueList(); + internal UniqueList BuildOrderDependencies = new UniqueList(); /// /// Gets the list of public dependencies for .NET projects. @@ -2839,6 +2840,8 @@ internal void Link(Builder builder) PlatformRegistry.Get(dependency.Platform).SetupStaticLibraryPaths(this, dependencySetting, dependency); if (dependencySetting.HasFlag(DependencySetting.LibraryFiles)) ConfigurationDependencies.Add(dependency); + if (dependencySetting == DependencySetting.OnlyBuildOrder) + BuildOrderDependencies.Add(dependency); } if (!goesThroughDLL) @@ -2870,6 +2873,8 @@ internal void Link(Builder builder) ConfigurationDependencies.Add(dependency); if (dependencySetting.HasFlag(DependencySetting.ForceUsingAssembly)) ForceUsingDependencies.Add(dependency); + if (dependencySetting == DependencySetting.OnlyBuildOrder) + BuildOrderDependencies.Add(dependency); // check if that case is valid: dll with additional libs if (isExport && !goesThroughDLL) @@ -2941,7 +2946,10 @@ internal void Link(Builder builder) else if (isImmediate) resolvedDotNetPrivateDependencies.Add(new DotNetDependency(dependency)); - ConfigurationDependencies.Add(dependency); + if (dependencySetting == DependencySetting.OnlyBuildOrder) + BuildOrderDependencies.Add(dependency); + else + ConfigurationDependencies.Add(dependency); } break; case OutputType.Utility: throw new NotImplementedException(dependency.Project.Name + " " + dependency.Output); From ddd6005e94d13328133bc4cb306f7d3a86782585 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Mon, 18 May 2020 14:52:09 +0200 Subject: [PATCH 38/43] Formatting --- .../Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs index 6cb3ad07d..8026c96a1 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Android/AndroidPlatform.cs @@ -258,7 +258,8 @@ public override void SelectCompilerOptions(IGenerationContext context) context.SelectOption ( - Options.Option(Options.Android.General.AndroidAPILevel.Latest, () => { + Options.Option(Options.Android.General.AndroidAPILevel.Latest, () => + { string lookupDirectory; if (context.Project is AndroidPackageProject) { From ff86c813a5be9a89d364b960b314b7dadb24cbb6 Mon Sep 17 00:00:00 2001 From: Louis-Michel VEILLEUX Date: Tue, 19 May 2020 08:00:13 +0000 Subject: [PATCH 39/43] [Util] Added file copy readonly policy Users now have some control over the readonly state of the destination file when doing a file copy via `Util.ForceCopy`. Options are: - Preserve (default) - SetReadOnly - UnsetReadOnly --- Sharpmake/Util.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Sharpmake/Util.cs b/Sharpmake/Util.cs index dc304c282..e36cc8ebd 100644 --- a/Sharpmake/Util.cs +++ b/Sharpmake/Util.cs @@ -1975,7 +1975,19 @@ public static string GetToolVersionString(DevEnv env, DotNetFramework desiredFra } } + public enum FileCopyDestReadOnlyPolicy : byte + { + Preserve, + SetReadOnly, + UnsetReadOnly + } + public static void ForceCopy(string source, string destination) + { + ForceCopy(source, destination, FileCopyDestReadOnlyPolicy.Preserve); + } + + public static void ForceCopy(string source, string destination, FileCopyDestReadOnlyPolicy destinationReadOnlyPolicy) { if (File.Exists(destination)) { @@ -1985,6 +1997,20 @@ public static void ForceCopy(string source, string destination) } File.Copy(source, destination, true); + + if (destinationReadOnlyPolicy != FileCopyDestReadOnlyPolicy.Preserve) + { + FileAttributes attributes = File.GetAttributes(destination); + if (destinationReadOnlyPolicy == FileCopyDestReadOnlyPolicy.SetReadOnly) + { + attributes |= FileAttributes.ReadOnly; + } + else + { + attributes &= ~FileAttributes.ReadOnly; + } + File.SetAttributes(destination, attributes); + } } public static bool IsDotNet(Project.Configuration conf) From 6293c07dc9386c704e3e233516e69b4a527fb9b1 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 19 May 2020 12:22:18 +0200 Subject: [PATCH 40/43] Fix versions marked as non-official when they shouldn't. --- Sharpmake.Application/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sharpmake.Application/Program.cs b/Sharpmake.Application/Program.cs index 8f5950b7d..29def49ce 100644 --- a/Sharpmake.Application/Program.cs +++ b/Sharpmake.Application/Program.cs @@ -176,7 +176,7 @@ private static int Main() Version version = sharpmakeAssembly.GetName().Version; string versionString = string.Join(".", version.Major, version.Minor, version.Build); string informationalVersion = sharpmakeAssembly.GetCustomAttribute()?.InformationalVersion; - if (version.Revision != 0 || informationalVersion == null || informationalVersion.IndexOf("+Branch.") == -1) + if (version.Revision != 0 || (informationalVersion != null && informationalVersion.IndexOf("+Branch.") == -1)) { versionString += " (non-official)"; if (DebugEnable && informationalVersion != null) From 148d714101e82dea04156af2213f84af76224977 Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 19 May 2020 12:26:45 +0200 Subject: [PATCH 41/43] Fix conditional on the version, again... --- Sharpmake.Application/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sharpmake.Application/Program.cs b/Sharpmake.Application/Program.cs index 29def49ce..b36bc983d 100644 --- a/Sharpmake.Application/Program.cs +++ b/Sharpmake.Application/Program.cs @@ -176,7 +176,7 @@ private static int Main() Version version = sharpmakeAssembly.GetName().Version; string versionString = string.Join(".", version.Major, version.Minor, version.Build); string informationalVersion = sharpmakeAssembly.GetCustomAttribute()?.InformationalVersion; - if (version.Revision != 0 || (informationalVersion != null && informationalVersion.IndexOf("+Branch.") == -1)) + if (version.Revision != 0 || (informationalVersion != null && informationalVersion.IndexOf("+Branch.") != -1)) { versionString += " (non-official)"; if (DebugEnable && informationalVersion != null) From 9520c200407338170b086741a0ca754fa75b2bea Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 19 May 2020 12:27:49 +0200 Subject: [PATCH 42/43] Revert "Fix conditional on the version, again..." This reverts commit 148d714101e82dea04156af2213f84af76224977. --- Sharpmake.Application/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sharpmake.Application/Program.cs b/Sharpmake.Application/Program.cs index b36bc983d..29def49ce 100644 --- a/Sharpmake.Application/Program.cs +++ b/Sharpmake.Application/Program.cs @@ -176,7 +176,7 @@ private static int Main() Version version = sharpmakeAssembly.GetName().Version; string versionString = string.Join(".", version.Major, version.Minor, version.Build); string informationalVersion = sharpmakeAssembly.GetCustomAttribute()?.InformationalVersion; - if (version.Revision != 0 || (informationalVersion != null && informationalVersion.IndexOf("+Branch.") != -1)) + if (version.Revision != 0 || (informationalVersion != null && informationalVersion.IndexOf("+Branch.") == -1)) { versionString += " (non-official)"; if (DebugEnable && informationalVersion != null) From b52a9a791faaa498d8ae44cde92d489f1a1e56cd Mon Sep 17 00:00:00 2001 From: Lambert Clara Date: Tue, 19 May 2020 15:34:30 +0200 Subject: [PATCH 43/43] Bump version number to 0.13.2 --- Sharpmake.Application/Properties/AssemblyInfo.cs | 2 +- Sharpmake.Generators/Properties/AssemblyInfo.cs | 2 +- .../Sharpmake.CommonPlatforms/Properties/AssemblyInfo.cs | 2 +- .../Sharpmake.NvShield/Properties/AssemblyInfo.cs | 2 +- Sharpmake.Platforms/Sharpmake.X360/Properties/AssemblyInfo.cs | 2 +- Sharpmake/Properties/AssemblyInfo.cs | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Sharpmake.Application/Properties/AssemblyInfo.cs b/Sharpmake.Application/Properties/AssemblyInfo.cs index dab70f558..c156347d7 100644 --- a/Sharpmake.Application/Properties/AssemblyInfo.cs +++ b/Sharpmake.Application/Properties/AssemblyInfo.cs @@ -43,4 +43,4 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.11.2.*")] +[assembly: AssemblyVersion("0.13.2.0")] diff --git a/Sharpmake.Generators/Properties/AssemblyInfo.cs b/Sharpmake.Generators/Properties/AssemblyInfo.cs index 12e79b6f5..f5b0a7a4a 100644 --- a/Sharpmake.Generators/Properties/AssemblyInfo.cs +++ b/Sharpmake.Generators/Properties/AssemblyInfo.cs @@ -44,6 +44,6 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.11.2.*")] +[assembly: AssemblyVersion("0.13.2.0")] [assembly: InternalsVisibleTo("Sharpmake")] diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Properties/AssemblyInfo.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Properties/AssemblyInfo.cs index fcb0d78f2..f059f2bb3 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Properties/AssemblyInfo.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Properties/AssemblyInfo.cs @@ -44,6 +44,6 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.11.2.*")] +[assembly: AssemblyVersion("0.13.2.0")] [assembly: SharpmakeExtension] diff --git a/Sharpmake.Platforms/Sharpmake.NvShield/Properties/AssemblyInfo.cs b/Sharpmake.Platforms/Sharpmake.NvShield/Properties/AssemblyInfo.cs index 0a57d90fc..1ec94ed82 100644 --- a/Sharpmake.Platforms/Sharpmake.NvShield/Properties/AssemblyInfo.cs +++ b/Sharpmake.Platforms/Sharpmake.NvShield/Properties/AssemblyInfo.cs @@ -44,6 +44,6 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.11.2.*")] +[assembly: AssemblyVersion("0.13.2.0")] [assembly: SharpmakeExtension] diff --git a/Sharpmake.Platforms/Sharpmake.X360/Properties/AssemblyInfo.cs b/Sharpmake.Platforms/Sharpmake.X360/Properties/AssemblyInfo.cs index 7b0534b44..cfa3c36de 100644 --- a/Sharpmake.Platforms/Sharpmake.X360/Properties/AssemblyInfo.cs +++ b/Sharpmake.Platforms/Sharpmake.X360/Properties/AssemblyInfo.cs @@ -44,6 +44,6 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.11.2.*")] +[assembly: AssemblyVersion("0.13.2.0")] [assembly: SharpmakeExtension] diff --git a/Sharpmake/Properties/AssemblyInfo.cs b/Sharpmake/Properties/AssemblyInfo.cs index 7d729f14d..db7f88edb 100644 --- a/Sharpmake/Properties/AssemblyInfo.cs +++ b/Sharpmake/Properties/AssemblyInfo.cs @@ -44,9 +44,9 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.11.2.*")] +[assembly: AssemblyVersion("0.13.2.0")] #pragma warning disable CS7035 -[assembly: AssemblyFileVersion("0.11.2.* (LocalBuild)")] +[assembly: AssemblyFileVersion("0.13.2.0 (LocalBuild)")] #pragma warning restore [assembly: InternalsVisibleTo("Sharpmake.Application")]