Cython Precompiler decision making [closed]

2019-08-21 02:59发布

问题:

I am looking for a solution to add pre-compiler logic in a cython file.

I have written a cython wrapper for a hardware device API that is in C++. This is a cython project that is typically compiled using MSVC for python 2.7 and 3.6. The entire package is written in cython without need for an external c++ or header file.

Initially, I have written this software for use on a windows machine, so I have used a number of base winapi functions to help access a kernel event loop and winapi error messages. It works very well, but I would like to also add in functionality for cross-platform compilation. This requires me to completely replace several key functions to make it work on a linux machine. For example, the hardware API even has different event handling functions depending on the OS. Also, the winapi event handling would need to be replaced.

Right now, I compile the whole project together into a single module to simplify import. All code resides in the same pyx file that compiles into a hwmodule.pyd file. However, to accomplish the goal of cross-platform compilation, I need to patch the file together from several small pyx files at setup time. This solution is not elegant and difficult to maintain. Not to mention, this is more difficult to train others who may want to add to the project.

Ideally, I would be able to write cython to c compile time flags that get interpretted and compiled depending on flags or variables. Is there any solution in cython that can accomplish my goal? Alternatively, is there a different organization that would be elegant and easy to maintain for this?

Some examples of plausible syntax (that may or may-not exist) that is similar to syntax found in c or python:

  • using an #ifdef or similar statement

    #ifdef __WINAPI
    def foo():
        print('bar win')
    #else
    def foo():
        print('bar linux')
    #endif
    
  • using a python-like with block

    with ifdef('__WINAPI'):
        def foo():
            print('bar win')
    
  • ending a function with a cython-like line-ending

    def foo() ifdef('__WINAPI'):
        print('bar win')
    
    def foo() ifndef('__WINAPI'):
        print('bar win')
    

回答1:

A brief answer expanded from a comment: this is a feature that Cython supports. It allows you to define compile time constants

DEF a = 5

and conditionally include code depending on those constants:

IF a==5:
    cdef f():
        return 1
ELSE:
    cdef f():
        return 2

It also defines some helpful constants: UNAME_SYSNAME lets you pick between Windows, OS X and Linux for example.


These expressions are evaluated at the point Cython is run on your .pyx file - therefore the generated C code is different on Windows vs Linux, and so if you want to compile on another platform you'll need to re-run Cython, rather than just recompiling the C files.