使用 ctypes.cdll.LoadLibrary 从 Python 加载库时,ELF 标头无效
我刚刚开始在 Linux 上使用 gcc。我正在遵循此处的教程,除了我使用的是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);
然后我在 shell 中运行以下命令:
$ 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
我的想法是用 c++ 编写一些函数并从 Python 调用它们。有什么想法吗?
更新:我能够让事情“工作”。根据 Cat Plus Plus 的说法,我可能不会朝这个方向发展新代码,但我能够让它与我从 Windows 移植到 Linux 的大型遗留 C++ 库一起使用。我们需要一个前端来调用这个库中的一些长时间运行的函数,所以我认为 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;
}
I am just getting started with gcc on Linux. I am following the tutorial here, except that I am using the g++ compiler.
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);
I then run the following in the shell:
$ g++ -Wall -c hello_fn.cpp
$ g++ -Wall -c bye_fn.cpp
$ ar cr libhello.a hello_fn.o bye_fn.o
Then I try the following from 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 idea was to write some functions in c++ and call them from Python. Any ideas?
UPDATE: I was able to get things "working". Based on what Cat Plus Plus said, I may not go this direction for new code, but I was able to get this to work with a large legacy c++ library that I was porting from Windows to Linux. We need a frontend to call some long running functions from this library, so I thought Python might be easiest. The functions create a lot of output and only return an integer return code, so maybe I can avoid the "painful" stuff Cat Plus Plus was saying.
Here is what I did.
Modified hello_fn.cpp
#include <stdio.h>
#include "hello.h"
extern "C" int
hello (void)
{
return 16;
}
Modified by_fn.cpp
#include <stdio.h>
#include "hello.h"
extern "C" void
bye (void)
{
printf ("Goodbye!\n");
}
Modified 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()
Try it in the terminal....
oob@ubuntu:~/development/libtest$ ./build_script.sh
oob@ubuntu:~/development/libtest$ python test.py
hello was 16
Goodbye!
Our legacy library doesn't really use any windows-specific c++ stuff (thanks to the guy who wrote that code), so it has been a pretty easy port. We had several functions that used extern "C" to expose functions. For the port, I have made the following changes:
#ifdef LINUX
#define __stdcall
#endif
#ifdef WINDOWS
#define __stdcall __stdcall
#endif
And for one of our functions, I can just leave it unchanged, for example:
extern "C" long __stdcall reform_proj {
//do a bunch of stuff
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
ctypes
用于加载共享库。ar
创建目标文件的档案,也称为静态库。您无法使用 ctypes 加载该文件,它只能被链接器理解。另一个问题是,通过
ctypes
使用 C++ 共享库即使不是完全不可能,也是痛苦的。只是不要。请改用 Cython,并编写一个与 C++ 代码交互的正确 Python 扩展(然后您可以静态或动态链接它) ,并且它会起作用)。另一个选择是 Boost.Python,但它的记录较少,但有一个好处是直接在 C++ 代码中定义 Python 模块,而不是使用用其他语言编写的包装器。
第三个是 SWIG,但我从未使用过它,所以无法告诉你它在实践中的效果如何。
ctypes
is for loading shared libraries.ar
creates archives of object files, also known as static libraries. You can't load that file withctypes
, it will only be understood by the linker.Another issue is that using C++ shared libraries via
ctypes
is painful if not downright impossible. Just don't. Use Cython instead, and write a proper Python extension that interfaces with your C++ code (then you can link it either statically or dynamically, and it'll work).Another option is Boost.Python, but it's somewhat less documented, but has a benefit of defining Python module directly in your C++ code, instead of using wrappers written in another language.
Third is SWIG, but I've never used it, so can't tell you how well it works in practice.