A professional boilerplate for integrating C native libraries into .NET applications using Foreign Function Interface (FFI) and P/Invoke.
This project serves as a starter template for developers who need to augment C# applications with native C code. It is designed to demonstrate a production-ready architecture for multi-language integration, focusing on memory safety, maintainability, and build automation.
As detailed in RULES.md, FFI is leveraged here to:
- Boost Performance: Offload computationally intensive tasks to C.
- System Access: Interact directly with low-level OS APIs or hardware.
- Reduce GC Pressure: Manage large memory blocks in unmanaged space to avoid .NET Garbage Collector pauses.
- Code Reuse: Integrate existing, high-performance C libraries.
.
├── native/ # Native C source code and headers
│ ├── my_lib.c # C implementation
│ └── my_lib.h # C interface definitions
├── tests/ # XUnit test suite for FFI boundary
│ └── NativeTests.cs # Edge-case and integration tests
├── NativeMethods.cs # Internal C# wrappers for P/Invoke
├── Program.cs # Application entry point and demo
├── Makefile # Build automation for native libraries
├── RULES.md # Strict development and synchronization rules
└── ffi-starter-csharp-lib.csproj
- .NET 10.0 SDK
- GCC (or equivalent C compiler)
- Make
-
Compile the native library:
make
This generates
libmy_lib.soand places it in the appropriate .NET output folders. -
Run the application:
dotnet run
The project includes a rigorous test suite covering boundary conditions and memory lifecycles:
dotnet test tests/ffi-starter-csharp-lib.tests.csprojThis project enforces a strict synchronization contract between the C and C# layers to prevent memory corruption and segmentation faults.
Before making any changes, read the RULES.md file.
Key mandates include:
- Atomic Changes: Updating C signatures and C# wrappers in the same commit.
- Memory Ownership: Strict rules on who allocates and who frees memory.
- Error Handling: Mandatory translation of C return codes into C# Exceptions.
- Encapsulation: All native imports must reside within the
NativeMethodsclass.
MIT