forked from chrisarg/Bit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
235 lines (196 loc) · 6.87 KB
/
Makefile
File metadata and controls
235 lines (196 loc) · 6.87 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
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
IS_CLEAN_GOAL := $(filter clean distclean,$(MAKECMDGOALS))
# Ensure plain `make` builds the libraries (not the first internal target).
.DEFAULT_GOAL := all
# Check for available compilers if user hasn't specified one
ifeq ($(origin CC),default)
ifeq ($(IS_CLEAN_GOAL),)
$(info Default compiler not set, checking for available compilers...)
# Check for gcc first
ifneq ($(shell which gcc 2>/dev/null),)
$(info Using gcc to compile)
CC=gcc
# Then check for clang
else ifneq ($(shell which clang 2>/dev/null),)
$(info Using clang to compile)
CC=clang
# Check for icx
else ifneq ($(shell which icx 2>/dev/null),)
$(info Using icx to compile)
CC=icx
endif
else
# For clean-only invocations we don't need compiler discovery.
CC=gcc
endif
endif
ifeq ($(origin GPU),undefined)
ifeq ($(IS_CLEAN_GOAL),)
$(info Default GPU offload not set, will set to NVIDIA)
GPU=NVIDIA
else
# For clean-only invocations, pick a quiet, valid default.
GPU=NONE
endif
endif
# Convert GPU to uppercase for case-insensitive comparison
GPU := $(shell echo $(GPU) | tr a-z A-Z)
# check to see if the CC is one of icx, clang, or gcc
# Skip validation/messages for clean-only invocations.
ifeq ($(IS_CLEAN_GOAL),)
ifneq ($(filter $(CC),gcc clang icx),)
$(info CC is set to $(CC), which is a supported compiler)
else
$(error CC=$(CC) is not one of the supported compilers (gcc, clang, icx))
endif
endif
## additional flags
DEFINES ?=
# Set the appropriate OpenMP flag based on compiler
ifeq ($(CC),gcc)
OPENMP_FLAG = -fopenmp
else ifeq ($(CC),g++)
OPENMP_FLAG = -fopenmp
else ifeq ($(CC),clang)
OPENMP_FLAG = -fopenmp
else
# For clang, icx, icc
OPENMP_FLAG = -qopenmp
endif
ifeq ($(IS_CLEAN_GOAL),)
$(info GPU is set to $(GPU))
endif
#Set the appropriate offload flag based on GPU type
ifeq ($(GPU),NONE)
ifeq ($(CC),gcc)
OFFLOAD_FL = -foffload=disable
else
OFFLOAD_FL =
endif
DEFINES += -DNOGPU
else ifeq ($(GPU),NVIDIA)
ifeq ($(CC),gcc)
OFFLOAD_FL = -fno-stack-protector -fcf-protection=none -foffload=nvptx-none
else ifeq ($(CC),clang)
OFFLOAD_FL = -fopenmp-targets=nvptx64 -foffload-lto
else ifeq ($(CC),icx)
OFFLOAD_FL = -fopenmp-targets=nvptx64-nvidia-cuda
endif
else ifeq ($(GPU),AMD)
ifeq ($(CC),gcc)
OFFLOAD_FL = -foffload=amdgcn-amd-amdhsa
else ifeq ($(CC),clang)
OFFLOAD_FL = -foffload=amdgcn-amd-amdhsa
else ifeq ($(CC),icx)
OFFLOAD_FL = -foffload=amdgcn-amd-amdhsa
endif
else ifeq ($(GPU),INTEL)
$(info GPU is set to INTEL, so will use Intel oneAPI icx Compiler)
CC=icx
OPENMP_FLAG = -fiopenmp
OFFLOAD_FL = -fopenmp-targets=spir64
else
$(error GPU = $(GPU) is not one of the supported GPUs (NVIDIA, AMD, INTEL))
endif
# Allow custom build directory, default to 'build' folder
BUILD_DIR ?= build
# Ensure the build directory exists
$(shell mkdir -p $(BUILD_DIR))
## compiler flags
CFLAGS0 = -Wall -Wextra -Iinclude -std=c11 -fPIC -O3 -g3 -march=native \
-Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable
CFLAGS += $(DEFINES) $(OPENMP_FLAG) $(OFFLOAD_FL) $(CFLAGS0)
# Rebuild objects when toolchain/config changes.
# Make does not automatically notice changes to variables like GPU/CC/CFLAGS,
# so without this you can get a stale $(BUILD_DIR)/bit.o built with offload
# flags from a previous invocation.
.PHONY: FORCE
CONFIG_STAMP := $(BUILD_DIR)/.config.stamp
# Treat the config stamp as a temporary build artifact.
# This keeps `build/` clean; note it will be regenerated on the next `make`.
.INTERMEDIATE: $(CONFIG_STAMP)
$(CONFIG_STAMP): FORCE
@mkdir -p $(BUILD_DIR)
@{ \
echo "CC=$(CC)"; \
echo "GPU=$(GPU)"; \
echo "DEFINES=$(DEFINES)"; \
echo "OPENMP_FLAG=$(OPENMP_FLAG)"; \
echo "OFFLOAD_FL=$(OFFLOAD_FL)"; \
echo "CFLAGS=$(CFLAGS)"; \
} > $(CONFIG_STAMP).tmp
@cmp -s $(CONFIG_STAMP).tmp $(CONFIG_STAMP) 2>/dev/null || mv $(CONFIG_STAMP).tmp $(CONFIG_STAMP)
@rm -f $(CONFIG_STAMP).tmp
# Default to enabled
LIBPOPCNT ?= 1
# Convert to lowercase for case-insensitive comparison
LIBPOPCNT_LC := $(shell echo $(LIBPOPCNT) | tr A-Z a-z)
# Check if it's one of the "false" values
ifneq ($(filter $(LIBPOPCNT_LC),0 no n false f off),)
# LIBPOPCNT is disabled - don't add the flag
$(info libpopcnt integration disabled)
else
# LIBPOPCNT is enabled
CFLAGS += -DUSE_LIBPOPCNT
ifeq ($(filter clean test bench distclean,$(MAKECMDGOALS)),)
$(info Using libpopcnt for population count)
endif
endif
SRC = src/bit.c
OBJ = $(BUILD_DIR)/bit.o
# Change from static to shared library
TARGET = $(BUILD_DIR)/libbit.so
TARGET_STATIC = $(BUILD_DIR)/libbit.a
TEST_SRC = tests/test_bit.c
TEST_OBJ = $(BUILD_DIR)/test_bit.o
TEST_EXEC = $(BUILD_DIR)/test_bit
# Add benchmark source and executable
BENCH_SRC = benchmark/benchmark.c
BENCH_OBJ = $(BUILD_DIR)/benchmark.o
BENCH_EXEC = $(BUILD_DIR)/benchmark
# Add OpenMP benchmark source and executable
BENCH_OMP_SRC = benchmark/openmp_bit.c
BENCH_OMP_OBJ = $(BUILD_DIR)/openmp_bit.o
BENCH_OMP_EXEC = $(BUILD_DIR)/openmp_bit
BENCH_OMP_NO_GPU_SRC = benchmark/openmp_bit_nogpu.c
BENCH_OMP_GPU_OBJ = $(BUILD_DIR)/openmp_bit_nogpu.o
BENCH_OMP_GPU_EXEC = $(BUILD_DIR)/openmp_bit_nogpu
.PHONY: all clean test bench LIBPOPCNT
# Default targets are to build the shared and static libraries
all: $(TARGET) $(TARGET_STATIC)
# Rule to build object files in the build directory
$(BUILD_DIR)/%.o: src/%.c $(CONFIG_STAMP)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o: tests/%.c $(CONFIG_STAMP)
$(CC) $(CFLAGS) -c $< -o $@
# Add pattern rule for benchmark source files
$(BUILD_DIR)/%.o: benchmark/%.c $(CONFIG_STAMP)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/openmp_bit.o: benchmark/openmp_bit.c $(CONFIG_STAMP)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/openmp_bit_nogpu.o: benchmark/openmp_bit_nogpu.c $(CONFIG_STAMP)
$(CC) $(CFLAGS) -c $< -o $@
# Change from static to shared library compilation
$(TARGET): $(OBJ)
$(CC) $(CFLAGS) -shared -o $@ $^ $(LDFLAGS)
# Build the static library as well
$(TARGET_STATIC): $(OBJ)
$(AR) rcs $@ $^
# Update test to use shared library
test: $(TARGET) $(TEST_OBJ)
$(CC) $(CFLAGS) -o $(TEST_EXEC) $(TEST_OBJ) -L$(BUILD_DIR) -Wl,-rpath,$(shell pwd)/$(BUILD_DIR) -lbit
# Add target to build the benchmark executable and the OpenMP benchmark
bench: $(TARGET) $(BENCH_OBJ) bench_omp
$(CC) $(CFLAGS) -o $(BENCH_EXEC) $(BENCH_OBJ) -L$(BUILD_DIR) -Wl,-rpath,$(shell pwd)/$(BUILD_DIR) -lbit -lrt
# Conditional bench_omp target based on GPU setting
ifeq ($(GPU),NONE)
bench_omp: $(TARGET) $(BENCH_OMP_GPU_OBJ)
$(CC) $(CFLAGS) -o $(BENCH_OMP_GPU_EXEC) $(BENCH_OMP_GPU_OBJ) -L$(BUILD_DIR) -Wl,-rpath,$(shell pwd)/$(BUILD_DIR) -lbit $(OPENMP_FLAG) -lrt
else
bench_omp: $(TARGET) $(BENCH_OMP_OBJ) $(BENCH_OMP_GPU_OBJ)
$(CC) $(CFLAGS) -o $(BENCH_OMP_EXEC) $(BENCH_OMP_OBJ) -L$(BUILD_DIR) -Wl,-rpath,$(shell pwd)/$(BUILD_DIR) -lbit $(OPENMP_FLAG) -lrt
$(CC) $(CFLAGS) -o $(BENCH_OMP_GPU_EXEC) $(BENCH_OMP_GPU_OBJ) -L$(BUILD_DIR) -Wl,-rpath,$(shell pwd)/$(BUILD_DIR) -lbit $(OPENMP_FLAG) -lrt
endif
clean:
@rm -rf $(BUILD_DIR)
# Additional target to clean everything including dependencies
distclean: clean