Functions in make are called with the same syntax as the variables using
) sequence, the arguments are passed after a space in a comma-separated-list.
$(wordlist one two three,two,three)
They can be used in the same contexts than variables (as prerequisites, inside recipes, as targets…) and you can nest as many as you want, so you can do some pretty nice processes.
$ cat Makefile path := $(home)/output binaries := $(addprefix $(path),$(basename $(wildcard %.c)) default: @echo $(wildcard %.c) @echo $(binaries) $ make program1.c program2.c /home/edupo/output/program1 /home/edupo/output/program2
Let see the binaries variable assignment more closer.
binaries := $(addprefix $(path),$(basename $(wildcard %.c))
To understand how this statement works we need to read it from the most inner parenthesis.
- The first function executed is
wildcardand it’s argument is
%.c. This function locates all the files in the current working directory that match the argument, so it will be locating all C source files available in the current directory.
You can use
wildcardto locate files inside folders relative to your current path. Just imagine that the stem (
%) will be replacing the name of the file you are looking for, so if your lookup string looks like
../subfolder/%.cit will do exactly what you are thinking.
This is a powerful characteristic, but I do not recommend to use it because you can over complicate your Makefile. The best practice is creating a Makefile per folder you have on your structure; If your Makefiles are automating a build process then make sense that every folder should create a binary (a library or executable) so that if one of such is a prerequisite of your final application
makecan call itself onto the desired folder.
Apparently the function has found in the example 2 source files:
- The second function
basenameis extracting from each word all but the file name. Even if the file name contains an extension you will be filtering that. The path is kept so make sure to remove it using
notdirif you are only interested on the file name.
Looking to our example the string at this point should look like:
- Finally comes the
addprefixfunction that will add the path to each word. If you want to prepend strings in make you can also use variable assignments
var := Hello, $(world)
But when your variables may contain many words this type of assignments should be avoided for more than static parameters definition.
After the execution of this part of the code you will get the desired final string:
As you can see
make is powerful processing strings in many ways. And not only that. You can display custom messages, break execution, doing loops through an array of words and much more.
Anyway, using the function table of the cheatsheets append here a summary of all the functions for your reference, descriptions are minimized.
|$(subst f,to,t)||Replace f with to in t|
|$(patsubst p,r,t) $(t:p=r)||Replace words matching p with r in t|
|$(strip s)||Remove excess spaces from s|
|$(findstring s,t)||Locate s in t|
|$(filter p…,t)||Words in t that match one p words|
|$(filter-out p…,t)||Words in t that don’t match p words|
|$(sort l)||Sort l lexicographically, removes dup.|
|$(word n,t)||Extract the nth word (one-origin) of t|
|$(words t)||Count the number of words in t|
|$(wordlist t,s,e)||List of words in t from s to e|
|$(firstword ns…)||Extract the first word of ns|
|$(lastword ns…)||Extract the last word of ns|
|$(dir ns…)||Directory part of each file name|
|$(notdir ns…)||Non-directory part of each file name|
|$(suffix ns…)||Deletes until the last ‘.’ in every ns|
|$(basename ns…)||Base name (no suffix) in every ns|
|$(addsuffix sf,ns…)||Append sf to each word in ns|
|$(addprefix pf,ns…)||Prepend pf to each word in ns|
|$(join l1,l2)||Join two parallel lists of words|
|$(wildcard p…)||Find files matching a pattern (not ‘%’)|
|$(realpath ns…)||Absolute name (no ., .., nor symlinks)|
|$(abspath ns…)||Absolute name (no. or ..)Preserves symlinks|
|$(error t…)||make fatal error with the message t|
|$(warning t…)||make warning with the message t|
|$(info t…)||make info with the message t|
|$(shell c)||Execute a shell cmd, returns output|
|$(origin v)||Origin of variable v|
|$(flavor v)||Flavor of variable v|
|$(foreach v,w,t)||Evaluate t with v bound to each word in w, and concatenate the results|
|$(if c,then-part[,else-part])||Evaluates c; if it’s non-empty substitute by then-part otherwise by else-part|
|$(or c1[,c2[,c3…]])||Evaluate each cN; substitute the first non-empty expansion|
|$(and c1[,c2[,c3…]])||Evaluate each cN; if any is empty substitution is empty. Expansion of the last condition otherwise|
|$(call v,p,…)||Evaluates v replacing any references to $(1), $(2) with the first, second, etc. p values|
|$(eval t)||Evaluate t and read the results as makefile commands|
|$(file op f,t)||Open the file f using mode op and write t to that file|
|$(value v)||Evaluates v, with no expansion|