setup.py 检查是否存在非 python 库依赖

setup.py check if non-python library dependency exists

我正在尝试为 cgal-bindings 制作一个 setup.py。要安装它,用户至少需要有特定版本的 CGAL。此外,CGAL 有一些可选目标,如果用户有一些库(如 Eigen3),则应构建这些目标。 Python 中是否有跨平台的方式来检查这个?

我可以在 ctypes.util 中使用 find_library 来检查库是否存在,但我没有看到任何简单的方法来获取版本 。 <-- 这实际上并不总是有效,有些库只是头文件,如 eigen3,它是一个 C++ 模板库。

使用 setup()install_requires 参数仅适用于 Python 库,而 CGAL 是一个 C/C++ 库。

是否应根据某些库版本的可用性编译特定扩展模块,可以通过在 setup.py 中动态生成 setup()ext_modules 参数来实现。

对于 ruamel.yaml_yaml.so 模块,只有当 libyaml 开发库已经安装在我的系统上时才应该编译:

import os
from textwrap import dedent

def check_extensions():
    """check if the C module can be build by trying to compile a small 
    program against the libyaml development library"""

    import tempfile
    import shutil

    import distutils.sysconfig
    import distutils.ccompiler
    from distutils.errors import CompileError, LinkError

    libraries = ['yaml']

    # write a temporary .c file to compile
    c_code = dedent("""
    #include <yaml.h>

    int main(int argc, char* argv[])
    {
        yaml_parser_t parser;
        parser = parser;  /* prevent warning */
        return 0;
    }
    """)
    tmp_dir = tempfile.mkdtemp(prefix = 'tmp_ruamel_yaml_')
    bin_file_name = os.path.join(tmp_dir, 'test_yaml')
    file_name = bin_file_name + '.c'
    with open(file_name, 'w') as fp:
        fp.write(c_code)

    # and try to compile it
    compiler = distutils.ccompiler.new_compiler()
    assert isinstance(compiler, distutils.ccompiler.CCompiler)
    distutils.sysconfig.customize_compiler(compiler)

    try:
        compiler.link_executable(
            compiler.compile([file_name]),
            bin_file_name,
            libraries=libraries,
        )
    except CompileError:
        print('libyaml compile error')
        ret_val = None
    except LinkError:
        print('libyaml link error')
        ret_val = None
    else:
        ret_val = [
            Extension(
                '_yaml',
                sources=['ext/_yaml.c'],
                libraries=libraries,
                ),
        ]
    shutil.rmtree(tmp_dir)
    return ret_val

这样您就不需要在分发中添加额外的文件。即使你不能在编译时根据版本号编译失败,你也应该 能够从临时目录运行生成程序并检查退出值and/or输出。