Недопустимый заголовок ELF при загрузке библиотеки из Python с использованием ctypes.cdll.LoadLibrary - PullRequest
1 голос
/ 25 ноября 2011

Я только начинаю работать с gcc в Linux.Я следую учебному пособию здесь , за исключением того, что я использую компилятор g ++.

hello_fn.cpp

#include <stdio.h>
#include "hello.h"

void 
hello (const char * name)
{
  printf ("Hello, %s!\n", name);
}

bye_fn.cpp

#include <stdio.h>
#include "hello.h"

void 
bye (void)
{
  printf ("Goodbye!\n");
}

hello.h

void hello (const char * name);
void bye (void);

Затем я запускаю в оболочке следующее:

$ g++ -Wall -c hello_fn.cpp
$ g++ -Wall -c bye_fn.cpp
$ ar cr libhello.a hello_fn.o bye_fn.o

Затем я пытаюсь из Python сделать следующее:

Python 2.7.1+ (r271:86832, Apr 11 2011, 18:05:24) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes 
>>> test = ctypes.cdll.LoadLibrary(r'/home/oob/development/libtest/libhello.a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/ctypes/__init__.py", line 431, in LoadLibrary
    return self._dlltype(name)
  File "/usr/lib/python2.7/ctypes/__init__.py", line 353, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: /home/jeff/development/libtest/libhello.a: invalid ELF header

MyИдея заключалась в том, чтобы написать некоторые функции на C ++ и вызывать их из Python.Есть идеи?

ОБНОВЛЕНИЕ: я смог заставить вещи "работать".Исходя из того, что сказал Cat Plus Plus, я, возможно, не пойду в этом направлении для нового кода, но я смог заставить его работать с большой устаревшей библиотекой c ++, которую я переносил из Windows в Linux.Нам нужен внешний интерфейс для вызова некоторых долго выполняющихся функций из этой библиотеки, поэтому я подумал, что Python может быть самым простым.Функции создают много выходных данных и возвращают только целочисленный код возврата, так что, возможно, я могу избежать «болезненных» вещей, которые говорил Cat Plus Plus.

Вот что я сделал.

Изменено hello_fn.cpp

#include <stdio.h>
#include "hello.h"

extern "C" int 
hello (void)
{
  return 16;
}                                                                                

Изменено by_fn.cpp

#include <stdio.h>
#include "hello.h"

extern "C" void 
bye (void)
{
  printf ("Goodbye!\n");
}

Изменено hello.h

extern "C" int hello (void);
extern "C" void bye (void);

buildscript.sh

#!/bin/bash

rm *.o
rm *.so

g++ -fpic -g -c -Wall hello_fn.cpp
g++ -fpic -g -c -Wall bye_fn.cpp
#make a shared library, not a static library (thanks cat plus plus)
g++ -shared -o libhello.so hello_fn.o bye_fn.o

test.py

#!/usr/bin/python

import ctypes

c = ctypes.cdll.LoadLibrary(r'/home/jeff/development/libtest/libhello.so')
a = c.hello()
print 'hello was ' + str(a)
c.bye()

Попробуйте в терминале ....

oob@ubuntu:~/development/libtest$ ./build_script.sh 
oob@ubuntu:~/development/libtest$ python test.py 
hello was 16
Goodbye!

НашиУстаревшая библиотека на самом деле не использует никаких специфичных для Windows вещей на языке c ++ (спасибо парню, написавшему этот код), так что это был довольно простой порт.У нас было несколько функций, которые использовали extern «C» для предоставления функций.Для порта я внес следующие изменения:

#ifdef LINUX
#define __stdcall
#endif
#ifdef WINDOWS
#define __stdcall __stdcall
#endif

А для одной из наших функций я могу просто оставить ее без изменений, например:

extern "C" long __stdcall reform_proj {
    //do a bunch of stuff
    return 0;
}

1 Ответ

5 голосов
/ 25 ноября 2011

ctypes для загрузки общих библиотек.ar создает архивы объектных файлов, также известные как статические библиотеки.Вы не можете загрузить этот файл с помощью ctypes, он будет понят только для компоновщика.

Другая проблема заключается в том, что использование разделяемых библиотек C ++ через ctypes является болезненным, если не невозможным.Просто не надо.Вместо этого используйте Cython и напишите правильное расширение Python, которое взаимодействует с вашим кодом C ++ (тогда вы можете связать его статически или динамически, и он будет работать).

Другой вариант - Boost.Python , но он несколько менее документирован, но имеет преимущество определения модуля Python непосредственно в коде C ++ вместо использования оболочек, написанных на другом языке.

Третье - SWIG, но я никогда не использовал его, поэтому не могу сказать вам, насколько хорошо он работает на практике.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...