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

setup.py检查是否存在非python库依赖项,python,setuptools,distutils,setup.py,cgal,Python,Setuptools,Distutils,Setup.py,Cgal,我正在尝试为创建setup.py。要安装它,用户需要至少有一个特定版本的CGAL。此外,如果用户有一些库(如Egeng3),那么CGAL还有一些可选的目标。Python中是否有跨平台的方法来检查这一点 我可以在ctypes.util中使用find_library来检查库是否存在,但我看不到任何简单的方法来获取版本 根据某些库版本的可用性,是否应编译特定的扩展模块,可以通过在setup.py中动态生成ext\u modules的setup()参数来完成 对于ruamel.yaml的\u yaml.

我正在尝试为创建setup.py。要安装它,用户需要至少有一个特定版本的CGAL。此外,如果用户有一些库(如Egeng3),那么CGAL还有一些可选的目标。Python中是否有跨平台的方法来检查这一点


我可以在
ctypes.util
中使用
find_library
来检查库是否存在,但我看不到任何简单的方法来获取版本 根据某些库版本的可用性,是否应编译特定的扩展模块,可以通过在
setup.py
中动态生成
ext\u modules
setup()
参数来完成

对于
ruamel.yaml
\u 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
导入操作系统
从textwrap导入dedent
def check_extensions():
“”“通过尝试编译一个小的
针对libyaml开发库“”的程序
导入临时文件
进口舒蒂尔
导入distutils.sysconfig
导入distutils.ccompiler
从distutils.errors导入编译器错误、链接错误
库=['yaml']
#编写一个临时的.c文件进行编译
c_代码=dedent(“”)
#包括
int main(int argc,char*argv[])
{
yaml_解析器_t解析器;
parser=parser;/*防止警告*/
返回0;
}
""")
tmp_dir=tempfile.mkdtemp(前缀为'tmp_ruamel_yaml_')
bin\u file\u name=os.path.join(tmp\u dir,“test\u yaml”)
file_name=bin_file_name+'.c'
以fp形式打开(文件名为“w”):
fp.write(c_代码)
#并尝试编译它
编译器=distutils.ccompiler.new_编译器()
断言isinstance(编译器,distutils.ccompiler.ccompiler)
distutils.sysconfig.customize\u编译器(编译器)
尝试:
compiler.link\u可执行文件(
compiler.compile([文件名]),
bin_文件名,
图书馆=图书馆,
)
除编译错误外:
打印('libyaml编译错误')
ret_val=无
链接器除外:
打印('libyaml链接错误')
ret_val=无
其他:
返回值=[
延伸(
"u yaml",,
sources=['ext/_yaml.c'],
图书馆=图书馆,
),
]
shutil.rmtree(tmp_目录)
返回返回值
这样,分发版中就不需要额外的文件。即使在编译时不能基于版本号编译失败,也应该
能够从临时目录运行生成的程序,并检查退出值和/或输出。

Autotools也能做到这一点,因此我认为这是一种方法。虽然我认为如果在distutils中使用CCompiler类,可以使它更跨平台。@sciencectn我更新了该函数(我知道我在走捷径,但我第一次尝试使用CCompiler时就陷入了困境)。如果标头或库不可用,则此操作将失败。如果distutils/setuptools有一些选项来检查库(及其版本)的可用性,以决定是否在setup.py中包含构建特定扩展,那就太好了。您第四次的评论和回答让我又开始了。很好,我正在使用这个。在我的setup.py中给了你荣誉。