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
10 changes: 5 additions & 5 deletions .nanvix/.gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
__pycache__/
venv/
cache/
sysroot/
buildroot/
__pycache__
venv
cache
sysroot
buildroot
.yamllint.yml
black.toml
env.json
Expand Down
77 changes: 36 additions & 41 deletions .nanvix/Makefile.nanvix
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
# NANVIX_TOOLCHAIN=<toolchain> [target]
#
# Targets:
# all Build libxml2.a and the test ELF
# all Build libxml2.a and the test ELF, then stage via install
# install Stage built artifacts into LIB_OUT/INCLUDE_OUT/TEST_OUT
# test Run functional tests
# test-functional Run the test ELF on nanvixd.elf
# package Create a release tarball with libs, headers, xml2-config
# verify-package Verify the contents of the release tarball
# clean Remove build artifacts

# ===========================================================================
Expand All @@ -19,8 +18,8 @@

# Some assumptions:
# 1. This makefile is expected to be invoked via z.py.
# 2. Build goals require the cross-toolchain at $(NANVIX_TOOLCHAIN); other
# goals (test-*, package, verify-package, clean) are pure host-side.
# 2. Build goals (all, install) require the cross-toolchain at
# $(NANVIX_TOOLCHAIN); other goals (test-*, clean) are pure host-side.
# 3. Build ALWAYS runs before test and release.

.DEFAULT_GOAL=all
Expand All @@ -30,11 +29,23 @@ STATICLIB := .libs/libxml2.a
TEST_SRC := .nanvix/test/test_libxml2.c
TEST_ELF := test_libxml2$(EXE)

_NANVIX_DOCKER_BUILD_GOALS := all $(STATICLIB) $(TEST_ELF)
_NANVIX_DOCKER_BUILD_GOALS := all install $(STATICLIB) $(TEST_ELF)
_NANVIX_GOALS := $(or $(MAKECMDGOALS),$(.DEFAULT_GOAL))

# Ensure required variables are defined.
_REQUIRED := PLATFORM PROCESS_MODE MEMORY_SIZE NANVIX_HOME NANVIX_BUILDROOT NANVIX_TOOLCHAIN
_REQUIRED := PLATFORM \
PROCESS_MODE \
MEMORY_SIZE \
NANVIX_HOME \
NANVIX_BUILDROOT \
NANVIX_TOOLCHAIN \
NANVIX_ROOT \
OUT_DIR \
DIST_DIR \
LIB_OUT \
INCLUDE_OUT \
BIN_OUT \
TEST_OUT
ifneq ($(filter-out clean,$(_NANVIX_GOALS)),)
$(foreach v,$(_REQUIRED),\
$(if $($v),,$(error Required variable $v not set))\
Expand Down Expand Up @@ -65,7 +76,22 @@ endif
# Build Targets
# ===========================================================================

all: $(STATICLIB) $(TEST_ELF)
all: $(STATICLIB) $(TEST_ELF) install

# Stage built artifacts into the release/test output tree so that
# `./z release` (which packages release_dir()) can find them.
install: $(STATICLIB) $(TEST_ELF)
@mkdir -p $(LIB_OUT) $(INCLUDE_OUT)/libxml2/libxml $(BIN_OUT) $(TEST_OUT)
cp -f $(STATICLIB) $(LIB_OUT)/
cp -f include/libxml/*.h $(INCLUDE_OUT)/libxml2/libxml/
cp -f $(TEST_ELF) $(TEST_OUT)/
@echo '#!/bin/sh' > $(BIN_OUT)/xml2-config
@echo 'case "$$1" in' >> $(BIN_OUT)/xml2-config
@echo ' --cflags) echo "-I$${NANVIX_HOME:-/mnt/sysroot}/include/libxml2" ;;' >> $(BIN_OUT)/xml2-config
@echo ' --libs) echo "-L$${NANVIX_HOME:-/mnt/sysroot}/lib -lxml2 -lz" ;;' >> $(BIN_OUT)/xml2-config
@echo ' --version) echo "2.12.9" ;;' >> $(BIN_OUT)/xml2-config
@echo 'esac' >> $(BIN_OUT)/xml2-config
chmod +x $(BIN_OUT)/xml2-config

$(STATICLIB):
sh -c '\
Expand Down Expand Up @@ -122,44 +148,13 @@ test-functional:
test: test-functional
@echo "=== All libxml2 tests PASSED ==="

# ===========================================================================
# Package Target
# ===========================================================================

package:
@echo "=== Packaging libxml2 release ==="
$(eval ARTIFACT_NAME := libxml2-$(PLATFORM)-$(PROCESS_MODE)-$(MEMORY_SIZE))
@test -f $(STATICLIB) || { echo " FAIL: $(STATICLIB) not found; run 'build' first"; exit 1; }
rm -rf dist/$(ARTIFACT_NAME)
mkdir -p dist/$(ARTIFACT_NAME)/sysroot/lib \
dist/$(ARTIFACT_NAME)/sysroot/include/libxml2/libxml \
dist/$(ARTIFACT_NAME)/sysroot/bin
cp -f $(STATICLIB) dist/$(ARTIFACT_NAME)/sysroot/lib/
cp -f include/libxml/*.h dist/$(ARTIFACT_NAME)/sysroot/include/libxml2/libxml/
@echo '#!/bin/sh' > dist/$(ARTIFACT_NAME)/sysroot/bin/xml2-config
@echo 'case "$$1" in' >> dist/$(ARTIFACT_NAME)/sysroot/bin/xml2-config
@echo ' --cflags) echo "-I$${NANVIX_HOME:-/mnt/sysroot}/include/libxml2" ;;' >> dist/$(ARTIFACT_NAME)/sysroot/bin/xml2-config
@echo ' --libs) echo "-L$${NANVIX_HOME:-/mnt/sysroot}/lib -lxml2 -lz" ;;' >> dist/$(ARTIFACT_NAME)/sysroot/bin/xml2-config
@echo ' --version) echo "2.12.9" ;;' >> dist/$(ARTIFACT_NAME)/sysroot/bin/xml2-config
@echo 'esac' >> dist/$(ARTIFACT_NAME)/sysroot/bin/xml2-config
chmod +x dist/$(ARTIFACT_NAME)/sysroot/bin/xml2-config
tar -czf dist/$(ARTIFACT_NAME).tar.gz -C dist/$(ARTIFACT_NAME) sysroot
@echo " Package: dist/$(ARTIFACT_NAME).tar.gz"

verify-package:
@echo "=== Verifying libxml2 package ==="
$(eval ARTIFACT_NAME := libxml2-$(PLATFORM)-$(PROCESS_MODE)-$(MEMORY_SIZE))
@test -f "dist/$(ARTIFACT_NAME).tar.gz" || { echo " FAIL: tarball not found"; exit 1; }
@tar tzf "dist/$(ARTIFACT_NAME).tar.gz" | grep -q 'sysroot/lib/libxml2.a' || { echo " FAIL: missing libxml2.a"; exit 1; }
@echo " PASS: libxml2 package verification"

# ===========================================================================
# Clean
# ===========================================================================

clean:
-$(MAKE) clean 2>/dev/null || true
rm -f $(TEST_ELF) Makefile
rm -rf dist/ .libs/
rm -rf $(OUT_DIR) dist/ .libs/

.PHONY: all clean test test-functional package verify-package
.PHONY: all install clean test test-functional
80 changes: 54 additions & 26 deletions .nanvix/z.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@
make_initrd,
run,
)
from nanvix_zutil.paths import (
bin_out,
buildroot,
dist_dir,
include_out,
lib_out,
nanvix_root,
out_dir,
repo_root,
test_out,
)

IS_WINDOWS = sys.platform == "win32"

Expand All @@ -44,16 +55,32 @@ class Libxml2Build(ZScript):
# from the container's build directory into the host workspace. The
# zutils Docker wrapper builds in a container-local scratch dir for
# performance (especially on Windows), so anything not listed here
# is discarded when the container exits.
_BUILD_OUTPUTS: tuple[str, ...] = (
".libs/libxml2.a",
"include/libxml/xmlversion.h",
"test_libxml2.elf",
)
# is discarded when the container exits. Two categories:
# * legacy repo-root paths needed at runtime (test_libxml2.elf is
# resolved by make_initrd via repo_root()/app);
# * install-staged paths under .nanvix/out/ for `./z release`
# (see _staged_output_files()).
_BUILD_OUTPUTS: tuple[str, ...] = ("test_libxml2.elf",)

def _staged_output_files(self) -> list[str]:
"""Return install-staged artifact paths (relative to repo_root())
so Windows tar-copy mode also copies them back to the host.
"""
root = repo_root()
return [
str((lib_out() / "libxml2.a").relative_to(root)),
str(
(include_out() / "libxml2" / "libxml" / "xmlversion.h").relative_to(
root
)
),
str((bin_out() / "xml2-config").relative_to(root)),
str((test_out() / "test_libxml2.elf").relative_to(root)),
]

def docker_config(self, image: str) -> DockerConfig:
cfg = super().docker_config(image)
cfg.output_files = list(self._BUILD_OUTPUTS)
cfg.output_files = list(self._BUILD_OUTPUTS) + self._staged_output_files()
return cfg

def _make_args(self, *targets: str) -> list[str]:
Expand All @@ -70,14 +97,13 @@ def _make_args(self, *targets: str) -> list[str]:
self.docker.translate_path(Path(sysroot)) if self.docker else Path(sysroot)
)

def translate(p: Path):
return self.docker.translate_path(p) if self.docker else p

# Buildroot contains dependency libraries (zlib).
buildroot_dir = self.nanvix_dir / "buildroot"
buildroot_dir = buildroot()
if buildroot_dir.is_dir():
buildroot_p = (
self.docker.translate_path(buildroot_dir)
if self.docker
else buildroot_dir
)
buildroot_p = translate(buildroot_dir)
else:
buildroot_p = sysroot_p

Expand All @@ -95,6 +121,13 @@ def _make_args(self, *targets: str) -> list[str]:
f"{_MAKE_VAR_PLATFORM}={self.config.machine}",
f"{_MAKE_VAR_PROCESS_MODE}={self.config.deployment_mode}",
f"{_MAKE_VAR_MEMORY_SIZE}={self.config.memory_size}",
f"NANVIX_ROOT={translate(nanvix_root())}",
f"OUT_DIR={translate(out_dir())}",
f"DIST_DIR={translate(dist_dir())}",
f"LIB_OUT={translate(lib_out())}",
f"INCLUDE_OUT={translate(include_out())}",
f"BIN_OUT={translate(bin_out())}",
f"TEST_OUT={translate(test_out())}",
]
)

Expand All @@ -103,7 +136,7 @@ def _make_args(self, *targets: str) -> list[str]:

def build(self) -> None:
"""Cross-compile libxml2.a for Nanvix."""
run(*self._make_args("all"), cwd=self.repo_root, docker=self.docker)
run(*self._make_args("all"), cwd=repo_root(), docker=self.docker)

# Test targets accepted by `./z test` on paths that bypass the
# Makefile (Windows and standalone Linux). Both aliases run the same
Expand Down Expand Up @@ -146,7 +179,7 @@ def test(self) -> None:
targets = self.targets if self.targets else ["test"]
run(
*self._make_args(*targets),
cwd=self.repo_root,
cwd=repo_root(),
)

def _get_sysroot(self) -> str:
Expand All @@ -166,7 +199,7 @@ def _run_functional_standalone(self) -> None:
Creates an initrd bundling test_libxml2.elf with system daemons via
make_initrd, and a ramfs providing /tmp for test file output.
"""
binary = self.repo_root / "test_libxml2.elf"
binary = repo_root() / "test_libxml2.elf"
if not binary.is_file():
log.fatal(
"test_libxml2.elf not found.",
Expand All @@ -181,7 +214,7 @@ def _run_functional_standalone(self) -> None:
mkramfs = sysroot_path / "bin" / "mkramfs.elf"

# Bundle test_libxml2.elf + daemons into an initrd.
initrd = make_initrd(self, "test_libxml2.elf")
initrd = make_initrd(self, "test_libxml2.elf", test=True)

try:
with tempfile.TemporaryDirectory(prefix="nanvix_libxml2_") as tmpdir:
Expand Down Expand Up @@ -251,7 +284,7 @@ def _run_tests_windows(self) -> None:

test_allowlist = {"test_libxml2.elf"}
test_binaries: list[Path] = []
for candidate in [self.repo_root, self.repo_root / "build"]:
for candidate in [repo_root(), repo_root() / "build"]:
if candidate.is_dir():
for elf in sorted(candidate.glob("*.elf")):
if elf.name in test_allowlist and elf.name not in {
Expand All @@ -275,7 +308,7 @@ def _run_tests_windows(self) -> None:
# copy the ELF there temporarily unless it already lives there.
# This is a constraint of the make_initrd API; cleanup is
# handled in the finally block below.
repo_elf = self.repo_root / binary.name
repo_elf = repo_root() / binary.name
copied_elf = False
initrd: Path | None = None
try:
Expand All @@ -286,7 +319,7 @@ def _run_tests_windows(self) -> None:
)
shutil.copy2(binary, repo_elf)
copied_elf = True
initrd = make_initrd(self, binary.name)
initrd = make_initrd(self, binary.name, test=True)
with tempfile.TemporaryDirectory(prefix=f"nanvix_{name}_") as tmpdir:
tmpdir_path = Path(tmpdir)
ramfs_dir = tmpdir_path / "ramfs"
Expand Down Expand Up @@ -336,19 +369,14 @@ def _run_tests_windows(self) -> None:
raise RuntimeError(f"{len(failed)} test(s) failed: {msg}")
print(f"\t\t*** All {len(test_binaries)} tests PASSED ***")

def release(self) -> None:
"""Package the libxml2 release tarball and verify it."""
run(*self._make_args("package"), cwd=self.repo_root)
run(*self._make_args("verify-package"), cwd=self.repo_root)

def clean(self) -> None:
"""Remove build artifacts."""
run(
"make",
"-f",
".nanvix/Makefile.nanvix",
"clean",
cwd=self.repo_root,
cwd=repo_root(),
)


Expand Down
2 changes: 1 addition & 1 deletion .zutils-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.10.4
v0.11.0
22 changes: 1 addition & 21 deletions z.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ catch {
$null
}

# Extract --with-zutils PATH and --with-nanvix PATH before forwarding to
# nanvix-zutil.
# Extract --with-zutils PATH before forwarding to nanvix-zutil.
#
# --with-zutils PATH (optional): install nanvix-zutil from a local source
# tree (editable) instead of fetching the pinned wheel from GitHub Releases.
Expand All @@ -85,25 +84,6 @@ while ($i -lt $ZArgs.Count) {
$withZutils = $Matches[1]
$i++
}
elseif ($ZArgs[$i] -eq '--with-nanvix') {
if ($i + 1 -ge $ZArgs.Count) {
throw "ERROR: --with-nanvix requires a path argument"
}
$item = Get-Item -LiteralPath $ZArgs[$i + 1] -ErrorAction Stop
if (-not $item.PSIsContainer) {
throw "ERROR: --with-nanvix path is not a directory: $($ZArgs[$i + 1])"
}
$env:WITH_NANVIX = $item.FullName
$i += 2
}
elseif ($ZArgs[$i] -match '^--with-nanvix=(.+)$') {
$item = Get-Item -LiteralPath $Matches[1] -ErrorAction Stop
if (-not $item.PSIsContainer) {
throw "ERROR: --with-nanvix path is not a directory: $($Matches[1])"
}
$env:WITH_NANVIX = $item.FullName
$i++
}
else {
$filteredArgs.Add($ZArgs[$i])
$i++
Expand Down
Loading
Loading