Makefile change directory and call git function - makefile

I am using a very basic makefile so far and there is the need to extend it.
Since I only know the most basic stuff about makefiles, I am seeking for help here.
The very top of my makefile defines a few values I use for different builds etc.
The important part here is the EVALFILE. It should link to a binary file and is mostly manually set when calling make like make ... EVALFILE="example.bin"
CC = g++
SRC = *.cpp syzygy/tbprobe.c
LIBS = -pthread -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
FOLDER = bin/
ROOT = ../
NAME = Koivisto
EVALFILE = none
EXE = $(ROOT)$(FOLDER)$(NAME)_$(MAJOR).$(MINOR)
MINOR = 0
MAJOR = 5
In case of no user-input for the EVALFILE, I like to get the file from the submodule in my git repository.
ifeq ($(EVALFILE),none)
pwd:=$(shell pwd); \
cd $(ROOT); \
git submodule update --init; \
cd $(pwd); \
EVALFILE := ../networks/default.net
endif
For this, I want to copy the pwd first to reset it later on. Then I change to the root of the repository, call my git submodule function to update the submodules. The submodule of interested here is ../networks/ which will contain a default.net which should be used as a binary eventually.
Unfortunately the code above seems to not work. When looking at the networks/ folder after I execute the make command, there seems to be no files inside of it. Furthermore the EVALFILEis not being set this way. If I move EVALFILE := ../networks/default.net to the top, it does get set but still nothing inside networks/.
I do assume I am not calling my cd, git.. calls correctly.
I am very happy if someone could help me out here.

You're doing something with the contents of $(EVALFILE). If it doesn't exist, you want to use a default file, and you might need to run a recipe to make that.
Assignments in the makefile aren't run if the variable's set on the command line.
So just do a plain assignment of the default value in the makefile, which you're expecting "is mostly manually set when calling make":
EVALFILE := ../networks/default.net
and supply a rule to make the default if it doesn't already exist:
../networks/default.net:
git -C .. submodule update --init
(with a tab subbed in for leading whitespace since markdown eats tabs).
Then in recipes that need the evalfile, pass it in as a dependency:
mytest: this that $(EVALFILE)
and everything works.

Related

Make: Avoiding issues from having same targets in multiple Makefiles

I need to know the best way of dealing with this. Also you could answer this -- after reading the sample below --: Look at the makelib target in package.make and tell me if there is a way to force this be treated as not updated if the recipe (make -C ../lib/ -f lib.make) reports as nothing to be made (not using ordered prequisites)?
I need to explain this point using an example. I have inherited this and I need the best way to make this right.
A target which other targets will be depending on:
File lib.make
--------------
.DEFAULT_GOAL = thelib.dll
%.dll: file1.obj file2.obj
makelib file1.obj file2.obj -o thelib.dll
This by itself is pretty solid. You run it once (make -f lib.make) and it creates the lib. If you run it subsequently, having no modified files, then it will tell you it has nothing to do.
Now we're going to use this in a special way somewhere else:
File: package.make
------------------
.DEFAULT_GOAL: all
all: package
makelib:
#make -C ../lib/ -f lib.make
package: makelib file3 file4
#package_files file3 file4 ../lib/out/*.dll -o package
This is how lib.make is referenced inside package.make.
The issue is even though the package gets created when you call make -f package.make all make assumes that package target needs to be rebuilt every time since one of its dependencies -- makelib -- had to be remade
Make considers makelib out of date despite what happens after entering lib.make.
To correct this I thought of a few choices:
moving makelib to the ordered prerequisites ( after the |) but that's not quite right because in case of a newly built library my package wont' be updated
adding the dll (thelib.dll) as the dependency to the makelib target a second time but this would almost duplicate the logic and break the encapsulation.
removing makelib target and moving the line #make -C ../lib/ -f lib.make to inside the package recipe. There is a problem with this and that is that I have removed the dependency between the package and lib. If lib requires update, the package won't know about it and won't get updated.
using include lib.make and then rewriting package rule to something like: package: thelib.dll file3 file4. There are problems with this also and the least of them is for a make file to be included, it must be written as such. Otherwise a lot of overwriting/conflicting targets and definitions will be introduced.
Are there any suggestions other than and directly listing the dll as the dependency?
There are two main ways this works:
First, if you use recursive make (please remember to always invoke a sub-make using $(MAKE), never make directly) then you should make the target in the parent makefile be the actual file generated by the sub-make:
package: lib/thelib.dll ...
...
lib/thelib.dll: FORCE
$(MAKE) -f lib
FORCE:
Second, you can use non-recursive make which means you include the sub-makefile into the parent make and write it so that it expects that. You can play tricks with variables etc. to make this more generic, so it can be invoked from either the parent or subdirectory, if you want.

Make starts in wrong directory under FreeBSD

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.

Makefile foreach

I'm trying to create a makefile which downloads some pre-requisite files to a path.
But the foreach documentation is sadly lacking in detail and examples.
I want something like:
image_files = a b
image_versions = 701.2 802.1
image_path = images
images = $(foreach ...) ??
I'd like that to result in an expansion to:
images/701.2/a
images/701.2/b
images/802.1/a
images/802.1/b
And have a phony target to download them from a URL like:
mytarget: $(images)
wget somepath $<
How do I do that?
Ok I have gotten a little further with this. But I'm still a little perplexed as to how I can get this to work.
tag = my-registry:8443/boot-server-data
versions = 557.0.0 607.0.0
images_a = $(foreach ver, $(versions), images/$(ver)/coreos_production_pxe_image.cpio.gz)
images_b = $(foreach ver, $(versions), images/$(ver)/coreos_production_pxe.vmlinuz)
all: build
.PHONY: build $(images_a) $(images_b)
build:
./make-profiles
docker build -t $(tag) .
docker push $(tag)
$(images_a):
wget http://stable.release.core-os.net/amd64-usr/$(foreach version... but depends on each image)/coreos_production
How do you do this?
In fact I only want it to download the images if they aren't there. But for some reason it downloads it every time. It's literally been years since I used Make. I normally use another build tool, but that build tool needs to be modified to make it do what I want here. So I thought I'd just whip this up in the meantime. It's prooving to be a little harder than expected.
You are pretty close, but the problem does not lie with foreach. Let's have a look at just the bit that does the downloading. When make reads the makefile it ends up with something like (after shortening the names a bit for clarity):
images/1/file.cpio.gz images/2/file.cpio.gz:
<recipe>
If, for some reason, make decides to rebuild images/1/file.cpio.gz say, at this point it will expand the recipe, and pass each line of that expansion to a separate shell.
Your job is to write a recipe that does not care whether the target is images/1/file.cpio.gz or images/2/file.cpio.gz. That's another way of saying the recipe should use macros like $# (it will expand to the target).
A sketch:
${images_a}:
wget -O $# http://stable.release.core-os.net/amd64-usr/$#
You may have to munge $# so that wget gets the right url. Just one example:
${images_a}:
wget -O $# http://stable.release.core-os.net/$(dirname $#)/deeper/$(notdir $#)
One complaint about your original makefile: the dependencies are wrong. build needs the downloads to have completed before it runs.
.PHONY: build
build: $(images_a) $(images_b)
...
The images are not phony (just ensure you don't lie to make abut their filenames) either.
The massive advantage of writing your makefile in this way is that it's parallel safe (and that's the whole point of make). When -j is in force, both wgets can proceed at the same time, halving the download time.

how to use recursive make with an option telling it not to travel down the tree if needed?

I setup make to build my tree using recursive make. So the setup is
A/Makefile a.c
A/B/Makefile a.c
A/B/C/Makefile a.c
where if I issue the command make all from level A/ then make will travel down the tree building everything and then come back up. Each Makefile contains a list of folders below it to build. There is a common.inc file in the root which is read in each Makefile.
This is just a standard layout for recursive make, and nothing new. The details is gives in many places. here and here are examples.
My question is this: many times I'd like to do make all but only build things in the current folder, and not actually travel down the tree, may be because I want to test some changes in the current folder at this time. So I end up editing the current folder's Makefile by commenting out the SUBDIRS=A B C which lists all folders below, or by adding new special targets for this folder only. Both are annoying things to have to keep doing.
Does any one have an idea or a small example of a recursive makefile that uses a switch to tell it if it should travel down the tree or not when called? may be there is a way to call make and pass it some flag at the command line, and this flag is used to remove SUBDIRS=A B C ..... list so it only stops at the current folder level?
Just to be clear. I am using standard SUBDIRS in the Rules.mk, which each Makefile in the tree includes. Here is the part. I copied this from the net long time ago
$(SUBDIRS)::
#if test -d $#; then \
set $(EXIT_ON_ERROR); \
echo "cd $#; make $#"; \
cd $#; make $#; \
set +e; \
else \
echo "Skipping non-directory $#..."; \
fi \
$(CLICK_STOPWATCH);
endif
and in each folder Makefile I write
SUBDIRS = A B C
include Rules.mk
all:: .......
Then I just write make all to build. If there is a way to do make all LOOP=0 where LOOP is some value I pass it or an option or a string or something and then change the above SUBDIRS logic to check for the value of this LOOP and based on the value then do the recursive make or not, then the problem is solved. The default can be to LOOP=1 if it is missing from the command line.
But I do not know enough Make to program this type of logic.
You should use power of rules' depencies. Add your sources files to the dependencies of the rule called from the "root Makefile". If these files are up to date, the recursivity in an folder will stop because the rule is 'up-to-date', and nothing will be done.
Don't add .PHONY for all your rules in the sub-directory Makefile, otherwise recursives rules will be called.
Play with the dependencies of the rules can be the key to not make recursive call, but if you modify sources in each folder and want to build only from the root Makfile, you have to create another rules. With make all, the make binary may not know if you want build all your projet or not (if all your sources has been modified).
EDIT: choice by the command line
You're near the answer, you can set env var while calling your make all and test the value to decide calling recursivly or not.
CC=g++
SUBDIR=a b
all: ${SUBDIR} main.cc
${CC} main.cc
${SUBDIR}:
ifneq ($(MK_LOOP), 0)
#echo "trust the recursivity !"
${MAKE} -C $#
endif
.PHONY: ${SUBDIR}
If you don't set the MK_LOOP var or you set to something else than 0, it will not be equal to 0 so recursive Makefile will be call; if you set to 0, $(SUBDIR) rule do nothing
42SH $ MK_LOOP=0 make # no recur
42SH $ make all
trust the recursivity !
42SH $ make all MK_LOOP=1 # recur by default; same as : make all
trust the recursivity !
42SH $

How do you run a command prior to including a component Makefile?

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 $#

Resources