j4x
j4x

Reputation: 3716

Makefile trick to get dependencies of a rule

Is there any trick in GNU Makefiles to get all dependencies of a rule?

Example:

rule1:  dep1_1 dep1_2 dep1_3

rule2:  dep2_1 dep2_2 rule1

dump_deps:
    echo "Dependencies of rule1: $(call do_the_trick, $(rule1))"
    echo "Dependencies of rule2: $(call do_the_trick, $(rule2))"

install:   $(prefix install-,$(call do_the_trick, $(rule1)))

I'd like to be able to call make dump_deps and see:

dep1_1 dep1_2 dep1_3
dep2_1 dep2_2 dep1_1 dep1_2 dep1_3

Or automatically install dependencies with make install and things like.

Is it possible?


EDIT:

I changed the example to show better that I want something automatic, and not having to hardcode dependency lists myself.

Upvotes: 3

Views: 2632

Answers (3)

The Real Edward Cullen
The Real Edward Cullen

Reputation: 438

You can't show the transitive dependencies, only the direct ones, however, you can take the output generated below and feed it into the programs dot (part of graphviz) to make sense of the these transitive relationships.

Edit: I guess you could also post-process the results in other ways to just list the deps, but I think pretty pictures are better; feel free to downvote if you disagree ;)

Here's a sample makefile (watch for missing tabs when c&p!):

# Makefile that demonstrates how to dump dependencies.
# The macros we use for compiling stuff.
CC_OBJ=$(CC) -o $@ -c $(CFLAGS) $<
CC_BIN=$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^

# If we get "DUMP_DEPS=1 DUMP_DOT=1" on the command line, then instead of
# make-style dependencies, we'll output 'dot' syntax.
# Note: normally, DUMP_DOT_TAIL is undefined, so it doesn't generate any noise.
ifeq ($(DUMP_DOT),1)
DUMP_DOT_HEAD=digraph dependencies {
DUMP_DOT_TAIL=@echo "}"
$(info $(DUMP_DOT_HEAD))
list_dep=@for f in $^; do echo "    \"$@\" -> \"$$f\";"; done
else 
list_dep=@echo "$@: $^"
endif

# If we get "DUMP_DEPS=1" on the command line, then
# instead of building the code, just print the dependencies.
ifeq ($(DUMP_DEPS),1)
CC_OBJ=$(list_dep)
CC_BIN=$(list_dep)
endif

# An implicit rule that builds *.c -> *.o.
%.o:%.c
    $(CC_OBJ)

# Variables for stuff we wanna build.
target=hello

objects=main.o
objects+=stuff.o
objects+=yeah.o

# The top-level 'all' target.
.PHONY: all
all: $(target)
    $(DUMP_DOT_TAIL)

# Builds our final executable
$(target): $(objects)
    $(CC_BIN)

# A standard clean target.
.PHONY: clean
clean:
    -rm -f $(target) $(objects)    

Now, you can do this:

make -B DUMP_DEPS=1

And it will go through and list all your pre-requisites is make style of "target: pre-requisite". Sample outputs:

Normal run:

cc -o main.o -c  main.c
cc -o stuff.o -c  stuff.c
cc -o yeah.o -c  yeah.c
cc -o hello  main.o stuff.o yeah.o

With make -B DUMP_DEPS=1:

main.o: main.c
stuff.o: stuff.c
yeah.o: yeah.c
hello: main.o stuff.o yeah.o

With make -B DUMP_DEPS=1 DUMP_DOT=1:

digraph dependencies {
    "main.o" -> "main.c";
    "stuff.o" -> "stuff.c";
    "yeah.o" -> "yeah.c";
    "hello" -> "main.o";
    "hello" -> "stuff.o";
    "hello" -> "yeah.o";
}

You could then run the following to output a pretty picture to an SVG image:

make -B DUMP_DEPS=1 DUMP_DOT=1 | dot -Tsvg > deps.svg

Here's what it looks like (this is actually a png, generated with -Tpng > deps.png):

image

I think this would need some extra work to produce accurate results in all situations, but the principle is sound (e.g. if you use gcc-generated dependency files, you'll need to create them first).

Upvotes: 3

Nitin4873
Nitin4873

Reputation: 17572

use the buit in variables available with the make utility , $^ -- this represents all the dependencies of the rule.

also looking thru your code , i did make the rule1 into a variable / macro form to suit my purpose ......

rule1 := dep1 dep2 dep3

Upvotes: 1

shargors
shargors

Reputation: 2157

This should list all of the dependencies:

DEPEND = dep1 dep2 dep3

.PHONY: $(DEPEND)

dump_deps: $(DEPEND)
     @printf "%s\n" $^

You should remove the line with .PHONY target for your needs. It is used for the sake of the example. And please note that there is a tab between the beginning of the line and printf.

Upvotes: 1

Related Questions