Conda 在 env 中编译时不会在正确的位置寻找 libpthread 和libpthread_nonshared



我有一个带有Cython扩展的python包,我正在尝试编译它。

我收到以下错误作为pip install的输出:

/home/user/anaconda3/envs/benchopt_lasso/bin/x86_64-conda-linux-gnu-c++ -pthread -shared 
-B /home/user/anaconda3/envs/benchopt_lasso/compiler_compat -L/home/user/anaconda3/envs/benchopt_lasso/lib -Wl,
-rpath=/home/user/anaconda3/envs/benchopt_lasso/lib -Wl,--no-as-needed -Wl,--sysroot=/ 
-Wl,-O2 -Wl,--sort-common -Wl,--as-needed -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags -Wl,--gc-sections -Wl,--allow-shlib-undefined 
-Wl,-rpath,/home/user/anaconda3/envs/benchopt_lasso/lib 
-Wl,-rpath-link,/home/user/anaconda3/envs/benchopt_lasso/lib -L/home/user/anaconda3/envs/benchopt_lasso/lib -march=nocona 
-mtune=haswell -ftree-vectorize -fPIC -fstack-protector-strong -fno-plt -O2 -ffunction-sections -pipe 
-isystem /home/user/anaconda3/envs/benchopt_lasso/include -DNDEBUG 
-D_FORTIFY_SOURCE=2 -O2 -isystem /home/user/anaconda3/envs/benchopt_lasso/include build/temp.linux-x86_64-3.8/celer/lasso_fast.o 
-o build/lib.linux-x86_64-3.8/celer/lasso_fast.cpython-38-x86_64-linux-gnu.so
/home/user/anaconda3/envs/benchopt_lasso/compiler_compat/ld: cannot find /lib64/libpthread.so.0
/home/user/anaconda3/envs/benchopt_lasso/compiler_compat/ld: cannot find /usr/lib64/libpthread_nonshared.a
collect2: error: ld returned 1 exit status

这些库不在/usr/lib64 中,它们在/home/user/anaconda3/envs/benchopt_lasso/x86_64-conda-linux-gnu/sysroot/usr/lib64/

为什么 conda 的编译器找不到它们?我怀疑选项-sysroot=/,而默认值指向正确的位置

/home/user/anaconda3/envs/benchopt_lasso/bin/x86_64-conda-linux-gnu-c++ --print-sysroot
/home/user/anaconda3/envs/benchopt_lasso/bin/../x86_64-conda-linux-gnu/sysroot

使用以下env.yml文件在新终端中重现(使用另一个包)的步骤:

name: reprod 
channels:
- conda-forge
- nodefaults
dependencies:
- python=3.8
- numpy
- cython
- compilers
- pip
conda env create -n reprod -f env.yml
conda activate reprod 
pip install git+https://bitbucket.org/mathurinm/cd_solver.git@module_structure -v

在 env 要求中更改为 python=3.9 可以解决这个问题。

TL;DR- 使用pyproject.toml构建项目时,默认使用构建隔离。此安装setuptools来自pypi,它未配置为与 conda 编译器一起使用。如果使用选项--no-build-isolation,则会生成包。


这里的问题是pyproject.toml构建隔离过程与具有自己的编译器conda环境不兼容。已经有几份关于这种不兼容的报告,例如这里提到了这一点。

这里的核心问题是setuptools依赖于一个名为sysconfigdata_xxx的包来获取有关如何构建包的信息(请参阅此处),特别是获取链接器标志。默认情况下,它会获取包'_sysconfigdata_{abi}_{platform}_{multiarch}'。当setuptools与 conda 一起安装时,它会被修补以获取在 conda env 中设置的 env 变量_CONDA_PYTHON_SYSCONFIGDATA_NAME中定义的不同系统配置。然后,_sysconfig_*模块使用正确的编译标志。

通过构建隔离,将创建一个新的环境(在/tmp/pip-build-env-XXX/年的 Linux 上),并安装一个新版本的setuptools,与conda中的不同。 这会将设置工具恢复为原始行为,获取原始_sysconfig_*文件。在 python3.8 中,此包为链接器标志设置了标志--sysroot=/。因此,pthread的共享库不是在conda库中搜索,而是在似乎不存在正确版本的系统/lib64中搜索,这就解释了为什么此配置会中断。这个_sysconfig_*模块在python3.9年已经更改,并且不再设置--sysroot=/标志。这就是为什么它适用于python3.9.

为了在不破坏构建隔离的情况下解决这个问题,我认为最好的方法是设法在调用构建环境时自动将_PYTHON_SYSCONFIGDATA_NAME(这是查找模块名称的主要来源)设置为指向构建环境中的_CONDA_PYTHON_SYSCONFIGDATA_NAME(指向正确的配置)。这需要使用以下补丁修补pip(在复制器环境中修补 pip 时,这在本地有效):

index daeb7fb..a1c92b4 100644
--- a/pip/_internal/build_env.py
+++ b/pip/_internal/build_env_modified.py
@@ -128,7 +128,8 @@ class BuildEnvironment:
def __enter__(self) -> None:
self._save_env = {
name: os.environ.get(name, None)
-            for name in ("PATH", "PYTHONNOUSERSITE", "PYTHONPATH")
+            for name in ("PATH", "PYTHONNOUSERSITE", "PYTHONPATH",
+                         "_PYTHON_SYSCONFIGDATA_NAME")
}

path = self._bin_dirs[:]
@@ -145,6 +146,8 @@ class BuildEnvironment:
"PYTHONPATH": os.pathsep.join(pythonpath),
}
)
+        if '_PYTHON_SYSCONFIGDATA_NAME' not in os.environ:
+            os.environ['_PYTHON_SYSCONFIGDATA_NAME'] = os.environ['_CONDA_PYTHON_SYSCONFIGDATA_NAME']

def __exit__(
self,

也许这可以传播到conda-forge/pip-feedstock但这似乎不切实际。我没有看到任何方法可以仅使用配置文件或setup.py更改 pip 构建系统中的 env 变量。

最新更新