diff options
| author | Geoff Liu <cangming.liu@gmail.com> | 2015-09-22 00:47:22 -0600 | 
|---|---|---|
| committer | Geoff Liu <cangming.liu@gmail.com> | 2015-09-22 00:47:22 -0600 | 
| commit | e2b7d19eae4fb2ad9af41dbd3b69f5a078540d7f (patch) | |
| tree | 149f6d07641b335f059382bbb5bf0882cb4f682d | |
| parent | a788a8749e91beced43c5bcf143a86a5fbecee07 (diff) | |
| parent | 55e22c0a8cbf68158892790d2942bb594960943b (diff) | |
Merge pull request #1234 from robochat/master
[make/en] Adding a tutorial on (gnu) make
| -rw-r--r-- | make.html.markdown | 243 | 
1 files changed, 243 insertions, 0 deletions
| diff --git a/make.html.markdown b/make.html.markdown new file mode 100644 index 00000000..9aca2c20 --- /dev/null +++ b/make.html.markdown @@ -0,0 +1,243 @@ +---
 +language: make
 +contributors:
 +    - ["Robert Steed", "https://github.com/robochat"]
 +filename: Makefile
 +---
 +
 +A Makefile defines a graph of rules for creating a target (or targets).
 +Its purpose is to do the minimum amount of work needed to update a
 +target to the most recent version of the source. Famously written over a
 +weekend by Stuart Feldman in 1976, it is still widely used (particularly
 +on Unix) despite many competitors and criticisms.
 +
 +There are many varieties of make in existance, this article assumes that
 +we are using GNU make which is the standard on Linux.
 +
 +```make
 +
 +# Comments can be written like this.
 +
 +# Files should be named Makefile and then be can run as `make <target>`.
 +# Otherwise we use `make -f "filename" <target>`.
 +
 +# Warning - only use TABS to indent in Makefiles, never spaces!
 +
 +#-----------------------------------------------------------------------
 +# Basics
 +#-----------------------------------------------------------------------
 +
 +# A rule - this rule will only run if file0.txt doesn't exist.
 +file0.txt:
 +	echo "foo" > file0.txt
 +	# Even comments in these 'recipe' sections get passed to the shell.
 +	# Try `make file0.txt` or simply `make` - first rule is the default. 
 +
 +
 +# This rule will only run if file0.txt is newer than file1.txt.
 +file1.txt: file0.txt
 +	cat file0.txt > file1.txt
 +	# use the same quoting rules as in the shell.
 +	@cat file0.txt >> file1.txt
 +	# @ stops the command from being echoed to stdout.
 +	-@echo 'hello'
 +	# - means that make will keep going in the case of an error.
 +	# Try `make file1.txt` on the commandline.
 +
 +# A rule can have multiple targets and multiple prerequisites
 +file2.txt file3.txt: file0.txt file1.txt
 +	touch file2.txt
 +	touch file3.txt
 +
 +# Make will complain about multiple recipes for the same rule. Empty 
 +# recipes don't count though and can be used to add new dependencies.
 +
 +#-----------------------------------------------------------------------
 +# Phony Targets
 +#-----------------------------------------------------------------------
 +
 +# A phony target. Any target that isn't a file.
 +# It will never be up to date so make will always try to run it.
 +all: maker process
 +
 +# We can declare things out of order.
 +maker:
 +	touch ex0.txt ex1.txt
 +
 +# Can avoid phony rules breaking when a real file has the same name by
 +.PHONY: all maker process
 +# This is a special target. There are several others.
 +
 +# A rule with a dependency on a phony target will always run
 +ex0.txt ex1.txt: maker
 +
 +# Common phony targets are: all make clean install ...
 +
 +#-----------------------------------------------------------------------
 +# Automatic Variables & Wildcards
 +#-----------------------------------------------------------------------
 +
 +process: file*.txt	#using a wildcard to match filenames
 +	@echo $^	# $^ is a variable containing the list of prerequisites
 +	@echo $@	# prints the target name
 +	#(for multiple target rules, $@ is whichever caused the rule to run)
 +	@echo $<	# the first prerequisite listed
 +	@echo $?	# only the dependencies that are out of date
 +	@echo $+	# all dependencies including duplicates (unlike normal)
 +	#@echo $|	# all of the 'order only' prerequisites
 +
 +# Even if we split up the rule dependency definitions, $^ will find them
 +process: ex1.txt file0.txt
 +# ex1.txt will be found but file0.txt will be deduplicated.
 +
 +#-----------------------------------------------------------------------
 +# Patterns
 +#-----------------------------------------------------------------------
 +
 +# Can teach make how to convert certain files into other files.
 +
 +%.png: %.svg
 +	inkscape --export-png %.svg
 +
 +# Pattern rules will only do anything if make decides to create the \
 +target.
 +
 +# Directory paths are normally ignored when matching pattern rules. But
 +# make will try to use the most appropriate rule available.
 +small/%.png: %.svg
 +	inkscape --export-png --export-dpi 30 %.svg
 +
 +# make will use the last version for a pattern rule that it finds.
 +%.png: %.svg
 +	@echo this rule is chosen
 +
 +# However make will use the first pattern rule that can make the target
 +%.png: %.ps
 +	@echo this rule is not chosen if %.svg and %.ps are both present
 +
 +# make already has some pattern rules built-in. For instance, it knows 
 +# how to turn *.c files into *.o files.
 +
 +# Older makefiles might use suffix rules instead of pattern rules
 +.png.ps:
 +    @echo this rule is similar to a pattern rule.
 +
 +# Tell make about the suffix rule
 +.SUFFIXES: .png
 +
 +#-----------------------------------------------------------------------
 +# Variables
 +#-----------------------------------------------------------------------
 +# aka. macros
 +
 +# Variables are basically all string types
 +
 +name = Ted
 +name2="Sarah"
 +
 +echo:
 +	@echo $(name)
 +	@echo ${name2}
 +	@echo $name    # This won't work, treated as $(n)ame.
 +	@echo $(name3) # Unknown variables are treated as empty strings.
 +
 +# There are 4 places to set variables.
 +# In order of priority from highest to lowest:
 +# 1: commandline arguments
 +# 2: Makefile
 +# 3: shell enviroment variables - make imports these automatically.
 +# 4: make has some predefined variables
 +
 +name4 ?= Jean
 +# Only set the variable if enviroment variable is not already defined.
 +
 +override name5 = David
 +# Stops commandline arguments from changing this variable.
 +
 +name4 +=grey
 +# Append values to variable (includes a space).
 +
 +# Pattern-specific variable values (GNU extension).
 +echo: name2 = Sara # True within the matching rule
 +	# and also within its remade recursive dependencies
 +	# (except it can break when your graph gets too complicated!)
 +
 +# Some variables defined automatically by make.
 +echo_inbuilt:
 +	echo $(CC)
 +	echo ${CXX)}
 +	echo $(FC)
 +	echo ${CFLAGS)}
 +	echo $(CPPFLAGS)
 +	echo ${CXXFLAGS}
 +	echo $(LDFLAGS)
 +	echo ${LDLIBS}
 +
 +#-----------------------------------------------------------------------
 +# Variables 2
 +#-----------------------------------------------------------------------
 +
 +# The first type of variables are evaluated each time they are used.
 +# This can be expensive, so a second type of variable exists which is
 +# only evaluated once. (This is a GNU make extension)
 +
 +var := hello
 +var2 ::=  $(var) hello
 +#:= and ::= are equivalent.
 +
 +# These variables are evaluated procedurely (in the order that they 
 +# appear), thus breaking with the rest of the language !
 +
 +# This doesn't work
 +var3 ::= $(var4) and good luck
 +var4 ::= good night
 +
 +#-----------------------------------------------------------------------
 +# Functions
 +#-----------------------------------------------------------------------
 +
 +# make has lots of functions available.
 +
 +sourcefiles = $(wildcard *.c */*.c)
 +objectfiles = $(patsubst %.c,%.o,$(sourcefiles))
 +
 +# Format is $(func arg0,arg1,arg2...)
 +
 +# Some examples
 +ls:	* src/*
 +	@echo $(filter %.txt, $^)
 +	@echo $(notdir $^)
 +	@echo $(join $(dir $^),$(notdir $^))
 +
 +#-----------------------------------------------------------------------
 +# Directives
 +#-----------------------------------------------------------------------
 +
 +# Include other makefiles, useful for platform specific code
 +include foo.mk
 +
 +sport = tennis
 +# Conditional compilation
 +report:
 +ifeq ($(sport),tennis)
 +	@echo 'game, set, match'
 +else
 +	@echo 'They think it's all over; it is now'
 +endif
 +
 +# There are also ifneq, ifdef, ifndef
 +
 +foo = true
 +
 +ifdef $(foo)
 +bar = 'hello'
 +endif
 +```
 +
 +
 +### More Resources
 +
 ++ [gnu make documentation](https://www.gnu.org/software/make/manual/)
 ++ [software carpentry tutorial](http://swcarpentry.github.io/make-novice/)
 ++ learn C the hard way [ex2](http://c.learncodethehardway.org/book/ex2.html) [ex28](http://c.learncodethehardway.org/book/ex28.html)
 +
 | 
