Skip to content

Conversation

bulenty584
Copy link

  • Add new 'pyodide xbuildenv install-emscripten' command
  • Add clone_emscripten() method to clone emsdk repository
  • Add install_emscripten() method to install and activate Emscripten SDK
  • Add tests for new functionality

Message echoed after installation complete for user to show the path to the emsdk_env.sh so that user can activate it manually in their shell.

bulenty584 and others added 2 commits October 15, 2025 15:39
  - Add new 'pyodide xbuildenv install-emscripten' command
  - Add clone_emscripten() method to clone emsdk repository
  - Add install_emscripten() method to install and activate Emscripten SDK
  - Add tests for new functionality
Comment on lines +507 to +508
"--embedded",
"--build=Release",
Copy link
Member

Choose a reason for hiding this comment

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

What's --embedded and --build=Release do?

Copy link
Author

Choose a reason for hiding this comment

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

I believe the --embedded flag tells emsdk to not modify your global shell startup files or system env. Essentially it places env variables into emsdk_env.sh so the user can call source on it later. The --build=Release flag causes emsdk to build or fetch pre-built tools in release mode instead of debug mode. Not quite sure if either is necessary for pyodide's build but I kept the commands identical to @ryanking13's shared script just to be safe.

Copy link
Member

Choose a reason for hiding this comment

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

I believe the --embedded flag tells emsdk to not modify your global shell startup files or system env.

This sounds like the default behavior. I think release build is also the default? Anyways we can leave it as is, but I normally would do this without either of these flags.

)

# Apply patches from xbuildenv/emsdk/patches directory to upstream/emscripten
# Patches are applied after install but before activate
Copy link
Member

Choose a reason for hiding this comment

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

It doesn't matter if they are applied before or after activate.

Copy link
Author

Choose a reason for hiding this comment

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

Noted and removed!

from pyodide_build.xbuildenv import CrossBuildEnvManager


class TestInstallEmscripten:
Copy link
Member

Choose a reason for hiding this comment

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

This seems like a lot more tests than we need.

Copy link
Author

Choose a reason for hiding this comment

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

I felt that as well but wanted to be thorough. Do you mean to get rid of all the tests or to keep some?

Copy link
Author

Choose a reason for hiding this comment

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

My latest commit has the tests file stripped of some of the bloated cases, let me know if this works better!

@hoodmane
Copy link
Member

Thanks for working on this @bulenty584!

@ryanking13 ryanking13 self-requested a review October 16, 2025 12:56
from pyodide_build.xbuildenv import CrossBuildEnvManager


class TestInstallEmscripten:
Copy link
Member

Choose a reason for hiding this comment

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

Remove the class? You don't seem to use it for anything.

Copy link
Author

Choose a reason for hiding this comment

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

Ah yeah, you are completely correct. Removed!

Copy link
Member

@ryanking13 ryanking13 left a comment

Choose a reason for hiding this comment

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

Thanks for working on this. Could you also update the integration test?

Currently we are installing Emscripten in CI for integration test, but I think we can replace this with this new command to test if this new command works correctly.

@app.command("install-emscripten")
def _install_emscripten(
version: str = typer.Option(
"latest", help="Emscripten SDK Version (default: latest)"
Copy link
Member

Choose a reason for hiding this comment

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

The default should be the one in the xbuildenv. Pyodide requires the same Emscripten version that is used to build the Pyodide runtime.

You can call get_build_flag("PYODIDE_EMSCRIPTEN_VERSION") to get the proper version.

Copy link
Author

Choose a reason for hiding this comment

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

Yup, added!

emsdk_dir = manager.install_emscripten(version)

print("Installing emsdk complete.")
print(f"Use `source {emsdk_dir}/emsdk_env.sh` to set up the environment.")
Copy link
Member

Choose a reason for hiding this comment

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

Instead of requiring people to manually source the directory, it would be nice to detect the emscripten installation directory and use it during the build.

Let's do that in a separate PR to reduce the diff, for now, it looks good.


xbuild_root = self.symlink_dir.resolve()
emsdk_dir = xbuild_root / "emsdk"
patches_dir = emsdk_dir / "patches"
Copy link
Member

Choose a reason for hiding this comment

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

I think the patches should be under self.pyodide_root / "emsdk" / "patches"

Copy link
Author

Choose a reason for hiding this comment

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

Ah yes, just saw that in the file as well. Edited in the new commit.


# Apply patches from xbuildenv/emsdk/patches directory to upstream/emscripten
subprocess.run(
f"cat {patches_dir}/*.patch | patch -p1 --verbose",
Copy link
Member

Choose a reason for hiding this comment

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

Note that the patch might fail is that emscripten version passed by the user is different from the version that the patch is generated. I think we ned to gracefully catch those errors and show proper error message.

Copy link
Author

Choose a reason for hiding this comment

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

Ah I must have overlooked that. I added some error handling for this case as well.

)


def test_install_emscripten_patch_application(tmp_path, monkeypatch):
Copy link
Member

Choose a reason for hiding this comment

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

This test looks redundant as the full pipeline is already tested in the previous tests.

Copy link
Author

Choose a reason for hiding this comment

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

Noted and changed!

manager.install_emscripten()


def test_install_emscripten_patch_application_sequence(tmp_path, monkeypatch):
Copy link
Member

Choose a reason for hiding this comment

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

This also looks a bit redundant


return version

def clone_emscripten(self, emsdk_dir: Path | str | None = None) -> Path:
Copy link
Member

Choose a reason for hiding this comment

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

Let's make this function private, to avoid using it directly outside.

Suggested change
def clone_emscripten(self, emsdk_dir: Path | str | None = None) -> Path:
def _clone_emscripten(self, emsdk_dir: Path | str | None = None) -> Path:

Comment on lines 69 to 70
# Verify subprocess calls
# install_emscripten makes 4 calls: clone + install + patch + activate
Copy link
Member

Choose a reason for hiding this comment

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

As these are already tested in test_install_emscripten.py, I think these are unnecessary. Testing the outputs should be enough. Same for all other functions in this file.

Copy link
Author

Choose a reason for hiding this comment

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

Yes after re-examining them I agree. Removed as well.

bulenty584 and others added 2 commits October 17, 2025 11:16
1. Changed default version to `get_build_flag("PYODIDE_EMSCRIPTEN_VERSION")`
2. Updated `clone_emscripten` to `_clone_emscripten`
3. Removed and edited redundant tests in both new test files
4. Updated patch path in `xbuildenv.py` and added new command to CI workflow
@ryanking13 ryanking13 added the integration This PR will run the integration tests. This label can be used as a persistent marker to do so. label Oct 19, 2025
Copy link
Member

@ryanking13 ryanking13 left a comment

Choose a reason for hiding this comment

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

Thanks! code wise looks good to me overall. I left some minor comments. Also, I added integration label to trigger integration tests.

Comment on lines 212 to 214
version: str = typer.Option(
get_build_flag("PYODIDE_EMSCRIPTEN_VERSION"),
help=f"Emscripten SDK Version (default: ${get_build_flag('PYODIDE_EMSCRIPTEN_VERSION')})",
Copy link
Member

Choose a reason for hiding this comment

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

Let's not call this inside the function's default value. Calling get_build_flag requires installing xbuildenv and it is a heavy operation.

You can set the default to None, and call get_build_flag inside the function explicitly when the version is not given.

Copy link
Author

Choose a reason for hiding this comment

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

Oh ok, I took it out and added the default check in the function.

with:
version: ${{ env.EMSCRIPTEN_VERSION }}
actions-cache-folder: ${{env.EMSDK_CACHE_FOLDER}}
run: pyodide install-emscripten
Copy link
Member

Choose a reason for hiding this comment

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

This should be pyodide xbuildenv install-emscripten.

Also as the current implementation does not activate the emsdk after running this command. It should be called manually.

Copy link
Author

Choose a reason for hiding this comment

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

Ah yes, totally my bad. Added both in now!

Removed the get_build_flag command from xbuildenv cli and added default behavior as none
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration This PR will run the integration tests. This label can be used as a persistent marker to do so.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants