My project has the following directory structure (some files hidden for
clarity):
Makefile.am
tests/
Makefile.am
a/
Makefile.am
b/
Makefile.am
c/
Makefile.am
If I put all the tests to run that are in the a/, b/, and c/
subdirectories in the TESTS variable of tests/Makefile.am, then with
make check in tests/, all the tests run, even if one test in one of
the subdirectories fail. Assume this is the behaviour I want.
With this configuration, however, I cannot go to b/, for example, and
run make check: since there's no TESTS variable there, make check
does nothing.
So I put a TESTS variable in a/Makefile.am, b/Makefile.am, and
c/Makefile.am, and remove the TESTS variable from tests/Makefile.am. Now
I can go to a/, b/, or c/ and run make check to test only specific
parts of the project. However, since each individual make check can
fail, now the "global" make check in tests/ fails as soon as one
subdirectory fails, which is the expected behaviour of Make.
My current workaround is to use make --keep-going check in tests/, so
that, as per make(1):
Continue as much as possible after an error. While the target that
failed, and those that depend on it, can‐ not be remade, the other
dependencies of these targets can be processed all the same.
This seems to run all the individual make check and exit with
something else than 0 if one of them fails.
I can also wrap this make --keep-going check in a new target, for
example:
test:
$(MAKE) $(AM_MAKEFLAGS) --keep-going check
Now make test does what I want in tests/.
Is there anything more "Automaky" I could do to achieve the same goal?
Or is using make --keep-going check the expected method here if I
don't want Make to stop as soon as one subdirectory test fails?
Related
I know what a .PHONY does.
If in the folder where my Makefile is, I add an empty file called clean and after I run make clean all of the clean target will not be executed since there was not any change in the file, so the target will not run and this is correct.
If I add .PHONY: clean, than the clean is seen as a command and this is also correct.
My question is why this behavior does not happen the same to all target, since I added a all file in the folder.So basically the all target still executes like if it was a .PHONY: all
I have the fallowing makefile code.
all: test1 test2
test1: test1.o
test1.o: test1.c
test2: test2.o
test2.o: test2.c
clean:
rm -rf *.o test1 test2
How do you know that the all rule is "still executing"? That rule has no recipe, so there's no way it can be "executed".
If what you mean is that even though the all file exists in the local directory, make is still building the targets test1 and test2, that's how make works (this doesn't have anything to do with phony vs. non-phony targets). When make decides whether or not build a particular target first it tries to build all the prerequisites of that target, and all the prerequisites of those targets, etc. Only after all that is complete, can make know whether or not to build the first target (all in this case).
make clean here doesn't have any dependencies, so putting a file named clean there is enough for the target to be considered built.
make all on the other hand has dependencies. Even if you put a file named all there, Make has to check whether the all file is newer than test1 and test2. This process triggers builds of test1 and test2, and it happens to have the same effect as if all was a phony target.
The basis is that all: test1 test2 is a recipe for building a file named all, that depends on the files test1 and test2.
If you ran make all, Make would do something like this:
Analyse the Makefile.
Find out that all depends on test1 and test2.
Check the timestamp of all and see if it is "up to date".
It is "up to date" if none of the dependencies are newer than itself.
In other words, Make can skip building a file if it's newer than all it's dependencies.
Build outdated or missing files.
Now, if you would like to prevent Make from considering the targets as files, you could specify them as phony targets. That is best practice for non-file targets like all.
(This answer isn't disagreeing with either of the existing answers, but suggesting another way of thinking about this).
When you have a rule like
dst: src
action
you're saying two things (as you know):
if dst doesn't exist, or is older than src, then do action; and
when action completes, the file dst will exist.
With targets such as all or clean, the second statement is of course not true. Make doesn't hold you to the promise in (2), so when you say make all, it'll compute and generate the required dependencies, and not complain that there's no file all in place afterwards. You're lying to Make, but it doesn't mind (it's cool with that...). That is, this is basically a makefile hack.
Where this goes wrong, of course, is if for some reason there happens to be a file called all or clean. Then Make will take the modification date of the file all into account when calculating the dependencies, and possibly come to a conclusion you didn't expect.
So what .PHONY: all does is legitimise the hack, and tells Make ‘even if a file all exists, pretend that it doesn't’; you're basically cancelling promise (2).
Therefore, as the other answers state, mentioning .PHONY isn't necessary. It simply forestalls an error – easy to make but easy to miss – when a file matching a phony target is accidentally created.
I have a source code folder structure as follows
src
|-tests
|-abc
I have a makefile in src which has a target called tests. tests has its own makefile which it uses to compile the source code into binary.(multiple targets).All that is managed by the Makefile in the test directory.
My src make file has the following targets.
all: main tests
main: $(DEPENDENCY IN SRC and ABC)
command
tests: ??
make -C tests
What dependancy can I specify for tests target in the main Makefile.. I don't want this Makefile to be aware of the source files in the tests folder.
all: main tests
main: $(DEPENDENCY IN SRC and ABC)
command
tests:
$(MAKE) -C tests
this will unconditionally invoke make of tests on its private subdirectory. Note that usage of special $(MAKE) variable helps to propagate command-line parameters and reduces overhead.
Just declare the target as PHONY meaning that make will not check for any produced file. Instead it just always executes the rule, letting the secondary call to make to decide what needs to be built.
Think about this: What happens if you have an aditional file src/tests? make will notice that the file already exists and, as no prerequisite is indicated, it will decide not to make that file. Preventing your rule tests from being executed.
all: main tests
main: $(DEPENDENCY IN SRC and ABC)
# Recipes (That is the word to describe commands in a make rule)
.PHONY: tests
tests:
$(MAKE) -C tests
Also add the answer by Alex: using $(MAKE) is a good practice. And allows your makefiles to work independently from the name of the make program. Imagine that you have a distribution where the program is called xyz-make.
I don't want this Makefile to be aware of the source files in the tests folder.
Perhaps, but you may want to reconsider. Peter Miller's Recursive Make Considered Harmful makes a strong case that one Makefile is all you ever need, or want. It changed my mind a long time ago.
I am trying to create a subdirectory in my project (let's call it $PROJECT/child) that needs to pull in a Makefile (let's call it ../Makefile.inc) from its parent, $PROJECT/Makefile.inc. Later I want to copy $PROJECT/child somewhere else so it can run independently of $PROJECT.
There is a common Makefile that needs to be included in both projects and shipped when the subdirectory is copied, and I want it to be included in both cases. So I thought I would link it in during the child build, if it isn't found. (I don't want to just include ../Makefile.inc, because this will disappear when I copy the project, and I don't want the calling build system to be responsible for putting the Makefile.inc in place.)
With those constraints, here's a horrible hack that I've come up with to do this, within $PROJECT/child/Makefile:
HACK = $(shell test -f Makefile.inc || ln -f ../Makefile.inc .)
include $(HACK)Makefile.inc
Notice the extra special duct tape on that second command. I have to actually include $(HACK) even though it's going to end up empty, so that the $(shell ...) will be evaluated. ;-)
Is there a cleaner way to make this happen?
Give a rule to build Makefile.inc. (make will complain that Makefile.inc doesn't exist when it parses the include line, but it will go on parsing the main makefile, apply any rule to build included files, and go back and re-parse the main makefile with the included files.)
include Makefile.inc
Makefile.inc:
ln ../Makefile.inc $#
Part of my Makefile:
CPUDEPS=./mydeps.cpu
(...)
deps: $(CPUDEPS)
$(CPUDEPS): $(CCFILES)
#echo [DEPS] CPU
$(CMDECHO)makedepend -Y -s'# CPU sources dependencies generated with "make deps"' \
-w4096 -f- -- $(CFLAGS) -- $^ 2> /dev/null > $(CPUDEPS)
(...)
sinclude $(CPUDEPS)
Problem 1: includes are done during the first phase of processing, targets during the second phase; so, if ./mydeps.cpu doesn't exist and I "make deps", I get first the error
Makefile:335: ./mydeps.cpu: No such file or directory
I hide the error using sinclude instead of include, but the problem is still there: the old file is included, not the just-generated-one. Have to run it twice to include the updated file. This is because make does a two-phase processing; is there any way to tell make to complete the target deps before parsing the includes?
Problem 2: even if the file ./mydeps.cpu doesn't exist and make deps actually creates it, I always get a "make: Nothing to do for deps". This doesn't happen with other targets. I don't understand why and how to avoid it.
Problem 1 is non-existant: before building a target, make automatically rebuilds makefiles (with implicit rules if no explicit rule is provided). So having a rule for the makefile ensures that will always be up to date, there is no need to run deps twice. Additionally, since CPUDEPS is a makefile, it will be updated automatically before any other rule is run, so dependencies will always be updated if necessary and make deps is not needed. You can probably notice this by yourself by observing the [DEPS] line being echoed if any of the CCFILES becomes more recent that the dependency file.
For Problem 2, adding anything to the recipe ensures that make doesn't complain about having nothing to do. If there is nothing else, you can use something like #echo OK to give feedback to the user, or a simple #true if you prefer totally silent makes.
What you are trying to achieve is useless: you can use the dependencies file that was created during the previous build. That's enough.
The main reasoning behind that rule is:
if you haven't changed any of your files, then the dependencies file is up-to-date, and there's nothing to build.
if you have changed anything, even very deep into your #include chain, on an existing file that were used by previous build, then the dependencies file have already caught it. You'll rebuild what is needed.
if you change something in a new file (you add that file!) then it was not used by previous build, and not listed in dependencies. But if you really want to use it, then you have to modify at least one of your other files that was used before, and you're back on the previous case.
The solution is to create the dependencies file during the normal process of the compilation, and to optionally include it (with sinclude) if it is present.
I have a project that I am working to release that actually contains 3 subprojects, all of which need to be compiled in one go. My makefile looks roughly like this:
all: a b c
a:
#cd a && make
b:
#cd b && make
c:
#cd c && make
Projects A and B both compile fine but for the 3rd project, it tells me there is nothing to be done although switching to the C directory and running make does in fact compile code.
To be a little more specific: Project C in the example above is actually Mozilla's SpiderMonkey. Whereas A and B are code/makefiles that I have written, C is just a raw copy of SpiderMonkey from the Mozilla website. The actually compile command for it is:
make JS_DIST=/usr JS_THREADSAFE=1 JS_HAS_FILE_OBJECT=1
In my master Makefile, I have:
spidermonkey:
#cd spidermonkey/src && $(MAKE) JS_DIST=/usr JS_THREADSAFE=1 JS_HAS_FILE_OBJECT=1
Running "make spidermonkey" outputs "make: Nothing to be done for `spidermonkey'." How do I get make to run the command?
EDIT:
I've tried adding the following lines to my makefile:
.PHONY: spidermonkey
As well as renaming the spidermonkey rule to sm, but still no change.
EDIT:
My bad! I had spaces when I should have had a tab. doh!
You probably have a file or directory at the toplevel called "spidermonkey". Make thinks this is what its supposed to create, and since it is already there, make stops.
One of the most important rules to follow when writing makefiles is each target should create one file with the same name as the target. In other words, if you have
a:
<some command>
That command should produce a single file called "a".
Rules which do not produce files but are only there as placeholders are called phony targets, and they should be declared like this:
.PHONY: a
Make will then always assume that a has to be remade.
Also, as a general rule do not use "make" to invoke make recursively, use $(MAKE) instead.
EDIT: changed "pseudo" to "phony"
Make only checks for the existance of a file (or directory) named the same as the rule target, and if there is (and it is newer than the dependencies) then from make's point of view there is nothing more to do.
So your problem is that you have a spidermonkey rule (with no dependencies) as well as a directory called spidermonkey, and then make thinks "the target is already made, nothing for me to do". To get make to do what you want, rename the spidermonkey rule (or the directory).
Speaking of recursive make by the way, this is not neccessarily a good idea,
see Recursive Make Considered Harmful.