Skip to content

Commit

Permalink
build: Remove build host Python from cross compiled environment
Browse files Browse the repository at this point in the history
When installing a Python program with a shebang the shebang points to the native Python.
Because the virtualenv builder symlinks packages to their original path, it means that we retain references to the native Python, bringing it into the runtime closure of a cross compiled application.

By rewriting the shebang to the _target host_ Python at install time we can avoid references to the _build host_ Python in the runtime closure.
  • Loading branch information
adisbladis committed Nov 25, 2024
1 parent 4b74b01 commit c1a70b2
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 3 deletions.
28 changes: 25 additions & 3 deletions build/hooks/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ let

pythonInterpreter =
if stdenv.buildPlatform != stdenv.hostPlatform then
"${crossPython}/bin/python"
"${crossPython}/bin/${baseNameOf pythonOnBuildForHost.interpreter}"
else
pythonOnBuildForHost.interpreter;

Expand Down Expand Up @@ -126,6 +126,26 @@ in
} ./pyproject-output-setup-hook.sh
) { };

/*
Rewrite shebangs for cross compiled Python programs.
When cross compiling & installing a Python program the shebang gets written
for the install-time Pythhon, which for cross compilation is for the _build host_.
This hook rewrites any shebangs pointing to the build host Python to the target host Python.
*/
pyprojectCrossShebangHook = callPackage (
_:
makeSetupHook {
name = "pyproject-cross-shebang-hook";
substitutions = {
script = ./patch-cross-shebangs.py;
inherit pythonInterpreter;
hostInterpreter = python.interpreter;
};
} ./pyproject-cross-shebang-hook.sh
) { };

/*
Create a virtual environment from buildInputs
Expand All @@ -136,7 +156,8 @@ in
makeSetupHook {
name = "pyproject-make-venv-hook";
substitutions = {
inherit pythonInterpreter python;
pythonInterpreter = python.interpreter;
inherit python;
makeVenvScript = ./make-venv.py;
};
} ./pyproject-make-venv-hook.sh
Expand All @@ -156,6 +177,7 @@ in
pyprojectBuildHook,
pyprojectInstallHook,
pyprojectOutputSetupHook,
pyprojectCrossShebangHook,
python,
}:
makeSetupHook {
Expand All @@ -167,7 +189,7 @@ in
pyprojectBuildHook
pyprojectInstallHook
pyprojectOutputSetupHook
];
] ++ lib.optional (stdenv.buildPlatform != stdenv.hostPlatform) pyprojectCrossShebangHook;
} ./meta-hook.sh
)
{
Expand Down
41 changes: 41 additions & 0 deletions build/hooks/patch-cross-shebangs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env python
import os
import os.path
import sys
from pathlib import Path
from typing import Optional


def main():
# Output directory
out_dir = Path(os.environ["out"])
bin_dir = out_dir.joinpath("bin")

# Cross python interpreter
cross_bin = os.path.dirname(sys.executable)
cross_shebang = f"#!{cross_bin}".encode()

# Target host interpreter
host_bin = os.path.dirname(sys.argv[1])
host_shebang = f"#!{host_bin}".encode()

if not bin_dir.exists():
return

for bin in bin_dir.iterdir():
script: Optional[bytes] = None

with bin.open(mode="rb") as fd:
preamble = fd.read(len(cross_shebang))
if preamble == cross_shebang:
script = host_shebang + fd.read()

if script:
print(f"Rewriting shebang for '{bin}'")

with bin.open(mode="wb") as fd:
fd.write(script)


if __name__ == "__main__":
main()
7 changes: 7 additions & 0 deletions build/hooks/pyproject-cross-shebang-hook.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pyprojectCrossShebangHook() {
@pythonInterpreter@ @script@ @hostInterpreter@
}

if [ -z "${dontUsePyprojectCrossShebangHook-}" ]; then
preFixupPhases+=" pyprojectCrossShebangHook"
fi
1 change: 1 addition & 0 deletions build/packages.nix
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ let
pyprojectInstallHook
pyprojectBytecodeHook
pyprojectOutputSetupHook
pyprojectCrossShebangHook
pyprojectMakeVenvHook
pyprojectHook
pyprojectWheelHook
Expand Down

0 comments on commit c1a70b2

Please sign in to comment.