开发者

Makefile: can (GNU) make internally report whether a target needs updating?

开发者 https://www.devze.com 2023-02-01 21:48 出处:网络
This is my problem: I can build a binary in one of two ways and each has checks that can be done on them (under their own make targets); I would like a check target to run whichever target is appropri

This is my problem: I can build a binary in one of two ways and each has checks that can be done on them (under their own make targets); I would like a check target to run whichever target is appropriate dependent on which build target was run under a previous call of make: can this be done internally without touching files or some other "external" way of recording which build target was run?

An illustration may help:

.PHONY: all modified
all: $(obj)
    $(CXX) ... -o $(BIN)

modified: $(obj) $(extra_objs)
    $(CXX) ... -o $(BIN)


.PHONY: check check_all check_modified
check_all: all
    ...

check_modified: modified
    ...

check:
    # ??? Some makefile variable I don't know about?

so that I can ask this of the shell:

make X       # <-- X = {all, modifie开发者_StackOverflow社区d}
...          # <-- this is important: this is not a question of target dependency
make check   # <-- have `check' run `check_X' target

I figure that the only way for a particular make call to know which target was run before is by determining if it needs updating or not. Id est, if all is up-to-date, then run check_all, if modified is up-to-date then run check_modified, and default to check_all.

So, can I ask make "internally" whether target X would be updated if I asked to run it? "Internal" meaning no calling of $(MAKE) -n, or no touch Y and then asking the shell if [ -f Y ] ....

As you can see, it's not quite a question of dependency because that, clearly, will build the dependency when all I want to do is check to see whether it has been run before. So, any ideas or (alternative suggestions)?

UPDATE:

OK, I guess the answer is: No. The best I can probably do is this:

.PHONY: check
check: $(if $(wildcard $(firstword $(extra_objs))),check_modified,check_all)

Obviously, this method is functionally the same as creating a file when creating one of the targets and then checking for that, but in this case the file I'm checking for is created anyway and unique to the target that creates it, which I suppose makes it slightly less ugly.

(Note: I ran into the problem that:

.PHONY: check
check:
    $(MAKE) -q modified && $(MAKE) check_modified || $(MAKE) check_all

won't exactly work for the code I had above because all and modified are phony and so will always need updating as far as make is concerned, so that kind of rules that one out! But, it's a simple and concise way of solving the problem for targets named after the file they'd create so I'll mention it for reference.)


Maybe spawning another make internally with the -q flag helps?

Usage: make [options] [target] ...

Options:

[...]

-q, --question Run no commands; exit status says if up to date.


You could record the build type in a file and read that back later to pick the right "check" target like so:

all: $(obj)
    $(CXX) ... -o $(BIN)
    echo $@ > $(BIN)-kind

modified: $(obj) $(extra_objs)
    $(CXX) ... -o $(BIN)
    echo $@ > $(BIN)-kind

check: $(if $(wildcard $(BIN)-kind),check_$(shell cat $(BIN)-kind))


To answer the title of your question, see double colon rules. Quoting the manual:

Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.

Sounds (almost) just what you are after.

0

精彩评论

暂无评论...
验证码 换一张
取 消