diff --git a/c/Makefile b/c/Makefile index 9d63979..24e848e 100644 --- a/c/Makefile +++ b/c/Makefile @@ -88,7 +88,11 @@ CUDA_HOME ?= /usr/local/cuda NVCC ?= $(CUDA_HOME)/bin/nvcc CUDA_ARCH ?= native NVCCFLAGS ?= -O3 -std=c++17 -arch=$(CUDA_ARCH) -Xcompiler=-Wall,-Wextra +ifeq ($(IS_WIN),) PYTHON ?= python3 +else +PYTHON ?= python +endif CUDA_OBJ = TEST_BINS = tests/test_json$(EXE) tests/test_st$(EXE) tests/test_tier$(EXE) tests/test_grammar$(EXE) tests/test_decode_batch$(EXE) tests/test_idot$(EXE) tests/test_i4_acc512$(EXE) @@ -205,7 +209,7 @@ tests/test_i4_acc512$(EXE): tests/test_i4_acc512.c $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) test-c: $(TEST_BINS) - @for test in $(TEST_BINS); do ./$$test || exit 1; done + $(PYTHON) tools/run_tests.py $(TEST_BINS) test-python: $(PYTHON) -m unittest discover -s tests -p 'test_*.py' @@ -219,7 +223,6 @@ check: $(MAKE) test clean: - rm -f olmoe$(EXE) glm$(EXE) iobench$(EXE) backend_cuda.o backend_loader.o backend_cuda_test$(EXE) backend_cuda_bench$(EXE) backend_metal.o backend_metal_test coli_cuda.dll coli_cuda.lib coli_cuda.exp $(TEST_BINS) - rm -rf tests/__pycache__ + $(PYTHON) tools/clean.py .PHONY: all glm cuda-test cuda-bench cuda-dll portable test-c test-python test check clean diff --git a/c/tools/clean.py b/c/tools/clean.py new file mode 100644 index 0000000..463618f --- /dev/null +++ b/c/tools/clean.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +"""Remove build artifacts. Used by `make clean` so it works from any shell. + +Works from cmd.exe, PowerShell, Git Bash, or MSYS2 — no `rm` or POSIX +`for` loop required. Silently ignores files that don't exist. +""" +import glob +import os +import shutil + +# Files (relative to c/) to remove if present. +FILES = [ + "olmoe", "olmoe.exe", + "glm", "glm.exe", + "iobench", "iobench.exe", + "backend_cuda.o", "backend_loader.o", + "backend_cuda_test", "backend_cuda_test.exe", + "backend_cuda_bench", "backend_cuda_bench.exe", + "backend_metal.o", "backend_metal_test", + "coli_cuda.dll", "coli_cuda.lib", "coli_cuda.exp", +] +# Test binaries match this pattern. Only remove executables (.exe on Windows, +# no extension on Unix) — never .c or .py source files. +TEST_GLOBS = ["tests/test_*.exe"] +# Directories to remove. +DIRS = ["tests/__pycache__"] + +removed = 0 +for f in FILES: + if os.path.exists(f): + os.remove(f) + removed += 1 +for pattern in TEST_GLOBS: + for f in glob.glob(pattern): + os.remove(f) + removed += 1 +for d in DIRS: + if os.path.isdir(d): + shutil.rmtree(d) + removed += 1 +print(f"clean: removed {removed} files/dirs") diff --git a/c/tools/run_tests.py b/c/tools/run_tests.py new file mode 100644 index 0000000..e2c17ac --- /dev/null +++ b/c/tools/run_tests.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +"""Run C test binaries, exiting non-zero on the first failure. + +Used by `make test-c` so the test runner works from any shell (cmd.exe, +PowerShell, Git Bash, MSYS2) without a POSIX `for` loop. Each test binary +is a positional argument. +""" +import subprocess +import sys + +failed = [] +for binary in sys.argv[1:]: + rc = subprocess.call([binary]) + if rc != 0: + failed.append(binary) +if failed: + for f in failed: + print(f"FAILED: {f}", file=sys.stderr) + sys.exit(1)