I'm looking for a way to bail out of a makefile if a certain string is not found when checking the version of a tool.
The grep expression I'm looking to match is:
dplus -VV | grep 'build date and time: Nov 1 2009 19:31:28'
which returns a matching line if the proper version of dplus is installed.
How do I work a conditional into my makefile based upon this expression?
Here's another way that works in GNU Make:
DPLUSVERSION = $(shell dplus -VV | grep 'build date and time: Nov 1 2009 19:31:28')
target_of_interest: do_things do_things_that_uses_dplus
do_things:
...
do_things_that_uses_dplus:
ifeq ($(DPLUSVERSION),)
$(error proper version of dplus not installed)
endif
...
This target can be something real, or just a PHONY target on which the real ones depend.
Here is one way:
.PHONY: check_dplus
check_dplus:
dplus -VV | grep -q "build date and time: Nov 1 2009 19:31:28"
If grep finds no match, it should give
make: *** [check_dplus] Error 1
Then have your other targets depend on the check_dplus target.
If this is gnu make, you can do
your-target: $(objects)
ifeq (your-condition)
do-something
else
do-something-else
endif
See here for Makefile contionals
If your make doesn't support conditionals, you can always do
your-target:
dplus -VV | grep -q "build date and time: Nov 1 2009 19:31:28" || $(MAKE) -s another-target; exit 0
do-something
another-target:
do-something-else
Related
Running my target twice in a row it gets executed twice. This is wrong, since configure file is newer.
$ cat makefile
.ONESHELL:
configure: configure.www
#REMOTE_FILE=$$(cat $<)
#wget $${REMOTE_FILE}
#tar -xf $$(basename $${REMOTE_FILE})
#mv pspp-1.4.1/configure .
$ cat configure.www
https://ftp.gnu.org/gnu/pspp/pspp-1.4.1.tar.gz
The $$(cat <$) happens before the cp that creates the configure file.
Posting #Renaud Pacalet answer from the comments for future users:
Indeed, the mv instruction does not change the modification date, so the makefile really compares between PSPP's last modification date of configure and my own configure.www modification date. Since the latter is newer (and will remain newer) the target will keep getting executed.
$ stat configure | grep "Modify"
Modify: 2020-09-06 01:20:01.000000000 +0300
$ stat configure.www | grep "Modify"
Modify: 2021-05-05 10:11:43.891400412 +0300 // Newer !
I solved it by adding a final touch (no pun intended :))
.ONESHELL:
configure: configure.www
#REMOTE_FILE=$$(cat $<)
#wget $${REMOTE_FILE}
#tar -xf $$(basename $${REMOTE_FILE})
#mv pspp-1.4.1/configure .
#touch $# <----------------------
I'd like to add a quick check to a (GNU) makefile which can alert the user to the availability of -j/--jobs (parallel make). That is, something like
$ make
TIP: this will build faster if you use use "make -j"
Building ..
$ make -j
Building in parallel ..
How can I determine the number of parallel jobs when a Makefile is executed?
There is a trick here
http://blog.jgc.org/2015/03/gnu-make-insanity-finding-value-of-j.html
and a proposed change to GNU Make itself here
https://github.com/esantoro/make/commit/b0334e7f3009dc58dbc8e6e6fdec94711537fb3b
but perhaps there is something newer and/or easier.
The simplest/best solution is to upgrade your version of GNU make to 4.2 or above. Starting with that version, the MAKEFLAGS variable will provide the full -j option including the number. The NEWS file says:
The amount of parallelism can be determined by querying MAKEFLAGS, even when
the job server is enabled (previously MAKEFLAGS would always contain only
"-j", with no number, when job server was enabled).
So:
$ make --version
GNU Make 4.2.1
...
$ echo 'all:;#echo $(MAKEFLAGS)' | make -f-
$ echo 'all:;#echo $(MAKEFLAGS)' | make -f- -j
-j
$ echo 'all:;#echo $(MAKEFLAGS)' | make -f- -j10
-j10 --jobserver-auth=3,4
$ echo 'all:;#echo $(patsubst -j%,%,$(filter -j%,$(MAKEFLAGS)))' | make -f- -j10
10
You can determine the number of jobs easier and faster than that blog proposes by using make Jobserver protocol:
SHELL := /bin/bash
all:
#${MAKE} --no-print-directory job_count_test
job_count_test:
#+[[ "${MAKEFLAGS}" =~ --jobserver[^=]+=([0-9]+),([0-9]+) ]] && ( J=""; while read -t0 -u $${BASH_REMATCH[1]}; do read -N1 -u $${BASH_REMATCH[1]}; J="$${J}$${REPLY}"; done; echo "Building with $$(expr 1 + $${#J}) jobs."; echo -n $$J >&$${BASH_REMATCH[2]} ) || echo "TIP: this will build faster if you use use \"make -j$$(grep -c processor /proc/cpuinfo)\""
.PHONY: all job_count_test
And then:
$ make
TIP: this will build faster if you use use "make -j8"
$ make -j12
Building with 12 jobs.
I have a GNU makefile that looks something like this:
SOME_BINARY := $(shell `which some-binary` --help 2> /dev/null)
all: test_if_some_binary_exists
test_if_some_binary_exists:
ifdef SOME_BINARY
#echo "some-binary found!"
else
#$(error 'some-binary' not found!)
endif
Let's say I already have a binary called some-binary, which takes the option --help and writes a help message to standard error:
$ some-binary --help
Some-Binary v1.2.3 (c) 2015 Foo Bar Baz
...
However, it is really a symbolic link to a file located elsewhere on the file system:
$ ls -l `which some-binary`
lrwxr-xr-x 1 alexpreynolds admin 34 Aug 18 15:01 /usr/local/bin/some-binary -> ../Cellar/some-binary/1.2.3/bin/some-binary
When I run make all or make test_if_some_binary_exists, then I get an error as if the binary does not exist (when in fact it does):
$ make test_if_some_binary_exists
makefile:9: *** 'some-binary' not found!. Stop.
How do I correctly test for existence of a binary — potentially a symbolic link — within a GNU makefile?
I have a Makefile that does performs a task if it hasn't happened in the last hour. It does so like this:
HOUR_FROM_NOW = $(shell perl -e '($$s,$$m,$$h,$$d,$$M)=localtime(time()+3600); printf("%02d%02d%02d%02d\n",$$M+1,$$d,$$h,$$m);')
NOW_FILE = $(shell mkdir -p .make; touch .make/now; echo .make/now )
.PHONY: externals
externals: $(PROJECTS:%=.make/proj_%)
.make/proj_%: $(NOW_FILE)
$(MAKE) -s $(*F)
touch -t $(HOUR_FROM_NOW) $#
.PHONY: $(PROJECTS)
$(PROJECTS):
# do stuff, specifically, clone git-repo if not exists, else pull latest
That part works great, except that I now get warnings:
make: Warning: File `.make/proj' has modification time 3.5e+03 s in the future
make: Nothing to be done for `externals'.
make: warning: Clock skew detected. Your build may be incomplete.
Anyone know how to suppress those warnings? (Or to do a periodic task in a makefile)
Most versions of touch I have come across can do some date time maths which allows for setting the timestamp of a file directly via the --date option.
That and the fact that variables assigned with := are only "evaluated once" makes this a bit easier to read.
HOUR_AGO := .make/hour_ago
__UGLY := $(shell mkdir -p .make && touch --date='1hour ago' $(HOUR_AGO))
# The preceding line will be executed once
.make/proj_%: .make/hour_ago | .make
$(MAKE) -s $(*F)
#touch $#
.make:
mkdir -p $#
I'm using something very similar to this to periodically refresh login tokens.
Never would have thought of it if it wasn't for Dave's answer though.
The directory is created by specifying it as a order-only-prerequisite
I suspect that the + 3600 is at fault. What happens if you remove it?
I thought and thought, and then the stupid-obvious solution hit me ...
Instead of setting timestamps in the future with HOUR_FROM_NOW, I use the real time and compare with HOUR_AGO_FILE ...
HOUR_AGO = $(shell perl -e '($$s,$$m,$$h,$$d,$$M)=localtime(time()-3600); printf("%02d%02d%02d%02d\n",$$M+1,$$d,$$h,$$m);')
HOUR_AGO_FILE = $(shell mkdir -p .make; touch -t $(HOUR_AGO) .make/hour_ago; echo .make/hour_ago )
.PHONY: externals
externals: $(PROJECTS:%=.make/proj_%)
.make/proj_%: $(HOUR_AGO_FILE)
$(MAKE) -s $(*F)
#touch $#
On this line:
GCCVER:=$(shell a=`mktemp` && echo $'#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$a" -xc -; "$a"; rm "$a")
I get:
*** unterminated call to function `shell': missing `)'. Stop.
What's wrong with my stupidly circuitous variable?
Update0
$ make --version
GNU Make 3.81
$ bash --version
GNU bash, version 4.2.8(1)-release (x86_64-pc-linux-gnu)
$ uname -a
Linux 2.6.38-10-generic #46-Ubuntu SMP x86_64 GNU/Linux
$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
when using $ for Bash inside a Makefile, you need to double them: $$a for example. I'm not familiar with the notation $' but I'll have to assume you know what you're doing with that. unless it's a Makefile construct, you need to double the dollar sign on that one too.
also, the hash sign # is terminating the shell expansion in Make's evaluation, which is why it never sees the right paren. escaping it helps, but I don't have it working quite right yet.
I'm debugging it by having two steps: first is setting GCCVER to be the list of commands without the enclosing $(shell), then in the 2nd step setting GCCVER := $(shell $(GCCVER)). you might want to try that too, commenting out the $(shell) step when it doesn't work, using export, and making a "set" recipe:
GCCVER := some commands here
#GCCVER := $(shell $(GCCVER)) # expand the commands, commented out now
export # all variables available to shell
set:
set # make sure this is prefixed by a tab, not spaces
Then:
make set | grep GCCVER
[update] this works:
GCCVER := a=`mktemp` && echo -e '\#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$$a" -xc -; "$$a"; rm "$$a"
GCCVER := $(shell $(GCCVER))
export
default:
set
jcomeau#intrepid:/tmp$ make | grep GCCVER
GCCVER=4.6
And full circle, having gotten rid of the extra step:
jcomeau#intrepid:/tmp$ make | grep GCCVER; cat Makefile
GCCVER=4.6
GCCVER := $(shell a=`mktemp` && echo -e '\#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$$a" -xc -; "$$a"; rm "$$a")
export
default:
set
Using the $' Bash construct:
jcomeau#intrepid:/tmp$ make | grep GCCVER; cat Makefile
GCCVER=4.6
GCCVER := $(shell a=`mktemp` && echo $$'\#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$$a" -xc -; "$$a"; rm "$$a")
export
default:
set
Since your system doesn't work the same as mine, I'm going to cop out and say either use reinierpost's suggestion or, alternatively:
GCCVER := $(shell gcc -dumpversion | cut -d. -f1,2)