# See https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
# for implicit variables and their default values

# See https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html
# for a list of built-in rules
# or use make -p (in a folder wihtout makefile)

# ------ IMPLICIT VARIABLES ----------

# C compiler
CC = gcc
# extra flags to give to the C compiler
CFLAGS = -Wall -Wextra -O2

# archiver
# it defaults to ar - a utility used (currently) mostly for creating and managing c/c++ static libraries  
# this line should be ommitted
AR = ar

# extra flags to give to the archiver
# it defaults to rv
# r - replace/add
# v - verbose output
# c - create archive without warning if it does not exist
# s - symbol table is created
ARFLAGS = rcs

# extra flags to give to compiler when is is supposed to invoke the linker
# -L - paths where the linker searches for libraries 
LDFLAGS = -L.

# ------ USER DEFINED VARIABLES --------

# final executable name
EXECUTABLE = myprogram

# source file(s) and mapping to object files 
MAIN_SRC = main.c
MAIN_OBJ = $(MAIN_SRC:.c=.o)

# library names
SHARED_LIB_NAME = mylib_shared
STATIC_LIB_NAME = mylib_static

# library source files and mapping to object files 
# (there may be multiple sources for a library)
SHARED_LIB_SRC = $(SHARED_LIB_NAME).c
STATIC_LIB_SRC = $(STATIC_LIB_NAME).c

SHARED_LIB_OBJ = $(SHARED_LIB_SRC:.c=.o)
STATIC_LIB_OBJ = $(STATIC_LIB_SRC:.c=.o)

# library output names
# it is a linux convention to prefix libraries with "lib"
SHARED_LIB_OUTPUT = lib$(SHARED_LIB_NAME).so  
STATIC_LIB_OUTPUT = lib$(STATIC_LIB_NAME).a

# -Wl,-rpath,. tells the linker to include current directory to rpath
RPATH_FLAG = -Wl,-rpath,.

# ----------- RULES --------------------

# a rule is of the form:
#
# target … : prerequisites …
#        recipe
#        …
#        …

# phony targets = targets not associated with a file
# if the target is explicitely marked as phony, conflicts with a file of the same name are avoided
.PHONY : all clean

# the first rule is the default one
all: $(EXECUTABLE)

# compile sources
# $< - prerequisite
# $@ - target
# PIC - position-independent code, necessary for shared libraries
$(MAIN_OBJ): $(MAIN_SRC)
	$(CC) $(CFLAGS) -c $< -o $@
$(STATIC_LIB_OBJ): $(STATIC_LIB_SRC)
	$(CC) $(CFLAGS) -c $< -o $@
$(SHARED_LIB_OBJ): $(SHARED_LIB_SRC)
	$(CC) $(CFLAGS) -fPIC -c $< -o $@

# create static library
# ar - Linux archiver utility
$(STATIC_LIB_OUTPUT): $(STATIC_LIB_OBJ)
	$(AR) $(ARFLAGS) $@ $^

# create dynamic library
# compiler is called, with -shared option
$(SHARED_LIB_OUTPUT): $(SHARED_LIB_OBJ)
	$(CC) -shared $^ -o $@

# link
# -L. tells the linker to search for libraries in current dir
# libraries are provided directly via exact filenames - alternatively, -l option can be used (LDLIBS implicit variable)
$(EXECUTABLE): $(MAIN_OBJ) $(STATIC_LIB_OUTPUT) $(SHARED_LIB_OUTPUT)
	$(CC) $(LDFLAGS) $(MAIN_OBJ)  $(STATIC_LIB_OUTPUT) $(SHARED_LIB_OUTPUT) -o $@  $(RPATH_FLAG)

# RM is an implicit variable that defaults to rm -f
clean:
	$(RM) $(EXECUTABLE) $(MAIN_OBJ) $(STATIC_LIB_OUTPUT) $(SHARED_LIB_OUTPUT) $(STATIC_LIB_OBJ) $(SHARED_LIB_OBJ) 