folder's content as makefile rule dependency - makefile

I would like to have all folder's content in dependency. My folder is created when the rule is called.
create-content:
mkdir -p sample_dir/subdir1
touch sample_dir/file1
touch sample_dir/subdir1/file2
list-content: create-content $(shell find sample_dir)
echo $^
I would like this output:
make list-content
create-content sample_dir sample_dir/file1 sample_dir/subdir1 sample_dir/subdir1/file2
But I have:
make list-content
create-content
The problem is that the shell function is called on make and not when the rule is running.
So shell is called before create-content, so the directory doesn't exist yet.
Is it possible to solve this?
Thank you.

The answer is no... and yes.
No, you can't because make builds all its dependency graph before it runs the first recipe. So, if a recipe creates new nodes of the dependency graph, it is too late for make to notice.
But there is a simple workaround: tell make to invoke make (recursive make). Despite what many people say, recursive make is not always harmful. It is even sometimes the only solution to a specific problem. This is your case. And with a bit of make magic (conditionals) you can hide this with two different behaviors depending on the existence of sample_dir:
create-content:
#mkdir -p sample_dir/subdir1 && \
touch sample_dir/file1 && \
touch sample_dir/subdir1/file2
ifeq ($(wildcard sample_dir),)
list-content: create-content
#$(MAKE) --no-print-directory $#
else
list-content: create-content $(shell find sample_dir)
#echo $^
endif
Now, the prerequisites of list-content are complete. Demo:
$ rm -rf sample_dir
$ make list-content
create-content sample_dir sample_dir/file1 sample_dir/subdir1 sample_dir/subdir1/file2
$ make list-content
create-content sample_dir sample_dir/file1 sample_dir/subdir1 sample_dir/subdir1/file2

Related

Makefile compile a library in another directory when it doesn't exist or the directory has been modify

Hi i have a makefile that compiles my library and then compiles the program. What i want to do is that the makefile recompile alway i modify my library's files for that i thought in this
ifneq ("$(wildcard $(PATH_LIB.A)","")
FILE_EXIST = 1
else
FILE_EXIST = 0
endif
$(MAIN_PROCESS): $(PATH_LIB.A) check_lib
...thing to do...
$(PATH_LIB.a):
FILE_EXIST = 0
check_lib:
ifeq("$(FILE_EXIST)","0")
$(MAKE) -C $(PATH_MAKEFILE_LIB.A)
endif
My problem es that when i compile it relinks all time "...thins to do..." because is checking all time check_lib as updateable what do you suggest for do what i want to do?
Make is not a scripting language like bash or python. What it needs is a description of inter-dependencies between targets and prerequisites, plus recipes to build them. In your case (but I am not sure I understood all details) you could try:
$(MAIN_PROCESS): $(PATH_LIB.A)
...thing to do...
$(PATH_LIB.A):
$(MAKE) -C $(PATH_MAKEFILE_LIB.A)
And that's all (but continue reading, there is more to understand). This tells make that:
$(MAIN_PROCESS) depends on $(PATH_LIB.A), plus the things to do to build $(MAIN_PROCESS) if it does not exist or if it is older than $(PATH_LIB.A).
$(PATH_LIB.A) depends on nothing, plus what to do if it does not exist.
It almost works. Almost only because if $(PATH_LIB.A) already exists but is out of date (with respect to its own source files) it will not be rebuilt. A solution is to declare it as phony:
.PHONY: $(PATH_LIB.A)
$(MAIN_PROCESS): $(PATH_LIB.A)
...thing to do...
$(PATH_LIB.A):
$(MAKE) -C $(PATH_MAKEFILE_LIB.A)
This way make will always try to rebuild it, even if it already exists. The sub-make will do it if needed, else it will just tell you that it was up to date. But it is not the whole story: as make always tries to rebuild $(PATH_LIB.A), it will consider that $(MAIN_PROCESS) must also be rebuilt, even if the sub-make didn't do anything because $(PATH_LIB.A) was up-to-date.
If this is a problem, more tricky solutions can be used, like using one more sub-make. The idea is the following:
Use make conditionals to create two different contexts of invocation with two different rules for your $(MAIN_PROCESS) target.
On the first invocation of make, the first context is used where $(MAIN_PROCESS) depends on the phony $(PATH_LIB.A) but its recipe, instead of ...thing to do... is a second invocation of make, in the other context.
For this second invocation $(MAIN_PROCESS) depends on the non-phony $(PATH_LIB.A) and will have its normal recipe.
The two contexts are distinguished thanks to a dedicated make variable (SECONDPASS in the code below).
Example:
host> cat lib/Makefile
foo.a: foo.c
touch $#
host> cat Makefile
ifeq ($(SECONDPASS),)
$(MAIN_PROCESS): $(PATH_LIB.A)
$(MAKE) SECONDPASS=1
.PHONY: $(PATH_LIB.A)
$(PATH_LIB.A):
$(MAKE) -C $(dir $#)
else
$(MAIN_PROCESS): $(PATH_LIB.A)
touch $#
endif
host> make --no-print-directory
make -C lib/
touch foo.a
make SECONDPASS=1
touch bar
host> make --no-print-directory
make[1]: 'foo.a' is up to date.
make SECONDPASS=1
make[1]: 'bar' is up to date.
host> touch lib/foo.c
host> make --no-print-directory
make -C lib/
touch foo.a
make SECONDPASS=1
touch bar
host> touch lib/foo.a
host> make --no-print-directory
make -C lib/
make[1]: 'foo.a' is up to date.
make SECONDPASS=1
touch bar

How do I get Make to do Second Expansion using two rules with the same target containing %?

I have a directory structure that looks like this:
$ tree
.
|-- dir
| `-- subdir
| `-- data
`-- makefile
where data is a file. My makefile looks like this:
all: dir/analysis
.SECONDEXPANSION:
%/analysis: %/subdir
%/analysis: $(addsuffix /data, $$^)
#echo TARGET: $# DEPS: $^
touch $#
When I run make, I would expect the result to look like this:
TARGET: dir/analysis DEPS: dir/subdir/data dir/subdir
touch dir/analysis
Instead, it just reports
make: *** No rule to make target `dir/analysis', needed by `all'. Stop.
If I change the first rule to dir/analysis: dir/subdir then it works as I expected. So I suspect that make ignores the first rule and skips straight to the second when the first rule is %/analysis: %/subdir. It also works as expected when both rules have dir/analysis as their target instead of just the first rule. MadScientists's answer to a different question here seemed to apply to my problem. I tried adding rules like
dummy_target: dir/subdir
mkdir -p dir/subdir
and
dir/subdir:
mkdir -p dir/subdir
to the end of makefile to try to make the dependency on the first rule an explicit target but this didn't change anything. I'm pretty new to make, so I'm probably missing something pretty stupid, but I can't for the life of me figure it out. How do I get the first and second rules to execute in the order they're written? I'm using Make version 3.81 in case that matters.
--EDIT--
If I actually add a command after the first rule, like #echo RULE 1 then that command executes and not the second one.
I think that you understand the makefile:
# Original
all: dir/analysis
.SECONDEXPANSION:
%/analysis: %/subdir
%/analysis: $(addsuffix /data, $$^)
#echo TARGET: $# DEPS: $^
touch $#
like this:
By default we make dir/analysis
We request secondary expansion
We say that whatever/analysis depends on whatever/subdir. So
that makes dir/subdir a prerequisite of dir/analysis
We say also that whatever/analysis depends on the thing we get by
suffixing /data to the prior prerequisites of whatever/analysis. (Secondary
expansion of $$^ gives us the prior prerequisites of the target). And
since the prior prerequisites of dir/analysis are dir/subdir, that now
makes dir/subdir dir/subdir/data the new prerequisites of dir/analysis.
Hence the output of the recipe ought to be:
TARGET: dir/analysis DEPS: dir/subdir/data dir/subdir
touch dir/analysis
This understanding is badly wrong. You're confusing and conflating the operation
of pattern rules with the operation or ordinary rules.
If a makefile says, e.g:
# A
xx: xa
xx: xb
xx: xc
touch $#
or even:
# B
xx: xa
xx: xb
%x: %c
touch $#
then the prerequisites of all the empty rules for the target xx are combined
with those of the (one) non-empty rule when xx is considered as a target. So
# A is equivalent to:
xx: xa xb xc
touch $#
and # B is equivalent to:
xx: xa xb
%x: %c
touch $#
and in both cases the prerequisites of xx are xa xb xc.
However:
%x: %a
%x: %b
touch $#
is not equivalent to:
%x: %a %b
touch $#
If you ever write an empty pattern rule, its effect is simply to delete
any prior pattern rule with the same target and prerequisite patterns. And if you
ever write a non-empty pattern rule, you simply replace
any prior pattern rule with the same target and prerequisite patterns. See
10.5.6 Canceling Implicit Rules
So:
.SECONDEXPANSION:
%/analysis: %/subdir
%/analysis: $(addsuffix /data, $$^)
#echo TARGET: $# DEPS: $^
touch $#
is equivalent to:
.SECONDEXPANSION:
%/analysis: $(addsuffix /data, $$^)
#echo TARGET: $# DEPS: $^
touch $#
Then when this pattern rule is considered with respect to dir/analysis,
there are no prior prerequisites: $^ will expand to the empty string, and
in secondary expansion, so will $$^. So finally the recipe is equivalent to:
# Residual
%/analysis: /data
#echo TARGET: $# DEPS: $^
touch $#
You can satisfy yourself of this by running both of the # Original and
# Residual makefiles in debug mode (-d) and comparing the outputs.
This explains why the outputs in both cases conclude:
make: *** No rule to make target 'dir/analysis', needed by 'all'. Stop.
A pattern rule will only be instantiated to make a target if doing so offers a way for the target to be made. Why else select it? Since the prerequisite /data does not exist, the pattern rule
is not viable and is discarded. Just as if you tried to make foo.o with the makefile:
%.o: %c
touch $#
when there is no foo.c in the directory.
If you really want to see the output you were expecting, then you can get it from:
.PHONY: all clean
all: dir/analysis
%/analysis: %/subdir %/subdir/data
#echo TARGET: $# DEPS: $^
touch $#
clean:
rm -f dir/analysis
But it is hard to believe that is what you really want to see. This makefile
makes the analysis dependent on the data and also on the directory where
the data resides. What can be the point of that?
%/analysis: %/subdir/data
presumably expresses the desired relationship between the data and the analysis:-
If the data doesn't exist then the analysis is out of date and cannot be made (till you get some data).
If the data exists and is older than the analysis then the analysis does not
need to be made.
If the data exists and is newer than the analysis then the analysis can and will be
made.
By making dir/subdir an independent prerequisite all that you achieve is to introduce
a requirement to remake the analysis if it becomes older than the directory in
which the data resides - regardless of the data. So if, e.g. I run touch dir/subdir,
that will require make to re-run the analysis, even though the data hasn't changed.
I can make sense of your motivation only by supposing that in
reality you also want make to make the data, and the directory where it resides, if
they happen not exist when an analysis is required. If that is the situation then
you want a makefile on the lines of:
.PHONY: all clean
all: dir/analysis
.SECONDARY:
%/subdir:
mkdir -p $#
%/subdir/data: | %/subdir
touch $#
%/analysis: %/subdir/data
#echo TARGET: $# DEPS: $^
touch $#
clean:
rm -f dir/analysis dir/subdir/data
Here, the pattern rule:
%/subdir/data: | %/subdir
makes %/subdir an order-only prerequisite
of %/subdir/data. It means that /dir/subdir is not considered when determining whether /dir/subdir/data needs
to be made, but if it is determined that /dir/subdir/data is to be made, then /dir/subdir will be made first. This
way, /dir/subdir will be created, if it does not exist, when you need it to put the data there, but will have no influence
on whether you need to make the data or the analysis.
The special target .SECONDARY is a technicality. It directs make not to automatically delete any subsequent targets
that it deduces to be intermediate artefacts that emerge from chained pattern rules. Without it, in this example make
would deduce that dir/subdir/data and dir/subdir/ are just waste-products of making dir/analysis and auto-delete them
at the end.
If you run this makefile initially with no dir/subdir/data and no dir/subdir/ you get:
$ make
mkdir -p dir/subdir
touch dir/subdir/data
TARGET: dir/analysis DEPS: dir/subdir/data
touch dir/analysis
And subsequently:
$ make clean
rm -f dir/analysis dir/subdir/data
$ make
touch dir/subdir/data
TARGET: dir/analysis DEPS: dir/subdir/data
touch dir/analysis
And then:
$ make
make: Nothing to be done for 'all'.
$ touch dir/subdir
$ make
make: Nothing to be done for 'all'.

How to avoid code repetition calling recursive Makefiles?

Is it possible to simplify a Makefile of the following form in order to avoid code repetition:
dir1/foo:
make -C dir1 foo
dir1/bar:
make -C dir1 bar
dir2/baz:
make -C dir2 baz
...
clean:
make -C dir1 clean
make -C dir2 clean
...
I imagine I could specify only:
MY_TARGETS=dir1/foo dir1/bar dir2/baz ...
And than have some general rules to derive targets, as presented in the Makefile above.
You haven't given us much information. Recursive Make can be a good solution, if your main makefile is as simple as your example (which I doubt).
You could do this:
%:
$(MAKE) -C $(dir $#) $(notdir $#)
clean:
$(MAKE) -C dir1 clean
$(MAKE) -C dir2 clean
...
If that clean recipe is too long, you can simplify it:
DIRS := dir1 dir2 ...
clean:
#for x in $(DIRS); do $(MAKE) -C $$x clean; done
Or if you don't like having that DIRS list there, you could have Make generate it, depending on whether you want to make clean in all subdirectories, or all that match the dir* pattern, or... you haven't given us enough information.

Makefile: rule that match multiple patterns

I have this rule in my Makefile, that responds to flags I pass:
$(BUILD_DIR)/disable_%:
mkdir -p $(BUILD_DIR)
touch $(BUILD_DIR)/disable_$*
rm -f $(BUILD_DIR)/enable_$*
cd $(BUILD_DIR) && rm -f Makefile
$(BUILD_DIR)/enable_%:
mkdir -p $(BUILD_DIR)
touch $(BUILD_DIR)/enable_$*
rm -f $(BUILD_DIR)/disable_$*
cd $(BUILD_DIR) && rm -f Makefile
What this means is that when changing the flags by which I invoke the makefile, I can trigger some recompilations that could depend on these flags.
The code presented above is a bit redundant: you see that I remove a file, touch another and remove a Makefile in both cases. The only thing that changes is the name of the files that I touch/remove, and they are related.
For instance,
make clean
make enable_debug=yes enable_video=no # will compile from zero
make enable_debug=no enable_video=no # flag change detected -> recompile some submodules that depend on this flag
Provided that the only thing that changes between the two rules ( [en|dis]able ), what I would like is to only have 1 generic rule, something like that:
# match 2 parts in the rule
$(BUILD_DIR)/%ble_%:
mkdir -p $(BUILD_DIR)
touch $(BUILD_DIR)/(???)ble_$* # should be $#
rm -f $(BUILD_DIR)/(???)able_$* # should be disable if $# is enable and inverse
cd $(BUILD_DIR) && rm -f Makefile
Is this possible ?
PS: Sorry if I didn't get the title correctly, I couldn't figure how to explain it better.
$(BUILD_DIR)/enable_% $(BUILD_DIR)/disable_%:
mkdir -p $(BUILD_DIR)
rm -f $(BUILD_DIR)/*able_$*
touch $#
cd $(BUILD_DIR) && rm -f Makefile
Not literally what you wanted (multi-wildcards are forbidden in make), but does quite the same.

Makefile: Copying files with a rule

I am trying to copy files using a my rule but my rule does not get triggered:
BUILDDIR = build
COPY_FILES = code/xml/schema/schema.xsd config.txt
all: $(BUILDDIR) $(COPY_FILES) copy
$(BUILDDIR):
mkdir -p $#
$(COPY_FILES):
cp -f $# $(BUILDDIR)
copy:
cp -f $(COPY_FILES) $(BUILDDIR)
I am trying to use $(COPY_FILES) but it is not being triggered, although $(BUILDDIR) and copy are triggered. I am not sure what is wrong with my Makefile. I would like to get the $(COPY_FILES) rule to work if possible please (and remove copy). Does anyone please know?
The problem with the $(COPY_FILES) rule is that the targets of that rule are two files that already exist, namely code/xml/schema/schema.xsd and config.txt. Make sees no reason to execute the rule. I'm not sure why Make doesn't execute the copy rule, but I suspect that there's a file called copy confusing the matter. Anyway, [copy] a bad rule.
Try this:
COPY_FILES = $(BUILD_DIR)/schema.xsd $(BUILD_DIR)/config.txt
all: $(COPY_FILES)
$(BUILD_DIR)/schema.xsd: code/xml/schema/schema.xsd
$(BUILD_DIR)/config.txt: config.txt
$(BUILD_DIR)/%:
cp -f $< $#
In my case, I use a simple "for loop" to cp all those files.
For examples, write the rule as following:
RELEASE_DIR = ../rc1
RELEASE_FILES = ai.h main.cc main_async.cc bmp_utils.h bmp_utils.cc
release: $(RELEASE_FILES)
for u in $(RELEASE_FILES); do echo $$u; cp -f $$u $(RELEASE_DIR); done
Then,
make release

Resources