Why does make always update this target? - makefile

Using make on my Gentoo machine (which is GNU make 3.82) with the following Makefile, I wonder why the target data/spectra/o4_greenblatt_296K.dat gets updated every time I execute make data/spectra/o4_greenblatt_296K.dat, even though none of the files params/base/fwhm.dat, params/base/wavelength_grid.dat, and data/raw/o4green_gpp.dat has changed, and the file data/spectra/o4_greenblatt_296K.dat already exists:
FWHM = params/base/fwhm.dat
WLGRID = params/base/wavelength_grid.dat
$(WLGRID): code/create_wavelength_grid.py
cp code/create_wavelength_grid.py params/base/wavelength_grid.dat
$(FWHM): code/create_fwhm_param.py
cp code/create_fwhm_param.py params/base/fwhm.dat
data/raw/o4green_gpp.dat:
echo 1 > data/raw//o4green_gpp.dat
input_spectra_o4_raw: data/raw/o4green_gpp.dat
data/spectra/o4_greenblatt_296K.dat: $(WLGRID) $(FWHM) input_spectra_o4_raw
echo 1 > data/spectra/o4_greenblatt_296K.dat
input_spectra_o4: data/spectra/o4_greenblatt_296K.dat
Any help you guys can give a make newbie is greatly appreciated :)

I would guess that it's because there is no file named input_spectra_o4_raw, which is a prerequisite of your data/spectra/o4_greenblatt_296K.dat.
The decision looks kind of like this:
1. params/base/wavelength_grid.dat and params/base/fwhm.dat are both up to date
2. check input_spectra_o4_raw - file does not exist, so build it first
3. there is a target for input_spectra_o4_raw, and it's prerequisite
data/raw/o4green_gpp.dat is up to date, so run all the commands to build
input_spectra_o4_raw (there are none, though, so we essentially just mark that we've
done everything we need to for input_spectra_o4_raw and that we built it new)
4. we just built input_spectra_o4_raw, so data/spectra/o4_greenblatt_296K.dat is out of
date with respect to that prerequisite and needs to be rebuilt
You should research how to use the .PHONY: pseudo-target.

Related

autoconf: how do I substitute the library prefix?

CLISP's interface to PARI is configured with the configure.in containing AC_LIB_LINKFLAGS([pari]) from lib-link.m4.
The build process also requires the Makefile to know where the datadir of PARI is located. To this end, Makefile.in has
prefix = #LIBPARI_PREFIX#
DATADIR = #datadir#
and expects to find $(DATADIR)/pari/pari.desc (normally
/usr/share/pari/pari.desc or /usr/local/share/pari/pari.desc).
This seems to work on Mac OS X where PARI is installed by homebrew in /usr/local (and LIBPARI_PREFIX=/usr/local), but not on Ubuntu, where PARI is in /usr, and LIBPARI_PREFIX is empty.
How do I insert the location of the PARI's datadir into the Makefile?
PS. I also asked this on the autoconf mailing list.
PPS. In response to #BrunoHaible's suggestion, here is the meager attempt at debugging on Linux (where LIBPARI_PREFIX is empty).
$ bash -x configure 2>&1 | grep found_dir
+ found_dir=
+ eval ac_val=$found_dir
+ eval ac_val=$found_dir
You are trying to use $(prefix) in an unintended way. In an Autotools-based build system, the $(prefix) represents a prefix to the target installation location of the software you're building. By setting it in your Makefile.in, you are overriding the prefix that configure will try to assign. However, since you appear not to have any installation targets anyway, at least at that level, that's probably more an issue of poor form than a cause for malfunction.
How do I insert the location of the PARI's datadir into the Makefile?
I'd recommend computing or discovering the needed directory in your configure script, and exporting it to the generated Makefile via its own output variable. Let's take the second part first, since it's simple. In configure.in, having in some manner located the wanted data directory and assigned it to a variable
DATADIR=...
, you would make an output variable of that via the AC_SUBST macro:
AC_SUBST([DATADIR])
Since you are using only Autoconf, not Automake, you would then manually receive that into your Makefile by changing the assignment in your Makefile.in:
DATDIR = #DATADIR#
Now, as for locating the data directory in the first place, you have to know what you're trying to implement before you can implement it. From your question and followup comments, it seems to me that you want this:
Use a data directory explicitly specified by the user if there is one. Otherwise,
look for a data directory relative to the location of the shared library. If it's not found there then
(optional) look under the prefix specified to configure, or specifically in the specified datadir (both of which may come from the top-level configure). Finally, if it still has not been found then
look in some standard locations.
To create a configure option by which the user can specify a custom data directory, you would probably use the AC_ARG_WITH macro, maybe like this:
AC_ARG_WITH([pari-datadir], [AS_HELP_STRING([--with-pari-datadir],
[explicitly specifies the PARI data directory])],
[], [with_pari_datadir=''])
Thanks to #BrunoHaible, we see that although the Gnulib manual does not document it, the macro's internal documentation specifies that if AC_LIB_LINKFLAGS locates libpari then it will set LIBPARI_PREFIX to the library directory prefix. You find that that does work when the --with-libpari option is used to give it an alternative location to search, so I suggest working with that. You certainly can try to debug AC_LIB_LINKFLAGS to make it set LIBPARI_PREFIX in all cases in which the lib is found, but if you don't want to go to that effort then you can work around it (see below).
Although the default or specified installation prefix is accessible in configure as $prefix, I would suggest instead going to the specified $datadir. That is slightly tricky, however, because by default it refers to the prefix indirectly. Thus, you might do this:
eval "datadir_expanded=${datadir}"
Finally, you might hardcode a set of prefixes such as /usr and /usr/local.
Following on from all the foregoing, then, your configure.in might do something like this:
DATADIR=
for d in \
${with_pari_datadir} \
${LIBPARI_PREFIX:+${LIBPARI_PREFIX}/share/pari} \
${datadir_expanded}/pari \
/usr/local/share/pari \
/usr/share/pari
do
AS_IF([test -r "$[]d/pari.desc"], [DATADIR="$[]d"; break])
done
AS_IF([test x = "x$DATADIR"], [AC_MSG_ERROR(["Could not identify PARI data directory"])])
AC_SUBST([DATADIR])
Instead of guessing the location of datadir, why don't you ask PARI/GP where its datadir is located? Namely,
$ echo "default(datadir)" | gp -qf
"/usr/share/pari"
does the trick.

automake: how set path to linker script?

I've just set up a cross-helloworld automake project (for stm32f4-discovery). There I have a custom discovery.ld scrpt. I put a line in my Makefile.amAM_LDFLAGS = -T discovery.ld. The problem starts when I run confgure from a different folder (e.g. /path/to/source/build) to the one in which the script is situated (/path/to/source). Effectively, being in /path/to/source/build directory, make runs gcc -T discovery.ld ... and fails to find the script because it's in /path/to/source directory and it's not included in the search path list.
-L/path/to/source or -L.. would solve the problem but I don't want to hardcode things.
Maybe there a autoconf/automake variable exists which points to the folder where configure script (and also my discovery.ld) are situated so that I could use it in my Makefile.am?
I'd be glad to any advice.
Many thanks to William Pursell:
AM_LDFLAGS = -T $(top_srcdir)/path/to/discovery.ld

Intltool with an autoconf-generated .desktop file

In the Emperor project, I'm having some issues getting intltool to work when doing an out-of-tree build. When running make check out-of-tree, which is one of the things make distcheck does, intltool fails thus:
INTLTOOL_EXTRACT="/usr/bin/intltool-extract" XGETTEXT="/usr/bin/xgettext" srcdir=../../po /usr/bin/intltool-update --gettext-package emperor --pot
can't open ../../po/../data/emperor.desktop.in: No such file or directory at /usr/bin/intltool-extract line 212.
intltool is looking for emperor.desktop.in, which is listed in po/POTFILES.in, in the source tree. However, emperor.desktop.in is generated by the configure script from a file called emperor.desktop.in.in, in order to insert the installed executable path as configured by the user, and lands in the build tree.
These are the relevant bootstrap.sh lines:
echo +++ Running intltoolize ... &&
intltoolize --force --copy &&
cat >>po/Makefile.in.in <<EOF
../data/_column_names.h:
cd ../data && \$(MAKE) _column_names.h
EOF
The setup code in configure.ac:
IT_PROG_INTLTOOL([0.35.0])
GETTEXT_PACKAGE=emperor
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"],
[The domain to use with gettext])
AM_GLIB_GNU_GETTEXT
data/emperor.desktop.in is listed in AC_CONFIG_FILES.
data/Makefile.am contains these lines:
desktopdir = $(datadir)/applications
desktop_in_files = emperor.desktop.in
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
#INTLTOOL_DESKTOP_RULE#
and po/POTFILES.in contains the line
data/emperor.desktop.in
You can review all the details in the public git repository if you wish.
Can I somehow tell intltool that this file will be located in the build tree, not in the source tree? Otherwise, my options appear to be to break make distcheck (not a great option), or to ship a desktop file that doesn't include the full path and assumes that the executable is installed in the PATH. (just as messy, IMHO) - Any other options?
In your source code you have emperor.desktop.in.in, which does not seem to be in any rule as a dependency. That file has to be converted first to emperor.desktop.in and later to emperor.desktop, which does not seem to be the case in your data/Makefile.am.
desktopdir = $(datadir)/applications
desktop_in_in_files = emperor.desktop.in.in
desktop_in_files = $(desktop_in_in_files:.desktop.in.in=.desktop.in)
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
#INTLTOOL_DESKTOP_RULE#
[...]
EXTRA_DIST = \
$(desktop_in_in_files) \
[...]
$(desktop_in_in_files) contains $(desktop_in_in_files), and Makefile will know how to deal with that.
Some further digging has brought me believe that the answer is: intltool does not support source files that aren't source files in the project. Ergo, any additional processing must be done after intltool is through
Intltool requires the lines in POTFILES to be relative to the (build-time) working directory. The file POTFILES is generated by the configure script from POTFILES.in with a simple sed script defined in the IT_PO_SUBDIR autoconf macro (called by IT_PROG_INTLTOOL) that simply prepends the relative location of the top-level source directory to the paths. Alas, modifying POTFILES does not help: the intltool-extract script does everything it can to get the source directory right. I don't believe files that are sometimes inside and sometimes outside the source tree can be supported without modifying intltool itself.

Using Make to create DPKG .debs always rebuilds, not when files have changed

This is a slightly odd one where I'm sure I'm missing something perfectly straightforward.
I'm trying to cut some of the cruft off our build time, part of that is rebuilding a set of .debs we use which occurs everytime we've changed an aspect of the system due to the way an ant script has been configured. I was hoping to use Makefiles to monitor the folders that are going to be used for the dpkg process, so only the directories that have had recent changes are recreated but:
build-printing:
fakeroot dpkg -b printing printing.deb
Is constantly rerun, even though the files in that specific directory haven't changed. I'm sure I've missed something really simple, but I can't spot it in the man pages.
Your build-printing rule doesn't depend on anything - tell it which files it should watch the timestamps of, e.g.:
build-printing: directory/myfile.src
....
will cause build-printing to only be run if the time stamp on directoy/myfile.src is newer than the timestamp of build-printing. Since the rule doesn't look like it actually creates build-printing as a file you probably want to rename it to match the output file, e..g.
printing.deb: directory/myfile.src
....
If you want to use a rule named build-printing you can either make that rule touch a file called build-printing, or make that rule depend upon printing.deb.

gnu make dependencies for data processing

I'm trying to set up an ETL system using GNU Make 3.81. The idea is to transform and load only what is necessary after a change to my source data.
My project's directory layout looks like this:
${SCRIPTS}/ <- transform & load scripts
${DATA}/incoming/ <- storage for extracted data
${DATA}/processed/ <- transformed, soon-to-be-loaded data
My ${TRANSFORM_SCRIPTS}/Makefile is filled with statements like this:
A_step_1: ${SCRIPTS}/A/do_step_1.sh ${DATA}/incoming/A_files/*
${SCRIPTS}/A/do_step_1.sh ${DATA}/incoming/A_files/* > ${DATA}/processed/A.step_1
A_step_2: ${SCRIPTS}/A/do_step_2.sh ${DATA}/processed/A.step_1
${SCRIPTS}/A/do_step_2.sh ${DATA}/processed/A.step_1 > ${DATA}/processed/A.step_2
B_step_1: ${SCRIPTS}/B/do_step_1.sh ${DATA}/incoming/B_files/*
${SCRIPTS}/B/do_step_1.sh ${DATA}/incoming/B_files/* > ${DATA}/processed/B.step_1
B_step_2: ${SCRIPTS}/B/do_step_2.sh ${DATA}/processed/B.step_1
${SCRIPTS}/B/do_step_2.sh ${DATA}/processed/B.step_1 > ${DATA}/processed/B.step_2
joined: A_step_2 B_step_2
join ${DATA}/processed/A.step_2 ${DATA}/processed/B.step_2 > ${DATA}/processed/joined
Calling `make joined' successfully produces the "joined" file I need, but it rebuilds every file every time, despite there being no changes to the dependency files.
I tried using the output file names as targets, but GNU Make doesn't seem to know how to cope:
${DATA}/processed/B.step_2: ${SCRIPTS}/B/do_step_2.sh ${DATA}/processed/B.step_1
${SCRIPTS}/B/do_step_2.sh ${DATA}/processed/B.step_1 > ${DATA}/processed/B.step_2
Any suggestions other than dropping the output of each process in the current working directory? Make seems like a reasonable tool to perform this work because, in reality, there tens of data sources and close to 100 steps altogether, and managing dependencies myself via script files is becoming too difficult.
You can do one of two things:
Either fix the target and its dependencies with something like:
JOINED=${DATA}/processed/joined
$(JOINED): ${DATA}/processed/A.step_2 ${DATA}/processed/B.step_2
or in the steps you can end each step with a
touch $#
for example:
A_step_2: ${SCRIPTS}/A/do_step_2.sh ${DATA}/processed/A.step_1
${SCRIPTS}/A/do_step_2.sh ${DATA}/processed/A.step_1 > ${DATA}/processed/A.step_2 && touch $# || $(RM) $#
including the joined step.
but this is ugly.

Resources