Skip to content

Commit

Permalink
Bump version number to 2.0.0 (#153)
Browse files Browse the repository at this point in the history
* Bump version number to 2.0.0

Drop targeting .NET 5, it is out of support
and shouldn't be targeted.

Add support for targeting .NET Framework 4.x.
Update the tests and samples to multi-target.

Use linux leg to upload package.

Add github CI status badge
  • Loading branch information
AaronRobinsonMSFT authored Feb 20, 2023
1 parent ac479b1 commit a7c684f
Show file tree
Hide file tree
Showing 17 changed files with 459 additions and 44 deletions.
16 changes: 10 additions & 6 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ jobs:
run: |
dotnet clean test/DNNE.UnitTests -c ${{ matrix.flavor }}
dotnet test test/DNNE.UnitTests -c ${{ matrix.flavor }} -p:BuildWithGPP=true
- name: Upload Package
uses: actions/upload-artifact@v2
with:
name: package.${{ matrix.flavor }}
path: src/dnne-pkg/bin/${{ matrix.flavor }}/DNNE.*.nupkg

windows:
runs-on: windows-latest
Expand All @@ -46,17 +51,16 @@ jobs:
include-prerelease: true
- name: Build Product and Package
run: dotnet build src\create_package.proj -c ${{ matrix.flavor }}
- name: Build ExportingAssembly (.NET Core and .NET Framework)
run: dotnet build test\ExportingAssembly -c ${{ matrix.flavor }}
- name: Unit Test Product (cpp)
run: dotnet test test\DNNE.UnitTests -c ${{ matrix.flavor }} -p:BuildAsCPPWithMSVC=true
run: |
dotnet clean test\DNNE.UnitTests -c ${{ matrix.flavor }}
dotnet test test\DNNE.UnitTests -c ${{ matrix.flavor }} -p:BuildAsCPPWithMSVC=true
- name: Unit Test Product
run: |
dotnet clean test\DNNE.UnitTests -c ${{ matrix.flavor }}
dotnet test test\DNNE.UnitTests -c ${{ matrix.flavor }}
- name: Upload Package
uses: actions/upload-artifact@v2
with:
name: package.${{ matrix.flavor }}
path: src\dnne-pkg\bin\${{ matrix.flavor }}\DNNE.*.nupkg
macos:
runs-on: macos-latest
Expand Down
11 changes: 8 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Native Exports for .NET

[![DNNE](https://github.com/AaronRobinsonMSFT/DNNE/actions/workflows/main.yml/badge.svg)](https://github.com/AaronRobinsonMSFT/DNNE/actions/workflows/main.yml)

Prototype for a .NET managed assembly to expose a native export.

This work is inspired by work in the [Xamarin][xamarin_embed_link], [CoreRT][corert_feature_link], and [DllExport][dllexport_link] projects.
Expand All @@ -8,7 +10,7 @@ This work is inspired by work in the [Xamarin][xamarin_embed_link], [CoreRT][cor

### Minimum

* [.NET 5.0](https://dotnet.microsoft.com/download/dotnet/5.0) or greater.
* [.NET 6.0](https://dotnet.microsoft.com/download) or greater.
* [C99](https://en.cppreference.com/w/c/language/history) compatible compiler.

### DNNE NuPkg Requirements
Expand All @@ -18,6 +20,7 @@ This work is inspired by work in the [Xamarin][xamarin_embed_link], [CoreRT][cor
- The x86_64 version of the .NET runtime is the default install.
- In order to target x86, the x86 .NET runtime must be explicitly installed.
* Windows 10 SDK - Installed with Visual Studio.
* .NET Framework SDK - Installed with Visual Studio. Only required if targeting a .NET Framework TFM.
* x86, x86_64, ARM64 compilation supported.
- The Visual Studio package containing the desired compiler architecture must have been installed.

Expand Down Expand Up @@ -183,7 +186,7 @@ In addition to providing declaration code directly, users can also supply `#incl

```xml
<ItemGroup>
<PackageReference Include="DNNE" Version="1.*" />
<PackageReference Include="DNNE" Version="2.*" />
</ItemGroup>
```

Expand Down Expand Up @@ -251,9 +254,11 @@ public class Exports
* How can I keep my project cross-platform and generate a native binary for other platforms than the one I am currently building on?
* The managed assembly will remain cross-platform but the native component is difficult to produce due to native tool chain constraints. In order to accomplish this on the native side, there would need to exist a C99 tool chain that can target any platform from any other platform. For example, the native tool chain could run on Windows but would need to provide a macOS SDK, linux SDK, and produce a macOS `.dylib` (Mach-O image) and/or a linux `.so` (ELF image). If such a native tool chain exists, it would be possible.
* How can I consume the resulting native binary?
* There are two primary options: (1) manually load the binary and discover its exports or (2) directly link against the binary. Both options are discussed in the [native sample](./sample/native/main.c).
* There are two options: (1) manually load the binary and discover its exports or (2) directly link against the binary. Both options are discussed in the [native sample](./sample/native/main.c).
* Along with exporting a function, I would also like to export data. Is there a way to export a static variable defined in .NET?
* There is no simple way to do this starting from .NET. DNNE could be updated to read static metadata and then generate the appropriate export in C code, but that approach is complicated by how static data can be defined during module load in .NET. It is recommended instead to define the desired static data in a separate translation unit (`.c` file) and include it in the native build through the `DnneCompilerUserFlags` property.
* Does DNNE support targeting .NET Framework?
* Yes. DNNE has support for targeting .NET Framework v4.x TFMs&mdash;there is no support for v2.0 or v3.5. DNNE respects multi-targeting using the `TargetFrameworks` MSBuild property. For any .NET Framework v4.x TFM, DNNE will produce a native binary that will activate .NET Framework. Note there are assembly loading semantic differences between .NET Framework and .NET Core. Tools like [`fuslogvw.exe`](https://learn.microsoft.com/dotnet/framework/tools/fuslogvw-exe-assembly-binding-log-viewer) can help to understand loading failures in .NET Framework. Due to how .NET Framework is being activated, the managed DLL typically needs to be located next to the running EXE rather than the native DLL produced by DNNE. Alternatively, the EXE can define a [`.config` file](https://learn.microsoft.com/dotnet/framework/configure-apps/) that defines probing paths.
# Additional References

Expand Down
18 changes: 18 additions & 0 deletions sample/Exports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,31 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Runtime.InteropServices;

public class Exports
{
#if NETFRAMEWORK
[DNNE.Export(EntryPoint = "FancyName")]
#else
[UnmanagedCallersOnly(EntryPoint = "FancyName")]
#endif // !NETFRAMEWORK
public static int MyExport(int a)
{
return a;
}
}

#if NETFRAMEWORK
// The experimental DNNE attribute is needed when targeting
// .NET Framework.
namespace DNNE
{
internal class ExportAttribute : Attribute
{
public ExportAttribute() { }
public string EntryPoint { get; set; }
}
}
#endif // NETFRAMEWORK
4 changes: 2 additions & 2 deletions sample/Sample.csproj
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFrameworks>net6.0;net472</TargetFrameworks>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="DNNE" Version="1.1.0" />
<PackageReference Include="DNNE" Version="2.0.0" />
</ItemGroup>

</Project>
16 changes: 11 additions & 5 deletions src/dnne-gen/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -586,11 +586,11 @@ private static void EmitC99(TextWriter outputStream, string assemblyName, IEnume
#include <stddef.h>
#include <stdint.h>
#ifdef {compileAsSourceDefine}
#include <dnne.h>
#include <dnne.h>
#else
// When used as a header file, the assumption is
// dnne.h will be next to this file.
#include ""dnne.h""
// When used as a header file, the assumption is
// dnne.h will be next to this file.
#include ""dnne.h""
#endif // !{compileAsSourceDefine}
");

Expand Down Expand Up @@ -658,7 +658,13 @@ private static void EmitC99(TextWriter outputStream, string assemblyName, IEnume
}

string id = $"t{count++}_name";
implStream.WriteLine($"static const char_t* {id} = DNNE_STR(\"{method.EnclosingTypeName}, {assemblyName}\");");
implStream.WriteLine(
$@"#ifdef DNNE_TARGET_NET_FRAMEWORK
static const char_t* {id} = DNNE_STR(""{method.EnclosingTypeName}"");
#else
static const char_t* {id} = DNNE_STR(""{method.EnclosingTypeName}, {assemblyName}"");
#endif // !DNNE_TARGET_NET_FRAMEWORK
");
map.Add(method.EnclosingTypeName, id);
}

Expand Down
2 changes: 1 addition & 1 deletion src/dnne-gen/dnne-gen.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>DNNE</RootNamespace>
<RollForward>major</RollForward>
</PropertyGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/dnne-pkg/dnne-pkg.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>dnne_pkg</RootNamespace>
<IncludeBuildOutput>False</IncludeBuildOutput>
<PseudoPackageDir>../pkg/</PseudoPackageDir>
Expand All @@ -17,7 +17,7 @@

<PropertyGroup>
<PackageId>DNNE</PackageId>
<Version>1.1.0</Version>
<Version>2.0.0</Version>
<Authors>AaronRobinsonMSFT</Authors>
<Owners>AaronRobinsonMSFT</Owners>
<Description>Package used to generated native exports for .NET assemblies.</Description>
Expand Down
37 changes: 28 additions & 9 deletions src/msbuild/DNNE.BuildTasks/CreateCompileCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ public class CreateCompileCommand : Task
[Required]
public string Configuration { get; set; }

[Required]
public string TargetFramework { get; set; }

// Optional
public string UserDefinedCompilerFlags { get; set; }

Expand Down Expand Up @@ -103,6 +106,13 @@ internal IEnumerable<ITaskItem> SafeAdditionalIncludeDirectories
get => AdditionalIncludeDirectories ?? Enumerable.Empty<ITaskItem>();
}

// Internal property used to help identify when the supplied TFM
// is targeting .NET Framework (i.e., has a 'net4' prefix).
internal bool IsTargetingNetFramework
{
get => TargetFramework.StartsWith("net4", StringComparison.OrdinalIgnoreCase);
}

[Output]
public string Command { get; set; }

Expand All @@ -126,6 +136,7 @@ public override bool Execute()
RuntimeID: {RuntimeID}
Architecture: {Architecture}
Configuration: {Configuration}
TargetFramework:{TargetFramework}
");

string command;
Expand All @@ -134,17 +145,25 @@ public override bool Execute()
{
Windows.ConstructCommandLine(this, out command, out commandArguments);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Linux.ConstructCommandLine(this, out command, out commandArguments);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
macOS.ConstructCommandLine(this, out command, out commandArguments);
}
else
{
throw new NotSupportedException("Unknown native build environment");
if (IsTargetingNetFramework)
{
throw new NotSupportedException(".NET Framework can only be targeted on Windows");
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Linux.ConstructCommandLine(this, out command, out commandArguments);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
macOS.ConstructCommandLine(this, out command, out commandArguments);
}
else
{
throw new NotSupportedException("Unknown native build environment");
}
}

this.Command = command;
Expand Down
Loading

0 comments on commit a7c684f

Please sign in to comment.