在 macOS 安装 MAJIQ 时 Clang 不支持 -fopenmp
结论
报错中的 gcc 实际调用的是 Apple Clang,并非 GNU GCC。macOS 自带的 /usr/bin/gcc 是 Clang 的兼容入口。由于 Apple Clang 默认不支持 -fopenmp,MAJIQ 扩展会编译失败:
clang: error: unsupported option '-fopenmp'
error: command 'gcc' failed with exit status 1
可以选择以下任一方案:
- 安装 Homebrew 提供的 GNU GCC,并通过
CC和CXX指定 Python 构建系统使用该编译器。这个方案通常更直接。 - 安装 Homebrew LLVM 和
libomp,再配置编译器及搜索路径。只执行brew install llvm或修改PATH,未必能让pip使用正确的编译器。
Apple Clang、Homebrew LLVM 和 GNU GCC 使用的运行库不要混用。
为什么命令显示 gcc,错误却来自 Clang
先确认当前命令实际指向哪个程序:
which -a gcc g++ clang clang++
gcc --version
g++ --version
xcrun --find gcc
默认的 macOS 环境通常会输出:
Apple clang version ...
因此,日志中的命令即使显示为:
gcc ... -fopenmp
实际执行它的仍是 Apple Clang。命令名为 gcc,并不等于使用了 GNU GCC。
安装 Conda 的 gcc、llvm 或 Homebrew LLVM 后,如果没有设置 CC 和 CXX,setuptools、distutils 或 pip 仍可能调用系统编译器。
方案一:使用 Homebrew GNU GCC
安装 GCC:
brew install gcc
为避免覆盖系统命令,Homebrew 通常会给 GNU GCC 的命令名添加版本号,例如:
gcc-14
g++-14
版本号取决于当前安装的 Homebrew formula,应先查看本机的实际文件:
brew --prefix gcc
ls "$(brew --prefix gcc)/bin/gcc-"*
ls "$(brew --prefix gcc)/bin/g++-"*
如果检查后确认命令为 gcc-14 和 g++-14,请在准备安装 MAJIQ 的同一终端会话中设置:
export CC="$(brew --prefix gcc)/bin/gcc-14"
export CXX="$(brew --prefix gcc)/bin/g++-14"
"$CC" --version
"$CXX" --version
把示例中的 14 换成本机实际版本。输出中应明确包含 GNU GCC 信息,不能出现 Apple clang。
然后创建新的虚拟环境并重新安装:
python3 -m venv env
source env/bin/activate
python -m pip install --upgrade pip setuptools wheel
python -m pip install --upgrade cython numpy GitPython
python -m pip install --no-cache-dir \
'git+https://bitbucket.org/biociphers/majiq_stable.git#egg=majiq'
使用 python -m pip 可以确认 pip 来自当前虚拟环境,避免误用其他 Python 环境中的 pip。
如果 MAJIQ 的构建脚本硬编码了绝对路径 /usr/bin/gcc,设置 CC 不会生效。此时需要检查源码中的 setup.py 或相关构建配置,让它读取 CC、CXX,或者将编译器路径改为实际的 Homebrew GCC 路径。不要替换或覆盖系统的 /usr/bin/gcc。
方案二:使用 Homebrew LLVM 和 libomp
继续使用 Clang 时,需要安装 Homebrew LLVM 和 OpenMP 运行库:
brew install llvm libomp
在当前终端中设置编译器和搜索路径:
export LLVM_PREFIX="$(brew --prefix llvm)"
export OMP_PREFIX="$(brew --prefix libomp)"
export PATH="$LLVM_PREFIX/bin:$PATH"
export CC="$LLVM_PREFIX/bin/clang"
export CXX="$LLVM_PREFIX/bin/clang++"
export CPPFLAGS="-I$OMP_PREFIX/include ${CPPFLAGS:-}"
export LDFLAGS="-L$OMP_PREFIX/lib -Wl,-rpath,$OMP_PREFIX/lib ${LDFLAGS:-}"
确认当前选中的编译器不是 /usr/bin/clang:
"$CC" --version
"$CXX" --version
command -v clang
再运行一个最小的 OpenMP 测试:
cat > /tmp/openmp-test.c <<'EOF'
#include <omp.h>
#include <stdio.h>
int main(void) {
printf("%d\n", omp_get_max_threads());
return 0;
}
EOF
"$CC" -fopenmp /tmp/openmp-test.c -o /tmp/openmp-test
/tmp/openmp-test
测试成功后,再安装 MAJIQ:
python3 -m venv env
source env/bin/activate
python -m pip install --upgrade pip setuptools wheel
python -m pip install --upgrade cython numpy GitPython
python -m pip install --no-cache-dir \
'git+https://bitbucket.org/biociphers/majiq_stable.git#egg=majiq'
旧资料中经常使用下面的参数绕过 Apple Clang 对 OpenMP 的限制:
-Xpreprocessor -fopenmp
这种写法适用于部分可以自行控制编译参数的项目。MAJIQ 的构建脚本已经直接添加了 -fopenmp。如果脚本无法分别设置编译参数和链接参数,这种处理方式并不稳妥,建议使用 Homebrew LLVM 或 GNU GCC。
正确配置 HTSlib
HTSlib 和 OpenMP 是两个独立的依赖。解决编译器问题后,如果 HTSlib 不在构建系统的默认搜索路径中,还需要设置:
brew install htslib
export HTSLIB_LIBRARY_DIR="$(brew --prefix htslib)/lib"
export HTSLIB_INCLUDE_DIR="$(brew --prefix htslib)/include"
可以用以下命令检查目录:
test -d "$HTSLIB_LIBRARY_DIR" && echo "HTSlib library directory found"
test -d "$HTSLIB_INCLUDE_DIR" && echo "HTSlib include directory found"
Apple Silicon 上的 Homebrew 默认前缀通常是 /opt/homebrew,Intel Mac 常见的是 /usr/local。使用 brew --prefix 获取路径比直接写死前缀更可靠。
原有配置为什么没有生效
下面的配置只添加了库文件和头文件的搜索路径:
export LDFLAGS="-L/usr/local/opt/llvm/lib"
export CPPFLAGS="-I/usr/local/opt/llvm/include"
它没有指定 Python 构建系统应该调用哪个编译器。如果 CC 仍指向系统 gcc,实际执行的依然是 Apple Clang。
原命令还先为 LDFLAGS 设置了 -Wl,-rpath,随后又执行:
export LDFLAGS="-L/usr/local/opt/llvm/lib"
后一次赋值会覆盖前一次赋值,导致 rpath 参数丢失。
当前 macOS 的默认 shell 通常是 zsh。写入 ~/.bash_profile 的配置不会被 zsh 会话自动读取。临时配置可以直接在当前终端执行。需要长期保存时,可根据实际使用的 shell 写入 ~/.zshrc,然后重新打开终端,或运行:
source ~/.zshrc
hash -r
安装前的最终检查
使用 GNU GCC 时,检查以下内容:
echo "$CC"
echo "$CXX"
"$CC" --version
"$CXX" --version
python -m pip --version
使用 Homebrew LLVM 时,还要再次测试 OpenMP:
"$CC" -fopenmp /tmp/openmp-test.c -o /tmp/openmp-test
/tmp/openmp-test
如果安装日志中仍然出现:
Apple clang version ...
或者编译命令仍由 /usr/bin/gcc 执行,说明环境变量没有传递到运行 pip 的终端,或构建脚本覆盖了编译器设置。
日志中的 NumPy deprecated API 信息只是警告,不会直接导致本次安装失败。退出状态为 1 是因为 Apple Clang 拒绝了 -fopenmp。
还要避免使用 sudo pip,也不要以 root 身份创建虚拟环境。示例日志中的路径位于 /private/var/root/env,说明当时很可能是在 root 环境中安装。使用普通用户的虚拟环境,更容易让 Homebrew、Python、编译器和依赖库保持一致的架构与路径。
备注:内容仅供参考。
