Skip to content

Commit 89159b2

Browse files
committed
Make auto-compiling of C# work with .NET Core
CodeDom doesn't work in .NET Core (dotnet/runtime#18768) and Roslyn turns out to be too low level (just a compiler and not a building framework) so the best approach is to invoke msbuild as a process. Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
1 parent 8683546 commit 89159b2

11 files changed

+65
-107
lines changed

Directory.Packages.props

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<Project>
22
<ItemGroup>
3-
<PackageVersion Include="System.CodeDom" Version="4.7.0" />
43
<PackageVersion Include="Microsoft.Win32.Registry" Version="4.7.0" />
54
<PackageVersion Include="Microsoft.VisualStudio.Setup.Configuration.Interop" Version="2.3.2262-g94fae01e" />
65
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />

build/Tests.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ function SetupTestProjectsCSharp(name, depends, extraFiles, suffix)
8484
str = "Std"
8585
end
8686

87-
SetupExternalManagedTestProject(name .. ".CSharp")
87+
if name ~= "NamespacesDerived" then
88+
SetupExternalManagedTestProject(name .. ".CSharp")
89+
end
8890
SetupExternalManagedTestProject(name .. ".Tests.CSharp")
8991
end
9092

src/Generator/CppSharp.Generator.csproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,4 @@
1212
<ProjectReference Include="..\Parser\CppSharp.Parser.csproj" />
1313
<ProjectReference Include="$(NativeProjectsDir)Std-symbols.vcxproj" ReferenceOutputAssembly="false" Condition="$(IsWindows)" />
1414
</ItemGroup>
15-
16-
<ItemGroup>
17-
<PackageReference Include="System.CodeDom" PrivateAssets="All" />
18-
</ItemGroup>
1915
</Project>

src/Generator/Driver.cs

Lines changed: 45 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
using System;
2-
using System.CodeDom.Compiler;
32
using System.Collections.Generic;
43
using System.IO;
54
using System.Linq;
6-
using System.Text;
75
using CppSharp.AST;
86
using CppSharp.Generators;
7+
using CppSharp.Generators.C;
98
using CppSharp.Generators.CLI;
9+
using CppSharp.Generators.Cpp;
1010
using CppSharp.Generators.CSharp;
1111
using CppSharp.Parser;
1212
using CppSharp.Passes;
1313
using CppSharp.Utils;
14-
using Microsoft.CSharp;
1514
using CppSharp.Types;
16-
using CppSharp.Generators.Cpp;
17-
using CppSharp.Generators.C;
1815

1916
namespace CppSharp
2017
{
2118
public class Driver : IDisposable
2219
{
23-
public DriverOptions Options { get; private set; }
20+
public DriverOptions Options { get; }
2421
public ParserOptions ParserOptions { get; set; }
2522
public BindingContext Context { get; private set; }
2623
public Generator Generator { get; private set; }
@@ -353,66 +350,52 @@ private void WriteGeneratedCodeToFile(string file, string generatedCode)
353350

354351
private static readonly Dictionary<Module, string> libraryMappings = new Dictionary<Module, string>();
355352

356-
public void CompileCode(Module module)
353+
public bool CompileCode(Module module)
357354
{
358-
var assemblyFile = Path.Combine(Options.OutputDir, module.LibraryName + ".dll");
359-
360-
var docFile = Path.ChangeExtension(assemblyFile, ".xml");
361-
362-
var compilerOptions = new StringBuilder();
363-
compilerOptions.Append($" /doc:\"{docFile}\"");
364-
compilerOptions.Append(" /debug:pdbonly");
365-
compilerOptions.Append(" /unsafe");
366-
367-
var compilerParameters = new CompilerParameters
368-
{
369-
GenerateExecutable = false,
370-
TreatWarningsAsErrors = false,
371-
OutputAssembly = assemblyFile,
372-
GenerateInMemory = false,
373-
CompilerOptions = compilerOptions.ToString()
374-
};
375-
376-
if (module != Options.SystemModule)
377-
compilerParameters.ReferencedAssemblies.Add(
378-
Path.Combine(Options.OutputDir, $"{Options.SystemModule.LibraryName}.dll"));
379-
// add a reference to System.Core
380-
compilerParameters.ReferencedAssemblies.Add(typeof(Enumerable).Assembly.Location);
381-
382355
var location = System.Reflection.Assembly.GetExecutingAssembly().Location;
383-
var outputDir = Path.GetDirectoryName(location);
384-
var locationRuntime = Path.Combine(outputDir, "CppSharp.Runtime.dll");
385-
compilerParameters.ReferencedAssemblies.Add(locationRuntime);
386-
387-
compilerParameters.ReferencedAssemblies.AddRange(
388-
(from dependency in module.Dependencies
389-
where libraryMappings.ContainsKey(dependency)
390-
select libraryMappings[dependency]).ToArray());
391-
392-
compilerParameters.ReferencedAssemblies.AddRange(module.ReferencedAssemblies.ToArray());
393-
394-
Diagnostics.Message($"Compiling {module.LibraryName}...");
395-
CompilerResults compilerResults;
396-
using (var codeProvider = new CSharpCodeProvider(
397-
new Dictionary<string, string> {
398-
{ "CompilerDirectoryPath", ManagedToolchain.FindCSharpCompilerDir() } }))
356+
string csproj = Path.Combine(Options.OutputDir, $"{module.LibraryName}.csproj");
357+
File.WriteAllText(Path.Combine(Options.OutputDir, "Directory.Build.props"), "<Project />");
358+
File.WriteAllText(csproj,
359+
$@"
360+
<Project Sdk=""Microsoft.NET.Sdk"">
361+
<PropertyGroup>
362+
<TargetFramework>netcoreapp3.1</TargetFramework>
363+
<PlatformTarget>AnyCPU</PlatformTarget>
364+
<OutputPath>{Options.OutputDir}</OutputPath>
365+
<Configuration>Release</Configuration>
366+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
367+
<EnableDefaultNoneItems>false</EnableDefaultNoneItems>
368+
<EnableDefaultItems>false</EnableDefaultItems>
369+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
370+
</PropertyGroup>
371+
<ItemGroup>
372+
{string.Join(Environment.NewLine, module.CodeFiles.Select(c => $"<Compile Include=\"{c}\" />"))}
373+
</ItemGroup>
374+
<ItemGroup>
375+
{string.Join(Environment.NewLine,
376+
new[] { Path.Combine(Path.GetDirectoryName(location), "CppSharp.Runtime.dll") }
377+
.Union(from dependency in module.Dependencies
378+
where libraryMappings.ContainsKey(dependency)
379+
select libraryMappings[dependency])
380+
.Select(reference =>
381+
$@"<Reference Include=""{Path.GetFileNameWithoutExtension(reference)}"">
382+
<HintPath>{reference}</HintPath>
383+
</Reference>"))}
384+
</ItemGroup>
385+
</Project>".Trim());
386+
387+
string output = ProcessHelper.Run("dotnet", $"msbuild -restore {csproj}",
388+
out int error, out string errorMessage);
389+
if (error == 0)
399390
{
400-
compilerResults = codeProvider.CompileAssemblyFromFile(
401-
compilerParameters, module.CodeFiles.ToArray());
391+
Diagnostics.Message($@"Compilation succeeded: {
392+
libraryMappings[module] = Path.Combine(Options.OutputDir, $"{module.LibraryName}.dll")}.");
393+
return true;
402394
}
403395

404-
var errors = compilerResults.Errors.Cast<CompilerError>().Where(e => !e.IsWarning &&
405-
// HACK: auto-compiling on OS X produces "errors" which do not affect compilation so we ignore them
406-
(!Platform.IsMacOS || !e.ErrorText.EndsWith("(Location of the symbol related to previous warning)", StringComparison.Ordinal))).ToList();
407-
foreach (var error in errors)
408-
Diagnostics.Error(error.ToString());
409-
410-
HasCompilationErrors = errors.Count > 0;
411-
if (!HasCompilationErrors)
412-
{
413-
libraryMappings[module] = Path.Combine(outputDir, assemblyFile);
414-
Diagnostics.Message("Compilation succeeded.");
415-
}
396+
Diagnostics.Error(output);
397+
Diagnostics.Error(errorMessage);
398+
return false;
416399
}
417400

418401
public void AddTranslationUnitPass(TranslationUnitPass pass)
@@ -498,12 +481,7 @@ public static void Run(ILibrary library)
498481

499482
driver.SaveCode(outputs);
500483
if (driver.Options.IsCSharpGenerator && driver.Options.CompileCode)
501-
foreach (var module in driver.Options.Modules)
502-
{
503-
driver.CompileCode(module);
504-
if (driver.HasCompilationErrors)
505-
break;
506-
}
484+
driver.Options.Modules.Any(m => !driver.CompileCode(m));
507485
}
508486
}
509487
}

tests/NamespacesBase/NamespacesBase.CSharp.csproj

Lines changed: 0 additions & 12 deletions
This file was deleted.

tests/NamespacesBase/premake4.lua

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,4 @@ end
88

99
group "Tests/Namespaces"
1010
SetupTestNativeProject("NamespacesBase")
11-
targetdir (path.join(gendir, "NamespacesDerived"))
12-
SetupWrapper("NamespacesBase")
11+
targetdir (path.join(gendir, "NamespacesDerived"))

tests/NamespacesDerived/NamespacesDerived.CSharp.csproj

Lines changed: 0 additions & 13 deletions
This file was deleted.

tests/NamespacesDerived/NamespacesDerived.Gen.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.IO;
2-
using System.Reflection;
32
using CppSharp.AST;
43
using CppSharp.Generators;
54
using CppSharp.Utils;
@@ -18,6 +17,7 @@ public override void Setup(Driver driver)
1817
base.Setup(driver);
1918
driver.Options.GenerateDefaultValuesForArguments = true;
2019
driver.Options.GenerateClassTemplates = true;
20+
driver.Options.CompileCode = true;
2121
driver.Options.DependentNameSpaces.Add("System.Runtime.CompilerServices");
2222
driver.Options.Modules[1].IncludeDirs.Add(GetTestsDirectory("NamespacesDerived"));
2323
var @base = "NamespacesBase";
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,13 @@
1-
<Project Sdk="Microsoft.NET.Sdk" />
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<ItemGroup>
3+
<ProjectReference Include="NamespacesDerived.Gen.csproj" ReferenceOutputAssembly="false" />
4+
</ItemGroup>
5+
<ItemGroup>
6+
<Reference Include="NamespacesBase">
7+
<HintPath>..\..\build\gen\NamespacesDerived\NamespacesBase.dll</HintPath>
8+
</Reference>
9+
<Reference Include="NamespacesDerived">
10+
<HintPath>..\..\build\gen\NamespacesDerived\NamespacesDerived.dll</HintPath>
11+
</Reference>
12+
</ItemGroup>
13+
</Project>

tests/NamespacesDerived/premake4.lua

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,4 @@ group "Tests/Namespaces"
66
end
77

88
SetupTestGeneratorProject("NamespacesDerived")
9-
SetupTestProjectsCSharp("NamespacesDerived", "NamespacesBase")
10-
11-
project("NamespacesDerived.Tests.CSharp")
12-
links { "NamespacesBase.CSharp" }
9+
SetupTestProjectsCSharp("NamespacesDerived", "NamespacesBase")

tests/Test.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</ItemGroup>
1010

1111
<ItemGroup>
12-
<ProjectReference Include="$(TestName).CSharp.csproj" Condition="$(MSBuildProjectName.EndsWith('CSharp'))" />
12+
<ProjectReference Include="$(TestName).CSharp.csproj" Condition="$(MSBuildProjectName.EndsWith('CSharp')) AND $(TestName) != 'NamespacesDerived'" />
1313
<ProjectReference Include="$(NativeProjectsDir)$(TestName).Native.vcxproj" Condition="$(IsWindows)" ReferenceOutputAssembly="false" />
1414
<ProjectReference Include="$(NativeProjectsDir)$(TestName).CLI.vcxproj" Condition="$(MSBuildProjectName.EndsWith('CLI')) AND $(IsWindows)" />
1515
</ItemGroup>

0 commit comments

Comments
 (0)