Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `pyodide config` exposes new variables: `pyodide_root`, `pyodide_abi_version`, and `python_include_dir`
[#186](https://github.com/pyodide/pyodide-build/pull/186)
- `pyodide config` exposes new variables: `pyodide_root`, `pyodide_abi_version`, and `python_include_dir`,
and `ignored_build_requirements`.
[#186](https://github.com/pyodide/pyodide-build/pull/186) and [#187](https://github.com/pyodide/pyodide-build/pull/187)

## [0.30.0] - 2025/04/08

Expand Down
11 changes: 10 additions & 1 deletion pyodide_build/build_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

from pyodide_build import __version__
from pyodide_build.common import default_xbuildenv_path, search_pyproject_toml, to_bool
from pyodide_build.config import ConfigManager, CrossBuildEnvConfigManager

RUST_BUILD_PRELUDE = """
rustup default ${RUST_TOOLCHAIN}
Expand Down Expand Up @@ -123,11 +122,20 @@ def in_xbuildenv() -> bool:
return pyodide_root.name == "pyodide-root"


def _load_config_manager():
"""Lazily load ConfigManager so that we can avoid circular imports."""
from pyodide_build.config import ConfigManager, CrossBuildEnvConfigManager

return ConfigManager, CrossBuildEnvConfigManager


@functools.cache
def get_build_environment_vars(pyodide_root: Path) -> dict[str, str]:
"""
Get common environment variables for the in-tree and out-of-tree build.
"""
_, CrossBuildEnvConfigManager = _load_config_manager()

config_manager = CrossBuildEnvConfigManager(pyodide_root)
env = config_manager.to_env()

Expand All @@ -147,6 +155,7 @@ def get_build_environment_vars(pyodide_root: Path) -> dict[str, str]:

@functools.cache
def get_host_build_environment_vars() -> dict[str, str]:
ConfigManager, _ = _load_config_manager()
manager = ConfigManager()
return manager.to_env()

Expand Down
2 changes: 1 addition & 1 deletion pyodide_build/cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def list_config():
configs = _get_configs()

for k, v in configs.items():
typer.echo(f"{k}={v}")
typer.echo(f'{k}="{v}"')


@app.command("get")
Expand Down
6 changes: 6 additions & 0 deletions pyodide_build/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
exit_with_stdio,
search_pyproject_toml,
)
from pyodide_build.constants import BASE_IGNORED_REQUIREMENTS
from pyodide_build.logger import logger


Expand Down Expand Up @@ -199,6 +200,7 @@ def _get_make_environment_vars(self) -> Mapping[str, str]:
"build_dependency_index_url": "BUILD_DEPENDENCY_INDEX_URL",
"default_cross_build_env_url": "DEFAULT_CROSS_BUILD_ENV_URL",
"xbuildenv_path": "PYODIDE_XBUILDENV_PATH",
"ignored_build_requirements": "IGNORED_BUILD_REQUIREMENTS",
# maintainer only
"_f2c_fixes_wrapper": "_F2C_FIXES_WRAPPER",
}
Expand All @@ -218,6 +220,7 @@ def _get_make_environment_vars(self) -> Mapping[str, str]:
"build_dependency_index_url",
"default_cross_build_env_url",
"xbuildenv_path",
"ignored_build_requirements",
# maintainer only
"_f2c_fixes_wrapper",
}
Expand All @@ -240,6 +243,8 @@ def _get_make_environment_vars(self) -> Mapping[str, str]:
"build_dependency_index_url": "https://pypi.anaconda.org/pyodide/simple",
"default_cross_build_env_url": "",
"xbuildenv_path": "",
# A list of PEP508 build-time requirements to be ignored when building a wheel
"ignored_build_requirements": " ".join(BASE_IGNORED_REQUIREMENTS),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(no action requird for this PR)

It would be great if we could support List types here. The question is how to support the list type in an env variable.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree – I faced this problem when implementing it. I feel there is no neat option to do it in this case, as cibuildwheel also largely suffers from the same limitation.

# maintainer only
"_f2c_fixes_wrapper": "",
}
Expand Down Expand Up @@ -279,4 +284,5 @@ def _get_make_environment_vars(self) -> Mapping[str, str]:
"pyodide_abi_version": "PYODIDE_ABI_VERSION",
"pyodide_root": "PYODIDE_ROOT",
"python_include_dir": "PYTHONINCLUDE",
"ignored_build_requirements": "IGNORED_BUILD_REQUIREMENTS",
}
8 changes: 8 additions & 0 deletions pyodide_build/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Some reusable constants that are used at various sources in our code.
# TODO: collect and add more constants here.

BASE_IGNORED_REQUIREMENTS: list[str] = [
# mesonpy installs patchelf in linux platform but we don't want it.
"patchelf",
"oldest-supported-numpy",
]
16 changes: 8 additions & 8 deletions pyodide_build/pypabuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from pyodide_build import _f2c_fixes, common, pywasmcross, uv_helper
from pyodide_build.build_env import (
get_build_flag,
get_host_build_flag,
get_hostsitepackages,
get_pyversion,
get_unisolated_packages,
Expand All @@ -31,12 +32,6 @@
_ProjectBuilder,
)

AVOIDED_REQUIREMENTS = [
# mesonpy installs patchelf in linux platform but we don't want it.
"patchelf",
"oldest-supported-numpy",
]

# corresponding env variables for symlinks
SYMLINK_ENV_VARS = {
"cc": "CC",
Expand Down Expand Up @@ -97,6 +92,8 @@ def _runner(cmd, cwd=None, extra_environ=None):


def symlink_unisolated_packages(env: DefaultIsolatedEnv) -> None:
from pyodide_build.build_env import get_build_flag, get_unisolated_packages

pyversion = get_pyversion()
site_packages_path = f"lib/{pyversion}/site-packages"
env_site_packages = Path(env.path) / site_packages_path
Expand Down Expand Up @@ -131,14 +128,17 @@ def remove_avoided_requirements(
def install_reqs(
build_env: Mapping[str, str], env: DefaultIsolatedEnv, reqs: set[str]
) -> None:
IGNORED_BUILD_REQUIREMENTS = [
pkg.strip() for pkg in get_host_build_flag("IGNORED_BUILD_REQUIREMENTS").split()
]
# propagate PIP config from build_env to current environment
with common.replace_env(
os.environ | {k: v for k, v in build_env.items() if k.startswith("PIP")}
):
env.install(
remove_avoided_requirements(
reqs,
get_unisolated_packages() + AVOIDED_REQUIREMENTS,
get_unisolated_packages() + IGNORED_BUILD_REQUIREMENTS,
)
)

Expand Down Expand Up @@ -256,7 +256,6 @@ def make_command_wrapper_symlinks(symlink_dir: Path) -> dict[str, str]:
-------
The dictionary of compiler environment variables that points to the symlinks.
"""

# For maintainers:
# - you can set "_f2c_fixes_wrapper" variable in pyproject.toml
# in order to change the script to use when cross-compiling
Expand Down Expand Up @@ -315,6 +314,7 @@ def get_build_env(
Returns a dict of environment variables that should be used when building
a package with pypa/build.
"""
from pyodide_build.build_env import get_build_flag

kwargs = {
"pkgname": pkgname,
Expand Down
6 changes: 6 additions & 0 deletions pyodide_build/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def test_load_config_from_file(self, tmp_path, reset_env_vars, reset_cache):
default_cross_build_env_url = "https://example.com/cross_build_env.tar.gz"
skip_emscripten_version_check = "1"
xbuildenv_path = "my_custom/xbuildenv_path"
ignored_build_requirements = "cmake foo bar"
""")

config_manager = ConfigManager()
Expand All @@ -54,6 +55,7 @@ def test_load_config_from_file(self, tmp_path, reset_env_vars, reset_cache):
)
assert config["skip_emscripten_version_check"] == "1"
assert config["xbuildenv_path"] == "my_custom/xbuildenv_path"
assert config["ignored_build_requirements"] == "cmake foo bar"


class TestCrossBuildEnvConfigManager_OutOfTree:
Expand Down Expand Up @@ -126,12 +128,14 @@ def test_load_config_from_env(self, dummy_xbuildenv, reset_env_vars, reset_cache
"CMAKE_TOOLCHAIN_FILE": "/path/to/toolchain",
"MESON_CROSS_FILE": "/path/to/crossfile",
"PYODIDE_XBUILDENV_PATH": "/path/to/xbuildenv",
"IGNORED_BUILD_REQUIREMENTS": "cmake foo bar",
}

config = config_manager._load_config_from_env(env)
assert config["cmake_toolchain_file"] == "/path/to/toolchain"
assert config["meson_cross_file"] == "/path/to/crossfile"
assert config["xbuildenv_path"] == "/path/to/xbuildenv"
assert config["ignored_build_requirements"] == "cmake foo bar"

def test_load_config_from_file(
self, tmp_path, dummy_xbuildenv, reset_env_vars, reset_cache
Expand All @@ -151,6 +155,7 @@ def test_load_config_from_file(
meson_cross_file = "$(MESON_CROSS_FILE)"
build_dependency_index_url = "https://example.com/simple"
xbuildenv_path = "../my_custom/xbuildenv_path" # also helps check relative paths
ignored_build_requirements = "cmake foo bar"
""")

xbuildenv_manager = CrossBuildEnvManager(
Expand All @@ -169,6 +174,7 @@ def test_load_config_from_file(
assert config["meson_cross_file"] == "/path/to/crossfile"
assert config["build_dependency_index_url"] == "https://example.com/simple"
assert config["xbuildenv_path"] == "../my_custom/xbuildenv_path"
assert config["ignored_build_requirements"] == "cmake foo bar"

def test_config_all(self, dummy_xbuildenv, reset_env_vars, reset_cache):
xbuildenv_manager = CrossBuildEnvManager(
Expand Down
5 changes: 3 additions & 2 deletions pyodide_build/tests/test_pypabuild.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pyodide_build import pypabuild, pywasmcross
from pyodide_build.constants import BASE_IGNORED_REQUIREMENTS


class MockIsolatedEnv:
Expand Down Expand Up @@ -27,8 +28,8 @@ def test_install_reqs(tmp_path, dummy_xbuildenv):
for req in reqs:
assert req in env.installed

pypabuild.install_reqs({}, env, set(pypabuild.AVOIDED_REQUIREMENTS)) # type: ignore[arg-type]
for req in pypabuild.AVOIDED_REQUIREMENTS:
pypabuild.install_reqs({}, env, set(BASE_IGNORED_REQUIREMENTS)) # type: ignore[arg-type]
for req in BASE_IGNORED_REQUIREMENTS:
assert req not in env.installed


Expand Down