Created
January 24, 2020 11:56
-
-
Save cwchentw/01040135fc810e51656af5b20eab9068 to your computer and use it in GitHub Desktop.
Cross-Platform Makefile for Library (Apache 2.0)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Detect underlying system. | |
ifeq ($(OS),Windows_NT) | |
detected_OS := Windows | |
else | |
detected_OS := $(shell sh -c 'uname -s 2>/dev/null || echo not') | |
endif | |
export detected_OS | |
# Set default C compiler. | |
# Clean implict CC variable. | |
CC= | |
ifndef CC | |
ifeq ($(detected_OS),Windows) | |
CC=cl | |
else ifeq ($(detected_OS),Darwin) | |
CC=clang | |
else | |
CC=gcc | |
endif | |
endif # CC | |
export CC | |
# Clean C_STD variable. | |
C_STD= | |
ifndef C_STD | |
ifeq ($(CC),cl) | |
C_STD= | |
else | |
C_STD=c11 | |
endif | |
endif # C_STD | |
export C_STD | |
# Set CFLAGS for Release target. | |
CFLAGS= | |
ifndef CFLAGS | |
ifeq ($(CC),cl) | |
CFLAGS=/W4 /sdl | |
else | |
CFLAGS:=-Wall -Wextra -std=$(C_STD) | |
endif | |
endif | |
# Set CFLAGS for Debug target. | |
ifneq (,$(DEBUG)) | |
ifeq ($(CC),cl) | |
CFLAGS+=/DDEBUG /Zi /Od | |
else | |
CFLAGS+=-DDEBUG -g -O0 | |
endif | |
else | |
ifeq ($(CC),cl) | |
CFLAGS+=/O2 | |
else | |
CFLAGS+=-O2 | |
endif | |
endif | |
export CFLAGS | |
# Set proper RM on Windows. | |
ifeq ($(detected_OS),Windows) | |
RM=del /q /f | |
endif | |
export RM | |
# Set proper path separator. | |
ifeq ($(detected_OS),Windows) | |
SEP=\\ | |
else | |
SEP=/ | |
endif | |
export SEP | |
# Set proper library name. | |
PROGRAM=mylib | |
ifeq ($(detected_OS),Windows) | |
ifeq ($(CC),cl) | |
DYNAMIC_LIB=$(PROGRAM).dll | |
else | |
DYNAMIC_LIB=lib$(PROGRAM).dll | |
endif # $(CC) | |
else | |
ifeq ($(detected_OS),Darwin) | |
DYNAMIC_LIB=lib$(PROGRAM).dylib | |
else | |
DYNAMIC_LIB=lib$(PROGRAM).so | |
endif # $(detected_OS),Darwin | |
endif # $(detected_OS),Windows | |
export DYNAMIC_LIB | |
ifeq ($(CC),cl) | |
STATIC_LIB=$(PROGRAM).lib | |
else | |
STATIC_LIB=lib$(PROGRAM).a | |
endif | |
export STATIC_LIB | |
# Add your own test programs as needed. | |
TEST_SOURCE=$(PROGRAM)_test.c | |
ifeq ($(CC),cl) | |
TEST_OBJS=$(TEST_SOURCE:.c=.obj) | |
else | |
TEST_OBJS=$(TEST_SOURCE:.c=.o) | |
endif | |
export TEST_OBJS | |
# Modify it if more than one source files. | |
SOURCE=$(PROGRAM:.exe=).c | |
# Set object files. | |
ifeq ($(CC),cl) | |
OBJS=$(SOURCE:.c=.obj) | |
else | |
OBJS=$(SOURCE:.c=.o) | |
endif # OBJS | |
export OBJS | |
# Set third-party include and library path | |
# Modify it as needed. | |
ifeq ($(CC),cl) | |
LDFLAGS= | |
LDLIBS= | |
else | |
LDFLAGS= | |
LDLIBS= | |
endif | |
export LDFLAGS | |
export LDLIBS | |
DYNAMIC := all test dynamic | |
.PHONY: all dynamic static clean | |
all: dynamic | |
test: dynamic | |
ifeq ($(detected_OS),Windows) | |
ifeq ($(CC),cl) | |
for %%x in ($(TEST_OBJS:.obj=.c)) do $(CC) $(CFLAGS) /I. /c %%x /link $(DYNAMIC_LIB:.dll=.lib) | |
for %%x in ($(TEST_OBJS)) do $(CC) %%x $(CFLAGS) /I. $(LDFLAGS) $(LDLIBS) /link $(DYNAMIC_LIB:.dll=.lib) | |
for %%x in ($(TEST_OBJS:.obj=.exe)) do .\%%x && if %%errorlevel%% neq 0 exit /b %%errorlevel%% | |
else | |
for %%x in ($(TEST_OBJS:.o=.c)) do $(CC) -c %%x $(CFLAGS) -I. | |
for %%x in ($(TEST_OBJS:.o=)) do $(CC) -o %%x.exe %%x.o $(CFLAGS) -I. -L. -lmylib $(LDFLAGS) $(LDLIBS) | |
for %%x in ($(TEST_OBJS:.o=.exe)) do .\%%x && if %%errorlevel%% neq 0 exit /b %%errorlevel%% | |
endif | |
else | |
for x in $(TEST_OBJS); do \ | |
$(CC) -c "$${x%.*}.c" -I. $(CFLAGS); \ | |
$(CC) -o "$${x%.*}" $(CFLAGS) $$x -I. -L. -lmylib $(LDFLAGS) $(LDLIBS); \ | |
LD_LIBRARY_PATH=. .$(SEP)"$${x%.*}"; \ | |
if [ $$? -ne 0 ]; then echo "Failed program state"; exit 1; fi \ | |
done | |
endif | |
testStatic: static | |
ifeq ($(detected_OS),Windows) | |
ifeq ($(CC),cl) | |
for %%x in ($(TEST_OBJS:.obj=.c)) do $(CC) /c %%x $(CFLAGS) /I. /link $(STATIC_LIB) | |
for %%x in ($(TEST_OBJS)) do $(CC) %%x $(CFLAGS) /I. $(LDFLAGS) $(LDLIBS) /link $(STATIC_LIB) | |
for %%x in ($(TEST_OBJS:.obj=.exe)) do .\%%x && if %%errorlevel%% neq 0 exit /b %%errorlevel%% | |
else | |
for %%x in ($(TEST_OBJS:.o=)) do -o %%x.exe %%x.c $(CC) $(CFLAGS) -I. -L. -lmylib $(LDFLAGS) $(LDLIBS) | |
for %%x in ($(TEST_OBJS:.o=.exe)) do .\%%x && if %%errorlevel%% neq 0 exit /b %%errorlevel%% | |
endif | |
else | |
for x in $(TEST_OBJS); do \ | |
$(CC) -c "$${x%.*}.c" $(CFLAGS) -I.; \ | |
$(CC) -o "$${x%.*}" $$x $(CFLAGS) -I. -L. -lmylib $(LDFLAGS) $(LDLIBS); \ | |
.$(SEP)"$${x%.*}"; \ | |
if [ $$? -ne 0 ]; then echo "Failed program state"; exit 1; fi \ | |
done | |
endif | |
dynamic: $(OBJS) | |
ifeq ($(detected_OS),Windows) | |
ifeq ($(CC),cl) | |
link /DLL /DEF:$(DYNAMIC_LIB:.dll=.def) /out:$(DYNAMIC_LIB) $(LDFLAGS) $(LDLIBS) $(OBJS) | |
else | |
$(CC) $(CFLAGS) -shared -o $(DYNAMIC_LIB) $(OBJS) -I. -L. $(LDFLAGS) $(LDLIBS) | |
endif | |
else | |
$(CC) $(CFLAGS) -shared -o $(DYNAMIC_LIB) $(OBJS) -I. -L. $(LDFLAGS) $(LDLIBS) | |
endif | |
static: $(OBJS) | |
ifeq ($(CC),cl) | |
lib /out:$(STATIC_LIB) $(OBJS) | |
else ifeq ($(detected_OS),Darwin) | |
libtool -static -o $(STATIC_LIB) $(OBJS) | |
else | |
$(AR) rcs $(STATIC_LIB) $(OBJS) | |
endif | |
%.obj: %.c | |
ifneq (,$(findstring $(MAKECMDGOALS),$(DYNAMIC))) | |
$(CC) /c $< $(CFLAGS) /MD | |
else | |
$(CC) /c $< $(CFLAGS) /MT | |
endif | |
%.o: %.c | |
ifneq (,$(findstring $(MAKECMDGOALS),$(DYNAMIC))) | |
$(CC) -c $< $(CFLAGS) -fPIC | |
else | |
$(CC) -c $< $(CFLAGS) | |
endif | |
clean: | |
$(RM) $(DYNAMIC_LIB) $(STATIC_LIB) $(OBJS) $(TEST_OBJS) | |
ifeq ($(detected_OS),Windows) | |
ifeq ($(CC),cl) | |
$(RM) $(TEST_OBJS:.obj=.exe) $(TEST_OBJS:.obj=.lib) $(TEST_OBJS:.obj=.exp) $(OBJS:.obj=.exp) $(OBJS:.obj=.lib) | |
else | |
$(RM) $(TEST_OBJS:.o=.exe) | |
endif | |
else | |
$(RM) $(TEST_OBJS:.o=) | |
endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment