Post date: Oct 22, 2012 7:42:35 AM
This was pretty easy. Following the history on this page I eventually landed on this process:
Unpack archive. Navigate to src tree.
gcc -I../include/chipmunk -O3 -ffast-math -std=gnu99 -c *.c
Success so far; no errors, no warnings.
(using -fPIC as per the forum post above spits out a warning that -fPIC is irrelevant because all code is position independent)
gcc --shared -o chipmunk-6.1.1.dll -Wl,--out-implib=chipmunk-6.1.1.dll.a -Wl,--output-def=chipmunk-6.1.1.dll.def cp*.o chipmunk.o
This produces a .dll that I confirmed is valid using dependency walker.
This one was more awkward. I didn’t know at first that mingw was producing x86 code, and I was trying to use x64. I eventually worked that out, and started using the x86 version of purebasic.
At first I used infratec’s tool to make a bare-bones almost-wrapper.. then I added some types..
; Warning! Achtung!
; This will be a Float on 32-bit MacOS installations!
; This will need to be addressed at some point.
Macro cpFloat
double
EndMacro
; See above. Floats on 32-bit MacOS.
Structure cpVect
x.d
y.d
EndStructure
and defined a single prototype to start with...
OSPrototype.d Proto_cpvtoangle(x.d, y.d)
And made a very simple test case.
tempvec1.cpVect
tempvec2.cpVect
tempvec3.cpVect
tempvec1\x = 1.0
tempvec1\y = 0.0
tempvec2\x = 0.0
tempvec2\y = 1.0
tempvec3\x = 0.7
tempvec3\y = 0.7
tempdouble.d
tempdouble = cpvtoangle(tempvec1\x, tempvec1\y)
Debug tempdouble
tempdouble = cpvtoangle(tempvec2\x, tempvec2\y)
Debug tempdouble
tempdouble = cpvtoangle(tempvec3\x, tempvec3\y)
Debug tempdouble
Results:
0.0
1.5707963267948966
0.78539816339744828
So far, so good.
Around this point, I started realizing a few things. One, an awful lot of chipmunk involves passing structures by value, not just as arguments, but as the return from functions.
At first, I pursued using assembly to play with hidden parameters, but then a simpler solution occurred: Make a shim in C that makes GCC do all that work for me.
Since I don’t HAVE to use this as a .dll, and in fact in the long term I don’t want to, the ASM approach is highly suboptimal.
This immediately presents a problem: I don’t know C. Okay, let’s back up.
For this process, first you need to befriend an expert in C. If you don’t have one, well, good luck.
Through a careful series of [redacted] I managed to create the following test case.
Using one of the inline functions from cpVect.h:
static inline cpFloat cpvdist(const cpVect v1, const cpVect v2)
{
return cpvlength(cpvsub(v1, v2));
}
I created the following shim:
#include “chipmunk.h”
void PB_cpvdist(cpFloat *result, cpVect *v1, cpVect *v2)
{
*result = cpvdist(*v1, *v2);
}
I put this in a shim.c file in the src folder, and went back to the compilation process in step one above.
Result: a .dll file with one extra function in it than before.
I created a new test .pb file:
Prototype.i proto_PB_cpvdist(*result.cpFloat, *v1.cpVect, *v2.cpVect)
Global PB_cpvdist.proto_PB_cpvdist
chipmunk = OpenLibrary(#PB_Any, "chipmunk-x86.dll")
PB_cpvdist = GetFunction(chipmunk, "PB_cpvdist")
vector1.cpVect
vector2.cpVect
dist.cpFloat
vector1\x = 1.0
vector1\y = 0.0
vector2\x = 0.0
vector2\y = 1.0
PB_cpvdist(@dist, @vector1, @vector2)
Debug dist
(Not pictured: the previously indicated macro and structure declaration from step Two)
Result:
1.4142135623730951
Well, that sure looks like it’s working. Just to be sure, I also tested 1.0,0.0 against 0.0,0.0, and got 1.0. Equal vectors result in a dist of 0.0. That’s enough to believe that it’s probably okay.
This seems simple on the surface. The forum post I found here implied that the .a output from mingw would work fine for this purpose.
I thought: Oh hey my .dll creation process ALSO created a .a file! I’m saved!
No.
Not even a little.
Even after correctly making a chipmunk-x86.desc file...
; Langage used to code the library: ASM or C
C
; Number of windows DLL than the library need
0
; Library type (Can be OBJ or LIB).
LIB
; Number of PureBasic library needed by the library. Here we need the Gadget library
0
; Help directory name. Useful when doing an extension of a library and want to put
; the help file in the same directory than the base library. This is not a facultative
; result.
chipmunk
; Library functions:
cpvdist, Long, Long, Long (*Result, *Vector1, *Vector2) - Result is Float/Double. Vector1 and Vector2 are cpVects
None
… it turns out that, no, that doesn’t work. Because the code was compiled as a shared library, the stub in the .a immediately tries to load in the .dll file, and things go sad from there.
At first I thought I would need to follow some complicated process involving using Microsoft’s Visual Studios tools to create a proper .lib file..
But I thought back to milan1612’s post in the PB forums, and did more digging.
This was the result of my search. Specifically, the following instruction for creating a .a file using mingw:
ar rcs libadd.a add.o
I thought: There is no way it could be that simple. There has to be more to this story.
Spoiler: Nope. That’s exactly what I needed.
ar rcs chipmunk-x86.a *.o
After feeding the .desc file and .a file (helpfully renamed as .lib) into the LibraryMaker.exe, I had myself a library. I dropped it into the userlibraries folder, and edited my above test code to use cpvdist instead of PB_cpvdist.
Result:
1.4142135623730951
Success! This process does, in fact work.
No, wait, that’s way too much work.
That sounds better.
This is still quite a bit of work, since it requires some infrastructure construction, but it has improved maintainability. I can maintain a single list of all functions, and have a tool autogenerate the shim and .desc files for any target architecture I desire. This should greatly simplify tracking the upstream library.