From 4dd23d9c11fd3d3f70afb0eec97e4c8d4caec7ab Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Thu, 17 Aug 2017 22:10:00 +1000 Subject: [PATCH 1/6] Build-time code generation for .NET Core --- Directory.Build.props | 4 + Directory.Build.targets | 9 +- Orleans.sln | 84 ++++-- .../ClientGenerator.Bootstrap.csproj | 37 +++ src/BootstrapBuild/Directory.Build.props | 13 + src/BootstrapBuild/Directory.Build.targets | 1 + .../Orleans/Orleans.Bootstrap.csproj | 47 +++ .../OrleansCodeGenerator.Bootstrap.csproj | 32 ++ src/ClientGenerator/AppDomainCodeGenerator.cs | 117 ++++++++ src/ClientGenerator/AssemblyResolver.cs | 135 +++++++++ src/ClientGenerator/BootstrapCodegen.proj | 81 ----- src/ClientGenerator/ClientGenerator.cs | 277 +++++------------- src/ClientGenerator/ClientGenerator.csproj | 67 +++-- src/ClientGenerator/CodeGenOptions.cs | 16 + src/ClientGenerator/CodeGenerator.cs | 117 ++++++++ src/ClientGenerator/GenerateOrleansCode.cs | 65 ++++ .../Properties/AssemblyInfo.cs | 5 - src/ClientGenerator/app.config | 6 - ...Orleans.OrleansCodeGenerator.Build.targets | 58 ++++ ...Orleans.OrleansCodeGenerator.Build.targets | 3 + src/Orleans.SDK.targets | 73 ----- src/Orleans/Orleans.csproj | 27 +- src/OrleansSQLUtils/OrleansSQLUtils.csproj | 6 +- 23 files changed, 834 insertions(+), 446 deletions(-) create mode 100644 src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj create mode 100644 src/BootstrapBuild/Directory.Build.props create mode 100644 src/BootstrapBuild/Directory.Build.targets create mode 100644 src/BootstrapBuild/Orleans/Orleans.Bootstrap.csproj create mode 100644 src/BootstrapBuild/OrleansCodeGenerator/OrleansCodeGenerator.Bootstrap.csproj create mode 100644 src/ClientGenerator/AppDomainCodeGenerator.cs create mode 100644 src/ClientGenerator/AssemblyResolver.cs delete mode 100644 src/ClientGenerator/BootstrapCodegen.proj create mode 100644 src/ClientGenerator/CodeGenOptions.cs create mode 100644 src/ClientGenerator/CodeGenerator.cs create mode 100644 src/ClientGenerator/GenerateOrleansCode.cs delete mode 100644 src/ClientGenerator/Properties/AssemblyInfo.cs delete mode 100644 src/ClientGenerator/app.config create mode 100644 src/ClientGenerator/build/Microsoft.Orleans.OrleansCodeGenerator.Build.targets create mode 100644 src/ClientGenerator/buildMultiTargeting/Microsoft.Orleans.OrleansCodeGenerator.Build.targets delete mode 100644 src/Orleans.SDK.targets diff --git a/Directory.Build.props b/Directory.Build.props index 7bcbdf3c6d..d136f4d14d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -26,6 +26,7 @@ true $(NoWarn);1591 true + true @@ -43,6 +44,9 @@ 4.3.0 + + 15.3.409 + 2.0.0 1.4.0 4.3.2 1.5.0 diff --git a/Directory.Build.targets b/Directory.Build.targets index 7e10fec20d..b03c872161 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,10 +1,9 @@ - + - + - - $(SourceRoot)/Bootstrap/$(Configuration)/ + $(SourceRoot)Bootstrap/$(BuildFlavor)/$(Configuration)/ClientGenerator.exe - + diff --git a/Orleans.sln b/Orleans.sln index d2af413cc8..0df2e6ffc3 100644 --- a/Orleans.sln +++ b/Orleans.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.15 +VisualStudioVersion = 15.0.26730.16 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4CD3AA9E-D937-48CA-BB6C-158E12257D23}" EndProject @@ -10,8 +10,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Versions", "Versions", "{91 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{2CAB7894-777C-42B1-8B1E-322868CE92C7}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientGenerator", "src\ClientGenerator\ClientGenerator.csproj", "{E782DD19-51F7-4F66-8217-BACAC33767E4}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Orleans", "src\Orleans\Orleans.csproj", "{BC1BD60C-E7D8-4452-A21C-290AEC8E2E74}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrleansCodeGenerator", "src\OrleansCodeGenerator\OrleansCodeGenerator.csproj", "{8D937706-F6DA-4D33-B0A9-24A260BD3080}" @@ -120,10 +118,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Orleans.Core.Abstractions", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Logging.Legacy", "src\Logging.Legacy\Logging.Legacy.csproj", "{0A5009BF-C7D2-463B-BF39-34E1F5EF2F23}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5A71FFF4-651D-4D9F-B57E-333D6CB38D27}" - ProjectSection(SolutionItems) = preProject - src\ClientGenerator\BootstrapCodegen.proj = src\ClientGenerator\BootstrapCodegen.proj - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientGenerator", "src\ClientGenerator\ClientGenerator.csproj", "{345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bootstrap", "bootstrap", "{DA143BBE-5D97-4792-8E36-44A3FA727C74}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Orleans.Bootstrap", "src\BootstrapBuild\Orleans\Orleans.Bootstrap.csproj", "{0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientGenerator.Bootstrap", "src\BootstrapBuild\ClientGenerator\ClientGenerator.Bootstrap.csproj", "{F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrleansCodeGenerator.Bootstrap", "src\BootstrapBuild\OrleansCodeGenerator\OrleansCodeGenerator.Bootstrap.csproj", "{9B07237D-651C-497D-9E8D-EADC8FAF26FF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Orleans.Transactions", "src\Orleans.Transactions\Orleans.Transactions.csproj", "{072B1B88-FE98-4354-86FA-AB6EF80EB9C4}" EndProject @@ -141,18 +144,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Debug|x64.ActiveCfg = Debug|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Debug|x64.Build.0 = Debug|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Debug|x86.ActiveCfg = Debug|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Debug|x86.Build.0 = Debug|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Release|Any CPU.Build.0 = Release|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Release|x64.ActiveCfg = Release|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Release|x64.Build.0 = Release|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Release|x86.ActiveCfg = Release|Any CPU - {E782DD19-51F7-4F66-8217-BACAC33767E4}.Release|x86.Build.0 = Release|Any CPU {BC1BD60C-E7D8-4452-A21C-290AEC8E2E74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BC1BD60C-E7D8-4452-A21C-290AEC8E2E74}.Debug|Any CPU.Build.0 = Debug|Any CPU {BC1BD60C-E7D8-4452-A21C-290AEC8E2E74}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -801,6 +792,54 @@ Global {0A5009BF-C7D2-463B-BF39-34E1F5EF2F23}.Release|x64.Build.0 = Release|Any CPU {0A5009BF-C7D2-463B-BF39-34E1F5EF2F23}.Release|x86.ActiveCfg = Release|Any CPU {0A5009BF-C7D2-463B-BF39-34E1F5EF2F23}.Release|x86.Build.0 = Release|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Debug|Any CPU.Build.0 = Debug|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Debug|x64.ActiveCfg = Debug|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Debug|x64.Build.0 = Debug|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Debug|x86.ActiveCfg = Debug|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Debug|x86.Build.0 = Debug|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Release|Any CPU.ActiveCfg = Release|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Release|Any CPU.Build.0 = Release|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Release|x64.ActiveCfg = Release|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Release|x64.Build.0 = Release|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Release|x86.ActiveCfg = Release|Any CPU + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511}.Release|x86.Build.0 = Release|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Debug|x64.ActiveCfg = Debug|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Debug|x64.Build.0 = Debug|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Debug|x86.ActiveCfg = Debug|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Debug|x86.Build.0 = Debug|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Release|Any CPU.Build.0 = Release|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Release|x64.ActiveCfg = Release|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Release|x64.Build.0 = Release|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Release|x86.ActiveCfg = Release|Any CPU + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B}.Release|x86.Build.0 = Release|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Debug|x64.ActiveCfg = Debug|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Debug|x64.Build.0 = Debug|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Debug|x86.ActiveCfg = Debug|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Debug|x86.Build.0 = Debug|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Release|Any CPU.Build.0 = Release|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Release|x64.ActiveCfg = Release|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Release|x64.Build.0 = Release|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Release|x86.ActiveCfg = Release|Any CPU + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1}.Release|x86.Build.0 = Release|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Debug|x64.ActiveCfg = Debug|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Debug|x64.Build.0 = Debug|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Debug|x86.ActiveCfg = Debug|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Debug|x86.Build.0 = Debug|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Release|Any CPU.Build.0 = Release|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Release|x64.ActiveCfg = Release|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Release|x64.Build.0 = Release|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Release|x86.ActiveCfg = Release|Any CPU + {9B07237D-651C-497D-9E8D-EADC8FAF26FF}.Release|x86.Build.0 = Release|Any CPU {072B1B88-FE98-4354-86FA-AB6EF80EB9C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {072B1B88-FE98-4354-86FA-AB6EF80EB9C4}.Debug|Any CPU.Build.0 = Debug|Any CPU {072B1B88-FE98-4354-86FA-AB6EF80EB9C4}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -832,7 +871,6 @@ Global GlobalSection(NestedProjects) = preSolution {9198D099-4C31-4017-8A02-E50C654CC7D4} = {A6573187-FD0D-4DF7-91D1-03E07E470C0A} {2CAB7894-777C-42B1-8B1E-322868CE92C7} = {A6573187-FD0D-4DF7-91D1-03E07E470C0A} - {E782DD19-51F7-4F66-8217-BACAC33767E4} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} {BC1BD60C-E7D8-4452-A21C-290AEC8E2E74} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} {8D937706-F6DA-4D33-B0A9-24A260BD3080} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} {8D33951F-683E-4513-8D7D-FB45206C9607} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} @@ -883,10 +921,14 @@ Global {8A652779-85EF-48E2-A639-1EED3CE2C39C} = {A6573187-FD0D-4DF7-91D1-03E07E470C0A} {A4F61392-36A3-457C-80D0-9CDC48F5922F} = {A6573187-FD0D-4DF7-91D1-03E07E470C0A} {1153256E-10C2-4729-ACDC-5DF18A7B92B5} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} - {6E5860C5-44E7-415C-80D6-3ECF15A80796} = {FE2E08C6-9C3B-4AEE-AE07-CCA387580D7A} + {6E5860C5-44E7-415C-80D6-3ECF15A80796} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} {EBD697E3-91BE-4844-B3F0-6997300A8C12} = {A6573187-FD0D-4DF7-91D1-03E07E470C0A} {73514686-D25D-478B-9943-A86F6B0F3A37} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} {0A5009BF-C7D2-463B-BF39-34E1F5EF2F23} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} + {345B12A5-C5F3-4AFC-84AA-A8CC00F8D511} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} + {0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B} = {DA143BBE-5D97-4792-8E36-44A3FA727C74} + {F7D70028-7E3B-48E3-92B9-DB889AE5ABD1} = {DA143BBE-5D97-4792-8E36-44A3FA727C74} + {9B07237D-651C-497D-9E8D-EADC8FAF26FF} = {DA143BBE-5D97-4792-8E36-44A3FA727C74} {072B1B88-FE98-4354-86FA-AB6EF80EB9C4} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} {CFD22413-CB67-40D6-B389-F038C8C38365} = {A6573187-FD0D-4DF7-91D1-03E07E470C0A} {FE2E08C6-9C3B-4AEE-AE07-CCA387580D7A} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23} diff --git a/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj b/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj new file mode 100644 index 0000000000..60c259faa2 --- /dev/null +++ b/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj @@ -0,0 +1,37 @@ + + + + net461 + Exe + ClientGenerator + Microsoft.Orleans.CodeGenerator.MSBuild + $(SourceRoot)src/ClientGenerator/ + $(SourceRoot)Bootstrap/$(BuildFlavor)/$(Configuration)/ + true + true + + + + + + _%(Filename).%(Extension) + false + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/BootstrapBuild/Directory.Build.props b/src/BootstrapBuild/Directory.Build.props new file mode 100644 index 0000000000..cfe795e723 --- /dev/null +++ b/src/BootstrapBuild/Directory.Build.props @@ -0,0 +1,13 @@ + + + <_ParentDirectoryBuildPropsPath Condition="'$(_DirectoryBuildPropsFile)' != ''">$([System.IO.Path]::Combine('..', '$(_DirectoryBuildPropsFile)')) + + + + + + false + $(DefineConstants);EXCLUDE_CODEGEN + true + + \ No newline at end of file diff --git a/src/BootstrapBuild/Directory.Build.targets b/src/BootstrapBuild/Directory.Build.targets new file mode 100644 index 0000000000..4230916164 --- /dev/null +++ b/src/BootstrapBuild/Directory.Build.targets @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/BootstrapBuild/Orleans/Orleans.Bootstrap.csproj b/src/BootstrapBuild/Orleans/Orleans.Bootstrap.csproj new file mode 100644 index 0000000000..1502bc27de --- /dev/null +++ b/src/BootstrapBuild/Orleans/Orleans.Bootstrap.csproj @@ -0,0 +1,47 @@ + + + + Orleans + Orleans + $(SourceRoot)src/Orleans/ + + + + + + _%(Filename).%(Extension) + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BootstrapBuild/OrleansCodeGenerator/OrleansCodeGenerator.Bootstrap.csproj b/src/BootstrapBuild/OrleansCodeGenerator/OrleansCodeGenerator.Bootstrap.csproj new file mode 100644 index 0000000000..3df749218f --- /dev/null +++ b/src/BootstrapBuild/OrleansCodeGenerator/OrleansCodeGenerator.Bootstrap.csproj @@ -0,0 +1,32 @@ + + + + OrleansCodeGenerator + OrleansCodeGenerator + $(SourceRoot)src/OrleansCodeGenerator/ + + + + + + _%(Filename).%(Extension) + false + + + + + + + + + + + + + + + + + + + diff --git a/src/ClientGenerator/AppDomainCodeGenerator.cs b/src/ClientGenerator/AppDomainCodeGenerator.cs new file mode 100644 index 0000000000..19bfb744c3 --- /dev/null +++ b/src/ClientGenerator/AppDomainCodeGenerator.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Orleans.CodeGeneration; +using Orleans.Runtime.Configuration; +using Orleans.CodeGenerator; +using Orleans.Serialization; + +#if NET461 +namespace Orleans.CodeGeneration +{ + public class AppDomainCodeGenerator : MarshalByRefObject + { + public static string GenerateCode(CodeGenOptions options) + { + AppDomain appDomain = null; + try + { + var assembly = typeof(AppDomainCodeGenerator).GetTypeInfo().Assembly; + + // Create AppDomain. + var appDomainSetup = new AppDomainSetup + { + ApplicationBase = Path.GetDirectoryName(assembly.Location), + DisallowBindingRedirects = false, + ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile + }; + appDomain = AppDomain.CreateDomain("Orleans-CodeGen Domain", null, appDomainSetup); + + // Set up assembly resolver + var refResolver = new ReferenceResolver(options.ReferencedAssemblies); + appDomain.AssemblyResolve += refResolver.ResolveAssembly; + + // Create an instance + var generator = + (AppDomainCodeGenerator) + appDomain.CreateInstanceAndUnwrap( + assembly.FullName, + // ReSharper disable once AssignNullToNotNullAttribute + typeof(AppDomainCodeGenerator).FullName); + + // Call a method + return generator.GenerateCodeInternal(options); + } + finally + { + if (appDomain != null) AppDomain.Unload(appDomain); // Unload the AppDomain + } + } + + private string GenerateCodeInternal(CodeGenOptions options) + { + // Load input assembly + // special case Orleans.dll because there is a circular dependency. + var assemblyName = AssemblyName.GetAssemblyName(options.InputAssembly.FullName); + var grainAssembly = Path.GetFileName(options.InputAssembly.FullName) != "Orleans.dll" + ? Assembly.LoadFrom(options.InputAssembly.FullName) + : Assembly.Load(assemblyName); + + // Create directory for output file if it does not exist + var outputFileDirectory = Path.GetDirectoryName(options.OutputFileName); + + if (!String.IsNullOrEmpty(outputFileDirectory) && !Directory.Exists(outputFileDirectory)) + { + Directory.CreateDirectory(outputFileDirectory); + } + + var config = new ClusterConfiguration(); + var codeGenerator = new RoslynCodeGenerator(new SerializationManager(null, config.Globals, config.Defaults)); + return codeGenerator.GenerateSourceForAssembly(grainAssembly); + } + + /// + /// Simple class that loads the reference assemblies upon the AppDomain.AssemblyResolve + /// + [Serializable] + public class ReferenceResolver + { + /// + /// Needs to be public so can be serialized accross the the app domain. + /// + public Dictionary ReferenceAssemblyPaths { get; } = new Dictionary(); + + /// + /// Inits the resolver + /// + /// Full paths of referenced assemblies + public ReferenceResolver(IEnumerable referencedAssemblies) + { + if (null == referencedAssemblies) return; + + foreach (var assemblyPath in referencedAssemblies) ReferenceAssemblyPaths[Path.GetFileNameWithoutExtension(assemblyPath)] = assemblyPath; + } + + /// + /// Handles System.AppDomain.AssemblyResolve event of an System.AppDomain + /// + /// The source of the event. + /// The event data. + /// The assembly that resolves the type, assembly, or resource; + /// or null if theassembly cannot be resolved. + /// + public Assembly ResolveAssembly(object sender, ResolveEventArgs args) + { + Assembly assembly = null; + string path; + var asmName = new AssemblyName(args.Name); + if (ReferenceAssemblyPaths.TryGetValue(asmName.Name, out path)) assembly = Assembly.LoadFrom(path); + else Console.WriteLine("Could not resolve {0}:", asmName.Name); + return assembly; + } + } + + } +} +#endif diff --git a/src/ClientGenerator/AssemblyResolver.cs b/src/ClientGenerator/AssemblyResolver.cs new file mode 100644 index 0000000000..56001cf25a --- /dev/null +++ b/src/ClientGenerator/AssemblyResolver.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using Microsoft.Extensions.DependencyModel; +using Microsoft.Extensions.DependencyModel.Resolution; + +namespace Orleans.CodeGeneration +{ + /// + /// Simple class that loads the reference assemblies upon the AppDomain.AssemblyResolve + /// + internal class AssemblyResolver + { + private readonly Action log; + + /// + /// Needs to be public so can be serialized accross the the app domain. + /// + public Dictionary ReferenceAssemblyPaths { get; } = new Dictionary(); + + private readonly ICompilationAssemblyResolver assemblyResolver; + + private readonly DependencyContext dependencyContext; + private readonly AssemblyLoadContext loadContext; + + public AssemblyResolver(string path, List referencedAssemblies, Action log) + { + this.log = log; + if (Path.GetFileName(path) == "Orleans.dll") this.Assembly = Assembly.Load("Orleans"); + else this.Assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path); + this.dependencyContext = DependencyContext.Load(this.Assembly); + + this.assemblyResolver = new CompositeCompilationAssemblyResolver( + new ICompilationAssemblyResolver[] + { + new AppBaseCompilationAssemblyResolver(Path.GetDirectoryName(path)), + new ReferenceAssemblyPathResolver(), + new PackageCompilationAssemblyResolver() + }); + + this.loadContext = AssemblyLoadContext.GetLoadContext(this.Assembly); + AppDomain.CurrentDomain.AssemblyResolve += this.ResolveAssembly; + this.loadContext.Resolving += this.AssemblyLoadContextResolving; + if (this.loadContext != AssemblyLoadContext.Default) + { + AssemblyLoadContext.Default.Resolving += this.AssemblyLoadContextResolving; + } + + foreach (var assemblyPath in referencedAssemblies) + { + var libName = Path.GetFileNameWithoutExtension(assemblyPath); + if (!string.IsNullOrWhiteSpace(libName)) this.ReferenceAssemblyPaths[libName] = assemblyPath; + var asmName = AssemblyName.GetAssemblyName(assemblyPath); + this.ReferenceAssemblyPaths[asmName.FullName] = assemblyPath; + } + } + + public Assembly Assembly { get; } + + public void Dispose() + { + AppDomain.CurrentDomain.AssemblyResolve -= this.ResolveAssembly; + this.loadContext.Resolving -= this.AssemblyLoadContextResolving; + if (this.loadContext != AssemblyLoadContext.Default) + { + AssemblyLoadContext.Default.Resolving -= this.AssemblyLoadContextResolving; + } + } + + /// + /// Handles System.AppDomain.AssemblyResolve event of an System.AppDomain + /// + /// The source of the event. + /// The event data. + /// The assembly that resolves the type, assembly, or resource; + /// or null if theassembly cannot be resolved. + /// + public Assembly ResolveAssembly(object sender, ResolveEventArgs args) + { + return this.AssemblyLoadContextResolving(AssemblyLoadContext.GetLoadContext(args.RequestingAssembly), new AssemblyName(args.Name)); + } + + public Assembly AssemblyLoadContextResolving(AssemblyLoadContext context, AssemblyName name) + { + bool NamesMatch(RuntimeLibrary runtime) + { + return string.Equals(runtime.Name, name.Name, StringComparison.OrdinalIgnoreCase); + } + + try + { + var library = this.dependencyContext?.RuntimeLibraries?.FirstOrDefault(NamesMatch); + if (library != null) + { + var wrapper = new CompilationLibrary( + library.Type, + library.Name, + library.Version, + library.Hash, + library.RuntimeAssemblyGroups.SelectMany(g => g.AssetPaths), + library.Dependencies, + library.Serviceable); + + var assemblies = new List(); + this.assemblyResolver.TryResolveAssemblyPaths(wrapper, assemblies); + foreach (var asm in assemblies) + { + try + { + return this.loadContext.LoadFromAssemblyPath(asm); + } + catch (Exception exception) + { + this.log($"Failed to load assembly {name} from path {asm}: {exception}"); + } + } + } + + Assembly assembly = null; + if (this.ReferenceAssemblyPaths.TryGetValue(name.FullName, out string path)) assembly = this.loadContext.LoadFromAssemblyPath(path); + else if (this.ReferenceAssemblyPaths.TryGetValue(name.Name, out path)) assembly = this.loadContext.LoadFromAssemblyPath(path); + else this.log($"Could not resolve {name.Name}"); + return assembly; + } + catch (Exception exception) + { + this.log($"Exception in AssemblyLoadContextResolving for assembly {name}: {exception}"); + throw; + } + } + } +} \ No newline at end of file diff --git a/src/ClientGenerator/BootstrapCodegen.proj b/src/ClientGenerator/BootstrapCodegen.proj deleted file mode 100644 index 2b2ffb13e0..0000000000 --- a/src/ClientGenerator/BootstrapCodegen.proj +++ /dev/null @@ -1,81 +0,0 @@ - - - - $(DefineConstants);EXCLUDE_CODEGEN;ORLEANS_BOOTSTRAP - $(MSBuildProjectDirectory)\bin\$(Configuration)\Bootstrap\ - - - - - Configuration=$(Configuration); - Bootstrap=true; - OutputPath=$(BootstrapOutputPath); - IntermediateOutputPath=$(BootstrapOutputPath)obj\; - DefineConstants=$(ExcludeCodegenConstants); - IsPackable=false; - GeneratePackageOnBuild=false; - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/ClientGenerator/ClientGenerator.cs b/src/ClientGenerator/ClientGenerator.cs index bedf4b601c..03932ccc1d 100644 --- a/src/ClientGenerator/ClientGenerator.cs +++ b/src/ClientGenerator/ClientGenerator.cs @@ -1,149 +1,19 @@ +using System; +using System.IO; +using System.Reflection; +using System.Text; + namespace Orleans.CodeGeneration { - using System; - using System.Collections.Generic; - using System.IO; - using System.Reflection; - using Orleans.CodeGenerator; - using Orleans.Runtime; - using Orleans.Serialization; - using Orleans.Runtime.Configuration; - /// /// Generates factory, grain reference, and invoker classes for grain interfaces. /// Generates state object classes for grain implementation classes. /// public class GrainClientGenerator : MarshalByRefObject { - [Serializable] - internal class CodeGenOptions - { - public FileInfo InputAssembly; - - public List ReferencedAssemblies = new List(); - - public string OutputFileName; - } - - [Serializable] - internal class GrainClientGeneratorFlags - { - internal static bool Verbose = false; - - internal static bool FailOnPathNotFound = false; - } - - private static readonly int[] suppressCompilerWarnings = - { - 162, // CS0162 - Unreachable code detected. - 219, // CS0219 - The variable 'V' is assigned but its value is never used. - 414, // CS0414 - The private field 'F' is assigned but its value is never used. - 649, // CS0649 - Field 'F' is never assigned to, and will always have its default value. - 693, // CS0693 - Type parameter 'type parameter' has the same name as the type parameter from outer type 'T' - 1591, // CS1591 - Missing XML comment for publicly visible type or member 'Type_or_Member' - 1998 // CS1998 - This async method lacks 'await' operators and will run synchronously - }; - - /// - /// Generates one GrainReference class for each Grain Type in the inputLib file - /// and output code file under outputLib directory - /// - private static bool CreateGrainClientAssembly(CodeGenOptions options) - { - string generatedCode = null; - AppDomain appDomain = null; - try - { - var assembly = typeof (GrainClientGenerator).GetTypeInfo().Assembly; - // Create AppDomain. - var appDomainSetup = new AppDomainSetup - { - ApplicationBase = Path.GetDirectoryName(assembly.Location), - DisallowBindingRedirects = false, - ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile - }; - appDomain = AppDomain.CreateDomain("Orleans-CodeGen Domain", null, appDomainSetup); - - // Set up assembly resolver - var refResolver = new ReferenceResolver(options.ReferencedAssemblies); - appDomain.AssemblyResolve += refResolver.ResolveAssembly; - - // Create an instance - var generator = - (GrainClientGenerator) - appDomain.CreateInstanceAndUnwrap( - assembly.FullName, - typeof(GrainClientGenerator).FullName); - - // Call a method - generatedCode = generator.CreateGrainClient(options); - } - finally - { - if (appDomain != null) AppDomain.Unload(appDomain); // Unload the AppDomain - } - - if (generatedCode != null) - { - using (var sourceWriter = new StreamWriter(options.OutputFileName)) - { - sourceWriter.WriteLine("#if !EXCLUDE_CODEGEN"); - DisableWarnings(sourceWriter, suppressCompilerWarnings); - sourceWriter.WriteLine(generatedCode); - RestoreWarnings(sourceWriter, suppressCompilerWarnings); - sourceWriter.WriteLine("#endif"); - } - - ConsoleText.WriteStatus("Orleans-CodeGen - Generated file written {0}", options.OutputFileName); - return true; - } - - return false; - } - - /// - /// Generate one GrainReference class for each Grain Type in the inputLib file - /// and output a string with the code - /// - private string CreateGrainClient(CodeGenOptions options) - { - // Load input assembly - // special case Orleans.dll because there is a circular dependency. - var assemblyName = AssemblyName.GetAssemblyName(options.InputAssembly.FullName); - var grainAssembly = (Path.GetFileName(options.InputAssembly.FullName) != "Orleans.dll") - ? Assembly.LoadFrom(options.InputAssembly.FullName) - : Assembly.Load(assemblyName); - - // Create directory for output file if it does not exist - var outputFileDirectory = Path.GetDirectoryName(options.OutputFileName); - - if (!String.IsNullOrEmpty(outputFileDirectory) && !Directory.Exists(outputFileDirectory)) - { - Directory.CreateDirectory(outputFileDirectory); - } - - var config = new ClusterConfiguration(); - var codeGenerator = new RoslynCodeGenerator(new SerializationManager(null, config.Globals, config.Defaults)); - - // Generate source - ConsoleText.WriteStatus("Orleans-CodeGen - Generating file {0}", options.OutputFileName); - - return codeGenerator.GenerateSourceForAssembly(grainAssembly); - } - - private static void DisableWarnings(TextWriter sourceWriter, IEnumerable warnings) - { - foreach (var warningNum in warnings) sourceWriter.WriteLine("#pragma warning disable {0}", warningNum); - } - - private static void RestoreWarnings(TextWriter sourceWriter, IEnumerable warnings) - { - foreach (var warningNum in warnings) sourceWriter.WriteLine("#pragma warning restore {0}", warningNum); - } - public int RunMain(string[] args) { - ConsoleText.WriteStatus("Orleans-CodeGen - command-line = {0}", Environment.CommandLine); + Console.WriteLine("Orleans-CodeGen - command-line = {0}", Environment.CommandLine); if (args.Length < 1) { @@ -163,14 +33,12 @@ public int RunMain(string[] args) string arg = args[0]; string argsFile = arg.Trim('"').Substring(1).Trim('"'); Console.WriteLine("Orleans-CodeGen - Reading code-gen params from file={0}", argsFile); - AssertWellFormed(argsFile, true); + AssertWellFormed(argsFile); args = File.ReadAllLines(argsFile); } - int i = 1; foreach (string a in args) { string arg = a.Trim('"').Trim().Trim('"'); - if (GrainClientGeneratorFlags.Verbose) Console.WriteLine("Orleans-CodeGen - arg #{0}={1}", i++, arg); if (string.IsNullOrEmpty(arg) || string.IsNullOrWhiteSpace(arg)) continue; if (arg.StartsWith("/")) @@ -182,7 +50,7 @@ public int RunMain(string[] args) string[] references = refstr.Split(';'); foreach (string rp in references) { - AssertWellFormed(rp, true); + AssertWellFormed(rp); options.ReferencedAssemblies.Add(rp); } } @@ -195,7 +63,7 @@ public int RunMain(string[] args) else if (arg.StartsWith("/out:")) { var outfile = arg.Substring(arg.IndexOf(':') + 1); - AssertWellFormed(outfile, false); + AssertWellFormed(outfile); options.OutputFileName = outfile; } } @@ -225,53 +93,36 @@ public int RunMain(string[] args) // STEP 3 : Dump useful info for debugging Console.WriteLine($"Orleans-CodeGen - Options {Environment.NewLine}\tInputLib={options.InputAssembly.FullName}{Environment.NewLine}\tOutputFileName={options.OutputFileName}"); - if (options.ReferencedAssemblies != null) - { - Console.WriteLine("Orleans-CodeGen - Using referenced libraries:"); - foreach (string assembly in options.ReferencedAssemblies) Console.WriteLine("\t{0} => {1}", Path.GetFileName(assembly), assembly); - } - // STEP 5 : Finally call code generation - if (!CreateGrainClientAssembly(options)) return -1; + if (!new CodeGenerator(options, Console.WriteLine).GenerateCode()) return -1; // DONE! return 0; } catch (Exception ex) { - Console.WriteLine("-- Code-gen FAILED -- \n{0}", LogFormatter.PrintException(ex)); + Console.WriteLine("-- Code Generation FAILED -- \n{0}", LogFormatter.PrintException(ex)); return 3; } } private static void PrintUsage() { - Console.WriteLine("Usage: ClientGenerator.exe /in: /out: /r:"); - Console.WriteLine(" ClientGenerator.exe @ - Arguments will be read and processed from this file."); + Console.WriteLine("Usage: /in: /out: /r:"); + Console.WriteLine(" @ - Arguments will be read and processed from this file."); Console.WriteLine(); - Console.WriteLine("Example: ClientGenerator.exe /in:MyGrain.dll /out:C:\\OrleansSample\\MyGrain\\obj\\Debug\\MyGrain.orleans.g.cs /r:Orleans.dll;..\\MyInterfaces\\bin\\Debug\\MyInterfaces.dll"); + Console.WriteLine("Example: /in:MyGrain.dll /out:C:\\OrleansSample\\MyGrain\\obj\\Debug\\MyGrain.orleans.g.cs /r:Orleans.dll;..\\MyInterfaces\\bin\\Debug\\MyInterfaces.dll"); } - private static void AssertWellFormed(string path, bool mustExist = false) + private static void AssertWellFormed(string path) { CheckPathNotStartWith(path, ":"); CheckPathNotStartWith(path, "\""); CheckPathNotEndsWith(path, "\""); CheckPathNotEndsWith(path, "/"); CheckPath(path, p => !string.IsNullOrWhiteSpace(p), "Empty path string"); - - bool exists = FileExists(path); - - if (mustExist && GrainClientGeneratorFlags.FailOnPathNotFound) CheckPath(path, p => exists, "Path not exists"); } - - private static bool FileExists(string path) - { - bool exists = File.Exists(path) || Directory.Exists(path); - if (!exists) Console.WriteLine("MISSING: Path not exists: {0}", path); - return exists; - } - + private static void CheckPathNotStartWith(string path, string str) { CheckPath(path, p => !p.StartsWith(str), string.Format("Cannot start with '{0}'", str)); @@ -294,60 +145,72 @@ private static void CheckPath(string path, Func condition, string throw new ArgumentException("FAILED: " + errMsg); } - - /// - /// Simple class that loads the reference assemblies upon the AppDomain.AssemblyResolve - /// - [Serializable] - internal class ReferenceResolver + private static class LogFormatter { /// - /// Dictionary : Assembly file name without extension -> full path + /// Utility function to convert an exception into printable format, including expanding and formatting any nested sub-expressions. /// - private Dictionary referenceAssemblyPaths = new Dictionary(); + /// The exception to be printed. + /// Formatted string representation of the exception, including expanding and formatting any nested sub-expressions. + public static string PrintException(Exception exception) + { + return exception == null ? String.Empty : PrintException_Helper(exception, 0, true); + } - /// - /// Needs to be public so can be serialized accross the the app domain. - /// - public Dictionary ReferenceAssemblyPaths + private static string PrintException_Helper(Exception exception, int level, bool includeStackTrace) { - get + if (exception == null) return String.Empty; + var sb = new StringBuilder(); + sb.Append(PrintOneException(exception, level, includeStackTrace)); + if (exception is ReflectionTypeLoadException loadException) { - return referenceAssemblyPaths; + var loaderExceptions = loadException.LoaderExceptions; + if (loaderExceptions == null || loaderExceptions.Length == 0) + { + sb.Append("No LoaderExceptions found"); + } + else + { + foreach (Exception inner in loaderExceptions) + { + // call recursively on all loader exceptions. Same level for all. + sb.Append(PrintException_Helper(inner, level + 1, includeStackTrace)); + } + } } - set + else if (exception is AggregateException) { - referenceAssemblyPaths = value; - } - } - - /// - /// Inits the resolver - /// - /// Full paths of referenced assemblies - public ReferenceResolver(IEnumerable referencedAssemblies) - { - if (null == referencedAssemblies) return; + var innerExceptions = ((AggregateException)exception).InnerExceptions; + if (innerExceptions == null) return sb.ToString(); - foreach (var assemblyPath in referencedAssemblies) referenceAssemblyPaths[Path.GetFileNameWithoutExtension(assemblyPath)] = assemblyPath; + foreach (Exception inner in innerExceptions) + { + // call recursively on all inner exceptions. Same level for all. + sb.Append(PrintException_Helper(inner, level + 1, includeStackTrace)); + } + } + else if (exception.InnerException != null) + { + // call recursively on a single inner exception. + sb.Append(PrintException_Helper(exception.InnerException, level + 1, includeStackTrace)); + } + return sb.ToString(); } - /// - /// Handles System.AppDomain.AssemblyResolve event of an System.AppDomain - /// - /// The source of the event. - /// The event data. - /// The assembly that resolves the type, assembly, or resource; - /// or null if theassembly cannot be resolved. - /// - public Assembly ResolveAssembly(object sender, ResolveEventArgs args) + private static string PrintOneException(Exception exception, int level, bool includeStackTrace) { - Assembly assembly = null; - string path; - var asmName = new AssemblyName(args.Name); - if (referenceAssemblyPaths.TryGetValue(asmName.Name, out path)) assembly = Assembly.LoadFrom(path); - else ConsoleText.WriteStatus("Could not resolve {0}:", asmName.Name); - return assembly; + if (exception == null) return String.Empty; + string stack = String.Empty; + if (includeStackTrace && exception.StackTrace != null) + stack = String.Format(Environment.NewLine + exception.StackTrace); + + string message = exception.Message; + + return string.Format(Environment.NewLine + "Exc level {0}: {1}: {2}{3}", + level, + exception.GetType(), + message, + stack); } } } diff --git a/src/ClientGenerator/ClientGenerator.csproj b/src/ClientGenerator/ClientGenerator.csproj index f1a12274b5..52e6237795 100644 --- a/src/ClientGenerator/ClientGenerator.csproj +++ b/src/ClientGenerator/ClientGenerator.csproj @@ -1,23 +1,42 @@ - + + Microsoft.Orleans.OrleansCodeGenerator.Build - Microsoft Orleans Build-time Code Generation - Microsoft Orleans Build-time Code Generation to install within the grain interfaces and implementation projects. - true - true + Microsoft Orleans Build-time Code Generator + Microsoft Orleans build-time code generator to install in all grain interface & implementation projects. + + netcoreapp2.0;net461 Exe - Orleans.CodeGeneration + true + tasks ClientGenerator - net461 + Orleans.CodeGeneration + true + + + + true + %(Identity) + true + + + true + %(Identity) + true + + - - all - + + + + + + @@ -32,17 +51,17 @@ - - - true - build\$(PackageId).targets - false - - - true - tools\ - false - - - - + + + + <_PackageFiles Include="bin\$(Configuration)\**\*" Exclude="bin\$(Configuration)\**\$(AssemblyName).*"> + tasks\%(RecursiveDir) + false + Content + + + + \ No newline at end of file diff --git a/src/ClientGenerator/CodeGenOptions.cs b/src/ClientGenerator/CodeGenOptions.cs new file mode 100644 index 0000000000..d15d73018d --- /dev/null +++ b/src/ClientGenerator/CodeGenOptions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Orleans.CodeGeneration +{ + [Serializable] + public class CodeGenOptions + { + public FileInfo InputAssembly; + + public List ReferencedAssemblies = new List(); + + public string OutputFileName; + } +} \ No newline at end of file diff --git a/src/ClientGenerator/CodeGenerator.cs b/src/ClientGenerator/CodeGenerator.cs new file mode 100644 index 0000000000..94b3697583 --- /dev/null +++ b/src/ClientGenerator/CodeGenerator.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.IO; +#if !NET461 +using System.Runtime.Loader; +using Orleans.Runtime.Configuration; +using Orleans.CodeGenerator; +using Orleans.Serialization; +#endif + +namespace Orleans.CodeGeneration +{ + public class CodeGenerator + { + private static readonly int[] SuppressCompilerWarnings = + { + 162, // CS0162 - Unreachable code detected. + 219, // CS0219 - The variable 'V' is assigned but its value is never used. + 414, // CS0414 - The private field 'F' is assigned but its value is never used. + 649, // CS0649 - Field 'F' is never assigned to, and will always have its default value. + 693, // CS0693 - Type parameter 'type parameter' has the same name as the type parameter from outer type 'T' + 1591, // CS1591 - Missing XML comment for publicly visible type or member 'Type_or_Member' + 1998 // CS1998 - This async method lacks 'await' operators and will run synchronously + }; + + private readonly CodeGenOptions options; + private readonly Action log; + + public CodeGenerator(CodeGenOptions options, Action log) + { + this.options = options; + this.log = log; + } + + public bool GenerateCode() + { + var outputFileName = this.options.OutputFileName; + + // Create directory for output file if it does not exist + var outputFileDirectory = Path.GetDirectoryName(outputFileName); + + if (!string.IsNullOrEmpty(outputFileDirectory) && !Directory.Exists(outputFileDirectory)) + { + Directory.CreateDirectory(outputFileDirectory); + } + +#if NET461 + var generatedCode = AppDomainCodeGenerator.GenerateCode(this.options); +#else + var generatedCode = this.GenerateCodeInternal(); +#endif + + if (!string.IsNullOrWhiteSpace(generatedCode)) + { + using (var sourceWriter = new StreamWriter(outputFileName)) + { + sourceWriter.WriteLine("#if !EXCLUDE_CODEGEN"); + DisableWarnings(sourceWriter, SuppressCompilerWarnings); + sourceWriter.WriteLine(generatedCode); + RestoreWarnings(sourceWriter, SuppressCompilerWarnings); + sourceWriter.WriteLine("#endif"); + } + + this.log($"Orleans-CodeGen - Generated file written {outputFileName}"); + return true; + } + + return false; + } + +#if !NET461 + private string GenerateCodeInternal() + { + var outputFileName = this.options.OutputFileName; + var inputAssembly = this.options.InputAssembly.FullName; + var referencedAssemblies = this.options.ReferencedAssemblies; + + // Set up assembly resolver + var refResolver = new AssemblyResolver(inputAssembly, referencedAssemblies, this.log); + + try + { + AppDomain.CurrentDomain.AssemblyResolve += refResolver.ResolveAssembly; + AssemblyLoadContext.Default.Resolving += refResolver.AssemblyLoadContextResolving; + + // Load input assembly + // Special-case Orleans.dll because there is a circular dependency. + var grainAssembly = refResolver.Assembly; + + + var config = new ClusterConfiguration(); + var codeGenerator = new RoslynCodeGenerator(new SerializationManager(null, config.Globals, config.Defaults)); + + // Generate source + this.log($"Orleans-CodeGen - Generating file {outputFileName}"); + return codeGenerator.GenerateSourceForAssembly(grainAssembly); + } + finally + { + refResolver.Dispose(); + AppDomain.CurrentDomain.AssemblyResolve -= refResolver.ResolveAssembly; + AssemblyLoadContext.Default.Resolving -= refResolver.AssemblyLoadContextResolving; + } + } +#endif + + private static void DisableWarnings(TextWriter sourceWriter, IEnumerable warnings) + { + foreach (var warningNum in warnings) sourceWriter.WriteLine("#pragma warning disable {0}", warningNum); + } + + private static void RestoreWarnings(TextWriter sourceWriter, IEnumerable warnings) + { + foreach (var warningNum in warnings) sourceWriter.WriteLine("#pragma warning restore {0}", warningNum); + } + } +} \ No newline at end of file diff --git a/src/ClientGenerator/GenerateOrleansCode.cs b/src/ClientGenerator/GenerateOrleansCode.cs new file mode 100644 index 0000000000..1c2f9044a7 --- /dev/null +++ b/src/ClientGenerator/GenerateOrleansCode.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using System.Diagnostics; +using System.Runtime.InteropServices; + +using Microsoft.Build.Framework; +using MSBuildTask = Microsoft.Build.Utilities.Task; + +namespace Orleans.CodeGeneration +{ + public class GetDotNetHost : MSBuildTask + { + [Output] + public string DotNetHost { get; set; } + + public override bool Execute() + { + this.DotNetHost = TryFindDotNetExePath(); + return true; + } + + private static string TryFindDotNetExePath() + { + var fileName = "dotnet"; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + fileName += ".exe"; + } + + var mainModule = Process.GetCurrentProcess().MainModule; + if (mainModule != null && !string.IsNullOrEmpty(mainModule.FileName) + && Path.GetFileName(mainModule.FileName).Equals(fileName, StringComparison.OrdinalIgnoreCase)) + { + return mainModule.FileName; + } + + // if Process.MainModule is not available or it does not equal "dotnet(.exe)?", fallback to navigating to the muxer + // by using the location of the shared framework + + var fxDepsFile = AppDomain.CurrentDomain.GetData("FX_DEPS_FILE") as string; + + if (string.IsNullOrEmpty(fxDepsFile)) + { + return fileName; + } + + var muxerDir = new FileInfo(fxDepsFile) // Microsoft.NETCore.App.deps.json + .Directory? // (version) + .Parent? // Microsoft.NETCore.App + .Parent? // shared + .Parent; // DOTNET_HOME + + if (muxerDir == null) + { + return fileName; + } + + var muxer = Path.Combine(muxerDir.FullName, fileName); + return File.Exists(muxer) + ? muxer + : fileName; + } + } +} \ No newline at end of file diff --git a/src/ClientGenerator/Properties/AssemblyInfo.cs b/src/ClientGenerator/Properties/AssemblyInfo.cs deleted file mode 100644 index 786fd1f20b..0000000000 --- a/src/ClientGenerator/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Runtime.CompilerServices; -using Orleans.CodeGeneration; - -[assembly: InternalsVisibleTo("UnitTests")] -[assembly: SkipCodeGeneration] diff --git a/src/ClientGenerator/app.config b/src/ClientGenerator/app.config deleted file mode 100644 index 7ded20c2fc..0000000000 --- a/src/ClientGenerator/app.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/ClientGenerator/build/Microsoft.Orleans.OrleansCodeGenerator.Build.targets b/src/ClientGenerator/build/Microsoft.Orleans.OrleansCodeGenerator.Build.targets new file mode 100644 index 0000000000..84773697e8 --- /dev/null +++ b/src/ClientGenerator/build/Microsoft.Orleans.OrleansCodeGenerator.Build.targets @@ -0,0 +1,58 @@ + + + $(OrleansCodeGeneratorAssembly) + true + $(MSBuildThisFileDirectory)..\tasks\netcoreapp2.0\ClientGenerator.dll + $(MSBuildThisFileDirectory)..\tasks\net461\ClientGenerator.exe + $(IntermediateOutputPath) + $(ProjectDir)$(IntermediateOutputPath) + $(CodeGenDirectory)$(TargetName).orleans.g.cs + true + + + + + + + + $(DefineConstants);EXCLUDE_CODEGEN + $(IntermediateOutputPath)codegen\ + $(IntermediateOutputPath)$(TargetName)$(TargetExt) + $(IntermediateOutputPath)$(TargetName).orleans.g.args.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ClientGenerator/buildMultiTargeting/Microsoft.Orleans.OrleansCodeGenerator.Build.targets b/src/ClientGenerator/buildMultiTargeting/Microsoft.Orleans.OrleansCodeGenerator.Build.targets new file mode 100644 index 0000000000..52c2907869 --- /dev/null +++ b/src/ClientGenerator/buildMultiTargeting/Microsoft.Orleans.OrleansCodeGenerator.Build.targets @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/Orleans.SDK.targets b/src/Orleans.SDK.targets deleted file mode 100644 index 21a31fc111..0000000000 --- a/src/Orleans.SDK.targets +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - $(MSBuildThisFileDirectory)../tools - - - - - - $(OrleansReferencesBase) - - - - - - - - $(CodeGenToolExeDir)ClientGenerator.exe - - - - - $(CodeGenToolExeDir)/ClientGenerator.exe - - - - - - - - - - - $(IntermediateOutputPath)$(TargetName).orleans.g.args.txt - $(IntermediateOutputPath) - $(ProjectDir)$(IntermediateOutputPath) - $(CodeGenDirectory)$(TargetName).orleans.g.cs - $(DefineConstants);EXCLUDE_CODEGEN - - - - - - - - - - - - - - - - diff --git a/src/Orleans/Orleans.csproj b/src/Orleans/Orleans.csproj index f4268db5f9..70d9e77797 100644 --- a/src/Orleans/Orleans.csproj +++ b/src/Orleans/Orleans.csproj @@ -17,10 +17,6 @@ PreserveNewest false - - Orleans.SDK.targets - PreserveNewest - @@ -57,25 +53,14 @@ - - - OrleansDllBootstrapUsingCodeGen - - - - - - + - - - $(SourceRoot)/Bootstrap/$(Configuration)/ - $(DefineConstants);EXCLUDE_CODEGEN;ORLEANS_BOOTSTRAP - - - - + diff --git a/src/OrleansSQLUtils/OrleansSQLUtils.csproj b/src/OrleansSQLUtils/OrleansSQLUtils.csproj index f2070fcc6b..6fef1ee619 100644 --- a/src/OrleansSQLUtils/OrleansSQLUtils.csproj +++ b/src/OrleansSQLUtils/OrleansSQLUtils.csproj @@ -23,17 +23,17 @@ - + PreserveNewest true lib\$(TargetFramework)\MySQL\ - + PreserveNewest true lib\$(TargetFramework)\PostgreSQL\ - + PreserveNewest true lib\$(TargetFramework)\SQLServer\ From 55636f8de46c99b867ab749af13de8a11fadff15 Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Thu, 21 Sep 2017 20:43:40 +1000 Subject: [PATCH 2/6] Fix build order. Remove BuildFlavor --- Directory.Build.targets | 2 +- .../ClientGenerator.Bootstrap.csproj | 8 ++++++-- .../OrleansCodeGenerator.Bootstrap.csproj | 3 --- src/Orleans/Orleans.csproj | 18 +++++++----------- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index b03c872161..c5bec2b47b 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -2,7 +2,7 @@ - $(SourceRoot)Bootstrap/$(BuildFlavor)/$(Configuration)/ClientGenerator.exe + $(SourceRoot)Bootstrap/$(Configuration)/ClientGenerator.exe diff --git a/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj b/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj index 60c259faa2..cf66c226f9 100644 --- a/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj +++ b/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj @@ -1,4 +1,4 @@ - + net461 @@ -6,7 +6,7 @@ ClientGenerator Microsoft.Orleans.CodeGenerator.MSBuild $(SourceRoot)src/ClientGenerator/ - $(SourceRoot)Bootstrap/$(BuildFlavor)/$(Configuration)/ + $(SourceRoot)Bootstrap/$(Configuration)/ true true @@ -34,4 +34,8 @@ + + + + \ No newline at end of file diff --git a/src/BootstrapBuild/OrleansCodeGenerator/OrleansCodeGenerator.Bootstrap.csproj b/src/BootstrapBuild/OrleansCodeGenerator/OrleansCodeGenerator.Bootstrap.csproj index 3df749218f..6bdf05130f 100644 --- a/src/BootstrapBuild/OrleansCodeGenerator/OrleansCodeGenerator.Bootstrap.csproj +++ b/src/BootstrapBuild/OrleansCodeGenerator/OrleansCodeGenerator.Bootstrap.csproj @@ -21,9 +21,6 @@ - - - diff --git a/src/Orleans/Orleans.csproj b/src/Orleans/Orleans.csproj index 70d9e77797..dcbaf6a1cc 100644 --- a/src/Orleans/Orleans.csproj +++ b/src/Orleans/Orleans.csproj @@ -51,16 +51,12 @@ + + false + + true + TargetFramework + + - - - - - - - From 4bcd3599fb4b52e024815bd75fe873c86fbb63fb Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Fri, 22 Sep 2017 07:35:44 +1000 Subject: [PATCH 3/6] sql --- ...rleansTables_MySql.sql => CreateOrleansTables_MySQL.sql} | 0 ...es_PostgreSql.sql => CreateOrleansTables_PostgreSQL.sql} | 0 ...bles_SqlServer.sql => CreateOrleansTables_SQLServer.sql} | 0 src/OrleansSQLUtils/OrleansSQLUtils.csproj | 6 +++--- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/OrleansSQLUtils/{CreateOrleansTables_MySql.sql => CreateOrleansTables_MySQL.sql} (100%) rename src/OrleansSQLUtils/{CreateOrleansTables_PostgreSql.sql => CreateOrleansTables_PostgreSQL.sql} (100%) rename src/OrleansSQLUtils/{CreateOrleansTables_SqlServer.sql => CreateOrleansTables_SQLServer.sql} (100%) diff --git a/src/OrleansSQLUtils/CreateOrleansTables_MySql.sql b/src/OrleansSQLUtils/CreateOrleansTables_MySQL.sql similarity index 100% rename from src/OrleansSQLUtils/CreateOrleansTables_MySql.sql rename to src/OrleansSQLUtils/CreateOrleansTables_MySQL.sql diff --git a/src/OrleansSQLUtils/CreateOrleansTables_PostgreSql.sql b/src/OrleansSQLUtils/CreateOrleansTables_PostgreSQL.sql similarity index 100% rename from src/OrleansSQLUtils/CreateOrleansTables_PostgreSql.sql rename to src/OrleansSQLUtils/CreateOrleansTables_PostgreSQL.sql diff --git a/src/OrleansSQLUtils/CreateOrleansTables_SqlServer.sql b/src/OrleansSQLUtils/CreateOrleansTables_SQLServer.sql similarity index 100% rename from src/OrleansSQLUtils/CreateOrleansTables_SqlServer.sql rename to src/OrleansSQLUtils/CreateOrleansTables_SQLServer.sql diff --git a/src/OrleansSQLUtils/OrleansSQLUtils.csproj b/src/OrleansSQLUtils/OrleansSQLUtils.csproj index 6fef1ee619..f2070fcc6b 100644 --- a/src/OrleansSQLUtils/OrleansSQLUtils.csproj +++ b/src/OrleansSQLUtils/OrleansSQLUtils.csproj @@ -23,17 +23,17 @@ - + PreserveNewest true lib\$(TargetFramework)\MySQL\ - + PreserveNewest true lib\$(TargetFramework)\PostgreSQL\ - + PreserveNewest true lib\$(TargetFramework)\SQLServer\ From 3371b13428db3b909f372c53555919f4829ad510 Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Fri, 22 Sep 2017 07:36:26 +1000 Subject: [PATCH 4/6] GetDotNetHost --- src/ClientGenerator/{GenerateOrleansCode.cs => GetDotNetHost.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/ClientGenerator/{GenerateOrleansCode.cs => GetDotNetHost.cs} (100%) diff --git a/src/ClientGenerator/GenerateOrleansCode.cs b/src/ClientGenerator/GetDotNetHost.cs similarity index 100% rename from src/ClientGenerator/GenerateOrleansCode.cs rename to src/ClientGenerator/GetDotNetHost.cs From c72b26ae24912f7cd400d9fdc9439988e4488049 Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Fri, 22 Sep 2017 07:41:23 +1000 Subject: [PATCH 5/6] build props --- Directory.Build.props | 4 ++-- .../ClientGenerator/ClientGenerator.Bootstrap.csproj | 2 +- src/ClientGenerator/ClientGenerator.csproj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index d136f4d14d..2f28e66a87 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -45,8 +45,6 @@ 4.3.0 - 15.3.409 - 2.0.0 1.4.0 4.3.2 1.5.0 @@ -54,6 +52,7 @@ 4.4.0 + 15.3.409 2.0.0 2.0.0 @@ -61,6 +60,7 @@ 2.0.0 2.0.0 2.0.0 + 2.0.0 2.0.0 2.0.0 2.0.0 diff --git a/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj b/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj index cf66c226f9..cfc40894f7 100644 --- a/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj +++ b/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/ClientGenerator/ClientGenerator.csproj b/src/ClientGenerator/ClientGenerator.csproj index 52e6237795..9f426d0f52 100644 --- a/src/ClientGenerator/ClientGenerator.csproj +++ b/src/ClientGenerator/ClientGenerator.csproj @@ -34,7 +34,7 @@ - + From d3d9d67e9a755e0aa8ecc67581d66c6f2fd04d73 Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Fri, 22 Sep 2017 07:47:49 +1000 Subject: [PATCH 6/6] netcoreapp2.0 bootstrap --- Directory.Build.targets | 2 +- .../ClientGenerator/ClientGenerator.Bootstrap.csproj | 2 +- .../build/Microsoft.Orleans.OrleansCodeGenerator.Build.targets | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index c5bec2b47b..3363930d67 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -2,7 +2,7 @@ - $(SourceRoot)Bootstrap/$(Configuration)/ClientGenerator.exe + $(SourceRoot)Bootstrap/$(Configuration)/ClientGenerator.dll diff --git a/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj b/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj index cfc40894f7..d813ca3683 100644 --- a/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj +++ b/src/BootstrapBuild/ClientGenerator/ClientGenerator.Bootstrap.csproj @@ -1,7 +1,7 @@ - net461 + netcoreapp2.0 Exe ClientGenerator Microsoft.Orleans.CodeGenerator.MSBuild diff --git a/src/ClientGenerator/build/Microsoft.Orleans.OrleansCodeGenerator.Build.targets b/src/ClientGenerator/build/Microsoft.Orleans.OrleansCodeGenerator.Build.targets index 84773697e8..a78fcdc26a 100644 --- a/src/ClientGenerator/build/Microsoft.Orleans.OrleansCodeGenerator.Build.targets +++ b/src/ClientGenerator/build/Microsoft.Orleans.OrleansCodeGenerator.Build.targets @@ -1,7 +1,7 @@ $(OrleansCodeGeneratorAssembly) - true + true $(MSBuildThisFileDirectory)..\tasks\netcoreapp2.0\ClientGenerator.dll $(MSBuildThisFileDirectory)..\tasks\net461\ClientGenerator.exe $(IntermediateOutputPath)