|
Home > Archive > Unix Programming > January 2004 > make picks wrong target: why?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
make picks wrong target: why?
|
|
| Fritz Foetzl 2004-01-23, 5:17 pm |
| I'm writing a compiler. My Makefile is driving me insane. By default,
I want it to 1) generate the parser with bison, 2) generate the
scanner with flex, 3) generate dependencies for all the *.cc sources,
and 4) compile and link the compiler.
My entire Makefile is included. The problem I'm having is that make
insists on generating dependencies no matter which target I ask for.
For example, "make clean" will generate the dependencies (if they're
not present already), then promptly remove them. I understand that
including the *.d files puts a lot of hidden targets into my Makefile,
but I deliberately put the include *after* all the other targets.
Therefore, in my mind, dependencies shouldn't get generated unless I
specify "make dep", "make all", or simply "make" (any target I request
has the same result.) Is there a hard-to-spot typo or other subtlety
I'm not seeing?
For the record, I've already R'ed the FM.
##### Start infuriating makefile
SRCS = ast.cc ast_api.cc ast_ctor.cc ast_sym.cc ast_sem.cc ast_gen.cc
ast_write.cc context.cc nasmGen.cc typeEnums.cc symbolTable.cc
GENSRCS = parser.cc lexan.cc
BISONSRC = parser.yy
LEXSRC = lexan.l
OBJS = $(SRCS:.cc=.o)
DEPS = $(SRCS:.cc=.d)
INCDIR = include
LIBDIR = lib
SRCDIR = src
YACC = bison
LEX = flex
CC = g++
YFLAGS = --defines=$(INCDIR)/$(BISONSRC:.yy=.hh) -o
$(SRCDIR)/$(BISONSRC:.yy=.cc)
CXXFLAGS = -c -g -I./$(INCDIR) -DDEBUG
LFLAGS = -i -t
LDFLAGS=-L./lib -lChildProc
EXE=mycompiler
vpath
vpath \%.cc $(SRCDIR)
#-------------------------------
# Targets
#-------------------------------
all: parser scanner remake
parser: $(BISONSRC:.yy=.cc)
scanner: $(LEXSRC:.l=.cc)
dep: $(SRCS:.cc=.d)
remake:
$(MAKE) dep $(EXE)
$(EXE): $(OBJS)
$(CXX) $(OBJS) $(LDFLAGS) -o $(EXE)
clean:
cd $(SRCDIR); $(RM) $(BISONSRC:.yy=.cc) $(LEXSRC:.l=.cc)
cd $(INCDIR); $(RM) $(BISONSRC:.yy=.hh)
$(RM) $(OBJS)
$(RM) $(DEPS)
$(RM) $(EXE)
-include $(DEPS)
%.cc: %.l
$(LEX) $(LFLAGS) $< > $(SRCDIR)/$(LEXSRC:.l=.cc)
%.hh:
%.cc: %.yy
$(YACC) $(YFLAGS) $<
%.d: %.cc
set -e; rm -f $@; \
$(CXX) -MM -I./$(INCDIR) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
#### End infuriating makefile
| |
| Paul D. Smith 2004-01-23, 5:17 pm |
| %% fritz_foetzl@hotmail.com (Fritz Foetzl) writes:
ff> My entire Makefile is included.
Hi; please remember to include important details such as which version
of make you're using, what system you're using it on, etc. Given the
content of your makefile I'm assuming you're using GNU make.
ff> The problem I'm having is that make insists on generating
ff> dependencies no matter which target I ask for. For example, "make
ff> clean" will generate the dependencies (if they're not present
ff> already), then promptly remove them. I understand that including
ff> the *.d files puts a lot of hidden targets into my Makefile, but I
ff> deliberately put the include *after* all the other targets.
ff> Therefore, in my mind, dependencies shouldn't get generated unless
ff> I specify "make dep", "make all", or simply "make" (any target I
ff> request has the same result.) Is there a hard-to-spot typo or
ff> other subtlety I'm not seeing?
No typo, and maybe you'd call it a subtlety, but it's really about the
most fundamental concept in make.
Makefiles are not sequential programming languages, like C or whatever.
You can't read a makefile from top to bottom as a sequence of steps that
will be performed: that's not how make works.
A makefile is an (mostly) unordered set of instructions which are all
read into the make program and internalized into a directed graph, where
the nodes are the targets and the links are the dependency relationships
between them. Once all the rules are read in and the internal graph is
completely constructed, _THEN_ make chooses a starting node and begins
its algorithm to determine whether that node needs to be updated. In
the process it checks each of its child nodes, recursively, to see if
_they_ need to be updated. If a node is not a child of the start node,
then it is completely ignored during that run of make; another run with
a different starting node may yield different results.
If no starting node (target) is specified on the command line (e.g. you
just run "make") then make starts with the first target listed in the
makefile; this is about the only time the order in which rules are
listed in the makefile comes into play. If one or more targets are
listed on the command line, then those are used as the starting nodes,
one at a time.
In GNU make, just like in C, the "preprocessor" directives like include,
ifdef, ifeq, etc. are all expanded as the makefile is read in: the
"graph parser" doesn't even see them (conceptually). For include it
just looks like a longer makefile.
SO, the fact that you put the include lines before or after a given
target in the makefile is totally irrelevant: what matters is the
dependency relationships that are contained in the makefile and the
included files.
ff> For the record, I've already R'ed the FM.
Does that mean the GNU make manual? Be sure you've read and understood
these sections:
How Makefiles are Remade
Arguments to Specify the Goals
Generating Prerequisites Automatically
Also, there's a more advanced way of handling automatically generated
prerequisites described on my web site below.
--
-------------------------------------------------------------------------------
Paul D. Smith <psmith@gnu.org> Find some GNU make tips at:
http://www.gnu.org http://make.paulandlesley.org
"Please remain calm...I may be mad, but I am a professional." --Mad Scientist
| |
| Fritz Foetzl 2004-01-23, 5:17 pm |
| "Paul D. Smith" <psmith@gnu.org> wrote in message news:<vpdrbrqjjv68.fsf@lemming.engeast.baynetworks.com>...quote:
> %% fritz_foetzl@hotmail.com (Fritz Foetzl) writes:
>
> ff> My entire Makefile is included.
>
> Hi; please remember to include important details such as which version
> of make you're using, what system you're using it on, etc. Given the
> content of your makefile I'm assuming you're using GNU make.
It's always something, isn't it?
I did neglect to mention that. Yes, I'm using GNU make version 3.79.1
on a Linux box.
quote:
>
> ff> The problem I'm having is that make insists on generating
> ff> dependencies no matter which target I ask for. For example, "make
> ff> clean" will generate the dependencies (if they're not present
> ff> already), then promptly remove them. I understand that including
> ff> the *.d files puts a lot of hidden targets into my Makefile, but I
> ff> deliberately put the include *after* all the other targets.
> ff> Therefore, in my mind, dependencies shouldn't get generated unless
> ff> I specify "make dep", "make all", or simply "make" (any target I
> ff> request has the same result.) Is there a hard-to-spot typo or
> ff> other subtlety I'm not seeing?
quote:
> If no starting node (target) is specified on the command line (e.g. you
> just run "make") then make starts with the first target listed in the
> makefile; this is about the only time the order in which rules are
> listed in the makefile comes into play. If one or more targets are
> listed on the command line, then those are used as the starting nodes,
> one at a time.
Right, but the GNU make manual goes out of its way to caution that
"-include ($SRC:.cc=.d)" should be placed *after* the first target to
prevent a random object file from becoming the default target. I did
that. However, it seems that all my dependencies are the default
target anyway, regardless of where the include statement is placed. I
understand Make's non-sequential nature, but according to the manual,
placing the include after the first target is supposed to prevent this
weirdness. It doesn't seem to be doing that, which leaves me confused.
quote:
> ff> For the record, I've already R'ed the FM.
>
> Does that mean the GNU make manual? Be sure you've read and understood
> these sections:
>
> How Makefiles are Remade
> Arguments to Specify the Goals
> Generating Prerequisites Automatically
Yes, the GNU make manual. And yes, I've pored over precisely those
sections and others. And done Google searches. And checked my books.
I've lurked here long enough to know better than to post a question
without exhausting available documentation first. I get so tired of
people responding "read the FAQ" or "RTFM", that I'd hoped I could
cirumvent that with my disclaimer. Alas...
quote:
> Also, there's a more advanced way of handling automatically generated
> prerequisites described on my web site below.
I'll check it out. Thanks!
ff
| |
| Paul D. Smith 2004-01-23, 5:17 pm |
| %% fritz_foetzl@hotmail.com (Fritz Foetzl) writes:
ff> I did neglect to mention that. Yes, I'm using GNU make version
ff> 3.79.1 on a Linux box.
Are you sure that the version of the manual you're reading is the one
associated with that version of GNU make?
ff> The problem I'm having is that make insists on generating
ff> dependencies no matter which target I ask for. For example, "make
ff> clean" will generate the dependencies (if they're not present
ff> already), then promptly remove them. I understand that including
ff> the *.d files puts a lot of hidden targets into my Makefile, but I
ff> deliberately put the include *after* all the other targets.
ff> Therefore, in my mind, dependencies shouldn't get generated unless
ff> I specify "make dep", "make all", or simply "make" (any target I
ff> request has the same result.) Is there a hard-to-spot typo or
ff> other subtlety I'm not seeing?
ff> Right, but the GNU make manual goes out of its way to caution that
ff> "-include ($SRC:.cc=.d)" should be placed *after* the first target
ff> to prevent a random object file from becoming the default target.
Yes, that's true.
ff> I did that. However, it seems that all my dependencies are the
ff> default target anyway,
That can't be true: the default target will be one and exactly one
target. It cannot be the case that "all the dependencies" are the
default target. Something else is going on here.
ff> regardless of there the include statement is placed. I understand
ff> Make's non-sequential nature, but according to the manual, placing
ff> the include after the first target is supposed to prevent this
ff> weirdness. It doesn't seem to be doing that, which leaves me
ff> confused.
The behavior you're seeing doesn't have anything to do with where in the
makefile these show up.
The reason I mentioned the manual is that (a) sometimes people check the
man page, which doesn't contain much info, rather than the user's
manual, which does, and you weren't specific about which FM you checked,
and (b) this section of the manual:
[QUOTE][color=darkred]
discusses in-depth GNU make's method of remaking makefiles. As
described in that chapter, before make tries to build any other target
(including the default target) it will first check every makefile, both
the makefile(s) listed on the command line AND ANY MAKEFILES INCLUDED
with the include or -include statement!! to determine if they are out of
date. If they ARE out of date and make knows how to remake them, then
it will (a) remake all the out-of-date makefiles, then (b) re-exec()
itself and start the processing of the makefiles all over again from
scratch.
You may not consider the files containing the dependency relationships
"makefiles", but any file in make syntax that is read by make is a
makefile to make. The above behavior is precisely what you are seeing:
make is checking each included makefile to see if it can be rebuilt, and
some can and so they are rebuilt, then make is re-exec()-ing itself (to
re-read the makefiles that were just rebuilt) and building the
Also, this section:
[QUOTE][color=darkred]
gives an example of a solution to _EXACTLY_ the problem you mentioned,
where dependency makefiles are rebuilt during a "clean" rule, when it
discusses the MAKECMDGOALS variable.
ff> Yes, the GNU make manual. And yes, I've pored over precisely those
ff> sections and others. And done Google searches. And checked my books.
ff> I've lurked here long enough to know better than to post a question
ff> without exhausting available documentation first. I get so tired of
ff> people responding "read the FAQ" or "RTFM", that I'd hoped I could
ff> cirumvent that with my disclaimer. Alas...
Strange, because this question (in one form or another) is asked about
once a month on mailing lists like bug-make@gnu.org and
help-make@gnu.org, and I know for a fact that Google walks various
archives of those lists available on the web.
Anyway, sometimes you just can't get the right search criteria to come
up with the answer you're looking for. Hope the above helps.
Cheers!
--
-------------------------------------------------------------------------------
Paul D. Smith <psmith@gnu.org> Find some GNU make tips at:
http://www.gnu.org http://make.paulandlesley.org
"Please remain calm...I may be mad, but I am a professional." --Mad Scientist
|
|
|
|
|