all: environment

NPROC := $(shell nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || printf 1)
CCACHE_BIN := $(shell command -v ccache 2>/dev/null)
NINJA_BIN := $(shell command -v ninja 2>/dev/null)
TORCH_CUDA_ARCH_LIST ?= $(shell uv run python -c "import torch; major, minor = torch.cuda.get_device_capability(0); print(f'{major}.{minor}')" 2>/dev/null)

CUDA_LOCAL_FAST_CMAKE_ARGS := -DKF_WITH_CUDA=ON -DKF_USE_NATIVE=ON -DKF_BLAS_VENDOR=MKL -DKF_BLAS_ILP64=ON -DCMAKE_CUDA_ARCHITECTURES=native

ifneq ($(CCACHE_BIN),)
CUDA_LOCAL_FAST_CMAKE_ARGS += -DCMAKE_CXX_COMPILER_LAUNCHER=$(CCACHE_BIN) -DCMAKE_CUDA_COMPILER_LAUNCHER=$(CCACHE_BIN)
endif

ifneq ($(NINJA_BIN),)
CUDA_LOCAL_FAST_CMAKE_ARGS += -G Ninja
endif

# Default Linux builds use g++ (not icpx). Native = -march=native on x86.
install-linux:
	CC=gcc CXX=g++ CMAKE_ARGS="-DKF_USE_NATIVE=ON" uv pip install -e .[test,dev] --verbose

install-linux-ilp64:
	CC=gcc CXX=g++ CMAKE_ARGS="-DKF_USE_NATIVE=ON -DKF_BLAS_ILP64=ON" uv pip install -e .[test,dev] --verbose

install-linux-mkl:
	CC=gcc CXX=g++ CMAKE_ARGS="-DKF_USE_NATIVE=ON -DKF_BLAS_VENDOR=MKL" uv pip install -e .[test,dev] --verbose

install-linux-mkl-ilp64:
	CC=gcc CXX=g++ CMAKE_ARGS="-DKF_USE_NATIVE=ON -DKF_BLAS_VENDOR=MKL -DKF_BLAS_ILP64=ON" uv pip install -e .[test,dev] --verbose

install-linux-openblas:
	CC=gcc CXX=g++ CMAKE_ARGS="-DKF_USE_NATIVE=ON -DKF_BLAS_VENDOR=OpenBLAS" uv pip install -e .[test,dev] --verbose

install-linux-openblas-ilp64:
	CC=gcc CXX=g++ CMAKE_ARGS="-DKF_USE_NATIVE=ON -DKF_BLAS_VENDOR=OpenBLAS -DKF_BLAS_ILP64=ON" uv pip install -e .[test,dev] --verbose

# Optional Intel oneAPI build (explicit; not the default).
install-linux-mkl-icpx:
	CC=icx CXX=icpx CMAKE_ARGS="-DKF_USE_NATIVE=ON -DKF_BLAS_VENDOR=MKL" uv pip install -e .[test,dev] --verbose

install-linux-mkl-ilp64-cuda:
	@uv pip install 'torch>=2.2' || { \
	  echo "error: could not install torch (needed for KF_WITH_CUDA)."; \
	  exit 1; \
	}
	@uv run python -c "import torch; assert torch.cuda.is_available(), 'torch.cuda is not available'" || { \
	  echo "error: torch imported but CUDA is unavailable (check driver / torch CUDA build)."; \
	  exit 1; \
	}
	CUDA_HOME="$${CUDA_HOME:-/usr/local/cuda}" PATH="$${CUDA_HOME}/bin:$${PATH}" \
	TORCH_CUDA_ARCH_LIST="$${TORCH_CUDA_ARCH_LIST:-$(if $(TORCH_CUDA_ARCH_LIST),$(TORCH_CUDA_ARCH_LIST),12.0)}" \
	CMAKE_BUILD_PARALLEL_LEVEL="$(NPROC)" \
	CMAKE_ARGS="$(CUDA_LOCAL_FAST_CMAKE_ARGS)" \
	uv pip install -e .[test,dev] --verbose

# Build CPU + companion CUDA wheels into dist/ (split PyPI layout).
wheel-cpu:
	CMAKE_ARGS="-DKF_WITH_CUDA=OFF" uv build --wheel -o dist

wheel-cuda:
	uv pip install 'setuptools-scm>=8' scikit-build-core pybind11 setuptools wheel
	cd packaging/kernelforge-cuda && \
	TORCH_CUDA_ARCH_LIST="$${TORCH_CUDA_ARCH_LIST:-$(if $(TORCH_CUDA_ARCH_LIST),$(TORCH_CUDA_ARCH_LIST),12.0)}" \
	CMAKE_BUILD_PARALLEL_LEVEL="$(NPROC)" \
	CMAKE_ARGS="$(CUDA_LOCAL_FAST_CMAKE_ARGS) -DKF_CUDA_ONLY=ON" \
	uv build --wheel --no-build-isolation -o ../../dist

# Fresh-venv smoke: CPU wheel + companion wheel → import cuda_* modules.
# Override with e.g. DEMO_PYTHON=3.12 if needed; default is the active interpreter.
DEMO_PYTHON ?=
demo-cuda-wheels: wheel-cpu wheel-cuda
	rm -rf /tmp/kf-cuda-demo-venv
	uv venv /tmp/kf-cuda-demo-venv $(if $(DEMO_PYTHON),--python $(DEMO_PYTHON),)
	uv pip install --python /tmp/kf-cuda-demo-venv $$(ls -1 dist/kernelforge-*.whl | grep -v kernelforge_cuda | grep -v kernelforge-cuda | tail -1)
	uv pip install --python /tmp/kf-cuda-demo-venv --find-links dist 'kernelforge-cuda'
	/tmp/kf-cuda-demo-venv/bin/python packaging/kernelforge-cuda/smoke_imports.py

install-macos:
	CMAKE_ARGS="-DCMAKE_C_COMPILER=/opt/homebrew/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ -DKF_USE_NATIVE=ON " uv pip install -e .[test,dev] --verbose

install-macos-ilp64:
	CMAKE_ARGS="-DCMAKE_C_COMPILER=/opt/homebrew/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ -DKF_USE_NATIVE=ON -DKF_BLAS_ILP64=ON" uv pip install -e .[test,dev] --verbose

test:
	uv run pytest

environment:
	uv venv --python 3.14
	uv pip install scikit-build-core pybind11

check: format lint typecheck

lint: lint-python

lint-python:
	uv run ruff check python/ tests/

format: format-python format-cpp

format-python:
	uv run ruff format python/ tests/
	uv run ruff check --select I --fix python/ tests/

format-cpp:
	clang-format -i src/*.cpp src/*.hpp src/*.h

tidy:
	clang-tidy src/*.cpp src/*.hpp -- -std=c++17 -Isrc

typecheck:
	uv run ty check python/ tests/

clean:
	rm -rf ./.venv/
	rm -rf ./.ruff_cache/
	rm -rf ./.pytest_cache/
