diff --git a/Sharpmake.Application/CommandLineArguments.cs b/Sharpmake.Application/CommandLineArguments.cs index aea1edb44..40b019f42 100644 --- a/Sharpmake.Application/CommandLineArguments.cs +++ b/Sharpmake.Application/CommandLineArguments.cs @@ -6,6 +6,7 @@ using System.IO; using System.Runtime.Serialization; using System.Text.RegularExpressions; +using Sharpmake.Generators.Rider; namespace Sharpmake.Application { diff --git a/Sharpmake.Application/Program.cs b/Sharpmake.Application/Program.cs index 5222bde81..61b73c9c9 100644 --- a/Sharpmake.Application/Program.cs +++ b/Sharpmake.Application/Program.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using Sharpmake.Generators; +using Sharpmake.Generators.Rider; using Sharpmake.Generators.VisualStudio; namespace Sharpmake.Application diff --git a/Sharpmake.Application/Properties/launchSettings.json b/Sharpmake.Application/Properties/launchSettings.json index 463c0e209..06f06b2b9 100644 --- a/Sharpmake.Application/Properties/launchSettings.json +++ b/Sharpmake.Application/Properties/launchSettings.json @@ -116,6 +116,11 @@ "commandLineArgs": "/sources(@\u0027QTFileCustomBuild.sharpmake.cs\u0027)", "workingDirectory": "$(ProjectDir)\\..\\samples\\QTFileCustomBuild" }, + "Sample (RiderJson)": { + "commandName": "Project", + "commandLineArgs": "/sources(@\u0027RiderJson.sharpmake.cs\u0027)", + "workingDirectory": "$(ProjectDir)\\..\\samples\\RiderJson" + }, "Sample (SimpleExeLibDependency)": { "commandName": "Project", "commandLineArgs": "/sources(@\u0027SimpleExeLibDependency.sharpmake.cs\u0027)", diff --git a/Sharpmake.Generators/GeneratorManager.cs b/Sharpmake.Generators/GeneratorManager.cs index 9055263af..e68fde9b4 100644 --- a/Sharpmake.Generators/GeneratorManager.cs +++ b/Sharpmake.Generators/GeneratorManager.cs @@ -5,6 +5,7 @@ using Sharpmake.Generators.Apple; using Sharpmake.Generators.FastBuild; using Sharpmake.Generators.Generic; +using Sharpmake.Generators.Rider; using Sharpmake.Generators.VisualStudio; namespace Sharpmake.Generators @@ -25,6 +26,9 @@ public class GeneratorManager : IGeneratorManager private MakeApplication _makeApplicationGenerator = null; public MakeApplication MakeApplicationGenerator => _makeApplicationGenerator ?? (_makeApplicationGenerator = new MakeApplication()); + public RiderJson _riderJsonGenerator = null; + public RiderJson RiderJsonGenerator => _riderJsonGenerator ?? (_riderJsonGenerator = new RiderJson()); + // Project generators private CSproj _csprojGenerator = null; public CSproj CsprojGenerator => _csprojGenerator ?? (_csprojGenerator = new CSproj()); @@ -104,6 +108,11 @@ public void Generate(Builder builder, BffGenerator.Generate(builder, project, configurations, projectFile, generatedFiles, skipFiles); break; } + case DevEnv.rider: + { + BffGenerator.Generate(builder, project, configurations, projectFile, generatedFiles, skipFiles); + break; + } default: { throw new Error("Generate called with unknown DevEnv: " + devEnv); @@ -158,6 +167,17 @@ public void Generate(Builder builder, SlnGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); break; } + case DevEnv.rider: + { + if (UtilityMethods.HasFastBuildConfig(configurations)) + { + var masterBff = new MasterBff(); + masterBff.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + } + + RiderJsonGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + break; + } default: { throw new Error("Generate called with unknown DevEnv: " + devEnv); diff --git a/Sharpmake.Generators/Generic/RiderJson.md b/Sharpmake.Generators/Generic/RiderJson.md new file mode 100644 index 000000000..4bee26161 --- /dev/null +++ b/Sharpmake.Generators/Generic/RiderJson.md @@ -0,0 +1,57 @@ +## Introduction + +Rider Json has project files of 2 levels: ++ ```root.json``` - "solution"-wide file which contains information about all projects +and their configurations; ++ ```__.json``` - contains information about single configuration of the project. + +The following is the mapping of Sharpmake properties to Rider Json. + +## Relations between Sharpmake and Rider Json properties +### Solution +| Sharpmake | Rider Json | +| --------- | ---------- | +| ``Solution.Configuration.IncludedProjectInfo.Configuration`` | ``ProjectConfig`` | +| ``Solution.Configuration`` | ``SolutionConfig`` | +| ``Solution.Configuration.IncludedProjectInfo.ToBuild`` | ``DoBuild`` | + +### Project +| Sharpmake | Rider Json | +| --------- | ---------- | +| ``Project.Configuration.ProjectName`` | ``Name`` | +| ``Project.Configuration.Name`` | ``Configuration`` | +| ``Configuration.Platform`` | ``Platform`` | +| ``IPlatformVcxproj.GetPlatformIncludePaths()`` | ``EnvironmentIncludePaths`` | +| ``IPlatformVcxproj.GetImplicitlyDefinedSymbols()`` | ``EnvironmentDefinitions`` | +| ``Project.Configuration.ResolvedDependencies`` | ``Modules`` | + +### Toolchain Info +| Sharpmake | Rider Json | +| --------- | ---------- | +| ``Options..Compiler.CppLanguageStandard``| ``ToolchainInfo.CppStandart`` | +| ``Options..Compiler.RTTI`` | ``ToolchainInfo.RTTI`` | +| ``Options..Compiler.Exceptions`` | ``ToolchainInfo.bUseExceptions`` | +| ``Project.Configuration.OutputType`` | ``ToolchainInfo.bIsBuildingLibrary``
``ToolchainInfo.bIsBuildingDll``| +| ``Options..Compiler.Optimization`` | ``ToolchainInfo.bOptimizeCode`` | +| ``Options.Vc.Compiler.Inline`` | ``ToolchainInfo.bUseInlining`` | +| ``Project.Configuration.IsBlobbed``
``Project.Configuration.FastBuildBlobbed`` | ``ToolchainInfo.bUseUnity`` | +| ``Options.Vc.General.DebugInformation``
``Options..Compiler.GenerateDebugInformation``
``Options.XCode.Compiler.GenerateDebuggingSymbols``
``Options.Android.Compiler.DebugInformationFormat`` | ``ToolchainInfo.bCreateDebugInfo`` | +| ``Options.Vc.Compiler.EnhancedInstructionSet`` | ``ToolchainInfo.bUseAVX`` | +| ``Configuration.Compiler`` | ``ToolchainInfo.Compiler`` | +| ``Options.Vc.Compiler.ConformanceMode`` | ``ToolchainInfo.bStrictConformanceMode`` | +| ``Options.Vc.SourceFile.PrecompiledHeader``
``IPlatformVcxproj.HasPrecomp()`` | ``ToolchainInfo.PrecompiledHeaderAction`` | +| ``FastBuildMakeCommandGenerator.GetCommand()`` | ``ToolchainInfo.BuildCmd``
``ToolchainInfo.ReBuildCmd``
``ToolchainInfo.CleanCmd`` | + +### Modules info +| Sharpmake | Rider Json | +| --------- | ---------- | +| ``Project.SourceRootPath`` | ``SourcePath`` | +| ``Project.SourceFilesExtensions`` | ``SourceExtensions`` | +| ``Project.Configuration.ResolvedPublicDependencies`` | ``PublicDependencyModules`` | +| ``Project.Configuration.ResolvedPrivateDependencies`` | ``PrivateDependencyModules`` | +| ``Project.Configuration.IncludePaths`` | ``PublicIncludePaths`` | +| ``Project.Configuration.IncludePrivatePaths`` | ``PrivateIncludePaths`` | +| ``Project.Configuration.ExportDefines`` | ``PublicDefinitions`` | +| ``Project.Configuration.Defines`` | ``PrivateDefinitions`` | + + diff --git a/Sharpmake.Generators/Rider/RiderJson.Template.cs b/Sharpmake.Generators/Rider/RiderJson.Template.cs new file mode 100644 index 000000000..e07dc8d1e --- /dev/null +++ b/Sharpmake.Generators/Rider/RiderJson.Template.cs @@ -0,0 +1,32 @@ +// Copyright (c) Ubisoft. All Rights Reserved. +// Licensed under the Apache 2.0 License. See LICENSE.md in the project root for license information. + +namespace Sharpmake.Generators.Rider +{ + public partial class RiderJson + { + + // See Sharpmake.BasePlatform.GenerateProjectConfigurationFastBuildMakeFile() + public static class Template + { + public static string FastBuildBuildCommand = @"cd [SolutionDir] +[BeforeBuildCommand] +[BuildCommand]"; + + public static string FastBuildCleanCommand = @"del ""[IntermediateDirectory]\*unity*.cpp"" >NUL 2>NUL +del ""[IntermediateDirectory]\*.obj"" >NUL 2>NUL +del ""[IntermediateDirectory]\*.a"" >NUL 2>NUL +del ""[IntermediateDirectory]\*.lib"" >NUL 2>NUL +del ""[IntermediateDirectory]\*.pch"" >NUL 2>NUL +del ""[IntermediateDirectory]\*.pdb"" >NUL 2>NUL +del ""[OutputDirectory]\[TargetFileFullName].exe"" >NUL 2>NUL +del ""[OutputDirectory]\[TargetFileFullName].elf"" >NUL 2>NUL +del ""[OutputDirectory]\[TargetFileFullName].exp"" >NUL 2>NUL +del ""[OutputDirectory]\[TargetFileFullName].ilk"" >NUL 2>NUL +del ""[OutputDirectory]\[TargetFileFullName].lib"" >NUL 2>NUL +del ""[OutputDirectory]\[TargetFileFullName].pdb"" >NUL 2>NUL"; + + public static string MsBuildBuildCommand = @"$(MsBuildPath) ""[ProjectFile]"" -t:[Command] -p:Configuration=""[ConfigurationName]"" -p:Platform=""[PlatformName]"""; + } + } +} diff --git a/Sharpmake.Generators/Rider/RiderJson.Util.cs b/Sharpmake.Generators/Rider/RiderJson.Util.cs new file mode 100644 index 000000000..1987487e5 --- /dev/null +++ b/Sharpmake.Generators/Rider/RiderJson.Util.cs @@ -0,0 +1,351 @@ +// Copyright (c) Ubisoft. All Rights Reserved. +// Licensed under the Apache 2.0 License. See LICENSE.md in the project root for license information. + +using System; +using System.Collections; +using System.Linq; +using Sharpmake.Generators.VisualStudio; + +namespace Sharpmake.Generators.Rider +{ + public static class RiderJsonUtil + { + public static class CppLanguageStandard + { + public const string Cpp14 = "Cpp14"; + public const string Cpp17 = "Cpp17"; + public const string Cpp20 = "Cpp20"; + public const string Latest = "Latest"; + + public const string Default = Cpp14; + } + + public static class PchAction + { + public const string None = "None"; + public const string Include = "Include"; + public const string Create = "Create"; + + public const string Default = None; + } + + public static class Compiler + { + public const string Unknown = "Unknown"; + public const string Clang = "Clang"; + public const string Vs15 = "VisualStudio2015"; + public const string Vs17 = "VisualStudio2017"; + public const string Vs19 = "VisualStudio2019"; + public const string Vs22 = "VisualStudio2022"; + + public const string Default = Unknown; + } + + public static class OutputType + { + public const string Executable = "Executable"; + public const string DynamicLibrary = "DynamicLinkLibrary"; + public const string StaticLibrary = "StaticLibrary"; + public const string Utility = "Utility"; + + public const string Default = Executable; + } + + public static string GetQualifiedName(this Project project) + { + if (project.SharpmakeProjectType == Project.ProjectTypeAttribute.Generate) + { + return project.Name; + } + + return $"{project.FullClassName}@{project.Name}"; + } + + public static void AddIfCondition(this IDictionary dict, string key, object value, bool condition) + { + if (!RiderJson.IgnoreDefaults || condition) + { + dict.Add(key, value); + } + } + + public static void AddIfNotDefault(this IDictionary dict, string key, object value, object defaultValue) + { + dict.AddIfCondition(key, value, !defaultValue.Equals(value)); + } + + public static string GetCompiler(this IGenerationContext context) + { + var toolset = Options.GetObject(context.Configuration); + if (toolset == Options.Vc.General.PlatformToolset.ClangCL + || toolset == Options.Vc.General.PlatformToolset.LLVM + || context.Configuration.Platform.IsUsingClang()) + { + return Compiler.Clang; + } + + switch (toolset.GetDefaultDevEnvForToolset()) + { + case DevEnv.vs2015: + return Compiler.Vs15; + case DevEnv.vs2017: + return Compiler.Vs17; + case DevEnv.vs2019: + return Compiler.Vs19; + case DevEnv.vs2022: + return Compiler.Vs22; + default: + return Compiler.Unknown; + } + } + + public static string GetCppStandard(this IGenerationContext context) + { + var res = CppLanguageStandard.Default; + if (Options.HasOption(context.Configuration)) + { + context.SelectOptionWithFallback + ( + () => res = CppLanguageStandard.Default, + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP20, () => res = CppLanguageStandard.Cpp20), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.Latest, () => res = CppLanguageStandard.Latest) + ); + return res; + } + if (Options.HasOption(context.Configuration)) + { + context.SelectOptionWithFallback + ( + () => res = CppLanguageStandard.Default, + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp2a, () => res = CppLanguageStandard.Latest), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp2a, () => res = CppLanguageStandard.Latest) + ); + return res; + } + if (Options.HasOption(context.Configuration)) + { + context.SelectOptionWithFallback + ( + () => res = CppLanguageStandard.Default, + Options.Option(Options.Makefile.Compiler.CppLanguageStandard.Cpp14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Makefile.Compiler.CppLanguageStandard.GnuCpp14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Makefile.Compiler.CppLanguageStandard.Cpp17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Makefile.Compiler.CppLanguageStandard.GnuCpp17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Makefile.Compiler.CppLanguageStandard.Cpp2a, () => res = CppLanguageStandard.Latest), + Options.Option(Options.Makefile.Compiler.CppLanguageStandard.GnuCpp2a, () => res = CppLanguageStandard.Latest) + ); + return res; + } + if (Options.HasOption(context.Configuration)) + { + context.SelectOptionWithFallback + ( + () => res = CppLanguageStandard.Default, + Options.Option(Options.XCode.Compiler.CppLanguageStandard.CPP14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.XCode.Compiler.CppLanguageStandard.GNU14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.XCode.Compiler.CppLanguageStandard.CPP17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.XCode.Compiler.CppLanguageStandard.GNU17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.XCode.Compiler.CppLanguageStandard.CPP20, () => res = CppLanguageStandard.Cpp20), + Options.Option(Options.XCode.Compiler.CppLanguageStandard.GNU20, () => res = CppLanguageStandard.Cpp20) + ); + return res; + } + + context.SelectOptionWithFallback + ( + () => res = CppLanguageStandard.Default, + Options.Option(Options.Android.Compiler.CppLanguageStandard.Cpp14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Android.Compiler.CppLanguageStandard.Cpp1y, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Android.Compiler.CppLanguageStandard.GNU_Cpp14, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Android.Compiler.CppLanguageStandard.GNU_Cpp1y, () => res = CppLanguageStandard.Cpp14), + Options.Option(Options.Android.Compiler.CppLanguageStandard.Cpp17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Android.Compiler.CppLanguageStandard.Cpp1z, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Android.Compiler.CppLanguageStandard.GNU_Cpp17, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Android.Compiler.CppLanguageStandard.GNU_Cpp1z, () => res = CppLanguageStandard.Cpp17), + Options.Option(Options.Android.Compiler.CppLanguageStandard.Cpp2a, () => res = CppLanguageStandard.Latest), + Options.Option(Options.Android.Compiler.CppLanguageStandard.GNU_Cpp2a, () => res = CppLanguageStandard.Latest) + ); + + return res; + } + + public static string GetArchitecture(this IGenerationContext context) + { + var architecture = Util.GetPlatformString(context.Configuration.Platform, context.Project, context.Configuration.Target); + if (architecture == "Any CPU") + { + architecture = "x64"; + } + + return architecture.ToLower(); + } + + public static string GetOutputType(this IGenerationContext context) + { + if (context.Project is FastBuildAllProject || context.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Export) + { + return OutputType.Utility; + } + + switch (context.Configuration.Output) + { + case Project.Configuration.OutputType.Lib: + return OutputType.StaticLibrary; + case Project.Configuration.OutputType.Dll: + return OutputType.DynamicLibrary; + default: + return OutputType.Executable; + } + } + + public static bool IsRttiEnabled(this IGenerationContext context) + { + if (!context.Configuration.CheckOptions(Options.Vc.Compiler.RTTI.Disable, + Options.Makefile.Compiler.Rtti.Disable, + Options.XCode.Compiler.RTTI.Disable, + Options.Clang.Compiler.Rtti.Disable)) + { + // Check default value + return Options.GetObject(context.Configuration) != + Options.Vc.Compiler.RTTI.Disable; + } + + return false; + } + + public static bool IsExceptionEnabled(this IGenerationContext context) + { + if (!context.Configuration.CheckOptions(Options.Vc.Compiler.Exceptions.Disable, + Options.Makefile.Compiler.Exceptions.Disable, + Options.XCode.Compiler.Exceptions.Disable, + Options.Clang.Compiler.Exceptions.Disable, + Options.Android.Compiler.Exceptions.Disable)) + { + // Check default value + return Options.GetObject(context.Configuration) != Options.Vc.Compiler.Exceptions.Disable; + } + + return false; + } + + public static bool IsOptimizationEnabled(this IGenerationContext context) + { + if (!context.Configuration.CheckOptions( + Options.Vc.Compiler.Optimization.Disable, + Options.Makefile.Compiler.OptimizationLevel.Disable, + Options.XCode.Compiler.OptimizationLevel.Disable, + Options.Clang.Compiler.OptimizationLevel.Disable)) + { + // Check default value + return Options.GetObject(context.Configuration) != Options.Vc.Compiler.Optimization.Disable; + } + + return false; + } + + public static bool IsInliningEnabled(this IGenerationContext context) + { + return Options.GetObject(context.Configuration) != + Options.Vc.Compiler.Inline.Disable; + } + + public static bool IsBlob(this IGenerationContext context) + { + return context.Configuration.IsBlobbed || context.Configuration.FastBuildBlobbed; + } + + public static bool IsDebugInfo(this IGenerationContext context) + { + if (!context.Configuration.CheckOptions( + Options.Vc.General.DebugInformation.Disable, + Options.Makefile.Compiler.GenerateDebugInformation.Disable, + Options.XCode.Compiler.GenerateDebuggingSymbols.Disable, + Options.Clang.Compiler.GenerateDebugInformation.Disable, + Options.Android.Compiler.DebugInformationFormat.None)) + { + // Check default option + return Options.GetObject(context.Configuration) != + Options.Vc.General.DebugInformation.Disable; + } + + return false; + } + + public static bool IsAvx(this IGenerationContext context) + { + bool res = false; + context.SelectOptionWithFallback( + () => res = false, + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.AdvancedVectorExtensions, () => res = true), + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.AdvancedVectorExtensions2, () => res = true), + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.AdvancedVectorExtensions512, () => res = true) + ); + + return res; + } + + public static bool IsConformanceMode(this IGenerationContext context) + { + return Options.GetObject(context.Configuration) == + Options.Vc.Compiler.ConformanceMode.Enable; + } + + public static string GetPchAction(this IGenerationContext context) + { + var platformVcxproj = PlatformRegistry.Query(context.Configuration.Platform); + + if (!Options.HasOption(context.Configuration)) + { + return platformVcxproj.HasPrecomp(context) ? PchAction.Include : PchAction.None; + } + + var pchOption = Options.GetObject(context.Configuration); + switch (pchOption) + { + case Options.Vc.SourceFile.PrecompiledHeader.UsePrecompiledHeader: + return PchAction.Include; + case Options.Vc.SourceFile.PrecompiledHeader.CreatePrecompiledHeader: + return PchAction.Create; + default: + return PchAction.None; + } + } + + /// + /// Checks if one of the presents in without trying to get default values. + /// Comparing to IGenerationContext.SelectOption(), can check options of different types. + /// + private static bool CheckOptions(this Project.Configuration config, params object[] options) + { + var optionsType = typeof(Options); + var getObjectArgsTypes = new Type[] { typeof(Project.Configuration) }; + var configArg = new object[] { config }; + + var getObjectMethod = optionsType.GetMethod("GetObject", getObjectArgsTypes); + var hasObjectMethod = optionsType.GetMethod("HasOption"); + + foreach (var option in options) + { + var genericHasOption = hasObjectMethod.MakeGenericMethod(option.GetType()); + if (!(bool)genericHasOption.Invoke(null, configArg)) + { + continue; + } + + var genericGetObj = getObjectMethod.MakeGenericMethod(option.GetType()); + return genericGetObj.Invoke(null, configArg).Equals(option); + } + + var genericGetFirstObj = getObjectMethod.MakeGenericMethod(options.First().GetType()); + return genericGetFirstObj.Invoke(null, configArg).Equals(options.First()); + } + } +} diff --git a/Sharpmake.Generators/Rider/RiderJson.cs b/Sharpmake.Generators/Rider/RiderJson.cs new file mode 100644 index 000000000..7024f9582 --- /dev/null +++ b/Sharpmake.Generators/Rider/RiderJson.cs @@ -0,0 +1,481 @@ +// Copyright (c) Ubisoft. All Rights Reserved. +// Licensed under the Apache 2.0 License. See LICENSE.md in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Text; +using Sharpmake.Generators.FastBuild; +using Sharpmake.Generators.VisualStudio; + +namespace Sharpmake.Generators.Rider +{ + /// + /// Generator for Rider project model json files. + /// + public partial class RiderJson : ISolutionGenerator + { + public static bool Minimize = false; + public static bool IgnoreDefaults = false; + + private const string RiderJsonFileExtension = ".rdjson"; + + /// + /// Helper class to keep all the project information for "Modules" section of json file. + /// + private class RiderProjectInfo + { + public string Name { get; } + + public Strings PublicDependencyModules { get; } + public Strings PrivateDependencyModules { get; } + public Strings PublicIncludePaths { get; } + public Strings PrivateIncludePaths { get; } + public Strings PublicDefinitions { get; } + public Strings PrivateDefinitions { get; } + + + public RiderProjectInfo(Project project) + { + Name = project.Name; + + PublicDependencyModules = new Strings(); + PrivateDependencyModules = new Strings(); + PublicIncludePaths = new Strings(); + PrivateIncludePaths = new Strings(); + PublicDefinitions = new Strings(); + PrivateDefinitions = new Strings(); + } + + /// + /// Gathers all the needed information from . + /// + public void ReadConfiguration(Project.Configuration config) + { + PublicDependencyModules.AddRange(config.ResolvedPublicDependencies.Select(it => it.Project.GetQualifiedName())); + PrivateDependencyModules.AddRange(config.ResolvedPrivateDependencies.Select(it => it.Project.GetQualifiedName())); + PublicIncludePaths.AddRange(config.IncludePaths); + PrivateIncludePaths.AddRange(config.IncludePrivatePaths); + PublicDefinitions.AddRange(config.ExportDefines); + PrivateDefinitions.AddRange(config.Defines); + } + + /// + /// Returns OrderedDictionary for json serialization + /// + public OrderedDictionary ToDictionary() + { + var resDict = new OrderedDictionary(); + + resDict.AddIfCondition("PublicDependencyModules", PublicDependencyModules, PublicDependencyModules.Count != 0); + resDict.AddIfCondition("PrivateDependencyModules", PrivateDependencyModules, PrivateDependencyModules.Count != 0); + resDict.AddIfCondition("PublicIncludePaths", PublicIncludePaths, PublicIncludePaths.Count != 0); + resDict.AddIfCondition("PrivateIncludePaths", PrivateIncludePaths, PrivateIncludePaths.Count != 0); + resDict.AddIfCondition("PublicDefinitions", PublicDefinitions, PublicDefinitions.Count != 0); + resDict.AddIfCondition("PrivateDefinitions", PrivateDefinitions, PrivateDefinitions.Count != 0); + + return resDict; + } + } + + /// + /// Helper class for storing all the project-related information. + /// + private class RiderGenerationContext : IGenerationContext + { + public Builder Builder { get; } + public Project Project { get; } + public Project.Configuration Configuration { get; } + public string ProjectDirectory { get; set; } + public string ProjectFileName { get; } + public string ProjectPath { get; } + + public string SolutionName { get; } + + public Resolver Resolver { get; } + + public DevEnv DevelopmentEnvironment { get; } + public Options.ExplicitOptions Options { get; } + public IDictionary CommandLineOptions { get; } + public string ProjectDirectoryCapitalized { get; } + public string ProjectSourceCapitalized { get; } + public bool PlainOutput => true; + + public FastBuildMakeCommandGenerator FastBuildMakeCommandGenerator { get; } + public string FastBuildArguments { get; } + + public RiderGenerationContext(Builder builder, Project project, Project.Configuration configuration, + string projectPath, string solutionName) + { + Builder = builder; + Resolver = new Resolver(); + + FileInfo fileInfo = new FileInfo(projectPath); + ProjectPath = fileInfo.FullName; + ProjectDirectory = Path.GetDirectoryName(fileInfo.FullName); + ProjectFileName = fileInfo.Name; + Project = project; + + Configuration = configuration; + ProjectDirectoryCapitalized = Util.GetCapitalizedPath(ProjectDirectory); + ProjectSourceCapitalized = Util.GetCapitalizedPath(Project.SourceRootPath); + DevelopmentEnvironment = configuration.Target.GetFragment(); + + SolutionName = solutionName; + + Options = new Options.ExplicitOptions(); + CommandLineOptions = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); + + if (configuration.IsFastBuild) + { + FastBuildMakeCommandGenerator = new Bff.FastBuildDefaultNMakeCommandGenerator(); + + var fastBuildCommandLineOptions = FastBuildMakeCommandGenerator.GetArguments(Configuration); + fastBuildCommandLineOptions.Add(" -config $(SolutionName)" + FastBuildSettings.FastBuildConfigFileExtension); + + FastBuildArguments = string.Join(" ", fastBuildCommandLineOptions); + } + } + + 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); + } + } + + /// + /// Generates ".rdjson" file for . + /// Also gathers information about projects for later usage in "Modules" section. + /// + public void Generate(Builder builder, Solution solution, List configurations, string solutionFile, + List generatedFiles, List skipFiles) + { + var configurationMapping = new Dictionary>(); + var fileInfo = new FileInfo(solutionFile); + var solutionPath = fileInfo.Directory.FullName; + + var solutionFileName = fileInfo.Name; + var file = new FileInfo( + Util.GetCapitalizedPath(solutionPath + Path.DirectorySeparatorChar + solutionFileName + RiderJsonFileExtension)); + + var projects = new OrderedDictionary(); + + foreach (var solutionConfig in configurations) + { + foreach (var proj in solutionConfig.IncludedProjectInfos) + { + if (proj.Project.SharpmakeProjectType != Project.ProjectTypeAttribute.Generate) + { + continue; + } + + var solutionFolder = string.IsNullOrEmpty(proj.SolutionFolder) + ? proj.Configuration.GetSolutionFolder(solution.Name) + : proj.SolutionFolder; + var projectEntry = solutionFolder + (solutionFolder.EndsWith("/") ? "" : "/") + proj.Project.Name; + if (!projects.Contains(projectEntry)) + { + projects.Add(projectEntry, new Dictionary>()); + } + + var projObject = projects[projectEntry] as Dictionary>; + var projConfig = new Dictionary(); + + var projectConfigurations = configurationMapping.GetValueOrAdd(proj.Project, new List()); + projectConfigurations.Add(proj.Configuration); + + projConfig.Add("ProjectConfig", proj.Configuration.Name); + projConfig.Add("SolutionConfig", solutionConfig.Name); + projConfig.Add("DoBuild", (proj.ToBuild != Solution.Configuration.IncludedProjectInfo.Build.No).ToString()); + + var platformConfigurations = projObject.GetValueOrAdd(proj.Configuration.Platform.ToString(), new List()); + platformConfigurations.Add(projConfig); + } + } + + using (var stream = new MemoryStream()) + using (var writer = new StreamWriter(stream, new UTF8Encoding(false))) + using (var serializer = new Util.JsonSerializer(writer) {IsOutputFormatted = true}) + { + serializer.IsOutputFormatted = !Minimize; + serializer.Serialize(projects); + serializer.Flush(); + + if (builder.Context.WriteGeneratedFile(null, file, stream)) + { + generatedFiles.Add(file.FullName); + } + else + { + skipFiles.Add(file.FullName); + } + } + + builder.LogWriteLine(" {0,5}", file.Name); + + var projectInfos = new Dictionary(); + foreach (var projectInfo in configurations + .SelectMany(solutionConfig => solutionConfig.IncludedProjectInfos)) + { + if (projectInfo.Project.SharpmakeProjectType != Project.ProjectTypeAttribute.Generate) + { + continue; + } + + GenerateConfiguration(builder, projectInfo.Project, projectInfos, projectInfo.Configuration, + Path.Combine(solutionPath, $".{solutionFileName}"), generatedFiles, skipFiles); + } + } + + private static void GenerateConfiguration(Builder builder, Project project, Dictionary projectInfos, Project.Configuration configuration, string projectFile, + List generatedFiles, List skipFiles) + { + var context = new RiderGenerationContext(builder, project, configuration, projectFile, + Path.GetFileName(projectFile).Substring(1)); + + var projectOptionsGen = new ProjectOptionsGenerator(); + projectOptionsGen.GenerateOptions(context); + GenerateConfiguration(context, projectInfos, generatedFiles, skipFiles); + } + + private static void GenerateConfiguration(RiderGenerationContext context, Dictionary projectInfos, List generatedFiles, List skipFiles) + { + var info = new OrderedDictionary(); + var includePaths = new Strings(); + var defines = new Strings(); + var modules = new OrderedDictionary(); + var toolchain = new OrderedDictionary(); + var buildInfo = new OrderedDictionary(); + var sourceFilesInfo = new OrderedDictionary(); + + toolchain.AddIfNotDefault("Compiler", context.GetCompiler(), RiderJsonUtil.Compiler.Default); + toolchain.AddIfNotDefault("CppStandard", context.GetCppStandard(), RiderJsonUtil.CppLanguageStandard.Default); + toolchain.AddIfNotDefault("Architecture", context.GetArchitecture(), "x64"); + toolchain.AddIfNotDefault("OutputType", context.GetOutputType(), RiderJsonUtil.OutputType.Default); + toolchain.AddIfNotDefault("bUseRTTI", context.IsRttiEnabled(), false); + toolchain.AddIfNotDefault("bUseExceptions", context.IsExceptionEnabled(), true); + toolchain.AddIfNotDefault("bIsBuildingDll", context.Configuration.Output == Project.Configuration.OutputType.Dll, false); + toolchain.Add("Configuration", context.Configuration.Name); + toolchain.AddIfNotDefault("bOptimizeCode", context.IsOptimizationEnabled(), false); + toolchain.AddIfNotDefault("bUseInlining", context.IsInliningEnabled(), false); + toolchain.AddIfNotDefault("bUseUnity", context.IsBlob(), false); + toolchain.AddIfNotDefault("bCreateDebugInfo", context.IsDebugInfo(), false); + toolchain.AddIfNotDefault("bUseAVX", context.IsAvx(), false); + toolchain.AddIfNotDefault("bStrictConformanceMode", context.IsConformanceMode(), false); + toolchain.AddIfNotDefault("PrecompiledHeaderAction", context.GetPchAction(), RiderJsonUtil.PchAction.Default); + + using (context.Resolver.NewScopedParameter("SolutionDir", context.ProjectDirectory)) + using (context.Resolver.NewScopedParameter("ProjectDir", context.Configuration.ProjectPath)) + { + var targetPath = Path.Combine(context.Configuration.TargetPath, context.Configuration.TargetFileFullNameWithExtension); + buildInfo.Add("TargetPath", targetPath); + + var commands = GetBuildCommands(context); + + buildInfo.AddIfNotDefault("BuildCmd", commands.Build, ""); + buildInfo.AddIfNotDefault("ReBuildCmd", commands.Rebuild, ""); + buildInfo.AddIfNotDefault("CleanCmd", commands.Clean, ""); + } + + var platformVcxproj = PlatformRegistry.Query(context.Configuration.Platform); + if (context.DevelopmentEnvironment.IsVisualStudio()) + { + var winIncludePath = context.DevelopmentEnvironment.GetWindowsIncludePath(); + includePaths.AddRange(winIncludePath.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); + } + + var platformIncludes = platformVcxproj.GetPlatformIncludePaths(context); + var includesString = context.Options["IncludePath"]; + if (includesString != FileGeneratorUtilities.RemoveLineTag) + { + var includesEntries = includesString.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries); + includePaths.AddRange(includesEntries); + } + + includePaths.AddRange(platformIncludes); + + defines.AddRange(platformVcxproj.GetImplicitlyDefinedSymbols(context)); + defines.AddRange(context.Options.ExplicitDefines); + + RiderProjectInfo GetOrCreateProjectInfo(Project.Configuration configuration) + { + var projectName = configuration.Project.Name; + if (projectInfos.TryGetValue(projectName, out RiderProjectInfo projectInfo)) + { + return projectInfo; + } + + var newProjectInfo = new RiderProjectInfo(configuration.Project); + newProjectInfo.ReadConfiguration(configuration); + projectInfos.Add(projectName, newProjectInfo); + + return projectInfos[projectName]; + } + + var curProjectInfo = GetOrCreateProjectInfo(context.Configuration); + modules.Add(curProjectInfo.Name, curProjectInfo.ToDictionary()); + + foreach (var dependency in context.Configuration.ResolvedDependencies) + { + var dependencyInfo = GetOrCreateProjectInfo(dependency); + var dependencyName = dependency.Project.GetQualifiedName(); + modules.Add(dependencyName, dependencyInfo.ToDictionary()); + } + + var sourceRoots = new Strings {context.Project.SourceRootPath}; + sourceRoots.AddRange(context.Project.AdditionalSourceRootPaths); + sourceFilesInfo.Add("SourceRoots", sourceRoots); + sourceFilesInfo.AddIfCondition("SourceFilesFilters", context.Project.SourceFilesFilters ?? new Strings(), + context.Project.SourceFilesFilters != null); + sourceFilesInfo.AddIfCondition("SourceFiltersRegex", + context.Project.SourceFilesIncludeRegex.Concat(context.Project.SourceFilesFiltersRegex), + context.Project.SourceFilesIncludeRegex.Count > 0 || context.Project.SourceFilesFiltersRegex.Count > 0); + sourceFilesInfo.AddIfCondition("ExcludeRegex", context.Project.SourceFilesExcludeRegex, + context.Project.SourceFilesExclude.Count > 0); + sourceFilesInfo.Add("SourceExtensions", context.Project.SourceFilesExtensions); + sourceFilesInfo.Add("SourceFiles", context.Project.ResolvedSourceFiles); + sourceFilesInfo.Add("ExcludedFiles", context.Project.SourceFilesExclude); + + info.Add("Name", context.Configuration.ProjectName); + info.Add("Configuration", context.Configuration.Name); + info.Add("Platform", context.Configuration.Platform.ToString()); + info.Add("ToolchainInfo", toolchain); + info.Add("BuildInfo", buildInfo); + + info.Add("EnvironmentIncludePaths", includePaths); + info.Add("EnvironmentDefinitions", defines); + info.Add("Modules", modules); + info.Add("SourceInfo", sourceFilesInfo); + + var file = new FileInfo(Path.Combine(context.ProjectPath, $"{context.Project.Name}_{context.Configuration.Platform}_{context.Configuration.Name}.json")); + + using (var stream = new MemoryStream()) + using (var writer = new StreamWriter(stream, new UTF8Encoding(false))) + using (var serializer = new Util.JsonSerializer(writer) { IsOutputFormatted = true }) + { + serializer.IsOutputFormatted = !Minimize; + serializer.Serialize(info); + serializer.Flush(); + + if (context.Builder.Context.WriteGeneratedFile(null, file, stream)) + { + generatedFiles.Add(Path.Combine(file.DirectoryName, file.Name)); + } + else + { + skipFiles.Add(Path.Combine(file.DirectoryName, file.Name)); + } + } + } + + private struct BuildCommands + { + public string Build; + public string Rebuild; + public string Clean; + } + + private static BuildCommands GetBuildCommands(RiderGenerationContext context) + { + if (context.Configuration.IsFastBuild) + { + var beforeBuildCommand = context.Configuration.FastBuildCustomActionsBeforeBuildCommand; + if (beforeBuildCommand == FileGeneratorUtilities.RemoveLineTag) + { + beforeBuildCommand = ""; + } + + using (context.Resolver.NewScopedParameter("BeforeBuildCommand", beforeBuildCommand)) + { + return new BuildCommands + { + Build = GetFastBuildCommand(context, FastBuildMakeCommandGenerator.BuildType.Build), + Rebuild = GetFastBuildCommand(context, FastBuildMakeCommandGenerator.BuildType.Rebuild), + Clean = GetFastBuildClean(context) + }; + } + } + + if (context.Configuration.CustomBuildSettings != null) + { + var buildSettings = context.Configuration.CustomBuildSettings; + return new BuildCommands + { + Build = buildSettings.BuildCommand, + Rebuild = buildSettings.RebuildCommand, + Clean = buildSettings.CleanCommand + }; + } + + var msBuildProjectFile = Options.PathOption.Get(context.Configuration, fallback: null); + if (msBuildProjectFile == null) + { + throw new Error( + $"`Options.Rider.MsBuildOverrideProjectFile` should be overriden in \n {context.Configuration} in order to use MSBuild with Rider"); + } + + var msBuildConfiguration = Options.StringOption.Get(context.Configuration) ?? context.Configuration.Name; + var msBuildPlatform = Options.StringOption.Get(context.Configuration) ?? Util.GetPlatformString(context.Configuration.Platform, context.Project, context.Configuration.Target); + + using (context.Resolver.NewScopedParameter("ProjectFile", msBuildProjectFile)) + using (context.Resolver.NewScopedParameter("ConfigurationName", msBuildConfiguration)) + using (context.Resolver.NewScopedParameter("PlatformName", msBuildPlatform)) + { + return new BuildCommands + { + Build = GetMsBuildCommand(context, "Build"), + Rebuild = GetMsBuildCommand(context, "Rebuild"), + Clean = GetMsBuildCommand(context, "Clean") + }; + } + } + + private static string GetFastBuildCommand(RiderGenerationContext context, FastBuildMakeCommandGenerator.BuildType commandType) + { + var unresolvedCommand = Template.FastBuildBuildCommand; + using (context.Resolver.NewScopedParameter("BuildCommand", + context.FastBuildMakeCommandGenerator.GetCommand( + commandType, + context.Configuration, context.FastBuildArguments))) + { + return context.Resolver.Resolve(unresolvedCommand) + .Replace("$(ProjectDir)", context.Configuration.ProjectPath + "\\") + .Replace("$(SolutionName)", context.SolutionName); + } + } + + private static string GetFastBuildClean(RiderGenerationContext context) + { + var unresolvedOutput = Template.FastBuildCleanCommand; + if (context.Options["IntermediateDirectory"] == FileGeneratorUtilities.RemoveLineTag + || context.Options["OutputDirectory"] == FileGeneratorUtilities.RemoveLineTag) + { + return ""; + } + + using (context.Resolver.NewScopedParameter("IntermediateDirectory", context.Options["IntermediateDirectory"])) + using (context.Resolver.NewScopedParameter("OutputDirectory", context.Options["OutputDirectory"])) + using (context.Resolver.NewScopedParameter("TargetFileFullName", context.Configuration.TargetFileFullName)) + { + return context.Resolver.Resolve(unresolvedOutput); + } + } + + private static string GetMsBuildCommand(RiderGenerationContext context, string buildCommand) + { + var unresolvedCommand = Template.MsBuildBuildCommand; + + using (context.Resolver.NewScopedParameter("Command", buildCommand)) + { + return context.Resolver.Resolve(unresolvedCommand); + } + } + } +} diff --git a/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs b/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs index ded0604ba..1d14065a1 100644 --- a/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs +++ b/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs @@ -1833,12 +1833,22 @@ private void GenerateLinkerOptions(IGenerationContext context, ProjectOptionsGen private void GenerateManifestToolOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) { + DevEnv compilerDevEnv = context.DevelopmentEnvironment; if (!context.DevelopmentEnvironment.IsVisualStudio()) // TODO: ideally this option generator should be split between VS / non-VS - return; + { + var platformToolset = Options.GetObject(context.Configuration); + var platformDevEnv = platformToolset.GetDefaultDevEnvForToolset(); + if (!platformDevEnv.HasValue) + { + return; + } + + compilerDevEnv = platformDevEnv.Value; + } Strings manifestInputs = new Strings(); - string vsManifestFilesPath = Util.SimplifyPath(Path.Combine(context.DevelopmentEnvironment.GetVisualStudioVCRootPath(), "Include", "Manifest")); + string vsManifestFilesPath = Util.SimplifyPath(Path.Combine(compilerDevEnv.GetVisualStudioVCRootPath(), "Include", "Manifest")); //EnableDpiAwareness context.SelectOption diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.cs index a839f9f47..b9525d296 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.cs @@ -500,63 +500,7 @@ private void GenerateImpl(GenerationContext context, IList generatedFile if (conf.IsFastBuild) { - var fastBuildCommandLineOptions = new List(); - - if (FastBuildSettings.FastBuildUseIDE) - fastBuildCommandLineOptions.Add("-ide"); - - if (FastBuildSettings.FastBuildReport) - fastBuildCommandLineOptions.Add("-report"); - - if (FastBuildSettings.FastBuildNoSummaryOnError) - fastBuildCommandLineOptions.Add("-nosummaryonerror"); - - if (FastBuildSettings.FastBuildSummary) - fastBuildCommandLineOptions.Add("-summary"); - - if (FastBuildSettings.FastBuildVerbose) - fastBuildCommandLineOptions.Add("-verbose"); - - if (FastBuildSettings.FastBuildMonitor) - fastBuildCommandLineOptions.Add("-monitor"); - - // Configuring cache mode if that configuration is allowed to use caching - if (conf.FastBuildCacheAllowed) - { - // Setting the appropriate cache type commandline for that target. - switch (FastBuildSettings.CacheType) - { - case FastBuildSettings.CacheTypes.CacheRead: - fastBuildCommandLineOptions.Add("-cacheread"); - break; - case FastBuildSettings.CacheTypes.CacheWrite: - fastBuildCommandLineOptions.Add("-cachewrite"); - break; - case FastBuildSettings.CacheTypes.CacheReadWrite: - fastBuildCommandLineOptions.Add("-cache"); - break; - default: - break; - } - } - - if (FastBuildSettings.FastBuildDistribution && conf.FastBuildDistribution) - fastBuildCommandLineOptions.Add("-dist"); - - if (FastBuildSettings.FastBuildWait) - fastBuildCommandLineOptions.Add("-wait"); - - if (FastBuildSettings.FastBuildNoStopOnError) - fastBuildCommandLineOptions.Add("-nostoponerror"); - - if (FastBuildSettings.FastBuildFastCancel) - fastBuildCommandLineOptions.Add("-fastcancel"); - - if (FastBuildSettings.FastBuildNoUnity) - fastBuildCommandLineOptions.Add("-nounity"); - - if (!string.IsNullOrEmpty(conf.FastBuildCustomArgs)) - fastBuildCommandLineOptions.Add(conf.FastBuildCustomArgs); + var fastBuildCommandLineOptions = FastBuildMakeCommandGenerator.GetArguments(conf); if (!string.IsNullOrEmpty(FastBuildCustomArguments)) fastBuildCommandLineOptions.Add(FastBuildCustomArguments); diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs index c72f49d90..9bd3a528f 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs @@ -100,7 +100,12 @@ Project.Configuration conf CompilerSettings compilerSettings = GetMasterCompilerSettings(masterCompilerSettings, compilerName, devEnv, projectRootPath, platformToolset, false); compilerSettings.PlatformFlags |= Platform.win64; - SetConfiguration(conf, compilerSettings.Configurations, CppConfigName(conf), projectRootPath, devEnv, false); + SetConfiguration(conf, compilerSettings.Configurations, CppConfigName(conf), projectRootPath, devEnv, platformToolset, false); + } + + private static DevEnv? GetCompilerFromToolset(DevEnv devEnv, Options.Vc.General.PlatformToolset platformToolset) + { + return platformToolset == Options.Vc.General.PlatformToolset.Default ? devEnv : platformToolset.GetDefaultDevEnvForToolset(); } public CompilerSettings GetMasterCompilerSettings( @@ -120,33 +125,22 @@ bool useCCompiler } else { - DevEnv? compilerDevEnv = null; string platformToolSetPath = null; string pathToCompiler = null; string compilerExeName = null; var compilerFamily = Sharpmake.CompilerFamily.Auto; var fastBuildSettings = PlatformRegistry.Get(Platform.win64); + var compilerDevEnv = GetCompilerFromToolset(devEnv, platformToolset); - switch (platformToolset) + if (platformToolset.IsLLVMToolchain()) { - case Options.Vc.General.PlatformToolset.Default: - compilerDevEnv = devEnv; - break; - case Options.Vc.General.PlatformToolset.LLVM: - case Options.Vc.General.PlatformToolset.ClangCL: - - platformToolSetPath = platformToolset == Options.Vc.General.PlatformToolset.ClangCL ? ClangForWindows.Settings.LLVMInstallDirVsEmbedded(devEnv) : ClangForWindows.Settings.LLVMInstallDir; - pathToCompiler = Path.Combine(platformToolSetPath, "bin"); - compilerExeName = "clang-cl.exe"; - - var compilerFamilyKey = new FastBuildWindowsCompilerFamilyKey(devEnv, platformToolset); - if (!fastBuildSettings.CompilerFamily.TryGetValue(compilerFamilyKey, out compilerFamily)) - compilerFamily = Sharpmake.CompilerFamily.ClangCl; + platformToolSetPath = platformToolset == Options.Vc.General.PlatformToolset.ClangCL ? ClangForWindows.Settings.LLVMInstallDirVsEmbedded(devEnv) : ClangForWindows.Settings.LLVMInstallDir; + pathToCompiler = Path.Combine(platformToolSetPath, "bin"); + compilerExeName = "clang-cl.exe"; - break; - default: - compilerDevEnv = platformToolset.GetDefaultDevEnvForToolset(); - break; + var compilerFamilyKey = new FastBuildWindowsCompilerFamilyKey(devEnv, platformToolset); + if (!fastBuildSettings.CompilerFamily.TryGetValue(compilerFamilyKey, out compilerFamily)) + compilerFamily = Sharpmake.CompilerFamily.ClangCl; } if (compilerDevEnv.HasValue) @@ -254,7 +248,7 @@ bool useCCompiler string executable = Path.Combine("$ExecutableRootPath$", compilerExeName); - compilerSettings = new CompilerSettings(compilerName, compilerFamily, Platform.win64, extraFiles, executable, pathToCompiler, devEnv, new Dictionary()); + compilerSettings = new CompilerSettings(compilerName, compilerFamily, Platform.win64, extraFiles, executable, pathToCompiler, compilerDevEnv ?? devEnv, new Dictionary()); masterCompilerSettings.Add(compilerName, compilerSettings); } @@ -267,6 +261,7 @@ private void SetConfiguration( string configName, string projectRootPath, DevEnv devEnv, + Options.Vc.General.PlatformToolset platformToolset, bool useCCompiler) { if (configurations.ContainsKey(configName)) @@ -275,12 +270,13 @@ private void SetConfiguration( string linkerPathOverride = null; string linkerExeOverride = null; string librarianExeOverride = null; + var compilerDevEnv = GetCompilerFromToolset(devEnv, platformToolset) ?? devEnv; GetLinkerExecutableInfo(conf, out linkerPathOverride, out linkerExeOverride, out librarianExeOverride); var fastBuildCompilerSettings = PlatformRegistry.Get(Platform.win64); string binPath; if (!fastBuildCompilerSettings.BinPath.TryGetValue(devEnv, out binPath)) - binPath = devEnv.GetVisualStudioBinPath(Platform.win64); + binPath = compilerDevEnv.GetVisualStudioBinPath(Platform.win64); string linkerPath; if (!string.IsNullOrEmpty(linkerPathOverride)) @@ -302,7 +298,7 @@ private void SetConfiguration( string resCompiler; if (!fastBuildCompilerSettings.ResCompiler.TryGetValue(devEnv, out resCompiler)) - resCompiler = devEnv.GetWindowsResourceCompiler(Platform.win64); + resCompiler = compilerDevEnv.GetWindowsResourceCompiler(Platform.win64); string capitalizedBinPath = Util.GetCapitalizedPath(Util.PathGetAbsolute(projectRootPath, binPath)); configurations.Add( diff --git a/Sharpmake/FastBuildSettings.cs b/Sharpmake/FastBuildSettings.cs index 06c98238e..2d909cdab 100644 --- a/Sharpmake/FastBuildSettings.cs +++ b/Sharpmake/FastBuildSettings.cs @@ -15,6 +15,67 @@ public enum BuildType }; public abstract string GetCommand(BuildType buildType, Sharpmake.Project.Configuration conf, string fastbuildArguments); + + public static List GetArguments(Sharpmake.Project.Configuration conf) + { + var arguments = new List(); + if (FastBuildSettings.FastBuildUseIDE) + arguments.Add("-ide"); + + if (FastBuildSettings.FastBuildReport) + arguments.Add("-report"); + + if (FastBuildSettings.FastBuildNoSummaryOnError) + arguments.Add("-nosummaryonerror"); + + if (FastBuildSettings.FastBuildSummary) + arguments.Add("-summary"); + + if (FastBuildSettings.FastBuildVerbose) + arguments.Add("-verbose"); + + if (FastBuildSettings.FastBuildMonitor) + arguments.Add("-monitor"); + + // Configuring cache mode if that configuration is allowed to use caching + if (conf.FastBuildCacheAllowed) + { + // Setting the appropriate cache type commandline for that target. + switch (FastBuildSettings.CacheType) + { + case FastBuildSettings.CacheTypes.CacheRead: + arguments.Add("-cacheread"); + break; + case FastBuildSettings.CacheTypes.CacheWrite: + arguments.Add("-cachewrite"); + break; + case FastBuildSettings.CacheTypes.CacheReadWrite: + arguments.Add("-cache"); + break; + default: + break; + } + } + + if (FastBuildSettings.FastBuildDistribution && conf.FastBuildDistribution) + arguments.Add("-dist"); + + if (FastBuildSettings.FastBuildWait) + arguments.Add("-wait"); + + if (FastBuildSettings.FastBuildNoStopOnError) + arguments.Add("-nostoponerror"); + + if (FastBuildSettings.FastBuildFastCancel) + arguments.Add("-fastcancel"); + + if (FastBuildSettings.FastBuildNoUnity) + arguments.Add("-nounity"); + + if (!string.IsNullOrEmpty(conf.FastBuildCustomArgs)) + arguments.Add(conf.FastBuildCustomArgs); + return arguments; + } } diff --git a/Sharpmake/Options.Rider.cs b/Sharpmake/Options.Rider.cs new file mode 100644 index 000000000..02fe7d32f --- /dev/null +++ b/Sharpmake/Options.Rider.cs @@ -0,0 +1,33 @@ +// Copyright (c) Ubisoft. All Rights Reserved. +// Licensed under the Apache 2.0 License. See LICENSE.md in the project root for license information. + +namespace Sharpmake +{ + public static partial class Options + { + public static class Rider + { + /// + /// Specify vcxproj for MSBuild + /// + public class MsBuildOverrideProjectFile : PathOption + { + public MsBuildOverrideProjectFile(string path) : base(path) { } + } + + public class MsBuildOverrideConfigurationName : StringOption + { + public static readonly string Default = null; + public MsBuildOverrideConfigurationName(string path) : base(path) {} + } + + public class MsBuildOverridePlatformName : StringOption + { + public static readonly string Default = null; + public MsBuildOverridePlatformName(string path) : base(path) {} + } + } + } +} + + diff --git a/Sharpmake/Target.cs b/Sharpmake/Target.cs index 06679096b..095ce1bd4 100644 --- a/Sharpmake/Target.cs +++ b/Sharpmake/Target.cs @@ -59,6 +59,11 @@ public enum DevEnv /// GNU Makefiles. /// make = 1 << 9, + + /// + /// Rider project files + /// + rider = 1 << 10, /// /// All supported Visual Studio versions. diff --git a/Sharpmake/Util.cs b/Sharpmake/Util.cs index 302cb27e9..88e05ad12 100644 --- a/Sharpmake/Util.cs +++ b/Sharpmake/Util.cs @@ -1437,7 +1437,9 @@ public static bool IsDotNet(Project.Configuration conf) public static bool IsCpp(Project.Configuration conf) { string extension = Path.GetExtension(conf.ProjectFullFileNameWithExtension); - return (string.Compare(extension, ".vcxproj", StringComparison.OrdinalIgnoreCase) == 0); + return (string.Compare(extension, ".vcxproj", StringComparison.OrdinalIgnoreCase) == 0) || + // RiderJson project files + (string.Compare(extension, ".json", StringComparison.OrdinalIgnoreCase) == 0); } public static string GetProjectFileExtension(Project.Configuration conf) @@ -1472,6 +1474,9 @@ public static string GetProjectFileExtension(Project.Configuration conf) case DevEnv.make: return ".make"; + case DevEnv.rider: + return ".json"; + default: throw new NotImplementedException("GetProjectFileExtension called with unknown DevEnv: " + devEnv); } diff --git a/samples/RiderJson/RiderJson.sharpmake.cs b/samples/RiderJson/RiderJson.sharpmake.cs new file mode 100644 index 000000000..9a51b5825 --- /dev/null +++ b/samples/RiderJson/RiderJson.sharpmake.cs @@ -0,0 +1,197 @@ +using System.IO; +using Sharpmake; + +namespace RiderJson +{ + public class BaseProject : Project + { + public BaseProject() + { + AddTargets(new Target( + Platform.win64, + DevEnv.rider | DevEnv.vs2022, + Optimization.Debug | Optimization.Release, + OutputType.Lib, + Blob.FastBuildUnitys, + BuildSystem.FastBuild | BuildSystem.MSBuild)); + } + + [Configure] + public virtual void ConfigureAll(Configuration conf, Target target) + { + conf.ProjectPath = @"[project.SharpmakeCsPath]\projects\[target.DevEnv]"; + conf.Name = "[target.Optimization] [target.BuildSystem]"; + conf.IntermediatePath = @"[conf.ProjectPath]\obj\[project.Name]\[target.Platform]_[target.Optimization]_[target.DevEnv]"; + conf.IsFastBuild = target.BuildSystem == BuildSystem.FastBuild; + conf.IsBlobbed = target.Blob == Blob.Blob; + conf.FastBuildBlobbed = target.Blob == Blob.FastBuildUnitys; + conf.AdditionalCompilerOptions.Add("/FS"); + conf.Options.Add(Options.Vc.Compiler.CppLanguageStandard.CPP17); + + if (conf.Compiler == DevEnv.rider) + { + if (target.BuildSystem == BuildSystem.MSBuild) + { + conf.TargetPath = @"[conf.ProjectPath]\..\vs2022\output\[target.Platform]\[conf.Name]"; + conf.Options.Add(new Options.Rider.MsBuildOverrideProjectFile(@"[conf.ProjectPath]\..\vs2022\[project.Name].vcxproj")); + } + + conf.Options.Add(Options.Vc.General.PlatformToolset.v143); + } + } + } + + public class LibraryBaseProject : BaseProject + { + public override void ConfigureAll(Configuration conf, Target target) + { + base.ConfigureAll(conf, target); + + conf.IncludePaths.Add(@"[project.SourceRootPath]\public"); + conf.IncludePrivatePaths.Add(@"[project.SourceRootPath]\private"); + conf.PrecompHeader = "precomp.hpp"; + conf.PrecompSource = "precomp.cpp"; + conf.Defines.Add("LIBRARY_COMPILE"); + conf.SolutionFolder = "Libs/"; + + conf.Output = Configuration.OutputType.Lib; + } + } + + [Generate] + public class LibraryProject1 : LibraryBaseProject + { + public LibraryProject1() + { + Name = "Lib1_Proj"; + SourceRootPath = @"[project.SharpmakeCsPath]\codebase\library1"; + } + } + + [Generate] + public class LibraryProject2 : LibraryBaseProject + { + public LibraryProject2() + { + Name = "Lib2_Proj"; + SourceRootPath = @"[project.SharpmakeCsPath]\codebase\library2"; + } + + public override void ConfigureAll(Configuration conf, Target target) + { + base.ConfigureAll(conf, target); + conf.AddPublicDependency(target); + } + } + + [Generate] + public class ExecutableProject1 : BaseProject + { + public ExecutableProject1() + { + Name = "Exe1_Proj"; + SourceRootPath = @"[project.SharpmakeCsPath]\codebase\executable1"; + } + + public override void ConfigureAll(Configuration conf, Target target) + { + base.ConfigureAll(conf, target); + conf.AddPrivateDependency(target); + } + } + + [Generate] + public class ExecutableProject2 : BaseProject + { + public ExecutableProject2() + { + Name = "Exe2_Proj"; + SourceRootPath = @"[project.SharpmakeCsPath]\codebase\executable2"; + } + + public override void ConfigureAll(Configuration conf, Target target) + { + base.ConfigureAll(conf, target); + conf.AddPrivateDependency(target); + } + } + + public class BaseSolution : Solution + { + public BaseSolution() + { + AddTargets(new Target( + Platform.win64, + DevEnv.rider | DevEnv.vs2022, + Optimization.Debug | Optimization.Release, + OutputType.Lib, + Blob.FastBuildUnitys, + BuildSystem.FastBuild | BuildSystem.MSBuild)); + } + + [Configure] + public virtual void ConfigureAll(Configuration conf, Target target) + { + conf.Name = @"[target.Optimization] [target.BuildSystem]"; + conf.SolutionPath = @"[solution.SharpmakeCsPath]\projects\[target.DevEnv]"; + } + } + + [Generate] + public class FirstSolution : BaseSolution + { + public FirstSolution() + { + Name = "Sol1"; + } + + public override void ConfigureAll(Configuration conf, Target target) + { + base.ConfigureAll(conf, target); + + conf.AddProject(target); + conf.AddProject(target); + conf.AddProject(target); + } + } + + [Generate] + public class SecondSolution : BaseSolution + { + public SecondSolution() + { + Name = "Sol2"; + } + + public override void ConfigureAll(Configuration conf, Target target) + { + base.ConfigureAll(conf, target); + + conf.AddProject(target); + conf.AddProject(target); + conf.AddProject(target); + conf.AddProject(target); + } + } + + public static class Main + { + [Sharpmake.Main] + public static void SharpmakeMain(Sharpmake.Arguments args) + { + string relativeRootPath = @".\codebase"; + FileInfo fileInfo = Util.GetCurrentSharpmakeFileInfo(); + string rootDirectory = Path.Combine(fileInfo.DirectoryName, relativeRootPath); + var rootDir = Util.SimplifyPath(rootDirectory); + + FastBuildSettings.SetPathToResourceCompilerInEnvironment = true; + + KitsRootPaths.SetUseKitsRootForDevEnv(DevEnv.vs2019, KitsRootEnum.KitsRoot10, Options.Vc.General.WindowsTargetPlatformVersion.v10_0_19041_0); + string sharpmakeFastBuildDir = Util.PathGetAbsolute(rootDir, @"..\..\..\tools\FastBuild"); + FastBuildSettings.FastBuildMakeCommand = Path.Combine(sharpmakeFastBuildDir, "Windows-x64", "FBuild.exe"); + + args.Generate(); + args.Generate(); + } + } +} diff --git a/samples/RiderJson/codebase/executable1/private/main.cpp b/samples/RiderJson/codebase/executable1/private/main.cpp new file mode 100644 index 000000000..166a35641 --- /dev/null +++ b/samples/RiderJson/codebase/executable1/private/main.cpp @@ -0,0 +1,8 @@ +#include +#include + +int main() { + std::cout << Ack() << std::endl; + + return 0; +} diff --git a/samples/RiderJson/codebase/executable2/private/main.cpp b/samples/RiderJson/codebase/executable2/private/main.cpp new file mode 100644 index 000000000..0d977f29d --- /dev/null +++ b/samples/RiderJson/codebase/executable2/private/main.cpp @@ -0,0 +1,10 @@ +#include + +#include + +int main() { + + std::cout << Ack2() << std::endl; + + return 0; +} diff --git a/samples/RiderJson/codebase/library1/private/function1.cpp b/samples/RiderJson/codebase/library1/private/function1.cpp new file mode 100644 index 000000000..ad349e300 --- /dev/null +++ b/samples/RiderJson/codebase/library1/private/function1.cpp @@ -0,0 +1,7 @@ +#include "precomp.hpp" +#include "function1.hpp" + +long Ack() +{ + return 1; +} diff --git a/samples/RiderJson/codebase/library1/public/apiexport.hpp b/samples/RiderJson/codebase/library1/public/apiexport.hpp new file mode 100644 index 000000000..49d7c5a58 --- /dev/null +++ b/samples/RiderJson/codebase/library1/public/apiexport.hpp @@ -0,0 +1,23 @@ +#if !defined(_LIBRARY_APIEXPORT_HPP) +#define _LIBRARY_APIEXPORT_HPP + +// dllexport boilerplate +#if defined(LIBRARY_DLL) +# if defined(_MSC_VER) +# if defined(LIBRARY_COMPILE) +# define LIBRARY_API __declspec(dllexport) +# else +# define LIBRARY_API __declspec(dllimport) +# endif +# elif defined(__GNUC__) || defined(__clang__) +# if defined(LIBRARY_COMPILE) +# define LIBRARY_API __attribute__ ((visibility ("default"))) +# endif +# endif +#endif + +#if !defined(LIBRARY_API) +# define LIBRARY_API +#endif + +#endif // _LIBRARY_APIEXPORT_HPP diff --git a/samples/RiderJson/codebase/library1/public/function1.hpp b/samples/RiderJson/codebase/library1/public/function1.hpp new file mode 100644 index 000000000..7637736d1 --- /dev/null +++ b/samples/RiderJson/codebase/library1/public/function1.hpp @@ -0,0 +1,8 @@ +#if !defined(_LIBRARY_FUNCTION_HPP) +#define _LIBRARY_FUNCTION_HPP + +#include + +LIBRARY_API long Ack(); + +#endif // _LIBRARY_FUNCTION_HPP diff --git a/samples/RiderJson/codebase/library1/public/precomp.cpp b/samples/RiderJson/codebase/library1/public/precomp.cpp new file mode 100644 index 000000000..22b304542 --- /dev/null +++ b/samples/RiderJson/codebase/library1/public/precomp.cpp @@ -0,0 +1 @@ +#include "precomp.hpp" diff --git a/samples/RiderJson/codebase/library1/public/precomp.hpp b/samples/RiderJson/codebase/library1/public/precomp.hpp new file mode 100644 index 000000000..69dc56070 --- /dev/null +++ b/samples/RiderJson/codebase/library1/public/precomp.hpp @@ -0,0 +1,6 @@ +#if !defined(_FUNCTION_PRECOMP_HPP) +#define _FUNCTION_PRECOMP_HPP + +#include "apiexport.hpp" + +#endif // _FUNCTION_PRECOMP_HPP diff --git a/samples/RiderJson/codebase/library2/private/function2.cpp b/samples/RiderJson/codebase/library2/private/function2.cpp new file mode 100644 index 000000000..aab04ddc4 --- /dev/null +++ b/samples/RiderJson/codebase/library2/private/function2.cpp @@ -0,0 +1,8 @@ +#include "precomp.hpp" +#include +#include "function2.hpp" + +long Ack2() +{ + return Ack() * 2; +} diff --git a/samples/RiderJson/codebase/library2/public/apiexport.hpp b/samples/RiderJson/codebase/library2/public/apiexport.hpp new file mode 100644 index 000000000..49d7c5a58 --- /dev/null +++ b/samples/RiderJson/codebase/library2/public/apiexport.hpp @@ -0,0 +1,23 @@ +#if !defined(_LIBRARY_APIEXPORT_HPP) +#define _LIBRARY_APIEXPORT_HPP + +// dllexport boilerplate +#if defined(LIBRARY_DLL) +# if defined(_MSC_VER) +# if defined(LIBRARY_COMPILE) +# define LIBRARY_API __declspec(dllexport) +# else +# define LIBRARY_API __declspec(dllimport) +# endif +# elif defined(__GNUC__) || defined(__clang__) +# if defined(LIBRARY_COMPILE) +# define LIBRARY_API __attribute__ ((visibility ("default"))) +# endif +# endif +#endif + +#if !defined(LIBRARY_API) +# define LIBRARY_API +#endif + +#endif // _LIBRARY_APIEXPORT_HPP diff --git a/samples/RiderJson/codebase/library2/public/function2.hpp b/samples/RiderJson/codebase/library2/public/function2.hpp new file mode 100644 index 000000000..db57ffc1a --- /dev/null +++ b/samples/RiderJson/codebase/library2/public/function2.hpp @@ -0,0 +1,8 @@ +#if !defined(_LIBRARY_FUNCTION_HPP) +#define _LIBRARY_FUNCTION_HPP + +#include + +LIBRARY_API long Ack2(); + +#endif // _LIBRARY_FUNCTION_HPP diff --git a/samples/RiderJson/codebase/library2/public/precomp.cpp b/samples/RiderJson/codebase/library2/public/precomp.cpp new file mode 100644 index 000000000..22b304542 --- /dev/null +++ b/samples/RiderJson/codebase/library2/public/precomp.cpp @@ -0,0 +1 @@ +#include "precomp.hpp" diff --git a/samples/RiderJson/codebase/library2/public/precomp.hpp b/samples/RiderJson/codebase/library2/public/precomp.hpp new file mode 100644 index 000000000..69dc56070 --- /dev/null +++ b/samples/RiderJson/codebase/library2/public/precomp.hpp @@ -0,0 +1,6 @@ +#if !defined(_FUNCTION_PRECOMP_HPP) +#define _FUNCTION_PRECOMP_HPP + +#include "apiexport.hpp" + +#endif // _FUNCTION_PRECOMP_HPP