2

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')
    
scicalculator
  • 1,498
  • 3
  • 16
  • 33
  • 1
    You know that Cython already supports [a feature a bit like this](http://cython.readthedocs.io/en/latest/src/userguide/language_basics.html#conditional-compilation)? – DavidW Nov 14 '17 at 07:06
  • @Olaf I had added tags for `c++`, `python`, and `c` because there may be valid solutions that are written in either language. ie. using python in the `setup.py`, or adding a `c++` file to handle special features. Such cross-language capabilities are made possible by cython. This is just an FYI in case you didn't understand that. – scicalculator Nov 14 '17 at 17:55
  • @DavidW That looks like it may suite my needs perfrectly, I'll take a closer look. If you submit an "answer" with that, I'd be glad to mark your answer as correct. – scicalculator Nov 14 '17 at 18:00
  • 1
    @scicalculator. Done. With respect to the tags - I think the logic is that the people watching the C and C++ tags probably won't know enough about Cython to help (even if the solution ultimately needs C and C++) and so they feel that adding those tags wastes their time. In contrast the people watching the Cython tags will usually be happy to show C or C++ solutions where necessary (so you don't really need to indicate it with tags). – DavidW Nov 14 '17 at 18:27
  • @DavidW Thanks for the help, I think I better understand how to improve my posts for the future. – scicalculator Nov 14 '17 at 18:34

1 Answers1

6

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.


There is no direct equivalent of C #ifdef/#ifndef in Cython - testing whether a compile time constant is defined is not a supported feature.

DavidW
  • 29,336
  • 6
  • 55
  • 86
  • This only says compile time definitions can be done, not that C-preprocessor-style IFDEF statements can be used. This does not fully answer the question of ifdef {thing} else {other} endif. Stating a constant vs a preprocessor def are two very different things. – Koala Bear Jul 28 '20 at 17:57
  • 1
    @KoalaBear Fair point. You cannot do `#ifdef` in Cython. I've updated the answer to reflect that. – DavidW Jul 28 '20 at 18:13