Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Portable Makefile Demo
# Detect system OS.
ifeq ($(OS),Windows_NT)
detected_OS := Windows
else
detected_OS := $(shell sh -c 'uname -s 2>/dev/null || echo not')
endif
# Clean the default value of CC.
CC=
# Detect proper C compiler by system OS.
ifndef CC
ifeq ($(detected_OS),Windows)
CC=cl
else ifeq ($(detected_OS),Darwin)
CC=clang
else
CC=gcc
endif
endif
# Set proper CFLAGS by both CC and TARGET.
ifndef CFLAGS
ifeq ($(CC),cl)
ifeq ($(TARGET),Debug)
CFLAGS=/Wall /sdl /Zi
else
CFLAGS=/Wall /sdl
endif # TARGET
else ifeq ($(detected_OS),Darwin)
ifeq ($(TARGET),Debug)
# CFLAGS for debug.
ifeq ($(CC),clang)
CFLAGS=-O1 -Wall -Wextra -g -std=c99 -fsanitize=address -fno-omit-frame-pointer
else
CFLAGS=-Wall -Wextra -g -std=c99
endif # CC
else
# CFLAGS for release.
CFLAGS=-Wall -Wextra -O2 -std=c99
endif # TARGET
else
ifeq ($(TARGET),Debug)
CFLAGS=-Wall -Wextra -g -std=c99
else
CFLAGS=-Wall -Wextra -O2 -std=c99
endif # TARGET
endif # CC
endif
# Set proper RM for Windows.
ifeq ($(detected_OS),Windows)
RM=del
endif
# Clean the default value of LINT.
LINT=
ifndef LINT
LINT=cppcheck
endif
INCLUDE_DIR=include/algo
ifndef PREFIX
PREFIX=/usr/local
endif
MEM_CHECK=valgrind
# Set proper DYNAMIC_LIB by system OS.
ifeq ($(detected_OS),Windows)
ifeq ($(CC),cl)
DYNAMIC_LIB=algodequei.dll
else
DYNAMIC_LIB=libalgodequei.dll
endif
else ifeq ($(detected_OS),Darwin)
DYNAMIC_LIB=libalgodequei.dylib
else
DYNAMIC_LIB=libalgodequei.so
endif
# Set proper STATIC_LIB by system OS.
ifeq ($(CC),cl)
STATIC_LIB=algodequei.lib
else
STATIC_LIB=libalgodequei.a
endif
# Set proper TEST_PROG by system OS.
ifeq ($(detected_OS),Windows)
TEST_PROG=test_deque_int.exe
else
TEST_PROG=test_deque_int.out
endif
ifeq ($(CC),cl)
OBJS=deque_int.obj test_deque_int.obj
else
OBJS=deque_int.o test_deque_int.o
endif
.PHONY: all dynamic static memo test lint trim clean install uninstall
all: dynamic
# Compile dynamic library.
# We assume the task is for end user; hence, no presquite *trim* task.
dynamic:
ifeq ($(CC),cl)
$(CC) $(CFLAGS) /c deque_int.c
link /DLL /OUT:$(DYNAMIC_LIB) deque_int.obj
else
$(CC) $(CFLAGS) -fPIC -c deque_int.c
$(CC) -shared -o $(DYNAMIC_LIB) deque_int.o
endif
# Compile static library.
# We assume the task is for end user; hence, no presquite *trim* task.
static: deque_int.o
ifeq ($(CC),cl)
lib /out:$(STATIC_LIB) deque_int.obj
else
$(AR) rcs $(STATIC_LIB) deque_int.o
endif
# Check memory usage.
memo: $(TEST_PROG)
ifeq ($(detected_OS),Windows)
@echo "Not supported"
else ifeq ($(detected_OS),Darwin)
ASAN_OPTIONS=symbolize=1 ASAN_SYMBOLIZER_PATH=$(shell which llvm-symbolizer) ./$(TEST_PROG)
echo $$?
else
$(MEM_CHECK) ./$(TEST_PROG)
echo $$?
endif
# Run the test program.
test: $(TEST_PROG)
ifeq ($(detected_OS),Windows)
.\$(TEST_PROG)
echo %errorlevel%
else
./$(TEST_PROG)
echo $$?
endif
# Compile the test program.
$(TEST_PROG): trim $(OBJS)
ifeq ($(CC),cl)
$(CC) $(CFLAGS) /Fe:$(TEST_PROG) $(OBJS)
else
$(CC) $(CFLAGS) -o $(TEST_PROG) $(OBJS)
endif
# Pattern rule for Visual C++.
%.obj: %.c
$(CC) $(CFLAGS) /c $<
# Pattern rule for GCC and Clang.
%.o: %.c
$(CC) $(CFLAGS) -c $<
# Run static code analysis.
lint:
ifeq ($(detected_OS),Windows)
for %%x in (*.h) do $(LINT) "%%x"
for %%x in (*.c) do $(LINT) "%%x"
else
$(LINT) *.h *.c
endif
# Trim tailing spaces by Perl.
trim:
ifeq ($(detected_OS),Windows)
for %%x in (*.h) do perl -lp -i~ -e "s{\s+$$}{}g;" "%%x"
for %%x in (*.c) do perl -lp -i~ -e "s{\s+$$}{}g;" "%%x"
else
perl -lpi -e "s{\s+$$}{}g;" *
endif
clean:
$(RM) $(TEST_PROG) *.obj *.o *.lib *.a *.dll *.dylib *.so
# Assisted installation.
install: SHELL := /bin/bash
install:
ifeq ($(detected_OS),Windows)
@echo "Not supported"
else
mkdir -p $(PREFIX)/$(INCLUDE_DIR)
mkdir -p $(PREFIX)/lib
install -m 644 deque_int.h $(PREFIX)/$(INCLUDE_DIR)
for f in `ls *.a *.so *.dylib 2>/dev/null`; do \
if [ -f $$f ]; then \
install -m 644 $$f $(PREFIX)/lib; \
fi \
done
endif
# Assisted uninstallation.
uninstall: SHELL := /bin/bash
uninstall:
ifeq ($(detected_OS),Windows)
@echo "Not supported"
else
mkdir -p $(PREFIX)/$(INCLUDE_DIR)
mkdir -p $(PREFIX)/lib
$(RM) $(PREFIX)/$(INCLUDE_DIR)/deque_int.h
declare -a arr=("libalgodequei.a" "libalgodequei.so" "libalgodequei.dylib"); \
for f in "$${arr[@]}"; do \
$(RM) $(PREFIX)/lib/"$$f"; \
done
endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment