How to execute make rule based on change/update in prerequisite timestamp? - makefile

I have listed few files into a variable BUILD ,then at my make rule i have given this variable as prerequisite. I have executed this make rule first time it executed that rule. i again executed the same make file without changing any prerequisite for that rule, at second execution, it should not execute that rule and should display a message "gmake: Nothing to be done for `Rule'." This rule is being executed all the time though there is no change in the prerequisites.
make file :
BUILD = \
D:/Build/PeGen/\*.exe \
D:/Build/PWrGen/\*.dll \
All:c1
c1: $(BUILD)
cd D:/Mo/Ap/Po/Co/Ts/Build && \
"$(MAKE)" -s -f Build2.mk

The rule for c1 target probably doesn't create that target file. Hence, make needs to build that target.
One possible fix:
c1: $(BUILD)
"$(MAKE)" -s -C D:/Mo/Ap/Po/Co/Ts/Build -f Build2.mk
touch $#
Target All should normally be called all and be .PHONY:
.PHONY: all All

Related

Force rebuild from within makefile

Is there a way to force a complete rebuild (eg -B) from within a makefile?
I have added a pre-build step that increments a build number, stored in a text file, that is used by my project. The build number is only incremented if newbuild=1 is passed as an argument to 'make'.
pre-build:
# This option increments build number
ifdef newbuild
increment_build_number
endif
If this code is called, I would like to force a complete rebuild so that nothing gets out of sync, and I don't have to type -B whenever newbuild=1 is used. Is there a way to do this?
Thanks!
You could:
declare the text file with the build number as a prerequisite of the other targets,
use make conditionals to also declare it phony if newbuild is defined.
Demo where build.txt is the text file with the build number and target is one of the targets to rebuild when newbuild is defined:
# Makefile
BUILD := build.txt
TARGETS := target
ifdef newbuild
.PHONY: $(BUILD)
endif
$(TARGETS): $(BUILD)
touch $#
$(BUILD):
#[ -f "$#" ] && build=$$(cat "$#") || build=0; \
printf 'build '; \
printf '%d\n' "$$((build+1))" | tee "$#"; \
$ make
build 1
touch target
$ make
make: 'target' is up to date.
$ make newbuild=1
build 2
touch target

Make rebuilds everytime

I have a Makefile as :
BUILD_DIR= $(BASE_DIR)/build
_OBJ := a.o b.o
CLEAN_OBJECTS := $(_OBJ)
.PHONY: clean
create_code:
python ../script/my_script.py
all: create_code $(_OBJ)
$(_OBJ): %.o: %.c
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $(INCLUDE_PATH) -c $< -o $#
cp *.o $(BUILD_DIR)
clean:
rm -f $(CLEAN_OBJECTS)
The target create_code executes the python script and generates a set of .c/.h files.
The target _obj compiles them.
Every time I run make all , create_code target is run even though there is no change to .c/.h generated earlier .
Any suggestions on why this is happening and how to make this create_code target run only if make clean was done earlier .
The underlying problem is that you have one or more generated files that depend on something other than the underlying file system -- namely the contents of your database.
One possibility would be to take advantage of the fact that make, having invoked a rule to rebuild a target will, nonetheless, always check the update time of that target when it is specified as a prerequisite in any other rule.
So, given the rule (untested)...
.PHONY: FORCE
%.c: FORCE
command-to-generate-source $#.tmp
diff -q $#.tmp $# || cp $#.tmp $#
Invoking make foo.c from the command line. make will run the commands...
command-to-generate-source foo.c.tmp
diff -q foo.c.tmp foo.c || cp foo.c.tmp foo.c
where command-to-generate-source foo.c.tmp is expected to leave its output in foo.c.tmp. If the newly generated output file is different than the existing file the cp operation will be run and, hence, the target timestamp will be updated and anything dependent on the target will be updated accordingly.
If, however, the newly generated output file is the same as the existing one then no cp will be run, the target file will be left untouched and make will not consider it to be changed when it appears as a prerequisite in other rules.
This is just one possibility but it's the obvious one given that you already have most (if not all) of the required logic in the command python ../script/my_script.py.

How to determine if Make target is a PHONY?

I have a make target that depends on a variable, which contains both PHONY and real targets.
This target needs to depend only on the real targets in the variable.
How can I test a variable to determine if it is a PHONY or not, so I can filter them out?
(I can test for a file's existence inside the recipe, but I don't want my target to be triggered by execution of any of the PHONY targets.)
Thanks!
There is a way to do it, but I would strongly recommend against it. First of, phony targets can be also file targets. And there is no way to tell a phony file target from a non-phony file target.
It looks like the question implies that the phony targets the author wants to ignore are all non-file targets. In this case see the example below.
.PHONY: phony_target .FORCE
.FORCE:
ALL_TARGETS = phony_target file_target undetermined_target
-include detect_phony.inc
all: final_target
# All done
final_target: $(REAL_TARGETS)
# create $# triggered by $?
#touch $#
ifeq (,$(MAKE_RESTARTS))
# Generate the list of real file targets in make include file
detect_phony.inc: .FORCE
#echo 'REAL_TARGETS = ' `ls $(ALL_TARGETS) 2>/dev/null` > $# |:
endif
file_target:
touch $#
undetermined_target phony_target:
# process $#
clean:
rm -f file_target final_target
Here are the test results:
$make clean
rm -f file_target final_target
$ make
# create final_target triggered by
# All done
$ touch file_target
$ make
# create final_target triggered by file_target
# All done
$ make
# All done
As you can see it only triggers the final target when the file target is updated.
Before you criticize - Here are the flaws of this implementation:
make is always called twice, updating the generated detect_phony.inc include file at every run
if detect_phony.inc gets corrupted somehow, make execution will be locked by syntax errors, until you manually delete it.
it can't handle phony file targets as I mentioned before
if another generated include is added in this makefile that requires another restart before detect_phony.inc this functionality will break.
So it this method is hacky and has several gotchas. I would not use it in production environment. I would insist on changing the top level Makefile first.

Why GNU make removes intermediate targets when using pattern rules?

I have a makefile like the following:
.PHONY: all
all: foo_1.txt foo_2.txt foo_xxx.txt
.PHONY: clean
clean:
rm -f foo_* bar_*
foo_%.txt: bar_%.txt
cp $< $#
#.PRECIOUS: bar_%.txt
bar_%.txt:
touch $#
bar_2.txt:
touch $#
The output of "make all" is folowing
touch bar_1.txt
cp bar_1.txt foo_1.txt
touch bar_2.txt
cp bar_2.txt foo_2.txt
touch bar_xxx.txt
cp bar_xxx.txt foo_xxx.txt
rm bar_xxx.txt bar_1.txt
The intermediate files created by the rule using pattern (bar_xxx.txt, bar_1.txt) are removed on the end. I have found that this behaviour can be supressed by .PRECIOUS (in the code is the line intentionally commented out).
Why are intermediate files created by rule with pattern removed by default and files created by rule without pattern are not?
By the definition of "intermediate files", you can't have an intermediate file created by an explicit rule (a rule "without a pattern").
See the section on Chains of Implicit Rules to understand this feature. If you have specific questions then please update your question.

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