How to properly use % or * (asterisk) symbols as a placeholder in makefile?

时间:2016-10-20 13:02:14

标签: c makefile

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...

1 个答案:

答案 0 :(得分:1)

*是一个通配符,它​​会为您提供一个列表,并且是&#34; shell&#34;涉及。

%是一个makefile内部通配符,它​​将作为for-each方式的占位符(我将在下面解释)。

虽然*.c为您提供了一个变量中所有c文件的列表,但您可以使用%

执行更多操作
%.o: %.c %.h
    gcc -o foo %@

例如,这称为pattern-rule,表示每个<placeholder>.c<placeholder>.h生成目标<placeholder>.o,其下方有相应的配方。

使用模式规则make会生成类似这样的内容

a.o : a.c a.h
    ...
b.o : b.c b.h
    ...
c.o : c.c c.h
    ...

您目前要做的事情将导致int

a.o b.o c.o : a.c b.c c.c a.h b.h c.h 
    gcc ....

虽然这可能有效,但您有不必要的依赖关系。 a.o不需要依赖b.c例如

同样_CFILES = *.c会导致&#34; *。c&#34;是变量中的字符串而不是实际文件。如果要扩展实际文件名,则应使用wildcard函数

_CFILES  := $(wildcard *.c)

现在

CFILES=$(patsubst %, $(SDIR)/%, $(_CFILES))

也有这个&#34; for-each&#34;喜欢placeholer %

这意味着每次%它都会被$(SDIR)/%取代。因为%没有匹配src的模式,但这会很奇怪。你想在这里实现什么?如果你想&#34;削减&#34;来自路径的CFILES=$(patsubst $(SRC)%, % , $(_CFILES))

.filter()

但我怀疑你想要这样做。你应该在makefile文档中阅读一下,这里有很多次链接。我解释了很多。