Domanda

I may not be a Makefile-guru, but I have some experience with them in the past. However, I've got a (rather unimportant) issue, which still baffles me.

Here's my Makefile :

#-------------------------
# Definitions
#-------------------------

APP   = lgm

# Tools & commands

CC    = gcc
LEX   = lex
YACC  = /usr/local/bin/bison
RM    = rm
CP    = cp
MV    = mv
DMD   = dmd

# Paths

SRC     = src
BIN     = bin
TEST    = test
LIB     = lib

# C stuff

CC_HEADERS  = logramm.tab.h
CC_SOURCES  = lex.yy.c logramm.tab.c
CC_OBJECTS  = lex.yy.o logramm.tab.o

CC_LEXER    = logramm.l
CC_PARSER   = logramm.y

# D stuff

D_SOURCES   = main.d
D_OBJECTS   = main.o

D_LFLAGS    = -m64

#-------------------------
# Main Functions
#-------------------------

all: ${APP} clean

${APP}: ${CC_OBJECTS} ${D_OBJECTS}
    ${DMD} ${CC_OBJECTS} ${D_OBJECTS} -of${APP} ${D_FLAGS}
    ${MV} ${APP} ${BIN}

${D_OBJECTS}:
    ${DMD} -c ${D_SOURCES}

${CC_OBJECTS}: ${CC_SOURCES}
    ${CC} -g -c ${CC_SOURCES}

${CC_SOURCES}: setup
    ${LEX} ${CC_LEXER}
    ${YACC} -d ${CC_PARSER}

setup:
    ${CP} ${SRC}/*.d .
    ${CP} ${SRC}/*.l .
    ${CP} ${SRC}/*.y .

clean:
    ${RM} *.d *.y *.l *.o *.hh *.c *.h

The trouble is :

When I'm looking at the output of make all, the ${CC_SOURCES} part is executed twice (2 lex, 2 bison commands). E.g. It outputs :

cp src/*.d .
cp src/*.l .
cp src/*.y .
lex logramm.l
/usr/local/bin/bison -d logramm.y
lex logramm.l
/usr/local/bin/bison -d logramm.y
gcc -g -c lex.yy.c logramm.tab.c
dmd -c main.d
dmd lex.yy.o logramm.tab.o main.o -oflgm 
mv lgm bin
rm *.d *.y *.l *.o *.hh *.c *.h
rm: *.hh: No such file or directory
make: *** [clean] Error 1

Why is that? What am I doing wrong?


UPDATE :

I've just managed to fix it, by taking setup from ${CC_SOURCES} and putting it at the all section, like :

all: setup ${APP} clean

So, it's ok. However, I still don't understand why. Have I misinterpreted the way Makefiles are structured? Any input would be more than welcome! :-)

È stato utile?

Soluzione

You have a basic misunderstanding of how make interprets rules with multiple targets: this makefile is really not going to work. Let's expand the rule that runs the lex/yacc:

lex.yy.c logramm.tab.c: setup
        ${LEX} ${CC_LEXER}
        ${YACC} -d ${CC_PARSER}

Make interprets this as if it were this (in an explicit rule, multiple targets create a separate rule for each target):

lex.yy.c: setup
        ${LEX} ${CC_LEXER}
        ${YACC} -d ${CC_PARSER}

logramm.tab.c: setup
        ${LEX} ${CC_LEXER}
        ${YACC} -d ${CC_PARSER}

Now you can probably see your issue. Make wants to build lex.yy.o and that depends on lex.yy.c, so make tries to build that. It sees that it depends on setup, which doesn't exist (because nothing creates it, but if someone WERE to create that file in your directory it would break badly). So, it run the lex and yacc steps (both, since that's the recipe) to build lex.yy.c.

Then it goes through exactly the same thing to build logramm.tab.c... thus the rules are run twice.

You have an identical problem with your object files; expanding that rule we see:

lex.yy.o logramm.tab.o: lex.yy.c logramm.tab.c
        ${CC} -g -c lex.yy.c logramm.tab.c

which is identical to:

lex.yy.o: lex.yy.c logramm.tab.c
        ${CC} -g -c lex.yy.c logramm.tab.c

logramm.tab.o: lex.yy.c logramm.tab.c
        ${CC} -g -c lex.yy.c logramm.tab.c

which is clearly not right.

Also, your setup rule (since it never exists) will cause everything to rebuild every time.

Your solution is better WRT setup, since the source files don't depend on it so they won't always be rebuilt. You still have the broken rules for object files. Also your solution will not work if you ever wanted to enable parallel builds, because the setup may be run in parallel with the other targets: you really WANT the dependency to ensure ordering.

In general when writing makefiles you should (a) have one rule to build one target, and (b) ensure the rule builds EXACTLY the target you told make it would build.

Try using this instead:

all: ${BIN}/${APP} clean

${BIN}/${APP}: ${APP}
        ${CP} $< $@

${APP}: ${CC_OBJECTS} ${D_OBJECTS}
    ${DMD} $^ -of$@ ${D_FLAGS}

%.o : %.d
        ${DMD} -c $<

%.o: %.c
        ${CC} -g -c $<

%: ${SRC}/%
        ${CP} $< $@

lex.yy.c: ${CC_LEXER}
        ${LEX} $<

%.tab.c %.tab.h: %.y
        ${YACC} -d $<

clean:
        ${RM} *.d *.y *.l *.o *.hh *.c *.h

Altri suggerimenti

The trouble is that CC_SOURCES = lex.yy.c logramm.tab.c so the target line (plus actions):

${CC_SOURCES}: setup
    ${LEX} ${CC_LEXER}
    ${YACC} -d ${CC_PARSER}

is equivalent to:

lex.yy.c: setup
    ${LEX} ${CC_LEXER}
    ${YACC} -d ${CC_PARSER}

logramm.tab.c: setup
    ${LEX} ${CC_LEXER}
    ${YACC} -d ${CC_PARSER}

The setup rule has no dependencies, but isn't a (GNU make extension) .PHONY target either (and I'm not sure that being a phony target would help, either), so it doesn't exist. Therefore, when make is trying to ensure that lex.yy.c is up to date, it has to execute the rules for setup; ditto for logramm.tab.c; hence the double execution.

Your solution looks reasonable. You could explore .PHONY and see whether that helps if you're using GNU make and don't mind being tied to GNU make.

This comes down to the way make handles dependencies. You can always examine exactly what make is doing by passing the -d flag (at least for GNU Make, ymmv, also consider adding -r if you aren't using any built-in rules as they clutter the output substantially).

Here's what happens in the case where setup is a dependency of ${CC_SOURCES}

...
Does lex.yy.c exist? no, okay check its prerequisites
    Does setup exist? no, okay check its prerequisites
        No prerequisites, run the recipe
    Prerequisites for lex.yy.c done, run the recipe
Does logramm.tab.c exist? yes, but check its prerequisites
    We already built setup, so prune this prerequisite, but treat it as newer than logramm.tab.c
    Prerequisites for logramm.tab.c done, run the recipe
...

Here's what happens in the case where setup is a dependency of all

...
Does setup exist? no, okay check its prerequisites
    No prerequisites, run the recipe
...
Does lex.yy.c exist? no, okay check its prerequisites
    No prerequisites, run the recipe
Does logramm.tab.c exist? yes, but check its prerequisites
    No prerequisites, so done
...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top