Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update build.py to support running on Windows using Docker via WSL2. #44

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,36 @@

- Should it list boards and variants? (yes, probably. Alternatively, '-a'.)


## requirements to use on Linux

- Docker or compatible container runtime
- Python 3.x

## Requirements to use on Windows

- Docker or compatible container runtime using WSL2
- Python 3.x
- WSL2
- Linux Distro: Ubuntu, Arch, Kali-linux have been tested

- micropython repo cloned to a WSL2 hosted directory
`/home/<user>/micropython`

- MICROPY_DIR set to the WSL2 hosted directory
`$env:MICROPY_DIR="\\wsl.localhost\Ubuntu\home\<user>\micropython"`

- Optional: Windows drive letter mapped to WSL2 hosted directory
`net use U: \\wsl$\Ubuntu`
`dir U:\home\<user>\micropython\ports\rp2\build_RPI_PICO\firmware.uf2`

## Development

- rye for managing the project
``` shell
rye sync
rye build
```
- Use ruff for formatting
- pre-commit
- ruff formatting and linting
Expand Down
70 changes: 62 additions & 8 deletions src/mpbuild/build.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
from typing import Optional, List
import sys
from typing import Optional, List, Tuple

from pathlib import Path
import multiprocessing
Expand Down Expand Up @@ -34,7 +35,7 @@ def build_board(
extra_args: List[str] = [],
build_container_override: Optional[str] = None,
idf: Optional[str] = IDF_DEFAULT,
mpy_dir: str|Path|None = None,
mpy_dir: str | Path | None = None,
) -> None:
# mpy_dir = mpy_dir or Path.cwd()
# mpy_dir = Path(mpy_dir)
Expand Down Expand Up @@ -75,11 +76,11 @@ def build_board(
args = " " + " ".join(extra_args)

make_mpy_cross_cmd = "make -C mpy-cross && "
update_submodules_cmd = (
f"make -C ports/{port} submodules BOARD={board}{variant_cmd} && "
)

uid, gid = os.getuid(), os.getgid()
update_submodules_cmd = f"make -C ports/{port} submodules BOARD={board}{variant_cmd} && "
if sys.platform != "win32":
uid, gid = os.getuid(), os.getgid()
else:
uid, gid = (1000, 1000) # Default to user id 1000 for Windows WSL2

if extra_args and extra_args[0].strip() == "clean":
# When cleaning we run with full privs
Expand All @@ -88,9 +89,11 @@ def build_board(
make_mpy_cross_cmd = ""
update_submodules_cmd = ""

home = os.environ["HOME"]
home = str(Path.home())
mpy_dir = db.mpy_root_directory

if sys.platform == "win32":
mpy_dir, home = adapt_for_wsl(mpy_dir, home)
# fmt: off
build_cmd = (
f"docker run -it --rm "
Expand All @@ -108,6 +111,8 @@ def build_board(
f'make -j {nprocs} -C ports/{port} BOARD={board}{variant_cmd}{args}"'
)
# fmt: on
if sys.platform == "win32":
build_cmd = f"wsl -- {build_cmd}"

title = "Build" if "clean" not in extra_args else "Clean"
title += f" {port}/{board}" + (f" ({variant})" if variant else "")
Expand Down Expand Up @@ -153,3 +158,52 @@ def clean_board(
idf=idf,
extra_args=["clean"],
)


def adapt_for_wsl(mpy_dir: Path, home: str) -> Tuple[str, str]:
"""Adapt paths for running docker from WSL2.
Both windows and wsl paths to the repo are supported , but wsl hosted paths are faster.
"""
# wsl2 home directory is /home/<username>
r = subprocess.run(
'wsl -e bash -c "printenv"', capture_output=True, text=True, universal_newlines=True
)
for line in r.stdout.splitlines():
if line.startswith("HOME="):
wsl_home = line.split("=")[1]
elif line.startswith("WSL_DISTRO_NAME="):
distro = line.split("=")[1]

# Translate windows paths to wsl paths
if ":\\" in str(mpy_dir):
warning = (
f"The MicroPython repo is located on the Windows path: [bold]{mpy_dir}[/bold].\n"
f"While this should work, please note that builds will be [bold]6-60 times slower[/bold].\n"
f"For the fastest performance speed, store your files on the WSL file system , for example in: [bold]{home}/micropython[/bold]\n"
f"See https://learn.microsoft.com/en-us/windows/wsl/filesystems#file-storage-and-performance-across-file-systems for more information."
)
print(Panel(warning, title="[bold]Warning[/bold]", title_align="left", style="yellow"))

# PYBV11 WSL Hosted : 19s 0:19 minutes
# PYBV11 Windows Hosted : 126s 2:06 minutes (6 times slower)
# RPI_PICO WSL Hosted : 12s 0:20 minutes
# RPI_PICO Windows Hosted: 1095s 18:25 minutes (60 times slower)
r = subprocess.run(
f'wsl wslpath "{mpy_dir}"', capture_output=True, text=True, universal_newlines=True
)
wsl_mpy_dir = r.stdout.strip()
else:
# Translate windows unc paths to wsl paths
# Assuming distro = Ubuntu
distro = distro or "TEST-Ubuntu"
wsl_mpy_dir = (
mpy_dir.as_posix()
.replace(f"//wsl$/{distro}/", "/")
.replace(f"//wsl.localhost/{distro}/", "/")
)
if "//wsl$" in wsl_mpy_dir:
raise ValueError(
f"mpy_dir: {mpy_dir} is not located on the default WSL2 distro: {distro}."
)
wsl_home = wsl_home or home
return wsl_mpy_dir, wsl_home