Questions about Makefile - what is “$+” & where ar

2019-06-27 20:52发布

问题:

I came across this Makefile (found it through an open source project called sendip)

I have two confusions regarding this file -

  1. Where are .c files being specified as dependencies here? Although all the libraries like ipv6.so, tcp.so are being generated fine, but which line here is responsible for it?

I think this is the line ..... Right ??

%.so: %.c $(LIBS)
                    $(CC) -o $@ $(CFLAGS) $(LIBCFLAGS) $+ $(LIBS)

but $(LIBS) only specify some .o files. IS this $+ doing something ?

2.I have never heard of $+. I tried to find it out and came across many others like $?, $@, $<, etc. but never seen this one. I think it behaves like $? but still it also demands .c depndencies to be specified.

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

回答1:

Yes you're right.

When a target definition start with the % character it defines a target pattern, not a specific pattern. So %.so means a target to generate all .so files needed by other targets or required by the user. The %.c also is a pattern and means all .c files.

So the $(CC) -o $@ $(CFLAGS) $(LIBCFLAGS) $+ $(LIBS) means the command output will have the name of the target being generated ($@ -> name of the target that matched the pattern) ... and the $+ means all the files that matched with the prerequisite pattern (i.e: %.c).

Take a look at the GNU make manual, specifically at the Catalogue of Rules to see what $+, $^, ... mean.



回答2:

Some of these are extensions to GNU Make (aka "gmake"):

  • http://www.gnu.org/software/make/manual/make.html#Reading-Makefiles

    Variable definitions are parsed as follows:

     immediate = deferred
     immediate ?= deferred
     immediate := immediate
     immediate += deferred or immediate
    

GNU make does its work in two distinct phases. During the first phase it reads all the makefiles, included makefiles, etc. and internalizes all the variables and their values, implicit and explicit rules, and constructs a dependency graph of all the targets and their prerequisites. During the second phase, make uses these internal structures to determine what targets will need to be rebuilt and to invoke the rules necessary to do so.

... We say that expansion is immediate if it happens during the first phase: in this case make will expand any variables or functions in that section of a construct as the makefile is parsed. We say that expansion is deferred if expansion is not performed immediately. Expansion of a deferred construct is not performed until either the construct appears later in an immediate context, or until the second phase.