[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