mirror of https://github.com/pyodide/pyodide.git
Fix pywasmcross when pyodide_build is installed out of tree (#2824)
Symlinking cc to pywasmcross.py only works if pywasmcross.py has execute permissions. When we install the package with pip, it will not set execute permissions on pywasmcross.py. It does set execute flags on entrypoints. Thus, define an entrypoint called _pywasmcross which calls pywasmcross.main. If a script called _pywasmcross exists, we are using an out-of-tree install so symlink cc to _pywasmcross. Otherwise, we should be in tree and pywasmcross.py should have the execute flag set, so symlink cc to pywasmcross.py. On the other side, if __main__.__file__ is in a folder named pyodide_build or bin we are being invoked normally, otherwise we are being invoked via a symlink.
This commit is contained in:
parent
e7ad0ce944
commit
b0a28579bf
|
@ -12,33 +12,45 @@ import json
|
|||
import os
|
||||
import sys
|
||||
from pathlib import Path, PurePosixPath
|
||||
from typing import Any
|
||||
|
||||
IS_MAIN = __name__ == "__main__"
|
||||
if IS_MAIN:
|
||||
from __main__ import __file__ as INVOKED_PATH_STR
|
||||
|
||||
INVOKED_PATH = Path(INVOKED_PATH_STR)
|
||||
|
||||
SYMLINKS = {"cc", "c++", "ld", "ar", "gcc", "gfortran", "cargo"}
|
||||
IS_COMPILER_INVOCATION = INVOKED_PATH.name in SYMLINKS
|
||||
|
||||
if IS_COMPILER_INVOCATION:
|
||||
# If possible load from environment variable, if necessary load from disk.
|
||||
if "PYWASMCROSS_ARGS" in os.environ:
|
||||
PYWASMCROSS_ARGS = json.loads(os.environ["PYWASMCROSS_ARGS"])
|
||||
else:
|
||||
with open(Path(__file__).parent / "pywasmcross_env.json") as f:
|
||||
try:
|
||||
with open(INVOKED_PATH.parent / "pywasmcross_env.json") as f:
|
||||
PYWASMCROSS_ARGS = json.load(f)
|
||||
except FileNotFoundError:
|
||||
raise RuntimeError(
|
||||
"Invalid invocation: can't find PYWASMCROSS_ARGS."
|
||||
f" Invoked from {INVOKED_PATH}."
|
||||
)
|
||||
|
||||
# restore __name__ so that relative imports work as we expect
|
||||
__name__ = PYWASMCROSS_ARGS.pop("orig__name__")
|
||||
sys.path = PYWASMCROSS_ARGS.pop("PYTHONPATH")
|
||||
os.environ["PATH"] = PYWASMCROSS_ARGS.pop("PATH")
|
||||
# restore __name__ so that relative imports work as we expect
|
||||
__name__ = PYWASMCROSS_ARGS.pop("orig__name__")
|
||||
|
||||
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
from collections import namedtuple
|
||||
from contextlib import contextmanager
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import Any, Iterator, Literal, MutableMapping, NoReturn
|
||||
from typing import Iterator, Literal, MutableMapping, NoReturn
|
||||
|
||||
from pyodide_build import common
|
||||
from pyodide_build._f2c_fixes import fix_f2c_input, fix_f2c_output, scipy_fixes
|
||||
|
||||
symlinks = {"cc", "c++", "ld", "ar", "gcc", "gfortran", "cargo"}
|
||||
|
||||
|
||||
def symlink_dir() -> Path:
|
||||
return Path(common.get_make_flag("TOOLSDIR")) / "symlinks"
|
||||
|
@ -68,13 +80,17 @@ def make_command_wrapper_symlinks(
|
|||
exist.
|
||||
"""
|
||||
exec_path = Path(__file__).resolve()
|
||||
for symlink in symlinks:
|
||||
for symlink in SYMLINKS:
|
||||
symlink_path = symlink_dir / symlink
|
||||
if os.path.lexists(symlink_path) and not symlink_path.exists():
|
||||
# remove broken symlink so it can be re-created
|
||||
symlink_path.unlink()
|
||||
try:
|
||||
symlink_path.symlink_to(exec_path)
|
||||
pywasmcross_exe = shutil.which("_pywasmcross")
|
||||
if pywasmcross_exe:
|
||||
symlink_path.symlink_to(pywasmcross_exe)
|
||||
else:
|
||||
symlink_path.symlink_to(exec_path)
|
||||
except FileExistsError:
|
||||
pass
|
||||
if symlink == "c++":
|
||||
|
@ -609,13 +625,13 @@ def environment_substitute_args(
|
|||
return subbed_args
|
||||
|
||||
|
||||
if IS_MAIN:
|
||||
REPLAY_ARGS = ReplayArgs(**PYWASMCROSS_ARGS)
|
||||
|
||||
def compiler_main():
|
||||
replay_args = ReplayArgs(**PYWASMCROSS_ARGS)
|
||||
basename = Path(sys.argv[0]).name
|
||||
args = list(sys.argv)
|
||||
args[0] = basename
|
||||
if basename in symlinks:
|
||||
sys.exit(handle_command(args, REPLAY_ARGS))
|
||||
else:
|
||||
raise Exception(f"Unexpected invocation '{basename}'")
|
||||
sys.exit(handle_command(args, replay_args))
|
||||
|
||||
|
||||
if IS_COMPILER_INVOCATION:
|
||||
compiler_main()
|
||||
|
|
|
@ -2,4 +2,10 @@
|
|||
import setuptools
|
||||
|
||||
if __name__ == "__main__":
|
||||
setuptools.setup()
|
||||
setuptools.setup(
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
"_pywasmcross = pyodide_build.pywasmcross:compiler_main",
|
||||
]
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue