install-component-a:
cp ...
db reload
install-component-b:
cp ...
db reload
install-component-b:
cp ...
db reload
My Makefile does not only build but also installs the software to a system.
The snippet expounds the software have 3 components. Sometimes I update component a while the other times I may update component b and c.
The three targets all require the database to refresh.
In case I update all three components, and I run make install, I only need the database to refresh ONCE not three times.
Is there a way to schedule additional targets to run within a target?
I like something like this:
install-component-a:
cp ...
a-make-command-to-add-new-target reload-database
install-component-b:
cp ...
a-make-command-to-add-new-target reload-database
install-component-b:
cp ...
a-make-command-to-add-new-target reload-database
reload-database:
db reload
Does such a-make-command-to-add-new-target exist?
Adding reload-database to the all target or the install target may not be ideal because if none of component a, b, and c changes, the db doesn't have to reload.
Make recipes have the automatic variable $? which expands to the prerequisites newer than target.
install-component-a:
cp ...
install-component-b:
cp ...
install-component-c:
cp ...
reload-database: install-component-a install-component-b install-component-c
add new target $?
db reload
Your example suggests the targets are not files. This may be an issue as all prerequisites are considered newer than a non-existing file. In case they are not consider having the components touch a file and use that file timestamp to determine necessity for rebuild.
You cannot add new targets to be built from within the makefile. What you appear to want is a way to define commands that will always be run once after all other rules have run. There isn't something like that available.
The only way I know of to make this work is to recursively invoke make. It would look something like this:
install-component-a install-component-b install-component-c: recurse ;
recurse:
$(MAKE) $(MAKECMDGOALS:%=r-%)
db reload
r-install-component-a:
cp ...
r-install-component-b:
cp ...
r-install-component-b:
cp ...
Use make's eval function, e.g. see Metaprogramming Make VI — The eval Function
Related
I'm exploring a feature of some software that's used in a very mature Makefile to see if that feature can be incorporated into the flow. There is a target like the following:
my_target: dependency_1 dependency_2
echo foo
touch bar
# etc...
In regular use, dependency_2 would always be called before my_target's commands were executed. But for my exploration purposes, I want to selectively call dependency_2 from its own make command. And then make my_target after, possibly several times, without re-doing dependency_2 each time.
For the time being I just copy/pasted my_target into my_target_2 and removed the dependency from my_target_2 (easy enough), but I'm wondering if there's a command-line option to disable a target's dependency without modifying the file.
EDIT: dependency_2 is a PHONY target
But for my exploration purposes, I want to selectively call dependency_2 from its own make command
This is done as easy as make dependency_2
And then make my_target after, possibly several times, without re-doing dependency_2 each time
Normally, dependency_2 should be a file on the disk, so make would skip rebuilding it until its own prerequisites (source files) are changed.
But if dependency_2 is a .PHONY target ("fake file"), it will be rebuilt on each run. In this case you still can fool it like this:
echo "dependency_2:;#:" | make -f Makefile -f -
However, make will issue a warning about overriding a recipe for dependency_2.
There's no way to do this without editing the makefile, that I can think of.
You can put dependency_2 into a variable then use the variable in the prerequisite list of my_target:
dependency_2 = dependency_2
my_target : dependency_1 $(dependency_2)
then when you don't want to rebuild it, run make dependency_2= to reset the variable to empty.
Consider the following (MCVE of a) Makefile:
my_target: prepare test.bin
prepare:
echo >test.dat
%.bin: %.dat
cp $? $#
If you run make in a clean directory, it fails:
echo >test.dat
make: *** No rule to make target 'test.bin', needed by 'my_target'. Stop.
Run it again and it succeeds:
echo >test.dat
cp test.dat test.bin
What seems to happen is that the rule to make *.bin from *.dat only recognises that it knows how to make test.bin if test.dat exists before anything is executed, even though according to the output it has already created test.dat before it tries to create test.bin.
This is inconvenient for me as I have to prepare a few files first (import them from a different, earlier part of the build).
Is there a solution? Perhaps some way to allow the rules to be (re)evaluated in the light of the files which are now present?
There are a number of issues with your makefile. However based on your comments I'm inclined to assume that the MCVE here is just a little too "M" and it's been reduced so much that it has a number of basic problems. So I won't discuss them, unless you want me to.
The issue here is that you're creating important files without indicating to make that that's what you're doing. Make keeps internally a cache of the contents of directories that it's worked with, for performance reasons, and that cache is only updated when make invokes a rule that it understands will modify it.
Here your target is prepare but the recipe actually creates a completely different file, test.dat. So, make doesn't modify its internal cache of the directory contents and when it checks the cache to see if the file test.dat exists, it doesn't.
You need to be sure that your makefile is written such that it doesn't trick make: if a recipe creates a file foo then the target name should be foo, not bar.
This happens for wildcard targets, like %.bin. They get evaluated at the first pass. You could add an explicit target of test.bin. Or, follow the advice of tkausl and have test.dat depend on prepare (a phony target). In this case, you don't need the double dependency anymore:
my_target: test.bin
you have to write
test.dat: prepare
or (when when you want to stay with wildcards)
%.dat: prepare
#:
Usually, you might want to create and use .stamp files instead of a prepare target.
i have something like this in my makefile :
JAR = jar1.jar
run:
java -cp $(JAR)
what i want to do is for the makefile to do run multiple times but with each iteration, it uses another jar, they're all called jarx.jar with x going from 1 to 10 for example
is it possible to do it without passing the jar name inside the statement? the example i gave is quite simple for the sake of simplicity but the actual makefile i'm working with is already quite complicated...
make uses filesystem objects to keep state. A common solution to keeping track of things which are not directly visible as files in the current directory is to create a local flag file.
JARS := first.jar 2nd.jar thirdjar.jar
.PHONY: all run
all: $(patsubst %, .made-%,$(JARS))
run: all
.made-%.jar: %.jar
java -cp $<
touch $#
So the existence of .made-first.jar signals to Make that this target has been performed for the prerequisite first.jar, etc.
If you have a clean target, or at least realclean, it should probably clean up all the flag files.
I am transitioning to git-annex for storing data files in my git repo. With git-annex you can clone a repository and exclude the files in the annex until you specifically request them. So, Im trying to create a system in which users can build the src tree without the git-annexed data files being present during the make stage. Currently, we assume the files are present on the users filesystem, so the following snippet of the Makefile.am is sufficient:
foo_DATA=datafile1 datafile2 datafile3
EXTRA_DIST=$(foo_DATA)
However, when using the _DATA primary, an error is generated when the user attempts to make and any of the files in the list are not present. So my question is, is there a way to define the data files so that no error is generated when the data file is not present during make, but behaves exactly as the above code if the files are present during the make install step?
I have tried avoiding the _DATA primary altogether, doing something simple like the follow:
data_files=datafile1 datafile2 datafile3
install:
test -z $(foodir) || mkdir -p $(foodir)
install -c -m 644 $(data_files) $(foodir)
But that is rather hackey. Im hardcoding the "install" binary and the permission flags instead of getting them from the configure script. Ide rather just have automake not fail during the make step if the files were not present, but behave as expected in all other circumstances.
TLDR: Can I define a set of files using the _DATA primary that will not error out during make if the file is not present? But also installs exactly as the _DATA primary would if it were present?
Your current approach seems reasonable. I'd write it as an install-data-local hook, though:
data_files=datafile1 datafile2 datafile3
install-data-local:
test -z $(foodir) || $(MKDIR_P) $(foodir)
$(INSTALL_DATA) $(data_files) $(foodir)
MKDIR_P and INSTALL_DATA should be set up for you by automake.
If you'd rather not do this, the following may work in combination with your first Makefile.am snippet. I've not used git-annex before, so this may be wrong:
$(foo_DATA) :
if test ! -e $#; then git annex get $#; fi
I have a list of libraries where each have 2 files (.so, .dll).
How should I create a make rule which would execute the recipe only once if both of the files are missing or if one of them is missing.
LIBS = alib blib
LIBS_SO = $(patsubst %, %.so, $(LIBS))
LIBS_DLL = $(patsubst %, %.dll, $(LIBS))
If I make this target
$(LIBS_SO) $(LIBS_DSS):
cp .....
it copies only once for all of the the possibilities.
If I make this:
all : $(LIBS_SO) $(LIBS_DSS):
$(LIBS_SO) $(LIBS_DSS):
cp .....
I copy in all cases of any missing files.
I want to copy the alib directory if both or one of the files alib.dll / alib.so is missing; the
the same with blib.
You have a consistent typo of LIBS_DSS where you (presumably) meant LIBS_DLL.
Your first 'rule' is a shorthand for:
alib.so:
cp ...
blib.so:
cp ...
alib.dll:
cp ...
blib.dll:
cp ...
So, when asked to build, make builds the first target in the file, which is alib.so. That's why it does it once.
The second version, when fixed to remove the extra colon and the typo, should work:
all: $(LIBS_SO) $(LIBS_DLL)
$(LIBS_SO) $(LIBS_DLL):
cp .....
The default rule is all; to make all, make ensures that each of the files alib.so, blib.so, alib.dll and blib.dll exists and is up to date. It should execute the commands once for each missing target.
You might conceivably run into trouble if you run a parallel make; make -j4 or something similar. It might launch four copy commands almost simultaneously to make each of the targets. But in a non-parallel build, it will ensure alib.so is up to date (and if it isn't, will do the copy). If that copy also copies alib.dll, then it won't recopy when it ensures alib.dll is up to date.
You haven't given us much information, but I think this will do what you want:
all : $(LIBS_SO) $(LIBS_DLL):
%.so %.dll:
cp $* directory ...
If both alib.so and alib.dll are missing, Make will execute this rule only once.
EDIT: Thanks to Jonathan Leffler for catching the typo.