how to pass a list of strings to a char* [] (like argv)?

1,300 views
Skip to first unread message

Marko Loparic

unread,
Feb 20, 2011, 6:43:04 AM2/20/11
to cython...@googlegroups.com
Hello,

I would like to call a C code using cython to avoid using subprocess. For the moment I don't want to change much on the C side, in particular the intricate getopt code. So I would like to call main(int argv, char* argv[]) from cython.

If I have an argv in Python like:

argv = ['calling_from_cython', '-v', '-i', '2', input_dir, output_dir]

how do I call the C code?

There is probably an obvious way to do this, but I couldn't find it by myself...

Thanks!
Marko

Dag Sverre Seljebotn

unread,
Feb 20, 2011, 8:04:16 AM2/20/11
to cython...@googlegroups.com

First, you *need* to rename the function C-side to something else (the
symbol will conflict with Python's main function).

Then, I think this should work:

# import malloc, free
def wrapper(args):
cdef char **c_argv
# make *sure* that we have the exact string object for every argument
#, and don't invoke __str__ on something else!!
args = [b'calling_from_cython'] + [bytes(x) for x in args]
# or, use str(x).encode(...) above, depending on what API you want
and what encoding C program expect
c_argv = <char**>malloc(sizeof(char*) * len(args)) # + try/finally
and free!!
for idx, s in enumerate(args):
c_argv[idx] = s
main_in_c(len(args), c_argv)

Dag Sverre

Stefan Behnel

unread,
Feb 20, 2011, 8:15:19 AM2/20/11
to cython...@googlegroups.com
Marko Loparic, 20.02.2011 12:43:

> I would like to call a C code using cython to avoid using subprocess.

I'd question this. The subprocess module is simple and relatively fast (at
least on well behaved operating systems). Unless you are calling the
program very often and it's short running so that the startup overhead
matters (or unless that would allow you to use a substantially faster way
of communicating with it than stdin/out), I'd go with subprocess.

Stefan

Marko Loparic

unread,
Feb 21, 2011, 10:00:57 AM2/21/11
to cython...@googlegroups.com
Hello,


On 20 February 2011 14:04, Dag Sverre Seljebotn <da...@student.matnat.uio.no> wrote:
Then, I think this should work:

# import malloc, free
def wrapper(args):
   cdef char **c_argv
   # make *sure* that we have the exact string object for every argument
   #, and don't invoke __str__ on something else!!
   args = [b'calling_from_cython'] + [bytes(x) for x in args]
   # or, use str(x).encode(...) above, depending on what API you want and what encoding C program expect
   c_argv = <char**>malloc(sizeof(char*) * len(args)) # + try/finally and free!!
   for idx, s in enumerate(args):
       c_argv[idx] = s
   main_in_c(len(args), c_argv)

Yes, Dag, it worked, thanks!

Is that what you mean by the try/finally?


    c_argv = <char**>malloc(sizeof(char*) * len(args))
    if c_argv is NULL:
        raise MemoryError()
    try:
        for idx, s in enumerate(args):
           c_argv[idx] = s
        test(len(args), c_argv)
    finally:
        free(c_argv)

In the example in http://wiki.cython.org/DynamicMemoryAllocation I don't see the check after the malloc. Is there a reason for not doing it?

Cython is fun, thanks a lot!
Marko

Stefan Behnel

unread,
Feb 21, 2011, 10:36:02 AM2/21/11
to cython...@googlegroups.com
Marko Loparic, 21.02.2011 16:00:
> On 20 February 2011 14:04, Dag Sverre Seljebotnwrote:

Yes, that's about what it takes.


> In the example in http://wiki.cython.org/DynamicMemoryAllocation I don't see
> the check after the malloc. Is there a reason for not doing it?

That page is slightly outdated. And, yes, the check is missing.

Stefan

Marko Loparic

unread,
Feb 21, 2011, 10:37:35 AM2/21/11
to cython...@googlegroups.com
Hi Stefan,


I am glad you asked. The story is a bit long so I refrained myself from telling it in the first email. But maybe you have never heard about it and it may turn out to be the 1001th reason for using Cython...:-)

Our code has to be deployed in desktops running microsoft windows. The core is in C and pre/postprocessing is in Python. The idea of sending the code in .py text files did not please our superiors so we run py2exe and deploy a nice .exe file. Our clients have the "privilege" to have a protected machine: they can only run executables in c:\Program Files directory, and they can't install anything there. All installation is controlled by the IT department, which uses a crappy installation application to manage what each user can run. Our code is no exception: it has to go through the pipes of the IT department before arising to the customers. This may take days and it often add bugs. So as you can imagine this frustrates a lot our wish to become more "agile"...

To overcome it we had the idea to deploy our software in the form of a pyd dll. We will put it in the application directory of the users (a directory that they have the permission to change). A small bootstrapping exe file will still be needed and will still be deployed by the IT department. But hopefully we will not need to change it often. This solves the problem for the python code. For the C code, which is also an exe and is called using subprocess we had the same problem. Using cython we expect to the same, turn it into a pyd, put it in the application directory of our users. And the headache we had to upgrade it will be gone. You have mentioned "well behaved operating systems", do you know one? :-) Here we are forced to use one that does not seem to have this characteristic. They consolation is to use cygwin...

Greetings,
Marko

Reply all
Reply to author
Forward
0 new messages