I am trying to get my own dependencies for the C # library that I use to compile on Linux x86_64. The code itself is platform independent and easy to compile.
However, by first trying to run my project on Linux with a compiled dependency, I started getting weird results from the library and segfault later. After some research, it turns out that the parameters in the P / Invoke functions were not passed in the correct order. It seems that they are being transferred back.
I tried to compile the native dependency in several ways and explicitly define various calling conventions. Nothing seems to work.
Extern Method Definition for C #
[DllImport(InteropUtil.PLATFORM_DLL)] public static extern NavStatus dtqFindPath(IntPtr query , NavmeshPoint startPosition , NavmeshPoint endPosition , IntPtr filter , [In, Out] uint[] resultPath , ref int pathCount , int maxPath);
C ++ Relevant Definition
#if _MSC_VER // TRUE for Microsoft compiler. #define EXPORT_API __declspec(dllexport) // Required for VC++ #else #define EXPORT_API // Otherwise don't define. #endif extern "C" { EXPORT_API dtStatus dtqFindPath(dtNavMeshQuery* query , rcnNavmeshPoint startPos , rcnNavmeshPoint endPos , const dtQueryFilter* filter , dtPolyRef* path , int* pathCount , const int maxPath) { return query->findPath(startPos.polyRef , endPos.polyRef , &startPos.point[0] , &endPos.point[0] , filter , path , pathCount , maxPath); } }
G ++ compiler settings
g++ -shared -o cai-nav-rcn.so.1 -g -fPIC -I Detour/Include -I DetourCrowd/Include -I Nav/Include Detour/Source/*.cpp DetourCrowd/Source/*.cpp Nav/Source/*.cpp
In the bottom output, the dtqFindPath line clearly shows the out-of-order parameters. maxPath should be 100 ( 0x64 ), but instead 1298. 1298 is the first int in the startPos structure. 100 instead of the path value.
Partial GDB Output
Thread 1 (Thread 0x7fef64330740 (LWP 3923)):
I already compared the sizes of the rcnNavmeshPoint and NavmeshPoint at both ends, they are the same. The parameters included in the P / Invoke call are in the correct order, checked using the debugger.
You can also include that the library I'm trying to use is CritterAI .
So my question is this: what should I change to align the calling convention between these two pieces of code?
Update
I highlighted the problem. These are structures that are not properly transmitted. I created SSCCE to demonstrate this:
interop.cpp
#include <cstdio> #if _MSC_VER #define EXPORT_API __declspec(dllexport) #else #define EXPORT_API #endif struct s { unsigned int a; float b[3]; }; extern "C" { EXPORT_API void testStruct(s str) { printf("STRUCT NATIVE\n"); printf("SIZE: %u\n", sizeof(s)); printf("%u, (%f, %f, %f)\n", str.a, str.b[0], str.b[1], str.b[2]); } }
cs.cs
using System; using System.Runtime.InteropServices; namespace InteropTest { [StructLayout(LayoutKind.Sequential)] public struct v { public float X; public float Y; public float Z; } [StructLayout(LayoutKind.Sequential)] public struct s { public uint A; public v B; } public class Test { [DllImport("./test.so")] public static extern void testStruct(s str); unsafe static void Main(string[] args) { s mStr; mStr.A = 22; mStr.BX = 33f; mStr.BY = 44f; mStr.BZ = 55f; Console.WriteLine("STRUCT MANAGED"); Console.WriteLine("SIZE: " + sizeof(s)); Console.WriteLine(mStr.A + ", (" + mStr.BX + ", " + mStr.BY + ", " + mStr.BZ + ")"); testStruct(mStr); } } }
Compiled with
g++ -shared -o test.so -g -fPIC interop.cpp && mcs /unsafe cs.cs && ./cs.exe
Logout on my system
STRUCT MANAGED SIZE: 16 22, (33, 44, 55) STRUCT NATIVE SIZE: 16 22, (33.000000, 0.000000, 3.179688)
Several other tests show that the structures are “skipped”, where printing str.a print the value of the next non-structural parameter. The rest of the structure seems like garbage.