Skip to content

Instantly share code, notes, and snippets.

@cwchentw
Created January 24, 2020 11:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cwchentw/01040135fc810e51656af5b20eab9068 to your computer and use it in GitHub Desktop.
Save cwchentw/01040135fc810e51656af5b20eab9068 to your computer and use it in GitHub Desktop.
Cross-Platform Makefile for Library (Apache 2.0)
# 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