I have a target
%.hgtForCoordsAndNeighbours
(example: +64-016.hgtForCoordsAndNeighbours
)
that represents a geo coordinate and depends on build steps that are run on all adjacent 1-degree chunks. These (prerequisite) build steps are called
%.hgtForCoords
.
My problem here is that I need a little calculation to expand from that 1 target name into the 8 (+1 for the centre) adjacent prerequisites and also to enforce the filename structure with the leading zeroes (%+03d%+04d
in printf).
I have not found a way to express that in Makefile syntax yet so I went for a sub-$(MAKE)
. Yet that brings its problems with concurrency (-j ...
) and I think is generally considered bad style to have a Makefile
call itself. I would also like to learn more about the Makefile
syntax.
Full example:
SHELL=/bin/bash
%.hgtForCoordsAndNeighbours:
# this looks too complicated but that's not the point here.
# It's an example for dependencies generated from a target name by a script
# and not in Makefile syntax.
coords=$$(basename $@ .hgtForCoordsAndNeighbours) \
&& echo "Prepare elevation data for $$coords and neighbours" \
&& lat=$$(echo $$coords | grep -Eo '^.{3}' | sed -E 's/([+-])0+/\1/') \
&& lon=$$(echo $$coords | grep -Eo '.{4}$$' | sed -E 's/([+-])0+/\1/') \
&& minLat=$$(($$lat -1)) \
&& maxLat=$$(($$lat +1)) \
&& minLon=$$(($$lon -1)) \
&& maxLon=$$(($$lon +1)) \
&& $(MAKE) -f $(lastword $(MAKEFILE_LIST)) \
$$(printf "%+03d%+04d" "$$minLat" "$$minLon").hgtForCoords \
$$(printf "%+03d%+04d" "$$lat" "$$minLon").hgtForCoords \
$$(printf "%+03d%+04d" "$$maxLat" "$$minLon").hgtForCoords \
$$(printf "%+03d%+04d" "$$minLat" "$$lon" ).hgtForCoords \
$$(printf "%+03d%+04d" "$$lat" "$$lon" ).hgtForCoords \
$$(printf "%+03d%+04d" "$$maxLat" "$$lon" ).hgtForCoords \
$$(printf "%+03d%+04d" "$$minLat" "$$maxLon").hgtForCoords \
$$(printf "%+03d%+04d" "$$lat" "$$maxLon").hgtForCoords \
$$(printf "%+03d%+04d" "$$maxLat" "$$maxLon").hgtForCoords \
;
Abstract example what I would like to achieve:
%.targetWithAPlaceholder: $(prerequisites generated by a
custom function based on the target name)
It is not a problem if that is not too portable. It is only run on a well-controlled environment (currently a Github actions Linux runner with GNU Make 4.3).
In this case it would be OK if all dependencies were evaluated once (since the coordinate space is finite (360 * 180)).
It's probably easiest to generate the dependencies with a short script. Perhaps something such as:
#!/bin/sh
for lat in $(seq -90 90)
do for lon in $(seq -180 180)
do for dx in -1 0 1
do for dy in -1 0 1
do printf "%+03d%+04d.hgtForCoordsAndNeighbours: %+03d%+04d.hgtForCoords\n" \
$lat $lon $((lat+dy)) $((lon+dx))
done
done
done
done
If we call this generate-deps
, then the (GNU) Makefile lines to ensure it's called and included are simply this:
neighbours.mak: generate-deps
./$< >$@
include neighbours.mak