Why make is locking up? - makefile

I've defined below function inside makefile.
# check debug xdc
define check_debug_xdc
if [ -f ${DEBUG_XDC} ]; then \
...
fi
endef
make runs fine, if directly call it.
# Optimize
${OUTPUTS1}: ${INPUTS1}
#echo ""
#echo "Optimization"
#date '+%Y_%m%d_%H%M'
#$(call check_debug_xdc)
But if I commented out DEBUG_XDC and put $(call check_debug_xdc) inside if-fi to check whether DEBUG_XDC is defined or not, make stops responding, nothing is printing out, even the date.
# DEBUG_XDC = ./fpga_ila/fpga_ila.srcs/constrs_1/new/${TOP}.xdc
...
# Optimize
${OUTPUTS1}: ${INPUTS1}
#echo ""
#echo "Optimization"
#date '+%Y_%m%d_%H%M'
#if [ ! -z "${DEBUG_XDC}" ]; then $(call check_debug_xdc); fi
Tried make -dn, it prints below message then stop responding.
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for i686-pc-linux-gnu
Reading makefiles...
Reading makefile `makefile'...
Updating makefiles....
Considering target file `makefile'.
...
Finished prerequisites of target file `fpga/fpga_opt.dcp'.
Must remake target `fpga/fpga_opt.dcp'.
How to fix it?

Related

gnu makefile when targets and dependencies are dynamic

I'm trying to create a makefile that creates a subsystem makefile if it does not exists, and then runs the make to create the subsystem using that subsystem makefile (using "echo" for simplicity)
If everything was static then I could use the following pattern
build_dir/config/makefile :
mkdir -p build_dir/config
echo create makefile > build_dir/config/makefile
use_make : build_dir/config/makefile
echo local makefile using `ls -l build_dir/config/makefile`
My problem is that the "config" is defined as part of the target (e.g Debug or Release)
I tried the following
.SECONDEXPANSION:
tgt_d : CONFIG = Debug
tgt_r : CONFIG = Release
tgt_d tgt_r : MAKEFILE_DIR = build_dir/${CONFIG}
${MAKEFILE_DIR}/makefile :
mkdir -p ${MAKEFILE_DIR}
echo create makefile > ${MAKEFILE_DIR}/makefile
use_make : ${MAKEFILE_DIR}/makefile
echo local makefile using `ls -l ${MAKEFILE_DIR}/makefile`
tgt_d tgt_r : use_make
My problem is that make is interpreting the ${MAKEFILE_DIR} in the target and the prerequisite directly (when it's undefined) not in a target-specific way (even when I added .SECONDEXPANSION or use ${${MAKEFILE_DIR}} - see output below
How can I achieve what I need to do ?
The next step is to define this in a general way so that I can use it for multiple targets (multiple Eclipse projects that are build together) using $< and % - so kudos to someone that takes me that extra step!
Thanks !
$ make --debug=v tgt_d
GNU Make 4.3
Built for x86_64-pc-cygwin
Copyright (C) 1988-2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile 'makefile'...
Updating makefiles....
Updating goal targets....
Considering target file 'tgt_d'.
File 'tgt_d' does not exist.
Considering target file 'use_make'.
File 'use_make' does not exist.
Considering target file 'build_dir//makefile'.
File 'build_dir//makefile' does not exist.
Finished prerequisites of target file 'build_dir//makefile'.
Must remake target 'build_dir//makefile'.
mkdir -p build_dir/Debug
echo create makefile > build_dir/Debug/makefile
Successfully remade target file 'build_dir//makefile'.
Finished prerequisites of target file 'use_make'.
Must remake target 'use_make'.
echo local makefile using `ls -l build_dir/Debug/makefile`
local makefile using -rw-r--r-- 1 yonatan.lehman 1049089 16 Oct 30 12:18 build_dir/Debug/makefile
Successfully remade target file 'use_make'.
Finished prerequisites of target file 'tgt_d'.
Must remake target 'tgt_d'.
Successfully remade target file 'tgt_d'.
The manual is pretty clear about when target-specific variables are in use and when they are not:
As with automatic variables, these values are only available within the context of a target’s recipe (and in other target-specific assignments).
So, clearly your use of them in targets and prerequisites cannot work. Secondary expansion has nothing to do with this (in any event, you're not actually using any secondary expansion here even though you've enabled the feature).
I think you'll have to use a recursive invocation of make:
tgt_d tgt_r :
$(MAKE) use_make MAKEFILE_DIR=build_dir/${CONFIG}

Makefile assignment to special variable .DEFAULT_GOAL is not expanded

.DEFAULT_GOAL=${IMG}
BUILD_DIR=build
IMG=${BUILD_DIR}/hd60M.img
BIN=${addprefix ${BUILD_DIR}/,${addsuffix .bin,${objects}}}
${IMG}:${BIN}
touch $#
make -n gives the result:
make: *** No rule to make target `${IMG}'. Stop.
If I change the first line to .DEFAULT_GOAL=build/hd60M.img, it works without error messages.
It seems that assignment to .DEFAULT_GOAL is not expanded. Why?
You should use := instead of =, () instead of {}, and expand variables AFTER setting them:
# Expand rhs on assignment
IMG := $(BUILD_DIR)/hd60M.img
…
# Set default goal after variable is set
.DEFAULT_GOAL := $(IMG)
I find the problem is due to my make version.
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for i386-apple-darwin11.3.0
After I updated GNU make to the newest version, the problem is solved.

Why is this makefile restarting/reparsing many times?

I wanted to keep a log of previously compiled code so I can be consistent when setting the compiling options. I devised the following scheme but it has a weird behavior that I don't quite fully understand. Here is a simplified version that reproduces the error:
Makefile:
.DEFAULT_GOAL = final
MKFILES = Makefile Makefile.checks
include Makefile.checks
.PHONY: final
final: info.txt results.txt
#cat $^
results.txt: $(MKFILES) | .PRELIM
#echo 'First file with opt=$(opt)' > $#
info.txt: info.src $(MKFILES) | .PRELIM
#cat $< > $#
#echo 'Internal record of opt=$(opt)' >> $#
.PHONY: .FORCE
.FORCE:
.PHONY: .PRELIM
.PRELIM: Makefile.log
.PHONY: clean
clean:
rm -rf *.txt *.log
Makefile.checks:
# SETUPS & CHECKS
opt ?= 0
BUILDSTAT := 0
ifneq ($(MAKECMDGOALS),clean)
ifneq ("$(wildcard Makefile.log)","")
include Makefile.log
ifneq ($(opt),$(oldopt))
$(warning Previously compiled opt = $(oldopt))
$(warning Currently requested opt = $(opt))
BUILDSTAT := 1
endif
endif
endif
# RESOLUTION SECTION
ifneq ($(BUILDSTAT),0)
info.txt: .FORCE
Makefile.log: .FORCE
$(warning The build is not consistent, a clean make is recomended. )
ifneq ($(MAKECMDGOALS),anyway)
$(warning To force compilation, run 'make anyway opt=X' )
$(error Aborting compilation)
endif
endif
.PHONY: anyway
anyway: $(.DEFAULT_GOAL)
Makefile.log:
#echo 'Creating new Makefile.log'
#echo '########################################' > Makefile.log
#echo 'oldopt := $(opt)' >> Makefile.log
#echo 'BUILDSTAT := $(BUILDSTAT)' >> Makefile.log
#echo '########################################' >> Makefile.log
The Makefiles create the log and check for the previous options: make followed by make opt=1 behaves as expected by issuing the warning and stopping. However, when I make anyway opt=1 the makefile seems to parse the Makefile.checks many times before actually compiling:
Makefile.checks:12: Previously compiled opt = 0
Makefile.checks:13: Currently requested opt = 1
Makefile.checks:26: The build is not consistent, a clean make is recomended.
Creating new Makefile.log
Makefile.checks:26: The build is not consistent, a clean make is recomended.
Creating new Makefile.log
(...repeated many times...)
Makefile.checks:26: The build is not consistent, a clean make is recomended.
Creating new Makefile.log
This is a personal log
Internal record of opt=1
First file with opt=0
I suspect this may have something to do with how Makefile re-parses itself after modifying the Makefile.log that is itself included in one of the MKFILES that causes the whole list of targets to recompile. I tried using the -d option but it is not helping me much. This design ended up being quite convoluted but I didn't know how to simplify it, and I don't know enough about how makefile works to decipher what is happening on my own either.
I would be really thankful for an explanation of this error. Which dependency is causing the cycle and why it eventually leaves it and moves on to finish compilation? Do you think there is a better way to record compilation options?
EDIT: I will be adding here further requested information/explanations. I modified a bit the code to simplify it.
What I'm trying to do is to store the compilation options used in the last build so as not to be mixing options when recompiling only part of a code (or at least to be warned that this is what I'm doing). The way I implemented this is in the Makefile.checks: options are written into / loaded from a Makefile.log and BUILDSTAT is a kind of boolean to check if there were discrepancies or not and keep track of it in the successive builds.
Makefile.checks first sets defaults, then checks if the log exist and loads the "old" options in separated variables and then compares the two to check for discrepancies. If any is found, it issues a warning here and then later checks again and stops (this separation makes more sense when you have more than one option) unless explicitly asked to ignore them by using the target anyway. In this last case, both the log and the file info.txt (which is another way to store the options) need to be updated with the last build info (and specially the BUILDSTAT=1 to keep record that the build may have a "mixed compilation").
EDIT - "SOLUTION": Apparently if instead of "forcing" the recompilation of the log, I make the log itself a phony target (inside the if), it prevents this behavior. I still have found no drawbacks to this approach, but it does feel a bit "dirty".

Can I tell if --jobs is used inside a Makefile?

I want to set some variables based on whether or not parallel builds are enabled, so I tried this:
jobs:
»·echo "executing jobs job"
ifneq (,$(findstring -j,$(MAKEFLAGS)))
»·$(warning "parallel!")
else
»·$(warning "not parallel!")
endif
And this is what happens:
$ make -j2
Makefile:2: "not parallel!"
echo "executing jobs job"
executing jobs job
I also tried testing $(JOBS), but no luck.
Is there a way for me to tell inside a Makefile that the --jobs parameter was used?
Additional info:
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for x86_64-pc-linux-gnu
Surprisingly, ${MAKEFLAGS} will only gain the -j when it is expanded at recipe expansion time.
Makefile:
$(warning [${MAKEFLAGS}])
.PHONY: all
all:
$(warning [${MAKEFLAGS}])
echo Now do something useful
Run:
$ make -j5
1:1: []
1:5: [ -j --jobserver-fds=3,4]
echo Now do something useful
Now do something useful
About the MAKEFLAGS expansion in #bobbogo's answer: If we look at the code I think I can explain the behavior:
Looking at the code, main function of make calls the define_makeflags function several times.
/* Define the MAKEFLAGS and MFLAGS variables to reflect the settings of the
command switches. Include options with args if ALL is nonzero.
Don't include options with the 'no_makefile' flag set if MAKEFILE. */
static struct variable *
define_makeflags (int all, int makefile)
{
......
Call locations in main:
1)
/* Set up the MAKEFLAGS and MFLAGS variables for makefiles to see.
Initialize it to be exported but allow the makefile to reset it. */
define_makeflags (0, 0)->export = v_export;
2)
/* Set up MAKEFLAGS and MFLAGS again, so they will be right. */
define_makeflags (1, 0);
3)
/* Set up 'MAKEFLAGS' specially while remaking makefiles. */
define_makeflags (1, 1);
There are other calls in sub-functions but this should be enough to explain.
The first call sets all parameter to false. The others set to true. With all set to false, the define_makeflags function only parses "simple flags" and j is not one of them. In order to understand the parsing one needs to look into this switch statement and the definition of command line params.
My SWAG is like the following:
I presume the parsing of ifneq statements happen after the first call to define_makeflags but before the subsequent calls. I can guess the reason of keeping the MAKEFLAGS simple at the start is to continue to support documented Makefile patterns like the following.
From doc1, doc2:
archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
+touch archive.a
+ranlib -t archive.a
else
ranlib archive.a
endif
If MAKEFLAGS contained long options or options that take parameters, then searching for single char flags in MAKEFLAGS would not be possible.
There is some guesstimate in my answer. Maybe someone who was involved in the design decision can also weigh in. Given this change Paul Smith may have an idea.

How to undo intermediate file deletion

I have a software stack that creates some intermediate files as a part of build process. There is some problem come up and the build breaks. I want to have a look at those intermediate generated files. To my surprise those files are being deleted as a part of build process.
Removing intermediate files...
rm fact_test_without_proxies.c fact_test_main.c fact_test_without_proxies.o
I went through the Makefiles I don't see any explicit rules deleting them. Can there be any implicit rules to delete intermediate files. If yes how can I disable those implicit rules ?
I see the print Removing intermediate files... only if make is executed with --debug option.
skmt#tux:~/coding/factorial/ut$ make --debug
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for x86_64-pc-linux-gnu
Reading makefiles...
Updating goal targets....
File `check' does not exist.
File `test_dept_run' does not exist.
File `fact_test' does not exist.
File `fact_using_proxies.o' does not exist.
File `fact_test_without_proxies' does not exist.
File `fact_test_without_proxies.o' does not exist.
File `fact_test_without_proxies.c' does not exist.
File `fact_test_main.c' does not exist.
Must remake target `fact_test_main.c'.
nm -p fact_test.o | build_main_from_symbols >fact_test_main.c
Successfully remade target file `fact_test_main.c'.
Must remake target `fact_test_without_proxies.c'.
cp fact_test_main.c fact_test_without_proxies.c
Successfully remade target file `fact_test_without_proxies.c'.
Must remake target `fact_test_without_proxies.o'.
gcc -I../src -c -o fact_test_without_proxies.o fact_test_without_proxies.c
Successfully remade target file `fact_test_without_proxies.o'.
Must remake target `fact_test_without_proxies'.
gcc fact_test_without_proxies.o fact.o fact_test.o -o fact_test_without_proxies
fact.o: In function `unknown':
fact.c:(.text+0x67): undefined reference to `do_update'
collect2: ld returned 1 exit status
make: *** [fact_test_without_proxies] Error 1
Removing intermediate files...
rm fact_test_without_proxies.c fact_test_main.c fact_test_without_proxies.o
If you're using GNUMake, you can use the special target .PRECIOUS:
.PRECIOUS: fact_test_without_proxies.c fact_test_main.c fact_test_without_proxies.o
or just
.PRECIOUS: %.c %.o
Its only effect is that these files will not be deleted if Make is killed or interrupted.
You can also use .SECONDARY, which will preserve the specified files even if the build does not break.
e.g.
.SECONDARY:
There is a restriction on the use of targets, which affects the behaviour of .PRECIOUS:
I have targets A/%.foo: and B/%.foo: , so I have set:
.PRECIOUS: %.foo
and this did not work; I don't understand why, but expansion does not work this way; I had to explicitely list targets exactly as they are written:
.PRECIOUS: A/%.foo B/%.foo
But even after reading https://www.gnu.org/software/make/manual/html_node/Special-Targets.html I do not understand the difference between .PRECIOUS: and .SECONDARY: .
It's accepted to use those special targets without depends, but I think this would be very dirty coding and would expect side effects. Some people just put .PRECIOUS: or .SECONDARY: without dep, and later, they complain they have to run make clean after a broken build ...

Resources