Skip to content

Lazily installing cross-build packages is currently not reliable #365

Description

@agriyakhetarpal

With #297 and #302, we added a feature to install cross-build packages only when we require them. However, as part of debugging the implementation devised in #21 and testing it in pyodide/pyodide-recipes#591, I think I have exposed a latent bug that has existed for a while, but our infrastructure has kept it from manifesting in CI builds.

To reproduce:

  1. Set up the pyodide-recipes repository
  2. Set up submodule to point to Install unisolated packages into the isolated build venv and overlay their cross-build files #21 (it is what exposes the bug right now, but the changes are not related)
  3. Run pyodide build-recipes RobotRaconteur in the pyodide-recipes repository, fresh, before building anything else.

Right now, ensure_cross_build_packages_installed() on main is called inside _build_in_isolated_env():

if in_xbuildenv() and needs_cross_build_install:
get_current_xbuildenv_manager().ensure_cross_build_packages_installed()

# first install the build dependencies
symlink_unisolated_packages(env, builder.build_system_requires)

Which is part of _compile(). Now, looking at _build_package at

def _build_package(self, bash_runner: BashRunnerWithSharedEnvironment) -> None:
if self.recipe.is_rust_package():
bash_runner.run(
RUST_BUILD_PRELUDE,
script_name="rust build prelude",
cwd=self.src_extract_dir,
)
bash_runner.run(
self.build_metadata.script,
script_name="build script",
cwd=self.src_extract_dir,
)
url = self.source_metadata.url
prebuilt_wheel = url and url.endswith(".whl")
if not prebuilt_wheel:
self._compile(bash_runner)
self._package_wheel(bash_runner)
shutil.copytree(self.src_dist_dir, self.dist_dir, dirs_exist_ok=True)

The order is bash_runner.run(self.build_metadata.script, ...), which runs the CMake configuration, and then this is followed by self._compile(bash_runner), which is where we lazily load cross-build packages.

In this case, the RobotRaconteur recipe has a script section that needs host_site_packages populated before CMake runs, but host_site_packages/numpy/_core/include is still empty at execution time, so headers such as ndarrayobject.h are not found because they do not exist yet. There is no .cross-build-packages-installed marker either. Slightly before the last few commits I pushed in #21, we were not installing the cross-build packages; instead, we were only installing the cross-build files. ndarrayobject.h and other similar headers are not included in our cross-build files.

Why this has never showed up for us is because by the time the build order reaches RobotRaconteur, some earlier package that lists numpy as a host dependency (could be scipy, pandas, or any other scientific package, etc.), has already necessitated the existence of the _compile() step and warmed up the host_site_packages directory, which is then used by all the packages.

Building RobotRaconteur in isolation (just the recipe and its direct dependencies) does not trigger the lazy installation, so nothing is present in the cross-build packages.

Therefore, a fix could be to change when the lazy trigger runs, so that we detect the need to install, and install, the cross-build packages at the start of a package build rather than at a different event (if the package's recipe lists them in the host: section, of course).

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions