我遇到了这个Makefile(通过名为sendip的开源项目找到它)
关于这个文件我有两个混淆 -
.c
文件在哪里被指定为依赖项?虽然像ipv6.so
,tcp.so
这样的所有库都生成得很好,但是这里的哪一行负责呢?我觉得这就行.....对吧?
%.so: %.c $(LIBS)
$(CC) -o $@ $(CFLAGS) $(LIBCFLAGS) $+ $(LIBS)
但$(LIBS)
只指定一些.o文件。是这个$+
做的事情?
我从来没有听说过$+
。我试图找到它,并遇到了许多其他像$?
,$@
,$<
等,但从未见过这一个。我认为它的行为类似于$?
,但它仍然需要指定.c
depndencies。
Makefile文件:
#configureable stuff
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man/man1
LIBDIR ?= $(PREFIX)/lib/sendip
#For most systems, this works
INSTALL ?= install
#For Solaris, you may need
#INSTALL=/usr/ucb/install
CFLAGS= -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings \
-Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align \
-DSENDIP_LIBS=\"$(LIBDIR)\"
#-Wcast-align causes problems on solaris, but not serious ones
LDFLAGS= -g -rdynamic -lm -ldl
#LDFLAGS_SOLARIS= -g -lsocket -lnsl -lm
LDFLAGS_SOLARIS= -g -lsocket -lnsl -lm -ldl
LDFLAGS_LINUX= -g -rdynamic -lm -ldl
LIBCFLAGS= -shared
CC= gcc-4.4
PROGS= sendip
BASEPROTOS= ipv4.so ipv6.so
IPPROTOS= tcp.so udp.so icmp.so
UDPPROTOS= rip.so ripng.so ntp.so
TCPPROTOS= bgp.so
PROTOS= $(BASEPROTOS) $(IPPROTOS) $(UDPPROTOS) $(TCPPROTOS)
LIBS= libsendipaux.a
LIBOBJS= csum.o compact.o protoname.o headers.o parseargs.o
cryptomod.o crc32.o
SUBDIRS= mec
all: $(LIBS) subdirs sendip $(PROTOS) sendip.1 sendip.spec
#there has to be a nice way to do this
sendip: sendip.o gnugetopt.o gnugetopt1.o compact.o
sh -c "if [ `uname` = Linux ] ; then \
$(CC) -o $@ $(LDFLAGS_LINUX) $(CFLAGS) $+ ; \
elif [ `uname` = SunOS ] ; then \
$(CC) -o $@ $(LDFLAGS_SOLARIS) $(CFLAGS) $+ ;\
else \
$(CC) -o $@ $(LDFLAGS) $(CFLAGS) $+ ; \
fi"
libsendipaux.a: $(LIBOBJS)
ar vr $@ $?
subdirs:
for subdir in $(SUBDIRS) ; do \
cd $$subdir ;\
make ;\
cd .. ;\
done
protoname.o: mec/protoname.c
$(CC) -o $@ -c -I. $(CFLAGS) $+
headers.o: mec/headers.c
$(CC) -o $@ -c -I. $(CFLAGS) $+
parseargs.o: mec/parseargs.c
$(CC) -o $@ -c -I. $(CFLAGS) $+
cryptomod.o: mec/cryptomod.c
$(CC) -o $@ -c -I. $(CFLAGS) $+
crc32.o: mec/crc32table.h mec/crc32.c
$(CC) -o $@ -c -I. $(CFLAGS) mec/crc32.c
mec/crc32table.h: mec/gen_crc32table
mec/gen_crc32table > mec/crc32table.h
sendip.1: ./help2man $(PROGS) $(PROTOS) subdirs VERSION
./help2man -n "Send arbitrary IP packets" -N >sendip.1
你是对的。
当目标定义以%
字符开头时,它定义目标模式,而不是特定模式。所以%.so
意味着生成其他目标或用户所需的所有.so文件的目标。 %.c
也是一种模式,意味着所有.c
文件。
所以$(CC) -o $@ $(CFLAGS) $(LIBCFLAGS) $+ $(LIBS)
意味着命令输出将生成目标的名称($ @ - >匹配模式的目标名称)...而$+
表示所有与prerequisite
模式匹配的文件(即:%.c
) )。
看看GNU制作手册,特别是在Catalogue of Rules上看看$+
,$^
,......的意思。
其中一些是GNU Make(又名“gmake”)的扩展:
immediate = deferred
immediate ?= deferred
immediate := immediate
immediate += deferred or immediate
GNU make在两个不同的阶段完成它的工作。在第一阶段,它读取所有makefile,包括makefile等,并内化所有变量及其值,隐式和显式规则,并构建所有目标及其先决条件的依赖关系图。在第二阶段,make使用这些内部结构来确定需要重建的目标,并调用执行此操作所需的规则。
...我们说如果在第一阶段发生扩展是立即的:在这种情况下,make将扩展构造的该部分中的任何变量或函数,因为解析了makefile。我们说如果不立即进行扩展,则推迟扩展。在构造稍后在直接上下文中出现或直到第二阶段之前,不执行延迟构造的扩展。