summaryrefslogtreecommitdiff
path: root/tests/Makefile.common
blob: d6c9bd60fc4a603bf3572904d0472f17a5c1a118 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# SPDX-License-Identifier: GPL-2.0-only

# This file contains common definitions, macros and targets for depthcharge
# unit-tests and screenshot utility. It requires list of defined variables:
# - src - source directory
# - testobj - build directory of tests
# - objutil - utility programs/libraries output directory

testsrc := $(top)/tests

cmockasrc := 3rdparty/cmocka
cmockaobj := $(objutil)/cmocka
coverage_dir := coverage_reports

CMOCKA_LIB := $(cmockaobj)/src/libcmocka.so

CMAKE := cmake
OBJCOPY ?= objcopy
OBJDUMP ?= objdump

TEST_DEFAULT_CONFIG ?= $(top)/configs/config.emulation_qemu_x86_i440fx
TEST_DOTCONFIG := $(testobj)/.config
TEST_KCONFIG_AUTOHEADER := $(testobj)/config.src.h
TEST_KCONFIG_AUTOCONFIG := $(testobj)/auto.conf
TEST_KCONFIG_DEPENDENCIES := $(testobj)/auto.conf.cmd
TEST_KCONFIG_SPLITCONFIG := $(testobj)/config/
TEST_KCONFIG_TRISTATE := $(testobj)/tristate.conf

# Include order should be same as in real build
TEST_INCLUDES := -include $(src)/include/kconfig.h \
	-include $(src)/include/rules.h \
	-include $(src)/commonlib/bsd/include/commonlib/bsd/compiler.h

# Include generic test mock headers, before original ones
TEST_INCLUDES += -I$(testsrc)/include/mocks -I$(testsrc)/include

TEST_INCLUDES += -I$(src) -I$(src)/include -I$(src)/commonlib/include \
	-I$(src)/commonlib/bsd/include -I$(src)/arch/x86/include \
	-I$(top)/3rdparty/vboot/firmware/include

# Path for Kconfig autoheader
TEST_INCLUDES += -I$(dir $(TEST_KCONFIG_AUTOHEADER))

# Note: This is intentionally just a subset of the warnings in the toplevel
# Makefile.mk. We don't need to be as strict with test code, and things like
# -Wmissing-prototypes just make working with the test framework cumbersome.
# Only put conservative warnings here that really detect code that's obviously
# unintentional.
TEST_CFLAGS += -Wall -Werror -Wundef -Wstrict-prototypes -Wno-inline-asm
TEST_CFLAGS += -Wno-unknown-warning-option -Wno-source-mgr -Wno-main-return-type
TEST_CFLAGS += -Wno-array-compare -Wno-packed-not-aligned -Wno-trigraphs
TEST_CFLAGS += -Wno-unused-but-set-variables

TEST_CFLAGS += -std=gnu11 -ffunction-sections -fdata-sections -fno-builtin

ifneq ($(filter-out 0,$(DEBUG)),)
TEST_CFLAGS += -Og -ggdb3
else
TEST_CFLAGS += -Os
endif

TEST_CFLAGS += -D__TEST__ -D__COREBOOT__

ifneq ($(filter-out 0,$(TEST_PRINT)),)
TEST_CFLAGS += -DTEST_PRINT=1
endif

TEST_LDFLAGS += -Wl,--gc-sections

# Some memlayout symbols don't work with userspace relocation -- disable it.
TEST_CFLAGS += -fno-pie -fno-pic
TEST_LDFLAGS += -no-pie

# Extra attributes for unit tests, declared per test
#   srcs              - sources linked with coreboot libc symbols
#   syssrcs           - sources linked with system libc, no coreboot includes
#   cflags            - attribute with additional CFLAGS
#   config            - Kconfig and defines override (`gcc -D` style)
#   mocks             - list of symbols to mock
#   no_test_framework - set to `1` not to link test framework
#   stage             - name of stage e.g. romstage, bootblock, etc.
attributes := srcs syssrcs cflags config mocks no_test_framework stage

# Copy attributes of one test to another.
# $1 - input test name
# $2 - output test name
copy-test = $(foreach attr,$(attributes), \
		$(eval $(strip $(2))-$(attr) := $($(strip $(1))-$(attr))))

# Create actual targets for unit test binaries
# $1 - test name
define TEST_CC_template

# Generate custom config.h redefining given config symbols, and declaring mocked
# functions weak. It is important that the compiler already sees that they are
# weak (and they aren't just turned weak at a later stage) to prevent certain
# optimizations that would break if the function gets replaced. (For clang this
# file needs to be marked `system_header` to prevent it from warning about
# #pragma weak entries without a matching function declaration, since there's no
# -Wno-xxx command line option for that.)
$(1)-config-file := $(testobj)/$(1)/config.h
$$($(1)-config-file): $(TEST_KCONFIG_AUTOHEADER)
	mkdir -p $$(dir $$@)
	printf '// File generated by tests/Makefile.mk\n// Do not change\n' > $$@
	printf '#include <%s>\n\n' "$(notdir $(TEST_KCONFIG_AUTOHEADER))" >> $$@
	for kv in $$($(1)-config); do \
		key="`echo $$$$kv | cut -d '=' -f -1`"; \
		value="`echo $$$$kv | cut -d '=' -f 2-`"; \
		printf '#undef %s\n' "$$$$key" >> $$@; \
		printf '#define %s %s\n\n' "$$$$key" "$$$$value" >> $$@; \
	done
	printf '#ifdef __clang__\n' >> $$@;
	printf '#pragma clang system_header\n' >> $$@;
	printf '#endif\n' >> $$@;
	printf '#ifdef __TEST_SRCOBJ__\n' >> $$@;
	for m in $$($(1)-mocks); do \
		printf '#pragma weak %s\n' "$$$$m" >> $$@; \
	done
	printf '#endif\n' >> $$@;

$($(1)-objs): TEST_CFLAGS += -I$$(dir $$($(1)-config-file)) \
	-D__$$(shell echo $$($(1)-stage) | tr '[:lower:]' '[:upper:]')__ \
	-D__TEST_NAME__=\"$(subst /,_,$(1))\" \
	-D__TEST_DATA_DIR__=\"$(testsrc)/data\"

# Give us a way to distinguish between coreboot source files and test files in code.
$($(1)-srcobjs): TEST_CFLAGS += -D__TEST_SRCOBJ__

# Add coreboot, vboot, kconfig etc. includes only to non-system libc linked objects
$(filter-out $($(1)-sysobjs),$($(1)-objs)): TEST_CFLAGS += $(TEST_INCLUDES)

# Compile sources and apply mocking/wrapping of selected symbols.
# For each listed mock add new symbol with prefix `__real_`,
# and pointing to the same section:address.
$($(1)-objs): $(testobj)/$(1)/%.o: $$$$*.c $$($(1)-config-file)
	mkdir -p $$(dir $$@)
	$(HOSTCC) $(HOSTCFLAGS) $$(TEST_CFLAGS) $$(TEST_INCLUDES) $($(1)-cflags) -MMD \
		-MF $$(basename $$@).d -MT $$@ -c $$< -o $$@.orig
	objcopy_wrap_flags=''; \
	for sym in $$($(1)-mocks); do \
		sym_line="$$$$($(OBJDUMP) -t $$@.orig \
			| grep -E "[0-9a-fA-F]+\\s+w\\s+F\\s+.*\\s$$$$sym$$$$")"; \
		if [ ! -z "$$$$sym_line" ] ; then \
			addr="$$$$(echo "$$$$sym_line" | awk '{ print $$$$1 }')"; \
			section="$$$$(echo "$$$$sym_line" | awk '{ print $$$$(NF - 2) }')"; \
			objcopy_wrap_flags="$$$$objcopy_wrap_flags --add-symbol __real_$$$${sym}=$$$${section}:0x$$$${addr},function,global"; \
		fi \
	done ; \
	$(OBJCOPY) $$@.orig $$$$objcopy_wrap_flags $$@

# Compile system-side sources linked with system libc, without mocking symbols
# or code-under-test includes.
$($(1)-sysobjs): $(testobj)/$(1)/%.o: $$$$*.c $$($(1)-config-file)
	mkdir -p $$(dir $$@)
	$(HOSTCC) $(HOSTCFLAGS) $$(TEST_CFLAGS) $($(1)-cflags) -MMD \
		-MF $$(basename $$@).d -MT $$@ -c $$< -o $$@

# Link against Cmocka if not disabled
ifeq ($(strip $(filter-out 0 n no,$($(1)-no_test_framework))),)
$($(1)-objs): TEST_CFLAGS += -I$(cmockasrc)/include
$($(1)-bin): TEST_LDFLAGS += -L$(cmockaobj)/src -lcmocka -Wl,-rpath=$(cmockaobj)/src
$($(1)-bin): TEST_CFLAGS += -I$(cmockasrc)/include
$($(1)-bin): $(CMOCKA_LIB)
endif

$($(1)-bin): $($(1)-objs) $($(1)-sysobjs)
	$(HOSTCC) $$^ $($(1)-cflags) $$(TEST_LDFLAGS) -o $$@

endef

# Build cmocka
$(CMOCKA_LIB):
	echo "*** Building CMOCKA ***"
	mkdir -p $(cmockaobj)
	cd $(cmockaobj) && $(CMAKE) $(abspath $(cmockasrc))
	$(MAKE) -C $(cmockaobj)

# Kconfig targets
$(TEST_DOTCONFIG):
	mkdir -p $(dir $@)
	cp $(TEST_DEFAULT_CONFIG) $(TEST_DOTCONFIG)

# Don't override default Kconfig variables, since this will affect all
# Kconfig targets. Change them only when calling sub-make instead.
$(TEST_KCONFIG_AUTOHEADER): TEST_KCONFIG_FLAGS := DOTCONFIG=$(TEST_DOTCONFIG) \
        KCONFIG_AUTOHEADER=$(TEST_KCONFIG_AUTOHEADER) \
        KCONFIG_AUTOCONFIG=$(TEST_KCONFIG_AUTOCONFIG) \
        KCONFIG_DEPENDENCIES=$(TEST_KCONFIG_DEPENDENCIES) \
        KCONFIG_SPLITCONFIG=$(TEST_KCONFIG_SPLITCONFIG) \
        KCONFIG_TRISTATE=$(TEST_KCONFIG_TRISTATE) \
        KBUILD_DEFCONFIG=$(TEST_DEFAULT_CONFIG)

$(TEST_KCONFIG_AUTOHEADER): $(TEST_DOTCONFIG)
	mkdir -p $(dir $@)
	$(MAKE) $(TEST_KCONFIG_FLAGS) olddefconfig
	$(MAKE) $(TEST_KCONFIG_FLAGS) syncconfig

$(TEST_KCONFIG_AUTOCONFIG): $(TEST_KCONFIG_AUTOHEADER)
	true

TEST_COMMON_DEPENDENCIES := $(CMOCKA_LIB) $(TEST_KCONFIG_AUTOCONFIG)