I have a directory tree like this with some "shared targets" in the file rules.Makefile:
├── Makefile
├── rules.Makefile
└── my_subdir
└── Makefile
I would like to invoke these "shared targets" in both the Makefile(s) in the parent directory and the child directory.
Also the "custom targets" in the Makefile in the child directory should be callable from the Makefile in the parent directory.
For some reason I am able to call the targets in rules.Makefile only from the sibling Makefile (the one in the parent directory). When using relative paths in the Makefile in the child directory trying to access the rules.Makefile in the parent directory I get some errors.
The content of the Makefile in the parent directory:
RULES_MAKEFILE_PATH=$(PWD)/rules.Makefile
include $(RULES_MAKEFILE_PATH)
foo-parent:
#echo $(RULES_MAKEFILE_PATH)
The content of the Makefile in the child directory (please note that double dot ..):
RULES_MAKEFILE_PATH=$(PWD)/../rules.Makefile
include "$(RULES_MAKEFILE_PATH)"
foo-child:
#echo $(RULES_MAKEFILE_PATH)
When calling from the parent directory make foo-parent then I see the expected path.
When calling from the child directyr make foo-child then I see this error:
$ make foo-child
Makefile:9: "/<PARENT_PATH>/my_subdir/../rules.Makefile": No such file or directory
make: *** No rule to make target '"/<PARENT_PATH>/my_subdir/../rules.Makefile"'. Stop.
How can I make the relative paths work in the "child directory"?
Also how can I call the targets defined in the Makefile in child directory (e.g. foo-child) from the Makefile in the parent directory?
Well first, $(PWD) is not a special variable to make. It's just a normal variable, that's imported from your shell. So it will always have the same value everywhere in your makefile and in all included makefiles, it won't change just because you're including a makefile from a different directory.
Second, even for $(CURDIR) (which is a special variable and is set by make to be the current directory when make starts), it is never reset when you include a makefile from another directory.
And, all paths in include lines are evaluated based on the directory make was in when it started, not on a path relative to the currently-parsed makefile. So if Makefile includes foo/Makefile, then foo/Makefile has an include bar.mk, make will look for bar.mk not foo/bar.mk.
The point about $(PWD) above is true. However, if that is not a concern, you could still use the shell function to execute commands to get paths of another Makefile to include: $(shell pwd)
I did something similar for a project that benefited from having the same Makefile used in many places, using git rev-parse --show-toplevel.
MAKEFILE := $(shell git rev-parse --show-toplevel)/makefiles/example.def
include $(MAKEFILE)
Related
I have the following directory structure
project
|-- aws-cdk
|-- data
|-- some_project_files
|-- Makefile
Using the Makefile, I'm executing the directory some_project_files and this is working fine. In addition to that, I want to execute aws-cdk as well. But I do not see a way to change the directory within the makefile. I tried cd aws-cdk and then execute but I keep on getting error make: *** No rule to make target. Stop.
How do I go back/change directory and then execute Makefile
Within one makefile you can change directory inside the rules, but you can't say this set of rules runs in one directory and this one runs in the other. Which does not prevent you running rules on files in a different directory by simply giving their path. The data/Makefile can contain rules for ../aws-cdk/something and even ../aws-cdk/%.out: ../aws-cdk/%.in and that's just fine.
If you do want to actually change directory, you need a separate makefile. I strongly recommend just putting it in the directory where it will run, so aws-cdk/Makefile and then you can just call it from the one in data like $(MAKE) -C ../aws-cdk. You can also put it anywhere else and give make an explicit argument like $(MAKE) -C ../aws-cdk -f aws-cdk.make, but putting it in the directory will be easier to understand when it needs fixing two years down the line and/or by someone who's never seen it.
Assume that I have a the following directory structure:
MyApplication
Module_A
mylib.c
Module_B
main.c
more.c
Configuration
Config1
Makefile
Config2
Makefile
When launch make in MyApplication directory with whatever target and whatever options, I would like it to be run in MyApplication/Configuration/Conig1 directory rather than the top directory. How can I make this happen without hardcoding the targets in the top level Makefile ?
You could create a makefile in MyApplication/Makefile as so:
CONFIG?=Config1
include Configuration/$(CONFIG)
If you want to build config1, you can either type make or make CONFIG=Config1. If you want to build config2, you type make CONFIG=Config2...
A Makefile contains
include ../../common/common.mk
at the end of the file. I want to see the full path during the invocation. How can I do that?
$(info full path to common.mk: $(abspath ../../common/common.mk))
include ../../common/common.mk
Usually, make does not change working directory during execution. Most likely, you can check for ../../common/common.mk from command line just before running **make*. But if you use make -C some/directory then the working directory will be whatever you specify after -C (relative to your current directory).
I have a very simple Makefile that just shells out to another Makefile:
all:
cd src && make all
My directory structure (the Makefile is in the top-level directory):
[I] mqudsi#php ~/bbcp> tree -d
.
├── bin
│ └── FreeBSD
├── obj
│ └── FreeBSD
├── src
└── utils
This works just fine under Linux, but under FreeBSD, it gives an error about src not being found.
To debug, I updated the Makefile command to pwd; cd src && make all and I discovered that somehow when I run make in the top-level directory, it is being executed under ./obj instead, meaning it's looking for ./obj/src/ to cd into.
Aside from the fact that I have no clue why it's doing that, I presumed for sure that calling gmake instead of make under FreeBSD would take care of it, but that wasn't the case (and I'm relieved, because I can't believe there is that huge of a difference between BSD make and GNU make in terms of core operation).
The odd thing is, deleting obj makes everything work perfectly. So in the presence of an obj directory, make cds into ./obj first; otherwise it executes as you'd expect it to.
Answering my own question here.
From the FreeBSD make man page:
.OBJDIR A path to the directory where the targets are built. Its
value is determined by trying to chdir(2) to the follow-
ing directories in order and using the first match:
1. ${MAKEOBJDIRPREFIX}${.CURDIR}
(Only if `MAKEOBJDIRPREFIX' is set in the environ-
ment or on the command line.)
2. ${MAKEOBJDIR}
(Only if `MAKEOBJDIR' is set in the environment or
on the command line.)
3. ${.CURDIR}/obj.${MACHINE}
4. ${.CURDIR}/obj
5. /usr/obj/${.CURDIR}
6. ${.CURDIR}
Variable expansion is performed on the value before it's
used, so expressions such as
${.CURDIR:S,^/usr/src,/var/obj,}
may be used. This is especially useful with
`MAKEOBJDIR'.
`.OBJDIR' may be modified in the makefile via the special
target `.OBJDIR'. In all cases, make will chdir(2) to
the specified directory if it exists, and set `.OBJDIR'
and `PWD' to that directory before executing any targets.
The key part being
In all cases, make will chdir(2) to specified directory if it exists, and set .OBJDIR'PWD' to that directory before executing any targets.
By contrast, the GNU make manual page makes no such reference to any sort of automatic determination of OBJDIR, only that it will be used if it is set.
The solution was to override the OBJDIR variable via the pseudotarget .OBJDIR:
.OBJDIR: ./
all:
cd src && make
clean:
cd src && make clean
An alternative solution is to prefix the cd targets with ${CURDIR}, which isn't modified after the chdir into OBJDIR.
I don't get why gmake behaved the same way, however. That feels almost like a bug to me.
I'm trying to understand the Makefile that is automatically produced by sphinx-quickstart. Here it is:
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = myproj
SOURCEDIR = source
BUILDDIR = build
.PHONY: help Makefile
%: Makefile
#$(SPHINXBUILD) -M $# "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
The lines that confuse me are:
.PHONY: help Makefile
%: Makefile
I think I understand:
The % target means capture anything (wildcard). E.g., if I typed make html, % would capture html.
.PHONY Makefile means that make shouldn't look for a file called Makefile in its directory, thus, shouldn't check the file's modified time to determine whether or not to run a rule.
I don't understand:
Why Makefile is listed as a prerequisite for the target %. The way I interpret this is:
The target rule captured by % should run when the Makefile is changed.
But that doesn't make any sense in the context. What I would expect is:
The target rule captured by % should run when the source files for the project documentation or the API source files have changed.
Directory structure
.
├── build
├── Makefile
├── source
└── utils
The .PHONY: foo has the effect that foo is never to be considered up-to-date. (but see https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html for the more detailed explanations: the main use is for targets which are not filenames)
If you then have bar: foo, the rules for bar target will always be executed on make bar because the target depends upon foo but foo is considered never up-to-date. This can also be achieved with declaring bar target to be PHONY itself.
The problem with the catch-all % target was in case the repertory where the Makefile is located contained a repertory or a file having same name as a Sphinx builder. Say for example there is an html or a man in repertory where Makefile is located: then make html will not do anything if % has no dependencies, because html is then a file or repertory with no dependencies, hence never to get updated.
Thus the % was made to depend on Makefile pseudo target, and Makefile itself declared PHONY so that it is considered never up-to-date.(*) Even if repertory contains a file html then make html will get executed (and html repertory in build dir modified; the html in Makefile repertory will not be modified).
(*) edit: I had forgotten the exact details: Makefile is always considered a target, see a surprising (?) behaviour of GNU Make when using ``%`` as target. For reasons explained here % was made to depend upon Makefile, and the Makefile was declared PHONY in fact to avoid make complaining about circular dependency...
The idea is that the Makefile should not contain the hard-coded list of all possible builders: else they could have been declared PHONY targets individually, but then Sphinx maintainers would have to worry about keeping the Makefile template up-to-date when adding a new builder. It would also cause problems when projects keep same Makefile but a new Sphinx release adds a new builder.
The Makefile now created by sphinx-quickstart does not have to be modified if a new builder is added to Sphinx. It is of course certain that never will Makefile be the name of a builder...