Makefile 5.81 KB
# Wendelin.core | Instructions to build & test
# Copyright (C) 2014-2015  Nexedi SA and Contributors.
#                     	   Kirill Smelkov <>
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
# You can also Link and Combine this program with other software covered by
# the terms of any of the Open Source Initiative approved licenses and Convey
# the resulting work. Corresponding source of such a combination shall include
# the source code for all other software used.
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# See COPYING file for full licensing terms.
all	:

PYTHON	?= python
PYTEST	?= $(PYTHON) -m pytest
PYBENCH ?= $(PYTHON) t/py.bench
VALGRIND?= valgrind

# use the same C compiler as python
# (for example it could be `gcc -m64` on a 32bit userspace)
CC	:= $(shell $(PYTHON) -c "from __future__ import print_function;	\
		import sysconfig as _;	\
ifeq ($(CC),)
$(error "Cannot defermine py-CC")

all	: bigfile/

ccan_config := 3rdparty/ccan/config.h

bigfile/ : $(ccan_config) FORCE
	$(PYTHON) ll_build_ext --inplace


$(ccan_config): 3rdparty/ccan/Makefile
	$(MAKE) -C $(@D) $(@F)

# if there is no ccan/Makefile - ccan submodule has not been initialized
# if there is - it is ok, as that Makefile does not need to be rebuilt
	@echo 'E: 3rdparty/ccan submodule not initialized'
	@echo 'E: please do `git submodule update --init`'

# -*- testing -*-

# XXX dup with
CPPFLAGS:= -Iinclude -I3rdparty/ccan -I3rdparty/include
CFLAGS	:= -g -Wall -D_GNU_SOURCE -std=gnu99 -fplan9-extensions	\
	   -Wno-declaration-after-statement	\
	   -Wno-error=declaration-after-statement	\

# XXX hack ugly
LOADLIBES=lib/bug.c lib/utils.c 3rdparty/ccan/ccan/tap/tap.c
TESTS	:= $(patsubst %.c,%,$(wildcard bigfile/tests/test_*.c))
test	: test.t test.fault test.asan test.tsan test.vgmem test.vghel test.vgdrd

# TODO move XFAIL markers into *.c

# TSAN fails on test_virtmem (
# NOTE the bug was fixed in compiler-rt 20140917 (6afe775d)
#      -> we can remove this xfail when the fix propagates to gcc/clang release
XFAIL_bigfile/tests/test_virtmem.tsanrun	:= y

# Before calling our SIGSEGV handler, Memcheck first reports "invalid read|write" error.
# A solution could be to tell memcheck via VALGRIND_MAKE_MEM_DEFINED that VMA
# address space is ok to access _before_ handling pagefault.
XFAIL_bigfile/tests/test_virtmem.vgmemrun	:= y

# extract what goes after RUNWITH: marker from command source, or empty if no marker
runwith = $(shell grep -oP '(?<=^// RUNWITH: ).*' $(basename $1).c)

# run a test, not failing if failure is expected
xrun	= $1 $(if $(XFAIL_$@),|| echo "($@ - expected failure)")
XRUN<	= $(call xrun,$(call runwith,$<) $<)

LINKC	= $(LINK.c) $< $(LOADLIBES) $(LDLIBS) -o $@

# tests without instrumentation
test.t	: $(TESTS:%=%.trun)
%.trun	: %.t

%.t	: %.c $(ccan_config)

# test with AddressSanitizer
test.asan: $(TESTS:%=%.asanrun)
%.asanrun: %.asan

%.asan	: CFLAGS += -fsanitize=address
%.asan	: %.c $(ccan_config)

# test with ThreadSanitizer

# TSAN works only on x86_64
# (can't rely on `uname -m` - could have 32bit userspace on 64bit kernel)
ifneq ($(shell $(CPP) -dM - </dev/null | grep __x86_64__),)
test.tsan: $(TESTS:%=%.tsanrun)
%.tsanrun: %.tsan
	@echo "Skip $@	# ThreadSanitizer does not support \"`$(CC) -v 2>&1 | grep '^Target:'`\""

%.tsan	: CFLAGS += -fsanitize=thread -pie -fPIC
%.tsan	: %.c $(ccan_config)

# run valgrind so errors affect exit code
# TODO stop on first error
# (
#  but it still asks interactively, whether to "run debugger")
VALGRINDRUN  = $(VALGRIND) --error-exitcode=1

# to track memory access on each instruction (e.g. without this reads from NULL are ignored)
# XXX why =allregs-at-mem-access is not sufficient?
#     see "Handling of Signals" in
#     without this option our SIGSEGV handler is not always called
#     see also:
VALGRINDRUN += --vex-iropt-register-updates=allregs-at-each-insn

# like XRUN< for valgrind
vgxrun	= $(call xrun,$(call runwith,$2) $(VALGRINDRUN) $1 $2)

# test with valgrind/memcheck
test.vgmem: $(TESTS:%=%.vgmemrun)
%.vgmemrun: %.t
	$(call vgxrun,--tool=memcheck, $<)

# test with valgrind/helgrind
test.vghel: $(TESTS:%=%.vghelrun)
%.vghelrun: %.t
	$(call vgxrun,--tool=helgrind, $<)

# test with valgrind/drd
test.vgdrd: $(TESTS:%=%.vgdrdrun)
%.vgdrdrun: %.t
	$(call vgxrun,--tool=drd, $<)

# run python tests
PYTEST_IGNORE	:=  --ignore=3rdparty --ignore=build --ignore=t	: bigfile/

# via Valgrind (very slow) bigfile/
	$(call vgxrun,--tool=helgrind, $(PYTEST) $(PYTEST_IGNORE)) bigfile/
	$(call vgxrun,--tool=drd, $(PYTEST) $(PYTEST_IGNORE))

# test pagefault for double/real faults - it should crash
tfault	:= bigfile/tests/tfault
# XXX FAULTS extraction fragile
FAULTS	:= $(shell grep '{"fault.*"' $(tfault).c | sed 's/"/ /g' |awk '{print $$2}')
test.fault : $(FAULTS:%=%.tfault)

%.tfault : $(tfault).t
	t/tfault-run $< $* $(shell grep '{"$*"' $(tfault).c | awk '{print $$NF}')

# -*- benchmarking -*-
bench	: bigfile/