Skip to content
Closed
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
3 changes: 1 addition & 2 deletions .github/workflows/nanvix-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@
jobs:
ci:
if: github.event_name != 'schedule'
uses: nanvix/workflows/.github/workflows/nanvix-ci.yml@v2.0.2
uses: nanvix/workflows/.github/workflows/nanvix-ci.yml@v2.2.0
with:
zutil-version: "v0.10.2"
docker-image: "ghcr.io/nanvix/toolchain-gcc@sha256:ea33e4cae4041dcf55f0ec49f58de90ae1b5e9fb7c3c507971b40975b14aecd3" # yamllint disable-line rule:line-length

Check warning on line 37 in .github/workflows/nanvix-ci.yml

View workflow job for this annotation

GitHub Actions / ci / Format & Lint

37:124 [comments] too few spaces before comment
platforms: '["microvm"]'
memory-sizes: '["128mb"]'
windows-matrix-exclude: '[]'
Expand Down
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
2 changes: 1 addition & 1 deletion .nanvix/nanvix.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "posix-tests"
version = "0.1.0"
nanvix-version = "0.15.26"
nanvix-version = "0.16.17"

[builds]
[builds.matrix]
Expand Down
118 changes: 63 additions & 55 deletions .nanvix/z.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import shutil
import subprocess
import sys
import tarfile
import tempfile
import urllib.request
import zipfile
Expand All @@ -40,6 +39,11 @@
run,
)
from nanvix_zutil.helpers import InitRdArgs
from nanvix_zutil.paths import (
bin_out,
nanvix_root,
repo_root,
)

# ---------------------------------------------------------------------------
# Platform detection
Expand All @@ -63,6 +67,7 @@
"c-bindings",
"dlfcn-c",
"dlfcn-global-c",
"dlfcn-init-runpath-c",
"dlfcn-needed-c",
"dlfcn-pie-c",
"echo-c",
Expand Down Expand Up @@ -97,6 +102,7 @@
# Suites that require ramfs-bundled shared libraries and only run in standalone mode.
STANDALONE_ONLY_SUITES = [
"dlfcn-c",
"dlfcn-init-runpath-c",
"dlfcn-pie-c",
]

Expand All @@ -109,6 +115,11 @@
# Maps suite name to a list of (source_filename_in_build_dir, ramfs_target_path).
SUITE_RAMFS_LIBS: dict[str, list[tuple[str, str]]] = {
"dlfcn-c": [("libmul.so", "lib/libmul.so")],
"dlfcn-init-runpath-c": [
("libctor.so", "lib/libctor.so"),
("libparent.so", "lib/libparent.so"),
("libchild.so", "lib/subdir/libchild.so"),
],
"dlfcn-pie-c": [("libmul-pie.so", "lib/libmul-pie.so")],
}

Expand Down Expand Up @@ -165,11 +176,11 @@ class PosixTestsBuild(ZScript):
# ---- CLI entry point -------------------------------------------------

@classmethod
def main(cls, *, repo_root: Path | None = None) -> None:
def main(cls) -> None:
"""Pre-parse ``--with-nanvix`` and delegate to ZScript.main()."""
if _EARLY_LOCAL_NANVIX is not None:
cls._local_nanvix_path = _EARLY_LOCAL_NANVIX
super().main(repo_root=repo_root)
super().main()

# ---- Local Nanvix overlay --------------------------------------------

Expand Down Expand Up @@ -319,7 +330,7 @@ def setup(self) -> bool:

from nanvix_zutil import Sysroot

sysroot_dir = self.nanvix_dir / "sysroot"
sysroot_dir = nanvix_root() / "sysroot"
if sysroot_dir.exists():
shutil.rmtree(sysroot_dir)
sysroot_dir.mkdir(parents=True)
Expand Down Expand Up @@ -405,7 +416,31 @@ def build(self) -> None:
if IS_WINDOWS or not self._has_native_toolchain():
self._docker_build()
else:
run(*self._make_args("all"), cwd=self.repo_root, docker=self.docker)
run(*self._make_args("all"), cwd=repo_root(), docker=self.docker)
self._stage_release_outputs()

def _stage_release_outputs(self) -> None:
"""Mirror build/<suite>.elf into bin_out() for the inherited release().

The inherited ``ZScript.release()`` packages ``release_dir()``
into ``dist_dir()``; copying the per-suite ELFs into
``bin_out()`` is what makes them appear in the tarball. Missing
suites are tolerated here (the docker build may produce a subset
on some hosts); the tarball will simply omit them and any
downstream consumer can fail loudly.
"""
build_dir = repo_root() / "build"
if not build_dir.is_dir():
return
dest = bin_out()
dest.mkdir(parents=True, exist_ok=True)
copied = 0
for suite in ALL_SUITES:
src = build_dir / f"{suite}.elf"
if src.is_file():
shutil.copy2(src, dest / src.name)
copied += 1
log.info(f"Staged {copied} test ELFs under {dest}")

def test(self) -> None:
"""Run the POSIX test suites.
Expand All @@ -417,58 +452,28 @@ def test(self) -> None:
self._run_tests_native()

def release(self) -> None:
"""Package the posix-tests release tarball and verify it."""
"""Package the posix-tests release tarball.

Staging happens in ``build()``; this override only short-circuits
on Windows (no release packaging supported) and delegates to the
inherited ``ZScript.release()`` everywhere else.
"""
self._overlay_local_nanvix()
if IS_WINDOWS:
log.warning("Release packaging is not supported on Windows.")
log.warning("Use a Linux host or CI to build release tarballs.")
return

build_dir = self.repo_root / "build"
dist_dir = self.repo_root / "dist"
dist_dir.mkdir(parents=True, exist_ok=True)

artifact = (
f"posix-tests-{self.config.machine}-{self.config.deployment_mode}"
f"-{self.config.memory_size}.tar.gz"
)
tarball = dist_dir / artifact

log.info("Packaging release...")
missing = [s for s in ALL_SUITES if not (build_dir / f"{s}.elf").is_file()]
if missing:
log.fatal(
f"Missing test binaries: {', '.join(missing)}",
code=EXIT_MISSING_DEP,
hint="Run `./z build` first.",
)

with tarfile.open(tarball, "w:gz") as tf:
for suite in ALL_SUITES:
src = build_dir / f"{suite}.elf"
tf.add(src, arcname=f"{suite}.elf")
log.info(f"Package: {tarball}")

log.info("Verifying package...")
with tarfile.open(tarball, "r:gz") as tf:
names = set(tf.getnames())
for suite in ALL_SUITES:
if f"{suite}.elf" not in names:
log.fatal(
f"Missing {suite}.elf in package",
code=EXIT_MISSING_DEP,
)
log.success(f"Package verified: {tarball}")
super().release()

def clean(self) -> None:
"""Remove build artifacts."""
if IS_WINDOWS:
build_dir = self.repo_root / "build"
build_dir = repo_root() / "build"
if build_dir.is_dir():
shutil.rmtree(build_dir)
log.info("Removed build/")
else:
run("make", "-C", "src", "clean", cwd=self.repo_root)
run("make", "-C", "src", "clean", cwd=repo_root())

# ---- Docker build ----------------------------------------------------

Expand All @@ -481,15 +486,15 @@ def _docker_build(self) -> None:
as Docker build args.
"""
docker_image = self._resolve_docker_image()
build_dir = self.repo_root / "build"
build_dir = repo_root() / "build"
build_dir.mkdir(exist_ok=True)

# Determine the sysroot path relative to the repo root.
# nanvix-zutil places files in .nanvix/sysroot/; the old 'make init'
# places them directly in .nanvix/. Pass the correct path so the
# Dockerfile can forward it to Make.
sysroot_rel = ".nanvix/sysroot"
if not (self.repo_root / sysroot_rel / "lib" / "libposix.a").is_file():
if not (repo_root() / sysroot_rel / "lib" / "libposix.a").is_file():
sysroot_rel = ".nanvix"

log.info(f"Building via Docker ({docker_image})...")
Expand All @@ -510,7 +515,7 @@ def _docker_build(self) -> None:
"--output",
"type=local,dest=build",
".",
cwd=self.repo_root,
cwd=repo_root(),
)

# Count produced binaries.
Expand All @@ -524,7 +529,7 @@ def _resolve_docker_image(self) -> str:
Falls back to the cached ``.docker-image`` file if present.
"""
# Check for cached .docker-image (from 'make init').
cached = self.repo_root / ".nanvix" / ".docker-image"
cached = repo_root() / ".nanvix" / ".docker-image"
if cached.is_file():
tag = cached.read_text().strip()
if tag:
Expand Down Expand Up @@ -560,7 +565,7 @@ def _run_tests_native(self) -> None:
code=EXIT_MISSING_DEP,
hint="Run `./z setup` first.",
)
build_dir = self.repo_root / "build"
build_dir = repo_root() / "build"

# --- Smoke tests ---
print("Running smoke tests...")
Expand Down Expand Up @@ -599,7 +604,7 @@ def _run_tests_standalone(
print(f"SKIP {suite}")
continue
print(f"RUN {suite}...")
repo_elf = self.repo_root / binary.name
repo_elf = repo_root() / binary.name
copied_elf = False
initrd: Path | None = None
try:
Expand All @@ -614,10 +619,13 @@ def _run_tests_standalone(
# misc-c.elf is a special case that needs the test
# environment variable set to pass its internal checks.
initrd = make_initrd(
self, binary.name, InitRdArgs(app_env=["NANVIX_TEST=1"])
self,
binary.name,
test=True,
args=InitRdArgs(app_env=["NANVIX_TEST=1"]),
)
else:
initrd = make_initrd(self, binary.name)
initrd = make_initrd(self, binary.name, test=True)
with tempfile.TemporaryDirectory(prefix=f"posix_test_{suite}_") as tmp:
tmp_path = Path(tmp)
ramfs_dir = tmp_path / "ramfs"
Expand Down Expand Up @@ -662,7 +670,7 @@ def _run_tests_standalone(
log.info(f"$ {' '.join(cmd)}")
subprocess.run(
cmd,
cwd=self.repo_root,
cwd=repo_root(),
stdin=subprocess.DEVNULL,
text=True,
check=True,
Expand Down Expand Up @@ -747,7 +755,7 @@ def _run_tests_non_standalone(
log.info(f"$ {' '.join(cmd)}")
subprocess.run(
cmd,
cwd=self.repo_root,
cwd=repo_root(),
stdin=subprocess.DEVNULL,
text=True,
check=True,
Expand Down Expand Up @@ -831,7 +839,7 @@ def _download_windows_binaries(self) -> None:
return

# Download to cache.
cache_dir = self.nanvix_dir / "cache"
cache_dir = nanvix_root() / "cache"
cache_dir.mkdir(parents=True, exist_ok=True)
zip_path = cache_dir / asset_name

Expand Down
1 change: 1 addition & 0 deletions .zutils-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v0.11.0
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ PROCESS_MODE ?= multi-process
MEMORY_SIZE ?= 128mb

# Test suites to build.
SUITES := c-bindings dlfcn-c dlfcn-pie-c echo-c echo-cpp file-c hello-c hello-cpp memory-c misc-c network-c noop-c noop-cpp thread-c
SUITES := c-bindings dlfcn-c dlfcn-init-runpath-c dlfcn-pie-c echo-c echo-cpp file-c hello-c hello-cpp memory-c misc-c network-c noop-c noop-cpp thread-c

# ELF binaries produced by each suite.
BINARIES := $(addsuffix .elf,$(SUITES))
Expand Down
2 changes: 1 addition & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export LIBRARIES_DIR ?= $(BINARIES_DIR)
# Test Suites
#===============================================================================

SUITES := c-bindings dlfcn-c dlfcn-global-c dlfcn-needed-c dlfcn-pie-c echo-c echo-cpp file-c hello-c hello-cpp memory-c misc-c network-c noop-c noop-cpp thread-c
SUITES := c-bindings dlfcn-c dlfcn-global-c dlfcn-init-runpath-c dlfcn-needed-c dlfcn-pie-c echo-c echo-cpp file-c hello-c hello-cpp memory-c misc-c network-c noop-c noop-cpp thread-c

#===============================================================================
# Build Rules
Expand Down
44 changes: 44 additions & 0 deletions src/dlfcn-init-runpath-c/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright(c) The Maintainers of Nanvix.
# Licensed under the MIT License.
#
# dlfcn-init-runpath-c: Tests for `.init_array` / `.fini_array`
# constructor and destructor invocation, and for DT_RUNPATH-driven
# DT_NEEDED dependency search.

PROGRAM_NAME := dlfcn-init-runpath-c

SOURCES := $(wildcard *.c)
OBJECTS := $(SOURCES:.c=.o)
BINARY := $(PROGRAM_NAME).elf

all: $(OBJECTS) libs-all
$(CC) $(LDFLAGS) -pie -rdynamic -Wl,--no-dynamic-linker $(OBJECTS) $(LIBRARIES) -o $(BINARIES_DIR)/$(BINARY)

clean: libs-clean
rm -f $(OBJECTS)
rm -f $(BINARIES_DIR)/$(BINARY)

# libctor.so - constructor/destructor witness, used by the .init_array tests.
# libchild.so - dependency of libparent.so. Will be staged into
# lib/subdir/ at ramfs time so it is only reachable via
# libparent.so's DT_RUNPATH (z.py SUITE_RAMFS_LIBS).
# libparent.so - DT_NEEDED=libchild.so, DT_RUNPATH=lib/subdir/.
#
# `--enable-new-dtags` ensures the linker emits DT_RUNPATH (not the
# deprecated DT_RPATH) for libparent.so, matching what modern
# toolchains produce by default.
libs-all:
$(CC) libs/ctor.c -shared -fPIC -o $(LIBRARIES_DIR)/libctor.so
$(CC) libs/subdir/child.c -shared -fPIC -o $(LIBRARIES_DIR)/libchild.so
$(CC) libs/parent.c -shared -fPIC \
-L$(LIBRARIES_DIR) -lchild \
-Wl,--enable-new-dtags,-rpath,lib/subdir \
-o $(LIBRARIES_DIR)/libparent.so

libs-clean:
rm -f $(LIBRARIES_DIR)/libctor.so
rm -f $(LIBRARIES_DIR)/libchild.so
rm -f $(LIBRARIES_DIR)/libparent.so

%.o: %.c
$(CC) $(CFLAGS) -fPIE $< -c -o $@
Loading
Loading