I compiled the dll under windows with the help of MingW.
I asked myself how to load that dll and use the functions.
The wiki suggested ffidl. However it's doesn't seem to be that easy to use.
::ffidl::typedef gpc_vertex double double
::ffidl::typedef gpc_vertex_list int gpc_vertex
::ffidl::typedef gpc_polygon int int gpc_vertex_list
::ffidl::typedef gpc_tristrip int gpc_vertex_list
... but how to define enums?
And how to bind the functions?
Could anyone give an example?
Thomas wrote:
> I'm currently working on a program, that requires polygon clipping.
> i've found a lib that seems to do it's job quiet well.
> It can be found here:
> I compiled the dll under windows with the help of MingW.
> I asked myself how to load that dll and use the functions.
> The wiki suggested ffidl. However it's doesn't seem to be that easy to use.
wow swig looks amazing. i just tried to build it under mingw with swig.
here are commands and outputs (i used the tutorial as a reference http://www.swig.org/tutorial.html)
/include/tcl contains the tcl headers
% swig -tcl gpc.i
% gcc -fpic -c gpc.c gpc_wrap.c -I/include/tcl
gpc.c:1:0: Warnung: -fpic für Ziel ignoriert (der gesamte Code ist positionsunabhängig) [standardmäßig aktiviert]
gpc_wrap.c:1:0: Warnung: -fpic für Ziel ignoriert (der gesamte Code ist positionsunabhängig) [standardmäßig aktiviert]
% gcc -shared gpc.o gpc_wrap.o -o gpc.dll
gpc_wrap.o:gpc_wrap.c:(.text+0x96b): undefined reference to `_imp__Tcl_ResetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x97f): undefined reference to `_imp__Tcl_SetObjResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x9a3): undefined reference to `_imp__Tcl_SetErrorCode'
gpc_wrap.o:gpc_wrap.c:(.text+0x9b8): undefined reference to `_imp__Tcl_ResetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x9dc): undefined reference to `_imp__Tcl_SetErrorCode'
gpc_wrap.o:gpc_wrap.c:(.text+0xa07): undefined reference to `_imp__Tcl_AppendResult'
gpc_wrap.o:gpc_wrap.c:(.text+0xa24): undefined reference to `_imp__Tcl_NewStringObj'
gpc_wrap.o:gpc_wrap.c:(.text+0xa4c): undefined reference to `_imp__Tcl_ObjSetVar2'
gpc_wrap.o:gpc_wrap.c:(.text+0xad8): undefined reference to `_imp__Tcl_InitHashTable'
gpc_wrap.o:gpc_wrap.c:(.text+0xb82): undefined reference to `_imp__Tcl_DeleteHashEntry'
gpc_wrap.o:gpc_wrap.c:(.text+0xc00): undefined reference to `_imp__Tcl_VarEval'
gpc_wrap.o:gpc_wrap.c:(.text+0xc11): undefined reference to `_imp__Tcl_GetObjResult'
gpc_wrap.o:gpc_wrap.c:(.text+0xc29): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0xc3c): undefined reference to `_imp__Tcl_ResetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0xc53): undefined reference to `_imp__Tcl_ResetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0xc81): undefined reference to `_imp__Tcl_VarEval'
gpc_wrap.o:gpc_wrap.c:(.text+0xc92): undefined reference to `_imp__Tcl_ResetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0xca9): undefined reference to `_imp__Tcl_GetObjResult'
gpc_wrap.o:gpc_wrap.c:(.text+0xcbb): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0xda7): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0xe37): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0xf3b): undefined reference to `_imp__Tcl_NewStringObj'
gpc_wrap.o:gpc_wrap.c:(.text+0xfcc): undefined reference to `_imp__Tcl_NewStringObj'
gpc_wrap.o:gpc_wrap.c:(.text+0xfff): undefined reference to `_imp__Tcl_GetVar'
gpc_wrap.o:gpc_wrap.c:(.text+0x107d): undefined reference to `_imp__Tcl_SetVar'
gpc_wrap.o:gpc_wrap.c:(.text+0x10ed): undefined reference to `_imp__TclFreeObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1140): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1164): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1211): undefined reference to `_imp__Tcl_DeleteCommandFromToken'
gpc_wrap.o:gpc_wrap.c:(.text+0x13ff): undefined reference to `_imp__TclFreeObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1445): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1469): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1511): undefined reference to `_imp__TclFreeObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1556): undefined reference to `_imp__Tcl_DuplicateObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1567): undefined reference to `_imp__Tcl_SetObjResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x15bb): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x15da): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1622): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x165b): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1731): undefined reference to `_imp__TclFreeObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x17bb): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x17f9): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1820): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1850): undefined reference to `_imp__Tcl_GetStringResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x18e3): undefined reference to `_imp__Tcl_AppendElement'
gpc_wrap.o:gpc_wrap.c:(.text+0x197e): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x199c): undefined reference to `_imp__Tcl_GetCommandInfo'
gpc_wrap.o:gpc_wrap.c:(.text+0x19c6): undefined reference to `_imp__Tcl_DuplicateObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1a08): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1a30): undefined reference to `_imp__Tcl_CreateObjCommand'
gpc_wrap.o:gpc_wrap.c:(.text+0x1ab4): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1aeb): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1b73): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1c02): undefined reference to `_imp__Tcl_GetObjResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1c0c): undefined reference to `_imp__Tcl_DuplicateObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1c2e): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1c66): undefined reference to `_imp__Tcl_DuplicateObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1c84): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1ca6): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1ccd): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1d2b): undefined reference to `_imp__TclFreeObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1db0): undefined reference to `_imp__Tcl_CreateObjCommand'
gpc_wrap.o:gpc_wrap.c:(.text+0x1e2f): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x1e8e): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1f03): undefined reference to `_imp__Tcl_GetLongFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x1fa5): undefined reference to `_imp__Tcl_GetDoubleFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x2027): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x2049): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x2068): undefined reference to `_imp__Tcl_GetStringFromObj'
gpc_wrap.o:gpc_wrap.c:(.text+0x2127): undefined reference to `_imp__Tcl_SetResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x21bc): undefined reference to `_imp__Tcl_AppendResult'
gpc_wrap.o:gpc_wrap.c:(.text+0x251c): undefined reference to `_imp__Tcl_InitHashTable'
gpc_wrap.o:gpc_wrap.c:(.text+0x2676): undefined reference to `_imp__Tcl_InitHashTable'
gpc_wrap.o:gpc_wrap.c:(.text+0x270f): undefined reference to `_imp__Tcl_PkgProvide'
gpc_wrap.o:gpc_wrap.c:(.text+0x2724): undefined reference to `_imp__Tcl_Eval'
gpc_wrap.o:gpc_wrap.c:(.text+0x2797): undefined reference to `_imp__Tcl_CreateObjCommand'
gpc_wrap.o:gpc_wrap.c:(.text+0x27eb): undefined reference to `_imp__Tcl_SetVar'
gpc_wrap.o:gpc_wrap.c:(.text+0x2833): undefined reference to `_imp__Tcl_TraceVar'
gpc_wrap.o:gpc_wrap.c:(.text+0x287b): undefined reference to `_imp__Tcl_TraceVar'
collect2.exe: Fehler: ld gab 1 als Ende-Status zurück
as you can see the dll is not compiled.
my gpc.i contains the following data:
> wow swig looks amazing. i just tried to build it under mingw with swig.
> here are commands and outputs (i used the tutorial as a reference http://www.swig.org/tutorial.html)
> /include/tcl contains the tcl headers
> % swig -tcl gpc.i
> % gcc -fpic -c gpc.c gpc_wrap.c -I/include/tcl
> gpc.c:1:0: Warnung: -fpic f r Ziel ignoriert (der gesamte Code ist positionsunabh ngig) [standardm ig aktiviert]
> gpc_wrap.c:1:0: Warnung: -fpic f r Ziel ignoriert (der gesamte Code ist positionsunabh ngig) [standardm ig aktiviert]
You fail to link against the Tcl library. Furthermore, you should make use of stubs. Try:
gcc -fpic -DUSE_TCL_STUBS -c gpc.c gpc_wrap.c -I/include/tcl
gcc -shared gpc.o gpc_wrap.o -o gpc.dll /lib/tcl/tclstub85.lib
# adopt the path to the lib file to get it to link
> # adopt the path to the lib file to get it to link
> Christian
there are still errors :/
gpc_wrap.o:gpc_wrap.c:(.text+0x965): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0x978): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0x992): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0x9c4): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0x9d7): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0xa01): more undefined references to `tclStubsPtr' follow
gpc_wrap.o:gpc_wrap.c:(.text+0x28d5): undefined reference to `Tcl_InitStubs'
gpc_wrap.o:gpc_wrap.c:(.text+0x28e8): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0x290b): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0x293f): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0x29c5): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0x29fa): undefined reference to `tclStubsPtr'
gpc_wrap.o:gpc_wrap.c:(.text+0x2a4b): more undefined references to `tclStubsPtr' follow
collect2.exe: Fehler: ld gab 1 als Ende-Status zurück
>> # adopt the path to the lib file to get it to link
>> Christian
> there are still errors :/
> gpc_wrap.o:gpc_wrap.c:(.text+0x965): undefined reference to `tclStubsPtr'
This is more-or-less the same error, only for the stubs-version: gcc fails to link against the Tcl-Library. Is the tclstub85.lib at the right place? Have you compiled that one yourself, too, or is it from the ActiveTcl distribution? What does "nm" tell about the library file?
I don't know about the current status of gcc linking against static libraries for Visual C (I asumed it is simply working), and I don't have this setup here now to test it for you, sorry.
> >> # adopt the path to the lib file to get it to link
> >> Christian
> > there are still errors :/
> > gpc_wrap.o:gpc_wrap.c:(.text+0x965): undefined reference to `tclStubsPtr'
> This is more-or-less the same error, only for the stubs-version: gcc
> fails to link against the Tcl-Library. Is the tclstub85.lib at the right
> place? Have you compiled that one yourself, too, or is it from the
> ActiveTcl distribution? What does "nm" tell about the library file?
> I don't know about the current status of gcc linking against static
> libraries for Visual C (I asumed it is simply working), and I don't have
> this setup here now to test it for you, sorry.
> Christian
nm showed nothing :/
i compiled tcl in mingw and used the created libstub.
at least gcc could now ling the object files and a dll was created.
i tried to load the dll in activestate's wish, but that didnt work.
the dll loads fine in mingw's compiled tclsh version.
after loading the dll i tried to check the new commands with info commands * and info commands ::gpc*.
Sadly no new commands were added :(.
> nm showed nothing :/
> i compiled tcl in mingw and used the created libstub.
> at least gcc could now ling the object files and a dll was created.
> i tried to load the dll in activestate's wish, but that didnt work.
> the dll loads fine in mingw's compiled tclsh version.
Congratulations! You managed the first step;) The dll not loading into ActiveTcl is probably due to the dependence on gcc's libc. You could try linking with -static to overcome this, but first you should try getting it working with mingw's tclsh.
> after loading the dll i tried to check the new commands with
> info commands * and info commands ::gpc*.
> Sadly no new commands were added :(.
Strange. Did SWIG give any output? It also has a -Wall flag. Maybe this gpc.h only includes other include files? By default, SWIG does not recursively follow include files in order to avoid wrapping math.h, stdio.h & friends.
You can also check SWIG's output. Wrapped functions compile to something like
SWIGINTERN int
_wrap_HDFpp_getname(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
(from one of my projects, HDFpp::getname was the original method)
Try adding a simple helloworld function to the gpc.h file like this
as you can see the commands are all there now!
thanks so far.
i now need to figure out how to use that monster lol.
typedef struct /* Vertex list structure */
{
int num_vertices; /* Number of vertices in list */
gpc_vertex *vertex; /* Vertex array pointer */
} gpc_vertex_list;
thats the first problem i ran into.
how are those defined 'Vertex array pointer' in tcl?
adding a gpc_vertex and defining values for x and y are no problem.
my example.....
load gpc.dll
set vertex1 [gpc_vertex]
set vertex2 [gpc_vertex]
set vertex3 [gpc_vertex]
> i tried the same procedure on another computer with a different activestate tcl version.
> i used activestate's tcl headers and the tclstub85.lib, which came with it.
> my swig inpute file had an error, which i fixed.
> and guess what? it linked and compiled just fine!
> the dll is now loadable in activestate's wish.
> % join [info commands gpc_*] \n
> gpc_vertex_list_vertex_get
> gpc_vertex_list_num_vertices_get
Congratulations so far:)
> i now need to figure out how to use that monster lol.
> typedef struct /* Vertex list structure */
> {
> int num_vertices; /* Number of vertices in list */
> gpc_vertex *vertex; /* Vertex array pointer */
> } gpc_vertex_list;
> thats the first problem i ran into.
> how are those defined 'Vertex array pointer' in tcl?
> adding a gpc_vertex and defining values for x and y are no problem.
Well, you ran into a point where it will be easier to extend it from the C level. The problem with that code is, that it expects a contiguous array of gpc_vertex, which you probably can't build from Tcl using SWIG alone. SWIG does not understand that this is an array, it instead knows only about raw pointers. The low-level variant would be a method to allocate this thing from C; something like
and a corresponding free method+accessor for the nth element. Most libraries I have seen so far profited from wrapping them up in a (trivial) C++ class, which then was converted to Tcl by SWIG into a usable form.
> Well, you ran into a point where it will be easier to extend it from the
> C level. The problem with that code is, that it expects a contiguous
> array of gpc_vertex, which you probably can't build from Tcl using SWIG
> alone. SWIG does not understand that this is an array, it instead knows
> only about raw pointers. The low-level variant would be a method to
> allocate this thing from C; something like
> gpc_vertex_list makelist(int n) {
> gpc_vertex_list result;
> result.num_vertices=n;
> result.vertex = malloc(sizeof(gpc_vertex)*n);
> return result;
> }
> and a corresponding free method+accessor for the nth element. Most
> libraries I have seen so far profited from wrapping them up in a
> (trivial) C++ class, which then was converted to Tcl by SWIG into a
> usable form.
> Christian
hmm i might be at the end of my knowledge, heh.
i'm not that good in c to fully understand the lib and add the functions needed :(. i'll try to add helper functions tho.
When you say "didn't work"; what have you tried? First, I haven't actually tried to compile this, there might be errors. Second, it was meant to be used like this:
set new_vert [makelist 5]
to construct the vertex list. There is a need to add another accessor function to be actually able to use it; it could look like this:
void set_vertex(gpc_vertex_list *list, int n, double x, double y) {
if (n<0 || n>= list->num_vertices) {
// throw error. This is painful if not using C++
// so I simply ignore it here
} else {
list->vertex[n].x=x;
list->vertex[n].y=y;
}
}
and an anologous get_vertex to read from that
// here we use the fact that SWIG returns a list of two values
// from the return value and from output
double get_vertex(gpc_vertex_list *list, int n, double *OUTPUT) {
double x=list->vertex[n].x;
OUTPUT=list->vertex[n].y;
return x;
}
If done correctly, you should be able to make your list from Tcl using
Beware that I have NOT tried to compile this code.
I will not really try nor go on about it. You have to be able to use the lib from C before you can do this, of course. Fortunately (I had a quick look at the header file), from that point on it should almost work: It seems you can use gpc_add_contour to build up your gpc_polygon from vertex lists (though you need a way to make an uninitialized gpc_polygon, where n=0). You'll also need to tell SWIG which of the parameters are actually output parameters. YOu do this by typemaps. For example, for gpc_polygon_clip to work, you must write
*before* SWIG reads the definition for gpc_polygon_clip.
Yes, I know this is not as easy as you might have hoped. That's because C isn't really object oriented and building the data structures in memory is also a low-level thing in C. If it would be an equivalent C++ class, it would be easier, because than there is the semantics of constructors, destructors, and accessors that allow SWIG to do meaningful wrapping. In pure C, SWIG can't know whether a pointer parameter is meant to hold an array, return a value, or an input parameter. You can make using the lib from Tcl less painful by moving the pain into these wrapper functions.
int gpc_polygon_num_get(gpc_polygon *polygon) {
return polygon->num_contours;
}
gpc_vertex_list gpc_polygon_vertex_list_get(gpc_polygon *polygon, int n) {
gpc_vertex_list *result;
result = polygon->contour;
return result[n];
}
void gpc_vertex_set(gpc_vertex_list *list, int n, double x, double y) {
if (n < 0 || n >= list->num_vertices) {
// throw error. This is painful if not using C++
// so I simply ignore it here
} else {
list->vertex[n].x = x;
list->vertex[n].y = y;
}
}
double gpc_vertex_get(gpc_vertex_list *list, int n, double *result) {
if (n < 0 || n >= list->num_vertices) {
// throw error. This is painful if not using C++
// so I simply ignore it here
} else {
double x=list->vertex[n].x;
*result=list->vertex[n].y;
return x;
}
}
int gpc_vertex_num_get(gpc_vertex_list *list) {
return list->num_vertices;
the last command doesn't work somehow. it crashes my wish instance.
i guess my gpc_polygon_create function is wrong? it's kinda weird, because the lib function gpc_write_polygon (creates a text file with all the points in it) works just fine with the polygon created with gpc_polygon_create!
my question is. are there any serious errors in the c functions i added?
I had a quick look at your code, but beware that it's hard to find the error without being able to compile this.
In generally, to find such an error you should compile with -g flag (to include debug information) and run the program under a debugger. It will tell you, at which line the program crashed. I don't know about mingw, in Linux it would be
gdb tclsh
r crash.tcl
Just what I see immediately:
Am 14.11.12 11:57, schrieb Thomas:
A quick look at the code of contour_add suggests, that the hole thing is a pointer to an array of the hole parameter. This function should therefore be something like
gpc_polygon gpc_polygon_create(gpc_vertex_list *list, int hole) {
gpc_polygon result;
result.num_contours = 1;
// create an array with one element of type int
result.hole = malloc(sizeof(int));
// assign hole to the first element
result.hole[0]=hole;
result.contour = list;
return result;
}
> double gpc_vertex_get(gpc_vertex_list *list, int n, double *result) {
> if (n < 0 || n >= list->num_vertices) {
> // throw error. This is painful if not using C++
> // so I simply ignore it here
> } else {
> double x=list->vertex[n].x;
> *result=list->vertex[n].y;
> return x;
> }
> }
This function probably does not work as intended. Reason: result is an output parameter, but SWIG does not know it. It will expect, that you feed a pointer to a double, which is impossible to construct from Tcl. What you really want, is that the result is inserted into the list of results. You can achieve this by calling the parameter OUTPUT instead of result, or - even better - tell SWIG to apply the OUTPUT rule to the parameter. Best way would be
---- c file ---
void gpc_vertex_get(gpc_vertex_list *list, int n, double *x, double *y) {
if (n < 0 || n >= list->num_vertices) {
// throw error. This is painful if not using C++
// so I simply ignore it here
*x=0; *y=0;
} else {
*x=list->vertex[n].x;
*y=list->vertex[n].y;
}
}
--- end ---
This tells SWIG that for the function gpc_vertex_get, it should apply the output rule for the x and y parameters.
Again, no guarantee for success, as I haven't compiled that code. Next time you could upload the code so that anybody can try to really compile that stuff.