一、问题描述:
Building wheels for collected packages: BoltzTrap2
  Building wheel for BoltzTrap2 (pyproject.toml) ... error
  error: subprocess-exited-with-error
  
  × Building wheel for BoltzTrap2 (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [146 lines of output]

---------------------------------------------------------------------------------

ubprocess.CalledProcessError: Command '['cmake', '-DCMAKE_POSITION_INDEPENDENT_CODE=ON', '-S', '.', '-B', '/tmp/pip-install-o4gg3anl/boltztrap2_a30a66816ca441df901f02689827407c/external/spglib-1.9.9/build-0d7iot62']' returned non-zero exit status 1.
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for BoltzTrap2
Failed to build BoltzTrap2
ERROR: Failed to build installable wheels for some 
二、原因分析(使用豆包深度思考):
1、主要原因(个人认为)并且 setup.py 中确实没有支持 --cmake 选项。

2、次要原因(没有排除)当前使用的 cmake 是 Conda 环境中的,而非期望的 /path(你自己的cmake安装路径,我是离线安装的)/bin/cmake 。【我自己的路径/home/LY/cmake/bin/cmake】

三、解决方法(豆包提供):
1、下载离线包
git clone https://github.com/boltztrap/boltztrap2.git
cd boltztrap2
2、安装好cmake 并添加路径(路径靠前)
3、修改 setup.py 以支持自定义 cmake 路径、在 setup.py 里添加对 --cmake 选项的支持,具体操作是在 BuildSPGlibCommand 类中添加该选项,同时在 run 方法里使用这个选项。
修好后的完整代码:
from __future__ import print_function

import contextlib
import os
import platform
import shutil
import subprocess
import tempfile
from os import PathLike

import numpy as np
from Cython.Build import cythonize
from setuptools import Command, Extension, setup
from setuptools.command.build_ext import build_ext as DefaultBuildExtCommand
# Set this to True to regenerate BoltzTraP2/sphere/frontend.cpp from its
# Cython sources as part of the build process.
USE_CYTHON: bool = True

# Extra header and library dirs for compiling the C and C++ source files.
INCLUDE_DIRS: list[PathLike] = []
LIBRARY_DIRS: list[PathLike] = []

EIGEN_DIR: PathLike = os.path.abspath(
    os.path.join(
        os.path.dirname(__file__), "external", "eigen-eigen-3215c06819b9"
    )
)


@contextlib.contextmanager
def dir_context(dn):
    """Create a context with a given directory as the CWD."""
    # Sabe the original CWD.
    original = os.getcwd()
    try:
        # Change to the new directory and return control.
        os.chdir(dn)
        yield
    finally:
        # Change back to the original directory.
        os.chdir(original)


class CleanSPGlibCommand(Command):
    """Custom command used to clean the spglib directory."""

    description = "remove libsymspg.a and all old spglib build directores"
    user_options = []

    def initialize_options(self):
        """Do nothing."""

    def finalize_options(self):
        """Do nothing."""

    def run(self):
        """Remove libsymspg.a and all spglib build directores."""
        self.announce("About to remove libsymspg.a", level=1)
        try:
            os.remove(BuildSPGlibCommand.static_library)
        except FileNotFoundError:
            self.announce("libsymspg.a did not exist", level=1)
        self.announce(
            "About to remove all old spglib build directories", level=1
        )
        import glob
        with dir_context(BuildSPGlibCommand.base_dir):
            build_dirs = [i for i in glob.glob("build-*") if os.path.isdir(i)]
            for d in build_dirs:
                shutil.rmtree(d, ignore_errors=True)


class BuildSPGlibCommand(Command):
    """Custom command used to compile a local static copy of spglib."""

    base_dir = os.path.abspath(
        os.path.join(os.path.dirname(__file__), "external", "spglib-1.9.9")
    )
    header_dir = os.path.join(base_dir, "src")
    if platform.system() == "Windows":
        static_library_basename = "symspg.lib"
        static_library_trailing = os.path.join(
            "Release", static_library_basename
        )
    else:
        static_library_basename = "libsymspg.a"
        static_library_trailing = static_library_basename
    static_library = os.path.join(base_dir, static_library_basename)

    user_options = [
        ('cmake=', None, 'Path to CMake executable'),
    ]

    def initialize_options(self):
        self.cmake = None

    def finalize_options(self):
        pass

    def run(self):
        """Run cmake with the right options, and then run make."""
        if os.path.isfile(self.static_library):
            self.announce("the static library exists, no need to rebuild it")
            return
        self.announce(
            "About to create a new build directory for spglib", level=1
        )
        build_dir = tempfile.mkdtemp(
            prefix="build-", dir=BuildSPGlibCommand.base_dir
        )
        self.announce("About to run 'cmake' for spglib", level=1)
        cmake_executable = self.cmake if self.cmake else "cmake"
        with dir_context(BuildSPGlibCommand.base_dir):
            subprocess.check_call(
                [
                    cmake_executable,
                    "-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
                    "-S",
                    ".",
                    "-B",
                    build_dir,
                ]
            )
        self.announce("About to build spglib", level=1)
        with dir_context(BuildSPGlibCommand.base_dir):
            tokens = [cmake_executable, "--build", build_dir]
            if platform.system() == "Windows":
                tokens += ["--config", "Release"]
            subprocess.check_call(tokens)
            shutil.copy2(
                os.path.join(
                    build_dir, BuildSPGlibCommand.static_library_trailing
                ),
                BuildSPGlibCommand.base_dir,
            )
        self.announce("About to remove the spglib build directory", level=1)
        shutil.rmtree(build_dir)


class BuildExtCommand(DefaultBuildExtCommand):
    """Custom build_ext command that will build spglib first."""

    system_specific_flags = {
        "Darwin": ["-std=c++11", "-stdlib=libc++"],
        "Linux": ["-std=c++11"],
        "Windows": ["/std:c++14"],
    }

    def build_extensions(self):
        self.announce("About to test compiler flags")
        # only add flags which pass the flag_filter
        try:
            opts = BuildExtCommand.system_specific_flags[platform.system()]
        except KeyError:
            opts = []
        for ext in self.extensions:
            ext.extra_compile_args = opts
        super().build_extensions()

    def run(self):
        """Run build_spglib and then delegate on the normal build_ext."""
        self.run_command("build_spglib")
        super().run()


extensions = [
    Extension(
        name="BoltzTraP2.sphere.frontend",
        sources=[
            "BoltzTraP2/sphere/frontend." + ("pyx" if USE_CYTHON else "cpp"),
            "BoltzTraP2/sphere/backend.cpp",
        ],
        language="c++",
        include_dirs=INCLUDE_DIRS
        + [np.get_include(), BuildSPGlibCommand.header_dir, EIGEN_DIR],
        library_dirs=LIBRARY_DIRS,
        runtime_library_dirs=LIBRARY_DIRS,
        extra_objects=[BuildSPGlibCommand.static_library],
    )
]

setup(
    ext_modules=cythonize(extensions) if USE_CYTHON else extensions,
    cmdclass={
        "build_ext": BuildExtCommand,
        "build_spglib": BuildSPGlibCommand,
        "clean_spglib": CleanSPGlibCommand,
    },
)
4、在终端中临时修改 PATH 变量,让系统优先使用你指定的 cmake:export PATH="/path(你自己的cmake安装路径,我是离线安装的)/bin:$PATH"
5、运行以下命令重新编译安装:
python setup.py build_spglib --cmake=/path(你自己的cmake安装路径,我是离线安装的)/bin/cmake
python setup.py build_ext
pip install .

四、安装结果:

Successfully installed BoltzTraP2-25.3.1 ase-3.24.0 certifi-2025.1.31 cftime-1.6.4.post1 contourpy-1.3.0 cycler-0.12.1 fonttools-4.56.0 importlib-resources-6.5.2 kiwisolver-1.4.7 matplotlib-3.9.4 netCDF4-1.7.2 packaging-24.2 pillow-11.1.0 pyparsing-3.2.3 python-dateutil-2.9.0.post0 scipy-1.13.1 six-1.17.0 spglib-2.6.0 typing-extensions-4.13.0 zipp-3.21.0
五、声明

这是我个人的一个解决经历,仅做参考。系统乌班图18.04,python3.9

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐