Makefile

Makefile


Files to make your automation of the project easy with defined targets , commands and rules.

compilation and building packaging and deploying tests and scripts automation Docker work and versioning

Q. build tools vs makefile ? ans. - similar but not made for the specific tasks or framework.

syntax

targets : prerequisites commands

essence of dependencies

	compile:
		cc blah.c -o blah

evry make will run the process again . but we dont want until we have changed the c file , so use as dependency. But but but ….

Putting the target name as compiled file name –

blah.o: blah.c
echo "compiling the file"
cc blah.c -o blah.o

Targets



automatice variables -

hey: one two 
	# Outputs "hey", since this is the target name 
	echo $@
	# Outputs all prerequisites newer than the target 
	echo $? 
	# Outputs all prerequisites 
	echo $^ 
	# Outputs the first prerequisite 
	echo $< 
	touch hey 
one: 
	touch one 
two: 
	touch two

Fancy Rules

Implicit Rules -

The important variables used by implicit rules are:

CC = gcc # Flag for implicit rules 
CFLAGS = -g # Flag for implicit rules. Turn on debug info 
# Implicit rule #1: blah is built via the C linker implicit rule 
# Implicit rule #2: blah.o is built via the C compilation implicit rule, because blah.c exists 
blah: blah.o 

blah.c: 
	echo "int main() { return 0; }" > blah.c 
clean: 
	rm -f blah*

Static Pattern Rule -

# Syntax - 
	targets ...: target-pattern: prereq-patterns ... 
	# In the case of the first target, foo.o, the target-pattern matches foo.o and sets the "stem" to be "foo". # It then replaces the '%' in prereq-patterns with that stem .
	$(objects): %.o: %.c 
		$(CC) -c $^ -o $@

Pattern Rule -

%.o : %.c 
	$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

Double-Colon Rules -

all: blah 

blah:: 
	echo "hello" 
blah:: 
	echo "hello again"

Commands -

Silence -

Shell Var SHELL=/bin/bash The shell change will only impact the later targets then the declaration , previous one will be in the same shell as default /bin/sh Shell Variables by $$ not by $ as the make variable . sh_var=’I am a shell variable’; echo $$sh_var

Error handling with -k-i, and -

Exporting the vars -

[!NOTE] When Make starts, it automatically creates Make variables out of all the environment variables that are set when it’s executed.

Functions -

	comma := , 
	empty:= 
	space := $(empty) $(empty) 
	foo := a b c 
	bar := $(subst $(space),$(comma),$(foo)) 
	
	all: 
		@echo $(bar)  # output a,b,c

Do NOT include spaces in the arguments after the first. That will be seen as part of the string.

> bar := $(subst $(space), $(comma) , $(foo)) # Watch out!
> # Output is ", a , b , c". Notice the spaces introduced
  1. Foreach - - $(foreach var,list,text)
         foo := who are you 
         # For each "word" in foo, output that same word with an exclamation after
         bar := $(foreach wrd,$(foo),$(wrd)!) 
         all: 
             # Output is "who! are! you!" 
             @echo $(bar)
    
  2. if - if checks if the first argument is nonempty. If so, runs the second argument, otherwise runs the third.
foo := $(if this-is-not-empty,then!,else!)
empty :=
bar := $(if $(empty),then!,else!)

all:
	@echo $(foo)
	@echo $(bar)
  1. shell - This calls the shell, but it replaces newlines with spaces!
all: 
	@echo $(shell ls -la) # Very ugly because the newlines are gone!
  1. Call - calling a user defined function with arguments
 sweet_new_fn = Variable Name: $(0) First: $(1) Second: $(2) Empty Variable: $(3) 
define add_numbers
	$(shell echo $(1) + $(2) | bc)
endef

define concat_strings
    $(1) $(2)
endef

# Call the function with 5 and 3 as arguments
result := $(call add_numbers, 5, 3)

# Call the function with strings
concatenated := $(call concat_strings, Hello, World)

all: 
	# Outputs "Variable Name: sweet_new_fn First: go Second: tigers Empty Variable:" 
	@echo $(call sweet_new_fn, go, tigers)
	@echo "The result is $(result)"
	@echo $(concatenated)
  1. filter - The filter function is used to select certain elements from a list that match a specific pattern. For example, this will select all elements in obj_files that end with .o.
obj_files = foo.result bar.o lose.o one.c two.c one.h
filtered_files = $(filter %.o %.c %.h,$(obj_files))

all:
	@echo $(filtered_files)

-> Negation - filter-out filters the files which don’t match the pattern -> Nested filter: You can nest filter functions to apply multiple filters. For example, $(filter %.o, $(filter-out test%, $(objects))) will select all object files that end with .o but don’t start with test.

Conditionals in Make -

foo = ok 
all: 
	ifeq ($(foo), ok) 
	echo "foo equals ok" 
	else echo "nope" 
	endif
Check if a variable is empty
nullstring =
foo = $(nullstring) # end of line; there is a space here

all:
ifeq ($(strip $(foo)),)
	echo "foo is empty after being stripped"
endif
ifeq ($(nullstring),)
	echo "nullstring doesn't even have spaces"
endif
Check if a variable is defined

ifdef does not expand variable references; it just sees if something is defined at all

bar =
foo = $(bar)

all:
ifdef foo
	echo "foo is defined"
endif
ifndef bar
	echo "but bar is not"
endif
$(MAKEFLAGS)

This example shows you how to test make flags with findstring and MAKEFLAGS. Run this example with make -i to see it print out the echo statement.

all:
	# Search for the "-i" flag. MAKEFLAGS is just a list of single characters, one per flag. So look for "i" in this case.
	ifneq (,$(findstring i, $(MAKEFLAGS)))
	echo "i was passed to MAKEFLAGS"
	endif