与distutils共享库依赖项

时间:2012-03-20 22:10:27

标签: python distribution packaging distutils software-distribution

我是distutils的新手,我遇到了一个让我陷入困境的问题。我正在编译一个需要扩展的包,所以我这样做了扩展:

    a_module = Extension(
          "amodule",
          ["initmodule.cpp"],
          library_dirs=libdirs,
          extra_objects = [
                    "unix/x86_64/lib/liba.so"
                    "unix/x86_64/lib/lib.so",
                    "unix/x86_64/lib/libc.so"],
    )

然后我运行安装方法:

    setup(name="apackage", version="7.2",
      package_dir = {'':instdir+'/a/b/python'},
      packages=['apackage','package.tests'],
      ext_modules=[hoc_module]
)

包分发正确,我可以“python setup.py install”很好,但是当我尝试导入我的包时出现错误 ImportError: liba.so.0: cannot open shared object file: No such file or directory

我意识到当我将liba.so.0的位置添加到我的LD_LIBRARY_PATH时,程序运行正常。不幸的是,我没有编写这些模块,也没有很好地理解编译。我一直试图解决这个问题几天无济于事。

UPDATE :我尝试将liba.a,libb.a等文件传递给extra_objects,但这不起作用,生成以下错误:liba.a:无法读取符号:错误值 collect2:ld返回1退出状态。我要做的是打包一个python模块,它需要编译一个库本身依赖于我需要以某种方式包含在包中的其他库。我怀疑我的问题非常类似于这个:{{3但是那个问题没有得到解决,我想也许已经有两年了,已经找到了决议?

更新2 :现在我通过以下方式解决了这个问题:

      data_files=[('/usr/local/lib', glob.glob('unix/x86_64/lib/*'))]

也就是说,我正在将我需要的库复制到/ usr / local / lib中。我对这个解决方案并不是非常满意,尤其是因为它要求我的用户拥有root权限,并且因为这可能仍然无法使用Redhat发行版。因此,如果有人能提出比此修复更好的建议,请告诉我。

2 个答案:

答案 0 :(得分:15)

您可以将标志传递给编译器或链接器,以便让它知道在运行时查找库的位置,从而减少正确设置LD_LIBRARY_PATH的需要。我将用几个例子来说明:

# Will link just fine, then fail to find libpcap.so unless it's in LD_LIBRARY_PATH
gcc -o blah blah.o -lpcap -L/opt/csw/lib

# If libpcap is in LD_LIBRARY_PATH, it'll link fine.  Other people who may not have
# LD_LIBRARY_PATH set properly can still run it without fixing their environment
gcc -o blah blah.o -lpcap -R/opt/csw/lib

# This will allow me to link and execute the binary without having LD_LIBRARY_PATH
# setup properly
gcc -o blah blah.o -lpcap -{L,R}/opt/csw/lib

# This makes it possible to use relative paths.  The literal string `$ORIGIN/../lib/`
# gets stored in the binary (`readelf -d binary_name` if you want to see the effect
# it has), which causes `$ORIGIN` to resolve to the directory containing the binary
# when it was executed.  In a makefile, you'll see that written as `$$ORIGIN/../lib/`
# to prevent `make` from expanding it.
gcc -o blah blah.o -lsomelib -L/whatever/path/floats/your/boat -R'$ORIGIN/../lib/'

以解释的方式,如果不明显(因为我讨厌答案而没有解释):

  • -L指定的路径仅用于在链接
  • 时查找库
  • -R给出的路径仅用于在执行二进制文件时查找库

答案 1 :(得分:10)

extra_objects类的Extension参数不是链接到扩展名的库列表,而是一个将传递给链接器的目标文件列表(文件名不应该是不包括扩展,因为distutils会添加扩展。)它不会做你想要的。

如果你想链接特定的共享库,就像你想要的那些文件的名称一样,你必须做两件事:告诉distutils告诉编译器链接这些共享库,并告诉动态链接器(通常ld.so)在哪里找到这些共享库。您可以通过使用libraries Extension参数来告诉编译器链接库,这些参数应该是库名称列表(没有lib前缀和{{1在你的示例中,似乎是.so(虽然看起来['a', 'b', 'c']看起来像'b'',但'lib.so实际上会与系统发生冲突的libc。)

告诉链接器可以通过设置'c'环境变量,或者通过更改系统范围的配置设置(使用LD_LIBRARY_PATH或编辑{ {1}}),或者通过在扩展模块中硬编码搜索路径;你可以通过将ldconfig参数传递给/etc/ld.so.conf来完成后者。硬编码路径确实有自己的问题 - 你必须将这些库保存在同一个地方,并且扩展模块的所有用户都可以访问。

(或者,你可以使用静态而不是动态链接,例如只提供静态形式的库,runtime_library_dirs档案(在这种情况下,distutils将自动静态链接到它们。)这基本上意味着整个库包含在扩展模块中,具有各种缺点和优势。)