[Pyrex] defining extern variables in pyrex

David M. Cooke cookedm at physics.mcmaster.ca
Wed Apr 13 00:58:37 CEST 2005

Thys Meintjes <thys at sentechsa.com> writes:

> Hi All,
> I've inherited a c library and is the process of wrapping it using
> Pyrex. The library code is a state machine and remembers previous values
> in order to determine new values on, for example, a decode() call. These
> "state-full" variables were all implemented using 'extern' in the c
> code.

Being extern means they are global variables in the program: there is
only *one* variable, no matter how you wrap it.

> My wrapper works fine if I have only one instance of my new type
> myclass. However, when I create more than one instance of myclass it
> seems that the different instances each share the same extern variables.
> And of course when one method call on a instance manipulates the
> internal state machine it invalidates the other instance's state. I
> guess this makes sense...

That's what you would expect. Basically, the library is storing state
in a global variable, so all instances use the same variables to store
state (which of course is a mess).

> So, how do I define variables in the pyrex wrapper that is visible as
> extern c values but are private to a instance ?  Look at the example,
> both val2 and val1 are defined as extern in some .h or .c files in the
> library, val2 is visible but not private to myclass, val1 is private to
> myclass but when I import myclasslib I get undefined symbol errors like
> these:
> ImportError: ./codex/efr/src/libgsmefr.so: undefined symbol: past_gain

What's past_gain? I'm guessing that's one of your extern variable
names? You should check that in some module, the variable is defined
without extern (that'll be where the variable actually lives: the
other extern declarations are just promises to the linker that it'll
be able to find the actual definition).

> example:
> cdef short val2
> cdef class myclass:
>     cdef short val1
> I reckon that if I can define all the state-full vars in the same scope
> as val1 and convince Pyrex (and the linker, I guess) that these are the
> elusive externs I wouldn't need to go through the pain of passing these
> state-full vars down each method call,
> Do I have any hope of doing it this way ?

No, I don't think so.

You've got two ways to do this:

1) (Hacky, inefficient solution) Have routines that will copy the
   state in-and-out of the global state variables. Call these in your
   wrappers before and after calling the library routines. Keep the
   copy of the state in your wrapped class.

2) (Better, more intrusive) Modify the library. Remove the global
   variables, and pass the state variables to each library routine.
   This becomes easy if you make a struct whose members are the old
   global variables, and pass that struct to each routine (instead of
   passing each variable individually). Again, keep that state in your
   wrapped class.

|David M. Cooke                      http://arbutus.physics.mcmaster.ca/dmc/
|cookedm at physics.mcmaster.ca

More information about the Pyrex mailing list