21
votes

According to what I have read about makefiles, a phony target is any target that does not correspond to an actual filename. My intuition says that a directory as a target would be treated the same as a file.

Why is this important? I have a directory as a target in my makefile. when I have it as a prerequisite to my primary executable, that executable always gets made, whether or not everything is up to date. If I take it out as a prerequisite, my makefile is smart enough to know when things need to be built, but I have the problem of not knowing if the directory needs to be created. According to what I have read about make, any phony targets are not good as prerequisites because make does not know if they are up to date, so they will always rebuild the associated target. Here is an excerpt from my makefile.

$(EXEC_WITH_PATH): ${OBJ_DIR} $(DPEND) $(OBJS)
    @echo "--------------------------------------------";
    @echo "$(THIS_DIR)  $(MACHINE)";
    @echo "Linking Shared Library";
    @echo "ar -rc $(EXEC_WITH_PATH) INSERT::{OBJS}";
    ar -rc $(EXEC_WITH_PATH)  $(OBJS);
    @echo "--------------------------------------------";


# Make dirs for object code and links
${OBJ_DIR} :
        @if [ ! -d ${OBJ_DIR} ]; then \
                mkdir ${OBJ_DIR};    \
        fi;

So in this case, is ${OBJ_DIR}, a directory name, a phony target or not?

2
anyway to solve your problem you can have a mkdir command preceded with a "-" so that make ignore the return value.siukurnin
@siukurnin: No, you should use mkdir -p, so that it will succeed if the directory already exists, but fail properly if the directory can't be created.Cascabel
For what it's worth, I think the problem is that the directory is a prerequisite for the file that is in that directory. So in most cases the prerequisite directory and the target have the same timestamp, causing the target to be made every time.Chance
Yes, thats the problem. See my answer on order-only prerequisites.camh

2 Answers

36
votes

Edit: This only applies to GNU make - a fair assumption given the "linux" tag.

Your target is a real target, not a PHONY one. The problem is that the output directory gets updated when you put targets in it so that it is always newer than your target. This means your target will always get built because it is out of date with respect to its dependencies.

What you need is an order-only prerequisite. These prerequisites allow you to specify that it needs to be built if it does not exist, but not to pay attention to the timestamp. That is, a target will not be out of date with respect to order-only prerequisites.

You specify it like this:

$(EXEC_WITH_PATH): $(DPEND) $(OBJS) | ${OBJ_DIR}
...

Anything after the vertical bar is an order-only prerequisite.

You can now make your OBJ_DIR target simpler:

${OBJ_DIR} :
        mkdir -p ${OBJ_DIR}

Note: I've used the ${OBJ_DIR} syntax instead of $(OBJ_DIR) because that is what you used. Order-only prerequisites do not depend on that syntax.

8
votes

It's a real target.

Phony targets are not detected automatically by the make system - they must be identified by you, using the .PHONY target.

Sensible phony targets include all and clean - these don't correspond to real files, but to actions you want the makefile to do. Here's how to explain this to make:

.PHONY: all clean install test

Directories are legitimate targets of makefile rules. You should not make these phony.

mydir:
     mkdir mydir

The .PHONY target is of course, phony.

GNU Documentation can be found here.