Q: python setup.py build_ext --inplace --debug 会先生成 c 文件吗?

A: 在执行 python setup.py build_ext --inplace --debug 命令时,会首先生成C文件,然后再将其编译为共享库(通常是扩展模块)。以下是该命令的工作流程:

  1. 生成C文件:当您运行 python setup.py build_ext 时,它会查找项目中的Cython或C扩展模块,然后使用Cython编译器将这些扩展模块的.pyx源文件转换为C代码(.c文件)。这些生成的C文件将会位于项目的构建目录中。
  2. 编译C代码:一旦C代码生成完毕,build_ext 命令将使用C编译器(通常是gcc或类似工具)将C代码编译为共享库(或扩展模块),以便它可以被Python导入和使用。
  3. 生成共享库:生成的共享库文件(通常是.so.dll等,具体取决于操作系统)会放置在与源文件相同的目录中,因为您使用了 --inplace 选项。这意味着不需要将共享库复制到其他地方,您可以直接从当前目录中导入和使用它。
  4. 调试支持:如果您使用了 --debug 选项,编译过程中会包括调试信息,以便在调试Python代码时提供更多的信息。

总之,python setup.py build_ext --inplace --debug 命令会在构建过程中生成C文件,并将它们编译为共享库或扩展模块,以便在Python中使用。

Q:如何指定「指定的构建目录」

A:要指定构建目录,您需要在您的项目的 setup.py 文件或者 pyproject.toml 文件中进行配置,具体取决于您使用的构建工具。以下是如何在两种情况下指定构建目录的方法:

在 setup.py 中指定构建目录(使用 setuptools)

如果您使用 setuptools 来构建项目,可以在项目的 setup.py 文件中指定构建目录。在 setup() 函数中,添加 ext_modules 参数并使用 cythonize() 函数来指定构建目录,如下所示:

from setuptools import setup
from Cython.Build import cythonize

setup(
    # ...
    ext_modules = cythonize("your_module.pyx", build_dir="build"),
    # ...
)

上述示例中,build_dir 参数设置了构建目录为 "build"。您可以将其替换为您想要的任何目录路径。

在 pyproject.toml 中指定构建目录(使用 Poetry 或 PEP 518)

如果您使用 Poetry 或遵循 PEP 518 的项目结构,通常会在 pyproject.toml 文件中指定构建目录。编辑 pyproject.toml 文件,添加以下配置:

[build-system]
requires = ["setuptools", "wheel", "cython"]
build-backend = "setuptools.build_meta"

[tool.cython]
build_dir = "build"

在上述配置中,build_dir 参数设置了构建目录为 "build"。您可以根据需要将其替换为您想要的目录路径。

无论您选择使用 setuptools 还是 Poetry,通过指定构建目录,您可以将生成的C文件和共享库隔离到指定的位置,以保持项目的组织结构干净。


我在编译和研究 pyav,遇到了一些问题

比如编译 pyav 的时候,为什么会生成 src 文件夹,并且这个 src 文件夹下面都是 c 文件

上面第一个 QA 日志回答第一个问题,因为 cython 编译为 so 文件的,中间需要先整成 c 文件才能,这样才能使用 gcc 等工具来做这件事情,比较 gcc 只认识 c 文件,不认识 pyx 文件

第二个问题「为什么会生成 src 文件夹」,生成 c 文件默认是在当前路径的,但是编译 pyav 的时候,会统一到 src 文件夹中去,研究了一下,正如 chatGPT 所说,是因为 pyav 添加了 build_dir="src"

# Construct the modules that we find in the "av" directory.
ext_modules = []
for dirname, dirnames, filenames in os.walk("av"):
    for filename in filenames:
        # We are looking for Cython sources.
        if filename.startswith(".") or os.path.splitext(filename)[1] != ".pyx":
            continue

        pyx_path = os.path.join(dirname, filename)
        base = os.path.splitext(pyx_path)[0]

        # Need to be a little careful because Windows will accept / or \
        # (where os.sep will be \ on Windows).
        mod_name = base.replace("/", ".").replace(os.sep, ".")

        # Cythonize the module.
        ext_modules += cythonize(
            Extension(
                mod_name,
                include_dirs=extension_extra["include_dirs"],
                libraries=extension_extra["libraries"],
                library_dirs=extension_extra["library_dirs"],
                sources=[pyx_path],
            ),
            compiler_directives=dict(
                c_string_type="str",
                c_string_encoding="ascii",
                embedsignature=True,
                language_level=2,
            ),
            build_dir="src",
            include_path=["include"],
        )

universe_king
3.4k 声望680 粉丝