How to properly use % or * (asterisk) symbols as a placeholder in makefile?
c, makefile
Solution
`*` is a wildcard which gets you a list and is "shell" related.
`%` is a makefile internal wildcard which will serve as a placeholder in a for-each manner (I will explain below).
While `*.c` gets you a list of all c files in one variable you can do more with `%`
%.o: %.c %.h
gcc -o foo %@
This for example is called a pattern-rule and means for each `<placeholder>.c` and `<placeholder>.h` generate the target `<placeholder>.o` with the according recipe below it.
With the pattern rule make would generate something like this
a.o : a.c a.h
...
b.o : b.c b.h
...
c.o : c.c c.h
...
What you are currently trying to do would result in
a.o b.o c.o : a.c b.c c.c a.h b.h c.h
gcc ....
While this may be valid you have unnecessary dependencies. `a.o` does not need to depend on `b.c` e.g.
Also `_CFILES = *.c` will result in "*.c" being the string in the variable not the actual files. If you want to expand the actual filenames you should use the wildcard function
_CFILES := $(wildcard *.c)
now
CFILES=$(patsubst %, $(SDIR)/%, $(_CFILES))
also has this "for-each" like placeholer `%`
this means everytime there is `%` it will be replaced by `$(SDIR)/%`. Because you have no pattern for `%` to match though in the patsubst this will get strange. What do you want to achieve here? If you want to "cut of" `src` from the path it would be the other way round
CFILES=$(patsubst $(SRC)%, % , $(_CFILES))
But I doubt you want to do this. You should read a bit in the makefile documentation which is linked quite a few times here. I explains quite a lot.
Problem
I have a problem with creating "context-free/filename-agnostic" makefile to build C project without specifying explicit file names each time I add new ones. I have the following project structure: ``` include/ #dir to store all header files lib1.h lib2.h ... src/ # dir of source code obj/ #temporary dir for storing all .o files lib1.o lib2.o ... lib1.c # start with #include "lib1.h" lib2.c # the same ... main.c ``` And the following makefile: ``` # dirs IDIR=include SDIR=src ODIR=src/obj _HEADS=*.h #or maybe % percentage instead? HEADS=$(patsubst %, $(IDIR)/%, $(_HEADS)) _OBJS=*.o OBJS=$(patsubst %, $(ODIR)/%, $(_OBJS)) _CFILES=*.c CFILES=$(patsubst %, $(SDIR)/%, $(_CFILES)) # compiler GCC=gcc CFLAGS=-I$(IDIR) $(OBJS): $(CFILES) $(HEADS) $(GCC) -c -o $@ $< $(CFLAGS) main: $(OBJS) $(GCC) -o $@ $^ $(CFLAGS) ``` What I'm trying to achieve is to build executable if any changes are occurred in *.c or *.h files under `src/` and `include/` folders (not sure the changes might be under `src/obj`). So now the `make` do not compile because it thinks the object files are "up-to-date". So I probably do something wrong, since I need to check .c and .h files first. Also I'm not sure (even after reading several tutorials) how to use % properly and what the difference between using % and * asterisk. For example, I saw something like these: ``` %.o: %.c %.h gcc -o foo %@ ... ``` How in the world the rule `%.o` is written as rule name (I suppose it's better if they are all plain names instead of some logical things)? Or it's make sense to do so only if you use placeholders like `%@` in the actual rule to avoid additional naming "overhead". Please, could anyone explain and help me to fix my makefile - I really messed up with these subtle things...