Merge pull request #807 from jbarlow83/pr-auditwheel-diag

Improve diagnostics when auditwheel repair fails
This commit is contained in:
Joe Rickerby
2021-08-28 15:02:59 +01:00
committed by GitHub
2 changed files with 61 additions and 17 deletions
+20 -4
View File
@@ -306,18 +306,27 @@ def build(options: BuildOptions) -> None:
log.step_end_with_error( log.step_end_with_error(
f"Command {error.cmd} failed with code {error.returncode}. {error.stdout}" f"Command {error.cmd} failed with code {error.returncode}. {error.stdout}"
) )
troubleshoot(options.package_dir, error) troubleshoot(options, error)
sys.exit(1) sys.exit(1)
def troubleshoot(package_dir: Path, error: Exception) -> None: def _matches_prepared_command(error_cmd: List[str], command_template: str) -> bool:
if len(error_cmd) < 3 or error_cmd[0:2] != ["sh", "-c"]:
return False
command_prefix = command_template.split("{", maxsplit=1)[0].strip()
return error_cmd[2].startswith(command_prefix)
def troubleshoot(options: BuildOptions, error: Exception) -> None:
if isinstance(error, subprocess.CalledProcessError) and ( if isinstance(error, subprocess.CalledProcessError) and (
error.cmd[0:4] == ["python", "-m", "pip", "wheel"] error.cmd[0:4] == ["python", "-m", "pip", "wheel"]
or error.cmd[0:3] == ["python", "-m", "build"] or error.cmd[0:3] == ["python", "-m", "build"]
or _matches_prepared_command(error.cmd, options.repair_command)
): ):
# the wheel build step failed # the wheel build step failed
print("Checking for common errors...") print("Checking for common errors...")
so_files = list(package_dir.glob("**/*.so")) so_files = list(options.package_dir.glob("**/*.so"))
if so_files: if so_files:
print( print(
@@ -326,10 +335,17 @@ def troubleshoot(package_dir: Path, error: Exception) -> None:
NOTE: Shared object (.so) files found in this project. NOTE: Shared object (.so) files found in this project.
These files might be built against the wrong OS, causing problems with These files might be built against the wrong OS, causing problems with
auditwheel. auditwheel. If possible, run cibuildwheel in a clean checkout.
If you're using Cython and have previously done an in-place build, If you're using Cython and have previously done an in-place build,
remove those build files (*.so and *.c) before starting cibuildwheel. remove those build files (*.so and *.c) before starting cibuildwheel.
setuptools uses the build/ folder to store its build cache. It
may be necessary to remove those build files (*.so and *.o) before
starting cibuildwheel.
Files that belong to a virtual environment are probably not an issue
unless you used a custom command telling cibuildwheel to activate it.
""" """
), ),
file=sys.stderr, file=sys.stderr,
+41 -13
View File
@@ -3,25 +3,23 @@ import subprocess
import pytest import pytest
from . import utils from . import utils
from .test_projects import TestProject from .test_projects import TestProject, new_c_project
so_file_project = TestProject() SO_FILE_WARNING = "NOTE: Shared object (.so) files found in this project."
so_file_project.files["libnothing.so"] = ""
so_file_project.files[
"setup.py"
] = """
raise Exception('this build will fail')
"""
def test_failed_project_with_so_files(tmp_path, capfd, build_frontend_env): @pytest.mark.parametrize("project_contains_so_files", [False, True])
def test_failed_build_with_so_files(tmp_path, capfd, build_frontend_env, project_contains_so_files):
project = TestProject()
project.files["setup.py"] = "raise Exception('this build will fail')\n"
if project_contains_so_files:
project.files["libnothing.so"] = ""
if utils.platform != "linux": if utils.platform != "linux":
pytest.skip("this test is only relevant to the linux build") pytest.skip("this test is only relevant to the linux build")
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
so_file_project.generate(project_dir) project.generate(project_dir)
with pytest.raises(subprocess.CalledProcessError): with pytest.raises(subprocess.CalledProcessError):
utils.cibuildwheel_run(project_dir, add_env=build_frontend_env) utils.cibuildwheel_run(project_dir, add_env=build_frontend_env)
@@ -29,4 +27,34 @@ def test_failed_project_with_so_files(tmp_path, capfd, build_frontend_env):
captured = capfd.readouterr() captured = capfd.readouterr()
print("out", captured.out) print("out", captured.out)
print("err", captured.err) print("err", captured.err)
assert "NOTE: Shared object (.so) files found in this project." in captured.err
if project_contains_so_files:
assert SO_FILE_WARNING in captured.err
else:
assert SO_FILE_WARNING not in captured.err
@pytest.mark.parametrize("project_contains_so_files", [False, True])
def test_failed_repair_with_so_files(tmp_path, capfd, project_contains_so_files):
if utils.platform != "linux":
pytest.skip("this test is only relevant to the linux build")
project = new_c_project()
if project_contains_so_files:
project.files["libnothing.so"] = ""
project_dir = tmp_path / "project"
project.generate(project_dir)
with pytest.raises(subprocess.CalledProcessError):
utils.cibuildwheel_run(project_dir, add_env={"CIBW_REPAIR_WHEEL_COMMAND": "false"})
captured = capfd.readouterr()
print("out", captured.out)
print("err", captured.err)
if project_contains_so_files:
assert SO_FILE_WARNING in captured.err
else:
assert SO_FILE_WARNING not in captured.err