pyodide-build 0.26.0.dev0__tar.gz → 0.26.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. pyodide_build-0.26.2/.gitignore +43 -0
  2. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/PKG-INFO +24 -26
  3. pyodide_build-0.26.2/pyodide_build/__init__.py +1 -0
  4. pyodide_build-0.26.2/pyodide_build/_f2c_fixes.py +198 -0
  5. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/_py_compile.py +4 -3
  6. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/bash_runner.py +1 -1
  7. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/build_env.py +37 -134
  8. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/buildall.py +14 -16
  9. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/buildpkg.py +37 -22
  10. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/cli/build.py +1 -0
  11. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/cli/build_recipes.py +7 -7
  12. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/cli/config.py +2 -2
  13. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/cli/create_zipfile.py +18 -0
  14. pyodide_build-0.26.2/pyodide_build/cli/xbuildenv.py +152 -0
  15. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/common.py +61 -4
  16. pyodide_build-0.26.2/pyodide_build/config.py +218 -0
  17. pyodide-build-0.26.0.dev0/pyodide_build/create_pypa_index.py → pyodide_build-0.26.2/pyodide_build/create_package_index.py +7 -7
  18. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/io.py +48 -61
  19. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/out_of_tree/build.py +5 -1
  20. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/out_of_tree/venv.py +26 -4
  21. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/pypabuild.py +11 -6
  22. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/pywasmcross.py +11 -2
  23. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/pyzip.py +14 -38
  24. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/recipe.py +5 -5
  25. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/vendor/_pypabuild.py +9 -0
  26. pyodide_build-0.26.2/pyodide_build/xbuildenv.py +345 -0
  27. pyodide_build-0.26.2/pyodide_build/xbuildenv_releases.py +159 -0
  28. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyproject.toml +16 -25
  29. pyodide-build-0.26.0.dev0/pyodide_build/__init__.py +0 -1
  30. pyodide-build-0.26.0.dev0/pyodide_build/_f2c_fixes.py +0 -600
  31. pyodide-build-0.26.0.dev0/pyodide_build/cli/xbuildenv.py +0 -61
  32. pyodide-build-0.26.0.dev0/pyodide_build/install_xbuildenv.py +0 -130
  33. pyodide-build-0.26.0.dev0/pyodide_build.egg-info/PKG-INFO +0 -52
  34. pyodide-build-0.26.0.dev0/pyodide_build.egg-info/SOURCES.txt +0 -44
  35. pyodide-build-0.26.0.dev0/pyodide_build.egg-info/dependency_links.txt +0 -1
  36. pyodide-build-0.26.0.dev0/pyodide_build.egg-info/entry_points.txt +0 -10
  37. pyodide-build-0.26.0.dev0/pyodide_build.egg-info/requires.txt +0 -27
  38. pyodide-build-0.26.0.dev0/pyodide_build.egg-info/top_level.txt +0 -2
  39. pyodide-build-0.26.0.dev0/setup.cfg +0 -4
  40. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/LICENSE +0 -0
  41. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/README.md +0 -0
  42. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/cli/__init__.py +0 -0
  43. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/cli/py_compile.py +0 -0
  44. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/cli/skeleton.py +0 -0
  45. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/cli/venv.py +0 -0
  46. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/create_xbuildenv.py +0 -0
  47. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/logger.py +0 -0
  48. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/mkpkg.py +0 -0
  49. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/out_of_tree/__init__.py +0 -0
  50. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/out_of_tree/pypi.py +0 -0
  51. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/tools/cmake/Modules/Platform/Emscripten.cmake +0 -0
  52. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/tools/emscripten.meson.cross +0 -0
  53. {pyodide-build-0.26.0.dev0 → pyodide_build-0.26.2}/pyodide_build/tools/pyo3_config.ini +0 -0
@@ -0,0 +1,43 @@
1
+ *.a
2
+ *.o
3
+ *.pyc
4
+ *.gen.*
5
+ src/js/generated
6
+ *.out.*
7
+
8
+ *.egg-info/
9
+
10
+ __pycache__
11
+
12
+ .docker_home
13
+ .hypothesis
14
+ .idea
15
+ .mozilla
16
+ .mypy_cache/
17
+ .pytest_cache/
18
+ .vscode
19
+ .venv*
20
+ tsconfig.tsbuildinfo
21
+
22
+ build
23
+ ccache
24
+ cpython/downloads
25
+ cpython/installs
26
+ cpython/build.log
27
+ dist*/
28
+ docs/_build/
29
+ emsdk/emsdk
30
+ geckodriver.log
31
+ node_modules
32
+ packages/.artifacts
33
+ packages/.build
34
+ packages/.libs
35
+ packages/*/build.log*
36
+ packages/build-logs
37
+ dist/
38
+ pyodide-build/**/build.log
39
+ xbuildenv/
40
+ pytest-pyodide
41
+ tools/symlinks
42
+ xbuildenv/
43
+ .pyodide-xbuildenv*
@@ -1,43 +1,41 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: pyodide-build
3
- Version: 0.26.0.dev0
3
+ Version: 0.26.2
4
4
  Summary: "Tools for building Pyodide"
5
- Author: Pyodide developers
6
- License: MPL-2.0
7
5
  Project-URL: Homepage, https://github.com/pyodide/pyodide
8
6
  Project-URL: Bug Tracker, https://github.com/pyodide/pyodide/issues
9
7
  Project-URL: Documentation, https://pyodide.org/en/stable/
10
- Classifier: Programming Language :: Python :: 3
8
+ Author: Pyodide developers
9
+ License: MPL-2.0
10
+ License-File: LICENSE
11
11
  Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
12
12
  Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
13
14
  Requires-Python: >=3.12
14
- Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
- Requires-Dist: pyyaml
17
- Requires-Dist: ruamel.yaml
15
+ Requires-Dist: auditwheel-emscripten~=0.0.9
16
+ Requires-Dist: build~=1.2.0
17
+ Requires-Dist: cmake>=3.24
18
+ Requires-Dist: loky
18
19
  Requires-Dist: packaging
19
- Requires-Dist: wheel
20
- Requires-Dist: build>=1.0.0
21
- Requires-Dist: virtualenv
22
- Requires-Dist: pydantic<2,>=1.10.2
20
+ Requires-Dist: pydantic<3,>=2
23
21
  Requires-Dist: pyodide-cli~=0.2.1
24
- Requires-Dist: cmake>=3.24
25
- Requires-Dist: unearth~=0.6
22
+ Requires-Dist: pyodide-lock==0.1.0a6
23
+ Requires-Dist: pyyaml
26
24
  Requires-Dist: requests
27
- Requires-Dist: types-requests
28
- Requires-Dist: typer
29
- Requires-Dist: auditwheel-emscripten~=0.0.9
30
- Requires-Dist: pyodide-lock==0.1.0a4
31
25
  Requires-Dist: resolvelib
32
26
  Requires-Dist: rich
33
- Requires-Dist: loky
27
+ Requires-Dist: ruamel-yaml
28
+ Requires-Dist: typer
29
+ Requires-Dist: types-requests
30
+ Requires-Dist: unearth~=0.6
31
+ Requires-Dist: virtualenv
32
+ Requires-Dist: wheel
34
33
  Provides-Extra: test
35
- Requires-Dist: pytest<8.0.0; extra == "test"
36
- Requires-Dist: pytest-pyodide==0.56.2; extra == "test"
37
- Requires-Dist: packaging; extra == "test"
38
- Provides-Extra: deploy
39
- Requires-Dist: boto3; extra == "deploy"
40
- Requires-Dist: moto; extra == "deploy"
34
+ Requires-Dist: packaging; extra == 'test'
35
+ Requires-Dist: pytest-httpserver; extra == 'test'
36
+ Requires-Dist: pytest-pyodide==0.57.0; extra == 'test'
37
+ Requires-Dist: pytest<8.0.0; extra == 'test'
38
+ Description-Content-Type: text/markdown
41
39
 
42
40
  # pyodide-build
43
41
 
@@ -0,0 +1 @@
1
+ __version__ = "0.26.2"
@@ -0,0 +1,198 @@
1
+ import os
2
+ import re
3
+ import subprocess
4
+ from pathlib import Path
5
+ from textwrap import dedent
6
+
7
+
8
+ def fix_f2c_input(f2c_input: Path) -> None:
9
+ if f2c_input.name.endswith("_flapack-f2pywrappers.f"):
10
+ content = f2c_input.read_text()
11
+ content = content.replace("character cmach", "integer cmach")
12
+ content = content.replace("character norm", "integer norm")
13
+ f2c_input.write_text(content)
14
+ return
15
+
16
+ if f2c_input.name in [
17
+ "_lapack_subroutine_wrappers.f",
18
+ "_blas_subroutine_wrappers.f",
19
+ ]:
20
+ content = f2c_input.read_text()
21
+ content = content.replace("character", "integer")
22
+ content = content.replace(
23
+ "ret = chla_transtype(", "call chla_transtype(ret, 1,"
24
+ )
25
+ f2c_input.write_text(content)
26
+
27
+
28
+ def fix_f2c_output(f2c_output: Path) -> None:
29
+ """
30
+ This function is called on the name of each C output file. It fixes up the C
31
+ output in various ways to compensate for the lack of f2c support for Fortran
32
+ 90 and Fortran 95.
33
+ """
34
+ if f2c_output.name == "_lapack_subroutine_wrappers.c":
35
+ content = f2c_output.read_text()
36
+ content = content.replace("integer chla_transtype__", "void chla_transtype__")
37
+ f2c_output.write_text(content)
38
+ return
39
+
40
+ if f2c_output.name.endswith("eupd.c"):
41
+ content = f2c_output.read_text()
42
+ content = re.sub(
43
+ r"ftnlen\s*(howmny_len|bmat_len),?", "", content, flags=re.MULTILINE
44
+ )
45
+ f2c_output.write_text(content)
46
+ return
47
+
48
+ if f2c_output.name.endswith("lansvd.c"):
49
+ content = f2c_output.read_text()
50
+ content += dedent(
51
+ """
52
+ #include <time.h>
53
+
54
+ int second_(real *t) {
55
+ *t = clock()/1000;
56
+ return 0;
57
+ }
58
+ """
59
+ )
60
+ f2c_output.write_text(content)
61
+ return
62
+
63
+
64
+ def scipy_fix_cfile(path: Path) -> None:
65
+ """
66
+ Replace void return types with int return types in various generated .c and
67
+ .h files. We can't achieve this with a simple patch because these files are
68
+ not in the sdist, they are generated as part of the build.
69
+ """
70
+ text = path.read_text()
71
+ text = text.replace("extern void F_WRAPPEDFUNC", "extern int F_WRAPPEDFUNC")
72
+ text = text.replace("extern void F_FUNC", "extern int F_FUNC")
73
+ text = text.replace("void (*f2py_func)", "int (*f2py_func)")
74
+ text = text.replace("static void cb_", "static int cb_")
75
+ text = text.replace("typedef void(*cb_", "typedef int(*cb_")
76
+ text = text.replace("void(*)", "int(*)")
77
+ text = text.replace("static void f2py_setup_", "static int f2py_setup_")
78
+
79
+ if path.name.endswith("_flapackmodule.c"):
80
+ text = text.replace(",size_t", "")
81
+ text = re.sub(r",slen\([a-z]*\)\)", ")", text)
82
+
83
+ path.write_text(text)
84
+
85
+ for lib in ["lapack", "blas"]:
86
+ if path.name.endswith(f"cython_{lib}.c"):
87
+ header_name = f"_{lib}_subroutines.h"
88
+ header_dir = path.parent
89
+ header_path = find_header(header_dir, header_name)
90
+
91
+ header_text = header_path.read_text()
92
+ header_text = header_text.replace("void F_FUNC", "int F_FUNC")
93
+ header_path.write_text(header_text)
94
+
95
+
96
+ def find_header(source_dir: Path, header_name: str) -> Path:
97
+ """
98
+ Find the header file that corresponds to a source file.
99
+ """
100
+ while not (header_path := source_dir / header_name).exists():
101
+ # meson copies the source files into a subdirectory of the build
102
+ source_dir = source_dir.parent
103
+ if source_dir == Path("/"):
104
+ raise RuntimeError(f"Could not find header file {header_name}")
105
+
106
+ return header_path
107
+
108
+
109
+ def scipy_fixes(args: list[str]) -> None:
110
+ for arg in args:
111
+ if arg.endswith(".c"):
112
+ scipy_fix_cfile(Path(arg))
113
+
114
+
115
+ def replay_f2c(args: list[str], dryrun: bool = False) -> list[str] | None:
116
+ """Apply f2c to compilation arguments
117
+
118
+ Parameters
119
+ ----------
120
+ args
121
+ input compiler arguments
122
+ dryrun
123
+ if False run f2c on detected fortran files
124
+
125
+ Returns
126
+ -------
127
+ new_args
128
+ output compiler arguments
129
+
130
+
131
+ Examples
132
+ --------
133
+
134
+ >>> replay_f2c(['gfortran', 'test.f'], dryrun=True)
135
+ ['gcc', 'test.c']
136
+ """
137
+ f2c_path = os.environ.get("F2C_PATH", "f2c")
138
+
139
+ new_args = ["gcc"]
140
+ found_source = False
141
+ for arg in args[1:]:
142
+ if not arg.endswith((".f", ".F")):
143
+ new_args.append(arg)
144
+ continue
145
+ found_source = True
146
+ filepath = Path(arg).resolve()
147
+ new_args.append(arg[:-2] + ".c")
148
+ if dryrun:
149
+ continue
150
+ fix_f2c_input(Path(arg))
151
+ if arg.endswith(".F"):
152
+ # .F files apparently expect to be run through the C
153
+ # preprocessor (they have #ifdef's in them)
154
+ # Use gfortran frontend, as gcc frontend might not be
155
+ # present on osx
156
+ # The file-system might be not case-sensitive,
157
+ # so take care to handle this by renaming.
158
+ # For preprocessing and further operation the
159
+ # expected file-name and extension needs to be preserved.
160
+ subprocess.check_call(
161
+ [
162
+ "gfortran",
163
+ "-E",
164
+ "-C",
165
+ "-P",
166
+ filepath,
167
+ "-o",
168
+ filepath.with_suffix(".f77"),
169
+ ]
170
+ )
171
+ filepath = filepath.with_suffix(".f77")
172
+ # -R flag is important, it means that Fortran functions that
173
+ # return real e.g. sdot will be transformed into C functions
174
+ # that return float. For historic reasons, by default f2c
175
+ # transform them into functions that return a double. Using -R
176
+ # allows to match what OpenBLAS has done when they f2ced their
177
+ # Fortran files, see
178
+ # https://github.com/xianyi/OpenBLAS/pull/3539#issuecomment-1493897254
179
+ # for more details
180
+ with (
181
+ open(filepath) as input_pipe,
182
+ open(filepath.with_suffix(".c"), "w") as output_pipe,
183
+ ):
184
+ subprocess.check_call(
185
+ [f2c_path, "-R"],
186
+ stdin=input_pipe,
187
+ stdout=output_pipe,
188
+ cwd=filepath.parent,
189
+ )
190
+ fix_f2c_output(Path(arg[:-2] + ".c"))
191
+
192
+ new_args_str = " ".join(args)
193
+ if ".so" in new_args_str and "libgfortran.so" not in new_args_str:
194
+ found_source = True
195
+
196
+ if not found_source:
197
+ return None
198
+ return new_args
@@ -122,9 +122,10 @@ def _compile(
122
122
  else:
123
123
  compression = zipfile.ZIP_STORED
124
124
 
125
- with zipfile.ZipFile(
126
- input_path
127
- ) as fh_zip_in, TemporaryDirectory() as temp_dir_str:
125
+ with (
126
+ zipfile.ZipFile(input_path) as fh_zip_in,
127
+ TemporaryDirectory() as temp_dir_str,
128
+ ):
128
129
  temp_dir = Path(temp_dir_str)
129
130
  output_path_tmp = temp_dir / output_name
130
131
  with zipfile.ZipFile(
@@ -106,7 +106,7 @@ def get_bash_runner(
106
106
  extra_envs: dict[str, str],
107
107
  ) -> Iterator[BashRunnerWithSharedEnvironment]:
108
108
  pyodide_root = get_pyodide_root()
109
- env = get_build_environment_vars()
109
+ env = get_build_environment_vars(pyodide_root)
110
110
  env.update(extra_envs)
111
111
 
112
112
  with BashRunnerWithSharedEnvironment(env=env) as b:
@@ -5,7 +5,6 @@ import functools
5
5
  import os
6
6
  import re
7
7
  import subprocess
8
- import tomllib
9
8
  from collections.abc import Iterator
10
9
  from contextlib import nullcontext, redirect_stdout
11
10
  from io import StringIO
@@ -13,8 +12,8 @@ from pathlib import Path
13
12
 
14
13
  from packaging.tags import Tag, compatible_tags, cpython_tags
15
14
 
16
- from .common import exit_with_stdio, xbuildenv_dirname
17
- from .logger import logger
15
+ from .common import search_pyproject_toml, xbuildenv_dirname
16
+ from .config import ConfigManager
18
17
  from .recipe import load_all_recipes
19
18
 
20
19
  RUST_BUILD_PRELUDE = """
@@ -23,47 +22,6 @@ rustup target add wasm32-unknown-emscripten --toolchain ${RUST_TOOLCHAIN}
23
22
  """
24
23
 
25
24
 
26
- BUILD_VARS: set[str] = {
27
- "CARGO_BUILD_TARGET",
28
- "CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_LINKER",
29
- "HOME",
30
- "HOSTINSTALLDIR",
31
- "HOSTSITEPACKAGES",
32
- "NUMPY_LIB",
33
- "PATH",
34
- "PLATFORM_TRIPLET",
35
- "PIP_CONSTRAINT",
36
- "PYMAJOR",
37
- "PYMICRO",
38
- "PYMINOR",
39
- "PYO3_CROSS_INCLUDE_DIR",
40
- "PYO3_CROSS_LIB_DIR",
41
- "PYODIDE_EMSCRIPTEN_VERSION",
42
- "PYODIDE_JOBS",
43
- "PYODIDE_PACKAGE_ABI",
44
- "PYODIDE_ROOT",
45
- "PYTHON_ARCHIVE_SHA256",
46
- "PYTHON_ARCHIVE_URL",
47
- "PYTHONINCLUDE",
48
- "PYTHONPATH",
49
- "PYVERSION",
50
- "RUSTFLAGS",
51
- "RUST_TOOLCHAIN",
52
- "SIDE_MODULE_CFLAGS",
53
- "SIDE_MODULE_CXXFLAGS",
54
- "SIDE_MODULE_LDFLAGS",
55
- "STDLIB_MODULE_CFLAGS",
56
- "SYSCONFIGDATA_DIR",
57
- "SYSCONFIG_NAME",
58
- "TARGETINSTALLDIR",
59
- "WASM_LIBRARY_DIR",
60
- "CMAKE_TOOLCHAIN_FILE",
61
- "PYO3_CONFIG_FILE",
62
- "MESON_CROSS_FILE",
63
- "PKG_CONFIG_LIBDIR",
64
- }
65
-
66
-
67
25
  @dataclasses.dataclass(eq=False, order=False, kw_only=True)
68
26
  class BuildArgs:
69
27
  """
@@ -114,14 +72,16 @@ def _init_xbuild_env(*, quiet: bool = False) -> Path:
114
72
  -------
115
73
  The path to the Pyodide root directory inside the xbuild environment
116
74
  """
117
- from . import install_xbuildenv # avoid circular import
75
+ from .xbuildenv import CrossBuildEnvManager # avoid circular import
118
76
 
119
- # TODO: Do not hardcode the path
120
77
  xbuildenv_path = Path(xbuildenv_dirname()).resolve()
121
-
122
78
  context = redirect_stdout(StringIO()) if quiet else nullcontext()
123
79
  with context:
124
- return install_xbuildenv.install(xbuildenv_path, download=True)
80
+ manager = CrossBuildEnvManager(xbuildenv_path)
81
+ if manager.current_version is None:
82
+ manager.install()
83
+
84
+ return manager.pyodide_root
125
85
 
126
86
 
127
87
  @functools.cache
@@ -136,24 +96,13 @@ def search_pyodide_root(curdir: str | Path, *, max_depth: int = 10) -> Path | No
136
96
  by looking for the pyproject.toml file in the parent directories
137
97
  which contains [tool.pyodide] section.
138
98
  """
99
+ pyproject_path, pyproject_file = search_pyproject_toml(curdir, max_depth)
139
100
 
140
- # We want to include "curdir" in parent_dirs, so add a garbage suffix
141
- parent_dirs = (Path(curdir) / "garbage").parents[:max_depth]
101
+ if pyproject_path is None or pyproject_file is None:
102
+ return None
142
103
 
143
- for base in parent_dirs:
144
- pyproject_file = base / "pyproject.toml"
145
-
146
- if not pyproject_file.is_file():
147
- continue
148
-
149
- try:
150
- with pyproject_file.open("rb") as f:
151
- configs = tomllib.load(f)
152
- except tomllib.TOMLDecodeError as e:
153
- raise ValueError(f"Could not parse {pyproject_file}.") from e
154
-
155
- if "tool" in configs and "pyodide" in configs["tool"]:
156
- return base
104
+ if "tool" in pyproject_file and "_pyodide" in pyproject_file["tool"]:
105
+ return pyproject_path.parent
157
106
 
158
107
  return None
159
108
 
@@ -164,84 +113,33 @@ def in_xbuildenv() -> bool:
164
113
 
165
114
 
166
115
  @functools.cache
167
- def get_build_environment_vars() -> dict[str, str]:
116
+ def get_build_environment_vars(pyodide_root: Path) -> dict[str, str]:
168
117
  """
169
118
  Get common environment variables for the in-tree and out-of-tree build.
170
119
  """
171
- env = _get_make_environment_vars().copy()
172
-
173
- # Allow users to overwrite the build environment variables by setting
174
- # host environment variables.
175
- # TODO: Add modifiable configuration file instead.
176
- # (https://github.com/pyodide/pyodide/pull/3737/files#r1161247201)
177
- env.update({key: os.environ[key] for key in BUILD_VARS if key in os.environ})
178
- env["PYODIDE"] = "1"
179
-
180
- tools_dir = Path(__file__).parent / "tools"
181
-
182
- if "CMAKE_TOOLCHAIN_FILE" not in env:
183
- env["CMAKE_TOOLCHAIN_FILE"] = str(
184
- tools_dir / "cmake/Modules/Platform/Emscripten.cmake"
185
- )
186
-
187
- if "PYO3_CONFIG_FILE" not in env:
188
- env["PYO3_CONFIG_FILE"] = str(tools_dir / "pyo3_config.ini")
189
-
190
- if "MESON_CROSS_FILE" not in env:
191
- env["MESON_CROSS_FILE"] = str(tools_dir / "emscripten.meson.cross")
192
-
193
- hostsitepackages = env["HOSTSITEPACKAGES"]
194
- pythonpath = [
195
- hostsitepackages,
196
- ]
197
- env["PYTHONPATH"] = ":".join(pythonpath)
198
-
199
- return env
200
-
201
-
202
- def _get_make_environment_vars(*, pyodide_root: Path | None = None) -> dict[str, str]:
203
- """Load environment variables from Makefile.envs
204
-
205
- This allows us to set all build vars in one place
206
-
207
- Parameters
208
- ----------
209
- pyodide_root
210
- The root directory of the Pyodide repository. If None, this will be inferred.
211
- """
212
-
213
- PYODIDE_ROOT = get_pyodide_root() if pyodide_root is None else pyodide_root
214
- environment = {}
215
- result = subprocess.run(
216
- ["make", "-f", str(PYODIDE_ROOT / "Makefile.envs"), ".output_vars"],
217
- capture_output=True,
218
- text=True,
219
- env={"PYODIDE_ROOT": str(PYODIDE_ROOT)},
120
+ config_manager = ConfigManager(pyodide_root)
121
+ env = config_manager.to_env()
122
+
123
+ env.update(
124
+ {
125
+ # This environment variable is used for packages to detect if they are built
126
+ # for pyodide during build time
127
+ "PYODIDE": "1",
128
+ # This is the legacy environment variable used for the aforementioned purpose
129
+ "PYODIDE_PACKAGE_ABI": "1",
130
+ "PYTHONPATH": env["HOSTSITEPACKAGES"],
131
+ }
220
132
  )
221
133
 
222
- if result.returncode != 0:
223
- logger.error("ERROR: Failed to load environment variables from Makefile.envs")
224
- exit_with_stdio(result)
225
-
226
- for line in result.stdout.splitlines():
227
- equalPos = line.find("=")
228
- if equalPos != -1:
229
- varname = line[0:equalPos]
230
-
231
- if varname not in BUILD_VARS:
232
- continue
233
-
234
- value = line[equalPos + 1 :]
235
- value = value.strip("'").strip()
236
- environment[varname] = value
237
- return environment
134
+ return env
238
135
 
239
136
 
240
137
  def get_build_flag(name: str) -> str:
241
138
  """
242
139
  Get a value of a build flag.
243
140
  """
244
- build_vars = get_build_environment_vars()
141
+ pyodide_root = get_pyodide_root()
142
+ build_vars = get_build_environment_vars(pyodide_root)
245
143
  if name not in build_vars:
246
144
  raise ValueError(f"Unknown build flag: {name}")
247
145
 
@@ -293,6 +191,11 @@ def platform() -> str:
293
191
  return f"emscripten_{version}_wasm32"
294
192
 
295
193
 
194
+ def wheel_platform() -> str:
195
+ abi_version = get_build_flag("PYODIDE_ABI_VERSION")
196
+ return f"pyodide_{abi_version}_wasm32"
197
+
198
+
296
199
  def pyodide_tags() -> Iterator[Tag]:
297
200
  """
298
201
  Returns the sequence of tag triples for the Pyodide interpreter.
@@ -301,10 +204,10 @@ def pyodide_tags() -> Iterator[Tag]:
301
204
  """
302
205
  PYMAJOR = get_pyversion_major()
303
206
  PYMINOR = get_pyversion_minor()
304
- PLATFORM = platform()
207
+ PLATFORMS = [platform(), wheel_platform()]
305
208
  python_version = (int(PYMAJOR), int(PYMINOR))
306
- yield from cpython_tags(platforms=[PLATFORM], python_version=python_version)
307
- yield from compatible_tags(platforms=[PLATFORM], python_version=python_version)
209
+ yield from cpython_tags(platforms=PLATFORMS, python_version=python_version)
210
+ yield from compatible_tags(platforms=PLATFORMS, python_version=python_version)
308
211
  # Following line can be removed once packaging 22.0 is released and we update to it.
309
212
  yield Tag(interpreter=f"cp{PYMAJOR}{PYMINOR}", abi="none", platform="any")
310
213
 
@@ -100,7 +100,7 @@ class BasePackage:
100
100
  class Package(BasePackage):
101
101
  def __init__(self, pkgdir: Path, config: MetaConfig):
102
102
  self.pkgdir = pkgdir
103
- self.meta = config.copy(deep=True)
103
+ self.meta = config.model_copy(deep=True)
104
104
 
105
105
  self.name = self.meta.package.name
106
106
  self.version = self.meta.package.version
@@ -772,16 +772,14 @@ def generate_lockfile(
772
772
  ) -> PyodideLockSpec:
773
773
  """Generate the package.json file"""
774
774
 
775
- from . import __version__
776
-
777
775
  # Build package.json data.
778
776
  [platform, _, arch] = build_env.platform().rpartition("_")
779
777
  info = {
780
778
  "arch": arch,
781
779
  "platform": platform,
782
- # This assumes that pyodide-build version == pyodide version.
783
- "version": __version__,
780
+ "version": build_env.get_build_flag("PYODIDE_VERSION"),
784
781
  "python": sys.version.partition(" ")[0],
782
+ "abi_version": build_env.get_build_flag("PYODIDE_ABI_VERSION"),
785
783
  }
786
784
  packages = generate_packagedata(output_dir, pkg_map)
787
785
  lock_spec = PyodideLockSpec(info=info, packages=packages)
@@ -875,7 +873,7 @@ def install_packages(
875
873
  """
876
874
  Install packages into the output directory.
877
875
  - copies build artifacts (wheel, zip, ...) to the output directory
878
- - create pyodide_lock.json
876
+ - create pyodide-lock.json
879
877
 
880
878
 
881
879
  pkg_map
@@ -905,15 +903,15 @@ def install_packages(
905
903
  def set_default_build_args(build_args: BuildArgs) -> BuildArgs:
906
904
  args = dataclasses.replace(build_args)
907
905
 
908
- if args.cflags is None:
909
- args.cflags = build_env.get_build_flag("SIDE_MODULE_CFLAGS") # type: ignore[unreachable]
910
- if args.cxxflags is None:
911
- args.cxxflags = build_env.get_build_flag("SIDE_MODULE_CXXFLAGS") # type: ignore[unreachable]
912
- if args.ldflags is None:
913
- args.ldflags = build_env.get_build_flag("SIDE_MODULE_LDFLAGS") # type: ignore[unreachable]
914
- if args.target_install_dir is None:
915
- args.target_install_dir = build_env.get_build_flag("TARGETINSTALLDIR") # type: ignore[unreachable]
916
- if args.host_install_dir is None:
917
- args.host_install_dir = build_env.get_build_flag("HOSTINSTALLDIR") # type: ignore[unreachable]
906
+ if not args.cflags:
907
+ args.cflags = build_env.get_build_flag("SIDE_MODULE_CFLAGS")
908
+ if not args.cxxflags:
909
+ args.cxxflags = build_env.get_build_flag("SIDE_MODULE_CXXFLAGS")
910
+ if not args.ldflags:
911
+ args.ldflags = build_env.get_build_flag("SIDE_MODULE_LDFLAGS")
912
+ if not args.target_install_dir:
913
+ args.target_install_dir = build_env.get_build_flag("TARGETINSTALLDIR")
914
+ if not args.host_install_dir:
915
+ args.host_install_dir = build_env.get_build_flag("HOSTINSTALLDIR")
918
916
 
919
917
  return args