-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
142 lines (118 loc) · 4.8 KB
/
Copy pathMakefile
File metadata and controls
142 lines (118 loc) · 4.8 KB
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
# =============================================================================
# FP-ASM — portable build system
#
# Produces a linkable library (static + shared) from the x64 AVX2 assembly
# kernels and their C wrappers, for consumption by games / graphics projects.
#
# make # build static + shared libraries into build/
# make static # build build/libfpasm.a
# make shared # build build/libfpasm.so (.dll on Windows)
# make test # build and run the test suite
# make install # install headers + libs under PREFIX (default /usr/local)
# make clean
#
# Requirements: NASM (>=2.13) and a C11 compiler (gcc/clang). The kernels
# require a CPU with AVX2 + FMA.
# =============================================================================
LIB := fpasm
SRC_ASM := src/asm
SRC_DIRS := src/wrappers src/algorithms
INCLUDE := include
BUILD := build
OBJ := $(BUILD)/obj
PREFIX ?= /usr/local
# --- Platform / toolchain detection ------------------------------------------
UNAME_S := $(shell uname -s 2>/dev/null || echo Unknown)
ASM ?= nasm
CC ?= cc
AR ?= ar
# CPU features: the ASM needs AVX2; override ARCH= to retarget the C code.
ARCH ?= native
CFLAGS ?= -O3 -std=c11 -Wall -Wextra
CFLAGS += -I$(INCLUDE) -march=$(ARCH) -fPIC
ASMINC := -I$(SRC_ASM)/
ifneq (,$(findstring MINGW,$(UNAME_S))$(findstring MSYS,$(UNAME_S))$(findstring CYGWIN,$(UNAME_S)))
ASMFMT := win64
SHLIB_EXT := dll
LDLIBS :=
else ifeq ($(UNAME_S),Darwin)
ASMFMT := macho64
SHLIB_EXT := dylib
LDLIBS := -lm
else
ASMFMT := elf64
SHLIB_EXT := so
LDLIBS := -lm
endif
STATIC := $(BUILD)/lib$(LIB).a
SHARED := $(BUILD)/lib$(LIB).$(SHLIB_EXT)
# --- Sources / objects -------------------------------------------------------
ASM_SRCS := $(wildcard $(SRC_ASM)/*.asm)
C_SRCS := $(foreach d,$(SRC_DIRS),$(wildcard $(d)/*.c))
ASM_OBJS := $(patsubst %.asm,$(OBJ)/%.o,$(notdir $(ASM_SRCS)))
C_OBJS := $(patsubst %.c,$(OBJ)/%.o,$(notdir $(C_SRCS)))
OBJS := $(ASM_OBJS) $(C_OBJS)
# Let make find sources in their subdirectories.
vpath %.asm $(SRC_ASM)
vpath %.c $(SRC_DIRS)
TEST_SRCS := $(wildcard tests/test_*.c)
TEST_BINS := $(patsubst tests/%.c,$(BUILD)/%,$(TEST_SRCS))
# --- Targets -----------------------------------------------------------------
.PHONY: all static shared test bench showcase clean install dirs
all: static shared
static: $(STATIC)
shared: $(SHARED)
$(STATIC): $(OBJS) | dirs
$(AR) rcs $@ $(OBJS)
@echo " AR $@"
$(SHARED): $(OBJS) | dirs
$(CC) -shared -o $@ $(OBJS) $(LDLIBS)
@echo " LD $@"
$(OBJ)/%.o: %.asm | dirs
$(ASM) -f $(ASMFMT) $(ASMINC) $< -o $@
@echo " ASM $<"
$(OBJ)/%.o: %.c | dirs
$(CC) $(CFLAGS) -c $< -o $@
@echo " CC $<"
# --- Tests: link each tests/test_*.c against the static library --------------
test: $(STATIC) $(TEST_BINS)
@echo "== running tests =="; \
fail=0; for t in $(TEST_BINS); do \
echo "-- $$t --"; $$t || fail=1; \
done; \
if [ $$fail -eq 0 ]; then echo "== ALL TEST BINARIES PASSED =="; else echo "== SOME TESTS FAILED =="; exit 1; fi
$(BUILD)/%: tests/%.c $(STATIC) | dirs
$(CC) $(CFLAGS) $< $(STATIC) -o $@ $(LDLIBS)
BENCH_SRCS := $(wildcard benchmarks/bench_*.c)
BENCH_BINS := $(patsubst benchmarks/%.c,$(BUILD)/%,$(BENCH_SRCS))
# Benchmarks are compiled at -O3 -march=native so the scalar reference is
# autovectorized too (a fair comparison against the hand-written kernels).
bench: $(STATIC) $(BENCH_BINS)
@for b in $(BENCH_BINS); do echo "== $$b =="; $$b >/dev/null; done
$(BUILD)/bench_%: benchmarks/bench_%.c $(STATIC) | dirs
$(CC) -I$(INCLUDE) -O3 -march=native $< $(STATIC) -o $@ $(LDLIBS)
# Showcases: real algorithms written imperatively vs. composed from the library,
# verified equal and timed. Compiled -O3 -march=native so the imperative
# baseline is as fast as the compiler can make it.
SHOWCASE_SRCS := $(wildcard showcases/showcase_*.c)
SHOWCASE_BINS := $(patsubst showcases/%.c,$(BUILD)/%,$(SHOWCASE_SRCS))
showcase: $(STATIC) $(SHOWCASE_BINS)
@fail=0; for s in $(SHOWCASE_BINS); do echo "== $$s =="; $$s || fail=1; echo; done; \
if [ $$fail -eq 0 ]; then echo "== ALL SHOWCASES VERIFIED =="; else echo "== SHOWCASE MISMATCH =="; exit 1; fi
$(BUILD)/showcase_%: showcases/showcase_%.c $(STATIC) | dirs
$(CC) -I$(INCLUDE) -O3 -march=native $< $(STATIC) -o $@ $(LDLIBS)
dirs:
@mkdir -p $(OBJ)
install: all
@mkdir -p $(DESTDIR)$(PREFIX)/lib $(DESTDIR)$(PREFIX)/include/$(LIB)
cp $(STATIC) $(SHARED) $(DESTDIR)$(PREFIX)/lib/
cp $(INCLUDE)/*.h $(DESTDIR)$(PREFIX)/include/$(LIB)/
@echo "installed to $(DESTDIR)$(PREFIX)"
clean:
rm -rf $(BUILD)
# Diagnostics
.PHONY: info
info:
@echo "platform : $(UNAME_S) asm-format: $(ASMFMT) shlib: .$(SHLIB_EXT)"
@echo "asm srcs : $(words $(ASM_SRCS)) c srcs: $(words $(C_SRCS))"
@echo "tests : $(TEST_SRCS)"