This example shows how to interface a C++ shared library from .NET (F# language) on Linux.
Objective - Find out how to:
- [ ] Pass and get arrays from C++ shared library.
- [ ] Pass and get C-structs form C++ and C shared library.
- [ ] Deal with C++ objects.
- [ ] Pass STL vectors to C++.
Files:
- hpc.cpp - C++ source code to build the Linux shared library hpc.so.
- wrapper.fsx - F# code that calls the shared library hpc.so.
- Makefile - Makefile build recipe to compile all sources.
Note:
- hpc - stands for high performance computing.
Shared Libraries
OS | Suffix | Dynamic Linker | Object Code file Format |
---|---|---|---|
Linux | .so | ld.so | ELF |
Mac OSX | .dylib | dyld | MacO |
Windows | .dll or .OCX (OLE Libraries) | PE - Portable Executable | |
Linux Tooling
g++ | GCC C++ Compiler |
nm | |
ldd | |
strings | |
strace | |
Terminology
- ABI - Application Binary Interface
- API - Application Programming Interface
- FFI - Foreign Function Interface
- CLR - Common Language Runtime (.NET Framework virtual machine)
- CIL - Common Language Infrastructure
- COM - Component Object Model
- Pinvoke - Platform Invocation Service. - The .NET FFI - Foreign Function Interface
- Managed Code - Code that runs in a virtual machine such as JVM or .NET (CLR).
- Unmanaged Code - Native code, bnary code. Generally a shared library such as *.dll (Windows) or *.so (Linux) files.
- Marshalling -
- Endianess
- Little Endian
- Big Endian
- Network Order
- Strings Representation (Enconding)
- ACII - 8 bits characters
- UTF-8
- UTF-16
- ISO-8859-1
- ANSI
- New Line Character
\n
- CR - Carriage Return (Unix, Linux)\r
- LF -\n\r
- CRLF - Windows
Notes about C# - Pinvoke
- C# Interface with unmanaged code (native code or shared libraries)
- Pinvoke -
- C++/CLI - Managed C++, A C++ version that compiles to the .NET virtual machine. It allows mixing managed and unmaneged C# code.
- COM (Component Object Model) Objects - Downside: Only available on windows.
- To interface C++ it is necessary to write a C-interface to the C++ shared library.
- Only C-types can be marshalled. In order to to marshall a non C-type it is necessary to write C-wrapper or C-interface with “extern” and void* pointer.
- Thre is no way to use a C++ class directly from a C# code. In order to use the C++ class, it is necesary to write c-wrappers for all C++ class methods that will be used and a .NET Pinvoke statement.
- System.Runtime.InteropServices namespace.
- StructLayout - C-struct.
- Dllimport
- EntryPoint
- CharSet
- CharSet.Auto
- CharSet.Ansi
- CharSet.Unicode
- CallingConvention
- CallingConvention.ThisCall
- CallingConvention.Cdecl
- CallingConvention.Winapi
- SetLastError
- MarshalAs
- UnmanagedType.LPArray
- MarshalAs(UnmanagedType.LPStr)
- MarshalAs(UnmanagedType.LPStruct)
C-type / Function Parameter | C# type | F# type | Description |
---|---|---|---|
char* | string, StringBuilder, byte [] or IntPtr | Const char terminated by null | |
const char* | |||
double | double | float | 64-bit IEEE Float point number |
(double xs [], int n) | double [] | float [] | C array passed with its size. |
& int | ref int | ref int | C-pointer to a varible of type int passed by reference. |
C Data Type | .NET Equivalent | C# Equivalent |
---|---|---|
char, boolean | System.SByte | sbyte |
wchar_t, short | System.Int16 | short |
unsigned char, byte | System.Int33 | int |
unsigned short | System.Uint16 | ushort |
unsigned long, unsigned int | System.Uint32 | uint |
BSTR, char*, LPSTR, wchar_t*, LPWSTR | System.String | string |
From: c++ - how to convert std::vector<vector> to void* - Stack Overflow
- Pre C++11: (void*)&piexls_[0] (!empty() check is recommended)
- Since C++11: static_cast<void*>(piexls_.data())
- data = static_cast<void*>(& myvector[0]) ?? - http://www.cplusplus.com/forum/general/13904/
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct A
{
int i:
double d;
.
.
. // and so on
}
[DllImport(Constants.LibraryPath, EntryPoint = "callculate", CallingConvention = CallingConvention.Cdecl)]
public static extern void callculate(ref A, int i);
- Marshalling Types During Platform Invoke (P/Invoke) on the Microsoft .NET Compact Framework
- How to: Marshal Structures Using PInvoke
- P/Invoke .NET Interop
- How to: Call Native Libraries from F#
- Marshalling Complicated Structures using PInvoke – Developer Support Languages – VC++, C# and VB.NET
- F# and Data Mining: Matrix and linear algebra in F#, Part V: Sparse matrix implementation in PowerPack, and PInvoke a large scale SVD library as an application.
- PInvoke Conventions for Unix
- Let’s call Fortran DLL from F# language. | Moonmile Solutions Blog
- Clatter from the Byte Kitchen | Working The Web, Software, User Interfaces | Page 2
- Marshalling a Variable-Length Array From Unmanaged Code In C# · Basildon Coder
- Solved - PInvoke C function that return pointer - CodeProject
- Marshaling native arrays back as managed arrays without copying | paint.net blog
- Mono: mono/tests/pinvoke2.cs | Fossies
- Packing structures with Mono or how to fix alignment problems for P/Invoke
- Cross-platform .NET: Everything you (n)ever wanted to know about Marshaling (and were afraid to ask!)
- P/Invoke ioctl system call - c# - linux - mono - pinvoke - TechQA
- Link native libraries from a .NET application
- F# yet another Interop example | F# Snippets
- P/Invoke Tutorial: Passing parameters (Part 3) | manski’s blog
Show all system’s shared libraries.
$ strings -n5 /etc/ld.so.cache
ld.so-1.7.0
glibc-ld.so.cache1.1
libzvbi.so.0
/usr/lib/libzvbi.so.0
libzvbi.so
/usr/lib/libzvbi.so
libzvbi-chains.so.0
/usr/lib/libzvbi-chains.so.0
libzvbi-chains.so
/usr/lib/libzvbi-chains.so
... ... ...
Filter the shared libraries:
# GNU Scientific Library
$ strings -n5 /etc/ld.so.cache | grep -i libgsl
libgslcblas.so.0
/usr/lib/libgslcblas.so.0
libgslcblas.so
/usr/lib/libgslcblas.so
libgsl.so.19
/usr/lib/libgsl.so.19
libgsl.so
/usr/lib/libgsl.so
# C-lib Math Library
$ strings -n5 /etc/ld.so.cache | grep -i libm.so
libm.so.6
/usr/lib/libm.so.6
libm.so.6
/usr/lib32/libm.so.6
libm.so
/usr/lib32/libm.so
# Libc
$ strings -n5 /etc/ld.so.cache | grep -i libc.so
libc.so.6
/usr/lib/libc.so.6
libc.so.6
/usr/lib32/libc.so.6
- Calling C++ class methods from C - C / C++
- Intro to Linux Shared Libraries (How to Create Shared Libraries)
- C++ Tutorial: Libraries - 2017
- C/C++ library programming on Linux – Part two: Dynamic libraries | TechyTalk
- Guides / Tutorials
- Platform Invoke Tutorial (C#)
- pinvoke.net: the interop wiki!
- Platform Invoke Cheat Sheet
- Marshaling with C# Pocket Reference
- Unmanged code InterOperability
- Marshaling .NET and STL Collections in C++/CLI | All Your Base Are Belong To Us
- Unmanaged Parallelization via P/Invoke
- pinvoke - Get an array of structures from native dll to c# application - Stack Overflow
- How can I pass a pointer to an array using p/invoke in C#? - Stack Overflow
- Calling Native Functions from Managed Code
- References
- Platform Invocation Services - Wikipedia
- Blittable types - Wikipedia
- using a class defined in a c++ dll in c# code - Stack Overflow
- Blittable types - Wikipedia
- SWIG and C#
- Calling Instrument Drivers from .NET Languages - Measurement Studio 2012 for Visual Studio 2010 Help - National Instruments
- Interacting with Unmanaged Code
- Wrapping C++ class API for C consumption - Stack Overflow
- Passing std::vector’s Underlying Array to C APIs – C++ and more!
- c++ - converting array to vector - Stack Overflow
- Tutorial: Arrays in C and C++
- An Introduction to the .C Inteface to R
- C++ FQA Lite: How to mix C and C++
- How does “void *” differ in C and C++? - GeeksforGeeks
- Linear Algebrar