Help with SWIG

Hi - I’m working on a prototype in Panda, and I’d like to add some C functionality. I’ve read a few posts about the topic, and I’d like to follow the route of adding an extension (rather than rebuilding Panda).

It sounds like SWIG is a good option, but I’m having trouble figuring out exactly how to use it. I’m using Visual Studio .NET 2003 (7.1), so it looks like I’ll be creating a .dll file if SWIG works correctly. So my first question is:

  1. Once SWIG creates a (hopefully correct) DLL, where do I place it for Panda to find? Also, will I need any extra files?

Unfortunately, I didn’t really find a forum on the net dedicated to SWIG. In addition, their documentation is a bit sparce when it comes to Windows (I’m not new to programming, but I don’t have much experience with huge projects using tons of libraries :confused: ). So if you can provide any pointers about using SWIG with VS.NET, that would also be appreciated. :wink:



Panda includes a swig-like tool called “interrogate.” So for the most part, that’s what panda developers use. If you choose to use “interrogate,” there will be several people here who can help you, but if you go the SWIG route, you may be on your own.

Have you tried rebuilding panda? I’ve worked pretty hard to make it easy. It might take a lot less effort than you think. Try using the ‘makepanda’ tool.

Thanks for your advice - I’ll try to rebuild Panda. I have the source files, and I’m still waiting for the DirectX 9 SDK to download. While I wait, I thought I’d ask a few more questions before I dive in.

I’m basically trying to add device code (in C) from a third party into Panda. I wrote a sample C program to interface with their code, and it works. Their code consists of two things - a .h file and a precompiled .lib file (I don’t have access to their original source files). To compile/run my test program, I just included their .h file and made sure that the .lib was also in the source section of my project.

I want to rewrite my test program in Panda, so I want to get this third party .h and .lib integrated. Will I run into any problems since their code is in the .lib format? I’ve been reading over this similar post:

and I’d like to make edits to makepanda if it’s possible (seems easier). If you have any other advice, please let me know. Thanks again!


Device code? Interesting. We’ve already used panda with tons of devices… head-mounted displays, digital cameras, phidgets, you name it. So I’m sure there’s a way to integrate whatever you’re interested in. What is this hardware device, anyhow?

When I recommended using “interrogate,” I may have spoken too soon. A library has to use a certain coding style to be used in conjunction with interrogate. If this library was designed by somebody else, then it may not be suitable.

The fact that it’s a LIB file won’t cause any problems. The only issue is - will the tool (swig or interrogate) be able to understand the dot-h file? If so, you’re good. But if the tool can’t figure out how to design a python interface for this library, things get harder.

Another question - how complicated is the API for this library? Just a few function calls, or a whole bunch? If it’s just a few, then things get easier — you can manually wrap any functions it doesn’t “get”.

  • Josh

I’m afraid I might get in trouble with my boss if I tell you about the device :wink:. Sorry about that…

I was able to build Panda normally (after getting the DirectX SDK). Then I tried following steps from an earlier post: I placed my two files in the ‘mathutil’ directory, added a new CompileC line, and added the .obj file to the libpanda list. When I try makepanda again, I get this error:

cl : Command line warning D4027 : source file 'panda/src/mathutil/*.LIB' ignored
cl : Command line warning D4021 : no action performed
Error: source file not readable: built/tmp/*.obj

Is there something simple I’m forgetting to do?

As for the API, I’m really only need a few functions (there are probably about 30 total). I’m also concerned that this library might be designed poorly for things like “interrogate.” I thought I’d just try it to see what happens.

I also have a DLL version of this API. In another sample C program, the author uses this DLL instead of the .h and .lib files I mentioned. In that program, he uses ‘LoadLibrary’ and ‘GetProcAddress’ to load up function pointers. Do you think this might be an easier route?

Thanks again for your help!


Let’s do this in two steps. Your first step is to figure out how to add a new C++ class to panda. For that, you should follow the instructions that you read about the “mathutil.” But don’t use your device library yet. Just see if you can add a new class — just a real simple class, maybe an integer adder or something like that.

Once you have successfully added a class to panda, then your next step is to add methods that call your device-handling library. The device-handling library itself is what we call a “thirdparty” library. You need to create a directory:


Put the dot-h file in one, put the lib file in the other.

Then, search makepanda for lines that look like this:


Add two more lines:

AddToVisualStudioPath(“LIB”, THIRDPARTY + “\win-libs-vc7\mydevice\lib”)
AddToVisualStudioPath(“INCLUDE”, THIRDPARTY + “\win-libs-vc7\mydevice\include”)

Pay attention… if you’re using visual toolkit, you have to add the lines in the visual toolkit section, and if you’re using visual studio, you have to add the lines in the visual studio section.

Ok - I was able to get my class into Panda (a simple integer adder). My files are called “CPP_Test.h/cxx”. I was able to call the methods in Panda, etc.

I then started adding device calls to the code. It compiles in VC7 with my .h and .lib device files added to the project. Unfortunately, I get this error when I run makepanda:

CAUTION: header file *.h cannot be found.
( cd panda/src/mathutil; ....
  *** Error in CPP_Test.h near line 23, column 19:
  parse error
Error parsing file: 'CPP_Test.h'

The error on line 23, column 19 is almost definitely due to the include problem - it’s a variable declaration using a struct defined by that missing .h file.

I added the thirdparty subdirectory and makepanda lines as you mentioned. I also tried copying my .h/.lib files directly into the VC7 “lib” and “include” directory (since they should already be in the compile path). Any ideas on what might be happening? Thanks again!


This is a weird error message:

CAUTION: header file *.h cannot be found.

Did you do something like this?

#include “*.h”

Show me the lines you added to makepanda. That might help me diagnose. Also, if you could show me your new test-class, that might help too.

Sorry - I was editing that for space and left out a bit too much…

Here are the lines I added to
(lines 2371-2379)

CompileC(ipath=IPATH, opts=OPTS, src='mathutil_composite1.cxx', obj='mathutil_composite1.obj')
CompileC(ipath=IPATH, opts=OPTS, src='mathutil_composite2.cxx', obj='mathutil_composite2.obj')
CompileC(ipath=IPATH, opts=OPTS, src='CPP_Test.cxx', obj='CPP_Test.obj')
Interrogate(ipath=IPATH, opts=OPTS, outd='', outc='libmathutil_igate.cxx',
            src='panda/src/mathutil',  module='panda', library='libmathutil', files=[
            'boundingHexahedron.h', 'boundingLine.h', 'boundingSphere.h', 'boundingVolume.h', 'config_mathutil.h', 'fftCompressor.h', 'finiteBoundingVolume.h', 'frustum.h', 'frustum_src.h', 'geometricBoundingVolume.h', 'linmath_events.h', 'look_at.h', 'look_at_src.h', 'omniBoundingVolume.h', 'plane.h', 'plane_src.h', 'rotate_to.h', 'CPP_Test.h', 'CPP_Test.cxx', 'mathutil_composite1.cxx', 'mathutil_composite2.cxx'])
CompileC(ipath=IPATH, opts=OPTS, src='libmathutil_igate.cxx', obj='libmathutil_igate.obj')

and (767-768):

        AddToVisualStudioPath("LIB", THIRDPARTY + "\\win-libs-vc7\\MyDevice\\lib")
        AddToVisualStudioPath("INCLUDE", THIRDPARTY + "\\win-libs-vc7\\MyDevice\\include")

and I added ‘CPP_Test.obj’ to the libpanda section.

Here’s my test class header:

 * CPP_Test.h

// Prevent multiple inclusion of header file
#ifndef CPP_TEST_H
#define CPP_TEST_H

#include "MyDevice.h"

class PandaTest
        short pType,pNum;
        *** other vars ***

        long WaitForSession(short, short);
        short InitDevice();


Here’s the class source (minus some code :wink: ):

 * CPP_Test.cxx

#include "CPP_Test.h"
#include <stdio.h>
#include <conio.h>

        pNum = 0;
        pType = 0;

long PandaTest::WaitForSession(short num, short type)

short PandaTest::InitDevice()

The error was about “MyDevice.h”, which is the .h file I placed in ‘\thirdparty\win-libs-vc7\MyDevice\include’ (and in the VC7 include directory).

Sorry again about having to be cryptic with the code/info - I was hoping that the problem might be something simple. I work for a startup, and we’re trying to be careful! Thanks!


Okay, I understand what’s going on.

As mentioned before, interrogate is our SWIG-clone. It’s trying to parse your file, and it’s failing because it can’t find MyDevice.h. The reason it can’t find your file is because it doesn’t know to look in:


The reason it doesn’t know to do that is because I screwed up.

The whole story is this: adding a third-party library to makepanda is nontrivial. I was hoping to avoid having to go into all that, but apparently, it didn’t work. So now I’m going to tell you the right way to add a new third-party library to makepanda.

First of all, if you look in makepanda, you’ll find this list of third-party libraries that makepanda can use:


Go ahead and add “MYDEVICE” to the list. Now, if you look just before the compile commands you added to makepanda, you’ll see this:

CompileC(ipath=IPATH, opts=OPTS, src=‘mathutil_composite1.cxx’, obj=‘mathutil_composite1.obj’)

See that list of options? Those options include the names of the packages “FFTW” and “NSPR”. By specifying the names of packages, I told the compiler to make those header files available. I also told interrogate to make those header files available. Go ahead and add “MYDEVICE” to those options as well.

The final thing you need to do, when compiling your program, is to specify “–use-mydevice”. If you do not specify “–use-mydevice,” then various mechanisms will cause those header files to be suppressed.

Finally, remove the “AddToVisualStudioPath” crap I told you to add before. That was a hack. You don’t need it anymore.

I believe that should do it.

Great - I think that fixes the include problem. I also added this around line 1485 (in CompileLink())- maybe this is wrong?

if (PkgSelected(opts,"MYDEVICE")):
    cmd = cmd + ' ' + THIRDPARTY + //win-libs-vc7/MyDevice/lib/MyDevice.LIB'

Also, this is what CPP_Test.h looks like (I left out PUBLISHED when I started trying to integrate the device):

 * CPP_Test.h

// Prevent multiple inclusion of header file
#ifndef CPP_TEST_H
#define CPP_TEST_H

#include "MyDevice.h"
#include "pandabase.h"

class PandaTest
	short pType, pNum;
	** other vars **

	long WaitForSession(short, short);
	short InitDevice();


Now I’m seeing something else… :wink: Actually, I received the same error earlier when I just threw my .h and .lib device files in ‘mathutil’ with the rest of my test classes.

Regenerating file: built/tmp/dtool_have_mydevice.dat
( cd panda/src/mathutil; ../../../built/bin/interrogate.exe ...
... CPP_Test.h CPP_Test.cxx ... )
    *** Error in MyDevice.h near line 143, column 28:
    parse error
Error parsing file: 'CPP_Test.h'

In MyDevice.h, a huge list of function declarations start at line 143 that look like this:

#ifdef __cplusplus
   extern "C" {

__declspec(dllimport) long pascal  Method1(short, short, void *);
__declspec(dllimport) long pascal  Method2(short);

extern long  far pascal Method1(short, short, void far *);
extern long  far pascal Method2(short);

I’m afraid that this might be where our discussion about the library’s poor design might return. I guess ‘interrogate’ is the program that’s taking issue with this stuff. Is it trying to turn this into Python?

I was hoping that I would make a few of my own C++ methods (like InitDevice) available to Panda/Python, and that those methods would make calls to this device library. Will ‘interrogate’ not allow that, or is that even feasible? Maybe I need yet another C++ layer between this device and Panda?

The device we’re working with also has a .DLL file (installed into windows\system32). I’ve thought about using that instead (with LoadLibrary and GetProcAddress methods), but I think that’ll be a headache too. :confused:

Sorry this issue is taking so long, but thanks for your help!


interrogate is the program that will turn C++ functions into Python functions. But, by default, it won’t do this for functions unless they are bracketed with:

function prototypes ...

Where the macros BEGIN_PUBLISH and END_PUBLISH are defined in dtoolbase.h to be __begin_publish and __end_publish when the code is compiled with interrogate, and nothing at all when the code is compiled with a real compiler.

The problem you are running into at the moment, however, has to do with the Windows syntax of __declspec(dllimport), and also the keyword pascal on the same lines. These are not part of standard C++, they are Windows extensions. Since interrogate is a standard C++ parser and knows nothing of Windows extensions, it can’t parse your header file–regardless of whether you have marked any of the functions in it for publishing or not.

You need to protect syntax like this from interrogate, for instance by defining a macro like this:

#define IMPORT
#define PASCAL
#define IMPORT __declspec(dllimport)
#define PASCAL pascal

And then your prototypes would be something like this:
IMPORT long PASCAL Method1(short, short, void *);

This works because interrogate defines the symbol CPPPARSER, while other compilers don’t.

Of course, if you are using interrogate to instrument a third-party header which you do not have control over, this is problematic. In this case, you may be better off writing your own wrapper functions and instrumenting those; your wrapper functions will in turn include the appropriate third-party header file and call the appropriate third-party functions.


What he said.

Let’s say, hypothetically, that you plan on publishing your own methods, which in turn call the MYDEVICE functions, instead of publishing the MYDEVICE functions directly.

Here’s what you do: create a “substitute” mydevice.h header file which is to be used by interrogate. Into this file, you put the same class/type definitions as in the “real” mydevice.h, but you leave out anything that interrogate doesn’t need to know. Often, all it needs to know is the class names. So very often, these substitute files look like this:

class MyDeviceGizmo1;
class MyDeviceGizmo2;

And that would be enough. You then take this “substitute” file and put it into dtool/src/parser-inc. In fact, you can browse that directory to see other “substitutes” we’ve written.

  • Josh

Maybe I should mention how I go about creating one of these substitute files. Typically, I start with a totally blank file. Then, I try interrogating, and I see what happens. Sometimes, interrogate will produce an error, say:

Undefined identifier “HeadMountDisplay”

I say, “oh, that’s a class name which was defined in the header file, and interrogate is barfing because it doesn’t realize that’s a class name.” I would then go into the substitute header file and add this line:

class HeadMountDisplay;

then, I would try compiling again to see if that’s enough for interrogate. Usually, it is. Occasionally, you’ll have to go a little deeper, but not usually.

  • Josh

This is great info - I think I’m getting close! I am, in fact, trying to make wrapper functions. I would like ‘CPP_Test’ to call the device specific functions. The ‘MyDevice.h’ is included in ‘CPP_Test.h’, but I don’t need to expose any of the ‘MyDevice.h’ methods to Panda. I’d rather leave all that to the C files and have Python just call things like "InitDevice()’.

I can edit ‘MyDevice.h’, so I followed David’s macro method. Everything started going smoothly (once I also made a macro for ‘far’), but then I hit this error:

CAUTION: header file MyDevice.h cannot be found.
cl.exe /Fobuilt/tmp/libmathutil_igate.obj /nologo /c /Ibuilt/python/include /Ith
irdparty/win-libs-vc7/nspr/include /Ithirdparty/win-libs-vc7/fftw/include /Ithir
dparty/win-libs-vc7/MyDevice/include /Ibuilt/tmp /Ipanda/src/mathutil /Ibuilt/inc
lude /Zc:forScope /MD /Zi /O2 /Ob2 /DFORCE_INLINING  /Fdbuilt/tmp/libmathutil_ig
ate.pdb /DBUILDING_PANDA /EHsc /Zm300 /DWIN32_VC /DWIN32 /W3 built/tmp/libmathut
thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(52) : error C2371: 'Struct1' : redefinition; different basic types
        thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(52) : see declaration of 'Struct1'
thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(60) : error C2371: 'Struct2' : redefinition; different basic types
        thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(60) : see declaration of 'Struct2'
thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(67) : error C2371: 'Struct3' : redefinition; different basic types
        thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(67) : see declaration of 'Struct3'
thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(70) : error C2011: 'Struct4' : 'struct' type redefinition
        thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(70) : see declaration of 'Struct4'

After I saw this, I also tried using the substitute header file method. I receive the same error - with a blank substitute file or with this file:

#ifndef MYDEVICE_H
#define MYDEVICE_H

struct Struct1;
struct Struct2;
struct Struct3;
struct Struct4;


After searching for this error on Google, it sounds like conflicting header files ( … stlfaq.asp).

These includes are in ‘MyDevice.h’:

/* includes */
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <windows.h>

I tried placing them between #else and #endif in David’s macro example, but that didn’t change anything. Have you run into anything like this before?


What the heck!?:

CAUTION: header file MyDevice.h cannot be found.

It still can’t find it? Show me the interrogate command-line. I want to see whether or not it specified the command-line option:


If not, something’s broken.

Ok - here is the full error message:

Makepanda Initial Status Report
Makepanda: Prefix Directory: built
Makepanda: Compiler: MSVC7
Makepanda: Optimize: 3
Makepanda: Omit Pkg: HELIX MILES MAYA5 MAYA65 MAX5 MAX6 MAX7
Makepanda: Thirdparty dir: thirdparty
Makepanda: DirectX SDK dir: C:/Program Files/Microsoft DirectX 9.0 SDK (June 200
Makepanda: Verbose vs. Quiet Level: 1
Makepanda: Don't generate API reference manual
Makepanda: Don't build installer
Makepanda: Don't build pprepackaged game
Makepanda: Version ID: 1.0.5
Makepanda: The registry does not appear to contain a pointer to the MAYA5 SDK.
Makepanda: I have automatically added this command-line option: --no-maya5
Makepanda: The registry does not appear to contain a pointer to the MAYA65 SDK.
Makepanda: I have automatically added this command-line option: --no-maya65
Makepanda: The registry does not appear to contain a pointer to MAX5
Makepanda: I have automatically added this command-line option: --no-max5
Makepanda: The registry does not appear to contain a pointer to MAX6
Makepanda: I have automatically added this command-line option: --no-max6
Makepanda: The registry does not appear to contain a pointer to MAX7
Makepanda: I have automatically added this command-line option: --no-max7
Makepanda: Using visual studio: C:\Program Files\Microsoft Visual Studio .NET 20
Makepanda: You do not have a copy of MILES sound system
Makepanda: I have automatically added this command-line option: --no-miles

CAUTION: header file MyDevice.h cannot be found.

Starting compile in "panda/src/mathutil" (4 sec):

cl.exe /Fobuilt/tmp/CPP_Test.obj /nologo /c /Ibuilt/python/include /Ithirdparty/
win-libs-vc7/nspr/include /Ithirdparty/win-libs-vc7/fftw/include /Ithirdparty/wi
n-libs-vc7/MyDevice/include /Ibuilt/tmp /Ipanda/src/mathutil /Ibuilt/include /Zc:
forScope /MD /Zi /O2 /Ob2 /DFORCE_INLINING  /Fdbuilt/tmp/CPP_Test.pdb /DBUILDING
_PANDA /EHsc /Zm300 /DWIN32_VC /DWIN32 /W3 panda/src/mathutil/CPP_Test.cxx
( cd panda/src/mathutil; ../../../built/bin/interrogate.exe -DCPPPARSER -D__STDC
__=1 -D__cplusplus -longlong __int64 -D_X86_ -DWIN32_VC -D_WIN32 -D"_declspec(pa
ram)=" -D_near -D_far -D__near -D__far -D__stdcall -DFORCE_INLINING -S../../../b
uilt/include/parser-inc -I../../../built/python/include -I../../../thirdparty/wi
n-libs-vc7/nspr/include -I../../../thirdparty/win-libs-vc7/fftw/include -I../../
../thirdparty/win-libs-vc7/MyDevice/include -oc ../../../built/tmp/libmathutil_ig
ate.cxx -od ../../../built/pandac/input/ -fnames -string -refcount
 -assert -python -I../../../built/tmp -I../../../panda/src/mathutil -I../../../b
uilt/include -DBUILDING_PANDA -module panda -library libmathutil boundingHexahed
ron.h boundingLine.h boundingSphere.h boundingVolume.h config_mathutil.h fftComp
ressor.h finiteBoundingVolume.h frustum.h frustum_src.h geometricBoundingVolume.
h linmath_events.h look_at.h look_at_src.h omniBoundingVolume.h plane.h plane_sr
c.h rotate_to.h CPP_Test.h CPP_Test.cxx mathutil_composite1.cxx mathutil_composi
te2.cxx )
CAUTION: header file MyDevice.h cannot be found.
cl.exe /Fobuilt/tmp/libmathutil_igate.obj /nologo /c /Ibuilt/python/include /Ith
irdparty/win-libs-vc7/nspr/include /Ithirdparty/win-libs-vc7/fftw/include /Ithir
dparty/win-libs-vc7/MyDevice/include /Ibuilt/tmp /Ipanda/src/mathutil /Ibuilt/inc
lude /Zc:forScope /MD /Zi /O2 /Ob2 /DFORCE_INLINING  /Fdbuilt/tmp/libmathutil_ig
ate.pdb /DBUILDING_PANDA /EHsc /Zm300 /DWIN32_VC /DWIN32 /W3 built/tmp/libmathut
thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(40) : error C2371: 'Struct1' 
: redefinition; different basic types
        thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(40) : see declaration
 of 'Struct1'
thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(48) : error C2371: 'Struct2' 
: redefinition; different basic types
        thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(48) : see declaration
 of 'Struct2'
thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(55) : error C2371: 'Struct3' 
: redefinition; different basic types
        thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(55) : see declaration
 of 'Struct3'
thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(58) : error C2011: 'Struct4' 
: 'struct' type redefinition
        thirdparty\win-libs-vc7\MyDevice\include\MyDevice.h(58) : see declaration
 of 'Struct4'

I do see the include line in the interrogate section. Also, it must be finding the .h file if it’s seeing errors! But certainly something fishy is going on - maybe it’s finding it twice? Please let me know if you have any advice - thanks!


Ok. It looks like it’s failing on the compilation of the interrogate output. Tell me: Does your header file MyDevice.h barf when included twice? Is it possible that the interrogate output, libmathutil_igate.cxx, is including your header file twice? Also, it says “redefinition, different basic types.” It is possible that you declared Struct1 as a “class” instead of a struct somewhere?

Alright - almost there :wink: I looked in libmathutil_igate.cxx - it was including “MyDevice.h” and “CPP_Test.h” (which also includes “MyDevice.h”). I just added:

#ifndef MYDEVICE_H
#define MYDEVICE_H

and things seem to work fine. There’s still one problem - I’m getting “unresolved symbol” errors (LNK2019) about 6 of the device-specific methods used my CPP_Test class. The problem is that ‘link.exe’ doesn’t seem to have “thirdparty/win-libs-vc7/mydevice/lib/MyDevice.LIB” in it’s path!

As I mentioned, I added these lines to makepanda (in the CompileLink function):

if (PkgSelected(opts,"MYDEVICE")):
    cmd = cmd + ' ' + THIRDPARTY + //win-libs-vc7/MyDevice/lib/MyDevice.LIB'

and my makepanda.bat looks like this:

@echo off
makepanda\makepanda.bat --everything --no-helix

Do you have anyidea why link.exe might be forgetting my library? I tried shoving “–use-mydevice” between “everything” and “mo-helix”, but no change. If you have any ideas, let me know - thanks!


Yes. The link command is preceded by an OPTS list:

OPTS=[bla, bla, bla]

CompileLink(opts=OPTS, yada yada…

The linker options need to include “MYDEVICE”