【问题标题】:How to access a module installed by setuptools' install_requires within setup.py?如何在 setup.py 中访问由 setuptools 的 install_requires 安装的模块?
【发布时间】:2016-05-06 00:21:42
【问题描述】:

我正在编写一个 setup.py 来安装我的包 reboundx,它有一个依赖项 rebound。我的包构建了一个扩展libreboundx.so,需要在 setup.py 中链接到librebound.so

rebxExt = Extension('libreboundx', libraries=['rebound'], library_dirs = [rebound_path]...)

我希望能够在setup(...) 调用中使用install_requires 来构建reboundx 模块,以确保安装了正确版本的rebound。有什么办法可以解决循环问题?

如果没有安装rebound,我会以某种方式需要setuptools 来通过install_requires 检测到这一点,安装rebound,然后找到正确的路径并构建扩展libreboundx.so

【问题讨论】:

  • 您是否在标题中标记了反弹版本?
  • 不,我不这么认为。不过,我也可以在反弹模块中进行任何必要的更改。

标签: python installation setuptools setup.py pkg-resources


【解决方案1】:

正如 sn6uv 所指出的,似乎 setuptools 确实通过 setup_requires 关键字使这成为可能。但是,我发现很难找到说明如何使用它的文档和/或示例。从我的发现来看,对于外行来说,这似乎有点微妙/复杂。

一方面,当使用 pip 时,setup_requires 中的依赖项的安装方式与其他所有内容不同(请参阅Install package which has setup_requires from local source distributions)。似乎如果您需要在 setup.py 中导入依赖项,则需要对 install 命令进行子类化以延迟导入直到它可用(在 distutils 邮件列表中争论 setup_requires 的线程深处,Donald Stufft 谈到这个和一个例子的链接:https://mail.python.org/pipermail/distutils-sig/2015-March/025882.html)。

所以我放弃并实施了类似于 goCards 建议的手动检查的方法。只是想我会为遇到此问题的更雄心勃勃的人发布链接。

【讨论】:

    【解决方案2】:

    您应该使用setup_requires 参数到setup()。从文档中,

    设置要求

    一个字符串或字符串列表,指定需要存在哪些其他发行版才能运行安装脚本。 setuptools 将在处理其余的设置脚本或命令之前尝试获取这些(甚至使用 EasyInstall 下载它们)。如果您在构建过程中使用 distutils 扩展,则需要此参数;例如,处理 setup() 参数并将它们转换为 EGG-INFO 元数据文件的扩展。

    (注意:setup_requires 中列出的项目不会自动安装在运行安装脚本的系统上。如果它们在本地不可用,它们会被简单地下载到 ./.eggs 目录。如果你想要它们要安装,以及在运行安装脚本时可用,您应该将它们添加到 install_requires 和 setup_requires。)

    https://pythonhosted.org/setuptools/setuptools.html#new-and-changed-setup-keywords

    编辑: 它应该为setup_requires 中的每个条目创建一个egg 目录。 然而,我只是用反弹的方式尝试了这个,它实际上无法在简单安装下构建。

    $> python2 setup.py install
    install_dir .
    warning: no files found matching 'src/rebound.h'
    src/rebound.c:38:21: fatal error: rebound.h: No such file or directory
    compilation terminated.
    Traceback (most recent call last):
      File "setup.py", line 187, in <module>
        url="http://www.mathics.github.io/",   # project home page, if any
      File "/usr/lib/python2.7/distutils/core.py", line 111, in setup
        _setup_distribution = dist = klass(attrs)
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/setuptools/dist.py", line 221, in __init__
        self.fetch_build_eggs(attrs.pop('setup_requires'))
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/setuptools/dist.py", line 245, in fetch_build_eggs
        parse_requirements(requires), installer=self.fetch_build_egg
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/pkg_resources.py", line 544, in resolve
        dist = best[req.key] = env.best_match(req, self, installer)
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/pkg_resources.py", line 786, in best_match
        return self.obtain(req, installer) # try and download/install
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/pkg_resources.py", line 798, in obtain
        return installer(requirement)
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/setuptools/dist.py", line 293, in fetch_build_egg
        return cmd.easy_install(req)
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/setuptools/command/easy_install.py", line 582, in easy_install
        return self.install_item(spec, dist.location, tmpdir, deps)
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/setuptools/command/easy_install.py", line 612, in install_item
        dists = self.install_eggs(spec, download, tmpdir)
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/setuptools/command/easy_install.py", line 802, in install_eggs
        return self.build_and_install(setup_script, setup_base)
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/setuptools/command/easy_install.py", line 1079, in build_and_install
        self.run_setup(setup_script, setup_base, args)
      File "/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg/setuptools/command/easy_install.py", line 1070, in run_setup
        raise DistutilsError("Setup script exited with %s" % (v.args[0],))
    distutils.errors.DistutilsError: Setup script exited with error: command 'gcc' failed with exit status 1
    

    【讨论】:

    • 这看起来正是我想要的。不过,我很难找到更多详细信息或示例。 librebound.so 和任何 package_data 会在 ./.eggs 目录中吗?我不在电脑前,所以没有乱来。
    • 原则上是的,但是在./rebound-VERSION-py2.7.egg 目录中,它似乎对反弹不起作用。我已经相应地编辑了我的答案。
    • 我无法重现该错误。你是怎么安装的?在从 github 克隆 repo 并从 pypi 下载 tarball 没有错误后,我尝试了 pip install 反弹和 python setup.py install。
    • pip install 工作正常(easy_install 也是如此)。当我只是将反弹添加到 setup_requires 字段并运行 setup.py install(并且我的系统上还没有反弹)时,就会发生该错误
    【解决方案3】:

    (如果您喜欢这种方法,我可以进一步详细说明) 考虑这个例子。我使用 ctypes 加载共享库。然后使用函数调用获取库的版本。

    >>> import ctypes
    >>> x = ctypes.cdll.LoadLibrary("libc.so.6")
    >>> x.gnu_get_libc_version
    <_FuncPtr object at 0x7f9a08e3e460>
    >>> getversion = x.gnu_get_libc_version
    >>> getversion.restype = ctypes.c_char_p
    >>> getversion()
    '2.19'
    

    您可以使用反弹.so 做类似的事情。使用 try 语句加载 librebound。 如果是错误的版本或者在库的标准搜索路径中没有找到,则编译 librebound。

    #setup.py
    import ctypes
    try:
        x = ctypes.cdll.LoadLibrary("librebound.so")
        x.restype = ctypes.c_char_p
        version = x.get_version()
        major,minor = version.split(".")
        if int(major) < REQUIRED_VERSION:
            raise False, "LIBREBOUND VERSION %s IS NOT SUPPORTED"%(str(version))
    
    except:
        pass
        #invoke rebound's makefile
        #probably install the new library to lib path.
        #link to new rebound 
    
    rebxExt = Extension('libreboundx', libraries=['rebound'], library_dirs = [rebound_path]...)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-02
      • 2020-06-10
      • 2018-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多