|
| 1 | +# Copilot Instructions for DNNE |
| 2 | + |
| 3 | +DNNE (Dotnet Native Exports) enables .NET managed assemblies to expose native exports consumable by native code. It generates C or Rust source from assemblies marked with `[UnmanagedCallersOnly]` and compiles them into platform-specific native binaries (`.dll`, `.so`, `.dylib`). |
| 4 | + |
| 5 | +## Build & Test |
| 6 | + |
| 7 | +```bash |
| 8 | +# Build the NuGet package (includes all components) |
| 9 | +dotnet build src/create_package.proj |
| 10 | + |
| 11 | +# Run all unit tests |
| 12 | +dotnet test test/DNNE.UnitTests |
| 13 | + |
| 14 | +# Run a single test by name |
| 15 | +dotnet test test/DNNE.UnitTests --filter "FullyQualifiedName~TestMethodName" |
| 16 | + |
| 17 | +# Test with alternative compilers (useful for cross-compiler validation) |
| 18 | +dotnet test test/DNNE.UnitTests -p:BuildWithGCC=true |
| 19 | +dotnet test test/DNNE.UnitTests -p:BuildAsCPPWithMSVC=true |
| 20 | +dotnet test test/DNNE.UnitTests -p:BuildWithClangPP=true |
| 21 | +``` |
| 22 | + |
| 23 | +The test framework is **xUnit**. Tests target `net8.0` (and `net472` on Windows). |
| 24 | + |
| 25 | +## Architecture |
| 26 | + |
| 27 | +The project has a pipeline architecture where each component feeds into the next: |
| 28 | + |
| 29 | +1. **dnne-analyzers** (`src/dnne-analyzers/`) — Roslyn source generator that emits the DNNE attribute types into consuming projects at compile time. Targets `netstandard2.0` and requires Roslyn 4.0+. Generated attributes include: |
| 30 | + - `ExportAttribute`, `C99DeclCodeAttribute`, `C99TypeAttribute` — for C99 output |
| 31 | + - `RustDeclCodeAttribute`, `RustTypeAttribute` — for Rust output |
| 32 | + |
| 33 | +2. **dnne-gen** (`src/dnne-gen/`) — CLI tool (.NET 8.0) that reads a compiled managed assembly via reflection, finds methods marked with `[UnmanagedCallersOnly]` or `[DNNE.Export]`, and generates native source code with the corresponding export signatures. Supports two output languages selected via `-l`: |
| 34 | + - `c99` (default) — generates C99 source with `DNNE_API` macros, C preprocessor platform guards, and lazy-init function pointer wrappers. |
| 35 | + - `rust` — generates Rust source with `pub unsafe fn` wrappers intended for Rust callers (no `extern "C"` / `#[no_mangle]`), `AtomicPtr` lazy initialization, `#[cfg(target_os)]` platform guards, and `core::ffi` types. |
| 36 | + |
| 37 | + The `Generator` class uses language-specific type providers (`C99TypeProvider` / `RustTypeProvider`) and emitters (`EmitC99` / `EmitRust`). Attribute detection is unified through `TryGetLanguageTypeAttributeValue` and `TryGetLanguageDeclCodeAttributeValue`, which select C99 or Rust attributes based on the output language. Exports with non-primitive value types that lack a type override are skipped in Rust mode. |
| 38 | + |
| 39 | +3. **MSBuild integration** (`src/msbuild/`) — `DNNE.props` defines configurable properties; `DNNE.targets` wires up the build pipeline (run dnne-gen, then invoke the native compiler). `DNNE.BuildTasks/` contains custom MSBuild tasks with platform-specific compilation logic in `Windows.cs`, `Linux.cs`, and `macOS.cs`. |
| 40 | + |
| 41 | +4. **Platform layer** (`src/platform/`) — Native source that bootstraps the .NET runtime via `nethost` and dispatches calls to managed exports. |
| 42 | + - `platform.c` / `dnne.h` — C implementation with platform-conditional code (`#ifdef DNNE_WINDOWS` etc.) for library loading, path resolution, error state preservation, and thread-safe runtime initialization via spinlock. |
| 43 | + - `platform_v4.cpp` — .NET Framework v4.x activation (C++ only). |
| 44 | + - `platform.rs` — Rust implementation targeting .NET (Core) only. Uses `std::sync::Mutex` for thread-safe initialization, platform-specific `sys` modules for Unix/Windows, and a UTF-8 public API (`*const u8`) with internal wide-string conversion on Windows. Expects a crate-root constant `DNNE_ASSEMBLY_NAME` (for example, generated into `lib.rs` by `DNNE.targets`). |
| 45 | + |
| 46 | +5. **dnne-pkg** (`src/dnne-pkg/`) — Orchestrates NuGet package creation, bundling analyzers, gen tool, build tasks, and platform source into the published package. |
| 47 | + |
| 48 | +## Key Conventions |
| 49 | + |
| 50 | +- Exported methods must be `public static` and marked with `[UnmanagedCallersOnly]` (preferred) or `[DNNE.Export]` (experimental). The enclosing class's accessibility doesn't matter. |
| 51 | +- When using `[DNNE.Export]`, a companion `Delegate` type named `<MethodName>Delegate` must exist at the same scope. |
| 52 | +- Custom native type mappings use language-specific attributes: |
| 53 | + - **C99**: `[DNNE.C99Type("...")]` on parameters/return values and `[DNNE.C99DeclCode("...")]` on methods for struct definitions or `#include` directives. |
| 54 | + - **Rust**: `[DNNE.RustType("...")]` on parameters/return values and `[DNNE.RustDeclCode("...")]` on methods for type definitions or `use` statements. |
| 55 | +- The generated native binary is named `<AssemblyName>NE` by default (suffix controlled by `DnneNativeBinarySuffix` MSBuild property). |
| 56 | +- MSBuild properties controlling behavior are defined in `src/msbuild/DNNE.props` — this is the reference for all DNNE configuration options. |
| 57 | +- C# language version varies by component: `C# 11.0` for analyzers, `C# 9.0` for build tasks, default for other projects. |
| 58 | +- The DNNE attribute types are source-generated into consuming projects — DNNE provides no assembly reference. |
0 commit comments