[Pyrex] Compiling in cpp mode
Lenard Lindstrom
len-l at telus.net
Tue May 25 02:13:31 CEST 2004
On Mon, 24 May 2004 19:08:51 +0200 Serge Barbosa Da Torre <sergiobdt at yahoo.com> wrote:
> Hi,
> For reference, here is a quick dirty solution for being able to run pyx in
> cpp mode with the MS VC6 compiler.
>
> By default Pyrex convert the pyx file to .c
> By using the --swig-cpp flag (as in a makefile: python Setup.py
> build_ext --inplace --swig-cpp), one can force the generation of cpp files
> instead.
> Pyrex distutil extension tries to perform some basic cleaning of the
> generated cpp file, however:
>
> A. there is a problem with the staticforward keyword which is defined as:
> #define staticforward static (in Python/include/object.h).
> In the case of MSVC, one needs to define it as an extern instead.
This is a quirk of MSVC++. It does not work with g++.
> My temporary solution is to include a compatcpp.h file on top of the pyrexc
> files as followed:
> // top of the pyx file
> cdef extern from "compatcpp.h":
> pass
>
> with:
> // File compatccp.h
> #ifndef COMPATCPP_H
> #define COMPATCPP_H
>
> #ifdef _MSC_VER
> # ifndef __cplusplus // Supporting in c mode with cross compilation with
> cpp
> # define inline __inline // VC++ do not recognize inline as a C
> keyword
> # else // Supporting in cpp mode
> # undef staticforward
> # undef statichere
> # define staticforward extern
> # define statichere static
> # endif
> #endif
> #endif // COMPATCPP_H
>
> B. pyrexc adds the macro directive on the first line: "extern "c" { } of
> the
> generated cpp file.
> This breaks in VC++. It should be placed after the list of #include.
> Patch need to be applied to Pyrex/Distutil/build_ext.py :
> f = open(filename, 'w')
> # SBDT - Hack: I change the original code so that the external "C" is
> # placed after all the includes
> k = 0
> while 1:
> if lines[k].startswith("typedef"): break
> k+=1
> lines.insert(k, 'extern "C" {\n')
> #end hack
>
I have had some success in compile Pyrex using VC++ module myself. But I have
been making the changes to the C file by hand.
One other problem I have found with C++ is when a (void *) cast operator is
used on the right hand side of an assignment as a general purpose pointer
conversion. I think this happens when C methods are declared in Pyrex.
The Pyrex language already has many of the tools needed to handle C++
classes. C name specifications are the trick. Here is an example I have
manage to compile.
// cppheader.h
class Klass {
public:
Klass(int x=0) { Klass::x = x; };
int x;
int two_x() { return 2*x; };
int operator==(int y) { return x == y; }
};
int foo(int x) {
return 10 * x;
}
double foo(double x) {
return 20.2 * x;
}
# This is an experiment to test the behavior of the Pyrex compiler.
# It does not generate a compilable C file.
cdef extern from "cppheader.h":
# Test way to handle overloaded functions.
int fooi "foo" (int x)
float foof "foo" (float x)
# Test way to handle class methods.
ctypedef struct klass "Klass":
int x
int (*two_x)()
int (*_eq_ "operator ==")(int y)
# Test way to handle class construction and deletion.
klass *klassfactory "new Klass" (int x)
void delete "delete " (void *o)
cdef class Klass:
"""Wraps a C++ class"""
cdef klass *value
def __new__(self, int x):
self.value = klassfactory(x)
property x:
def __get__(self):
return self.value[0].x
def __richcmp__(x, y, op):
if isinstance(x, Klass):
self, other = x, y
else:
self, other = y, x
if op == 2:
return self._eq(other)
if op == 3:
return not self._eq(other)
return NotImplemented
def _eq(self, int y):
return self.value[0]._eq_(y) != 0
def two_x(self):
return self.value[0].two_x()
def __dealloc__(self):
delete(self.value)
def FooI(int x):
return fooi(x)
def FooF(double x):
return foof(x)
Lenard Lindstrom
<len-l at telus.net>
More information about the Pyrex
mailing list