Q: python setup.py build_ext --inplace --debug
会先生成 c 文件吗?
A: 在执行 python setup.py build_ext --inplace --debug
命令时,会首先生成C文件,然后再将其编译为共享库(通常是扩展模块)。以下是该命令的工作流程:
- 生成C文件:当您运行
python setup.py build_ext
时,它会查找项目中的Cython或C扩展模块,然后使用Cython编译器将这些扩展模块的.pyx
源文件转换为C代码(.c
文件)。这些生成的C文件将会位于项目的构建目录中。 - 编译C代码:一旦C代码生成完毕,
build_ext
命令将使用C编译器(通常是gcc或类似工具)将C代码编译为共享库(或扩展模块),以便它可以被Python导入和使用。 - 生成共享库:生成的共享库文件(通常是
.so
、.dll
等,具体取决于操作系统)会放置在与源文件相同的目录中,因为您使用了--inplace
选项。这意味着不需要将共享库复制到其他地方,您可以直接从当前目录中导入和使用它。 - 调试支持:如果您使用了
--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"],
)