canonical way to use pkg-config variables in Makefile.am - makefile

A bunch of projects foo-A-B, foo-B-C, foo-A-C etc. each depend on foo-A, foo-B, foo-C etc.
Each of foo-X installs a pkg-config file (foo-X.pc.in) which contains a variable srcdir=#datarootdir#/foo/foo-B. A foo-X-Y project needs to refer to files in Xsrcdir and Ysrcdir.
Currently we do it like this in configure.ac:
PKG_CHECK_MODULES([foo_X], [foo-X])
AC_ARG_VAR(XSRC, "Source directory for foo-X")
AS_IF([test -z "$XSRC"], [XSRC=`pkg-config --variable=srcdir foo-X`])
(so Makefile.am gets to have rules like compile "$XSRC"/file.bar $#). This also lets developers override XSRC on running ./configure.
My question: is there a more canonical way to use non-standard pkg-config variables in autotools configury/makefiles? For e.g. libdir, I see pkg-config sets the variables itself so no configure.ac line is needed apart from PKG_CHECK_MODULES; are there other m4 macros we should be using?

I know this is fairly late, but since somebody was asking me about this recently, I thought it might be worth answering this too.
What you're looking for is PKG_CHECK_VAR, indeed most of that code can be replaced by a single line:
PKG_CHECK_VAR([XSRC], [foo-X], [srcdir], ,
AC_MSG_FAILURE([Unable to find value for XSRC]))
The error message is a bit less clear than the one triggered by PKG_CHECK_MODULES, but it also triggers in case the srcdir variable is not defined.
I wrote some more details as part of my Autotools Mythbuster.

Related

Generate include files for the Makefile by the same Makefile

In my program, I have a somewhat complicated build process. Currently, in one directory I use include in Makefile.am with a file, that does not exist but has to be build on its own. The reason is that this include file is quite long. Further in the real program it is not just only one file but several and the generation process for this file can change from time to time.
The Makefile.am looks something like this
noinst_LIBRARIES = libtest.a
nodist_libtest_a_SOURCES = file.c
CLEANFILES = file.c Make_file.mk
$(builddir)/Make_test.mk: $(srcdir)/Perl/generate_mk_files.pl
perl $(srcdir)/Perl/generate_mk_files.pl file
include $(builddir)/Make_file.mk
After creation of Make_file.mk it looks something like
$(builddir)/file.c: $(srcdir)/file.template $(srcdir)/Perl/generate_c.pl
perl $(srcdir)/Perl/generate_c.pl $(srcdir)/file.template
Automake works and the final build process as well. The output to make is something like (I have shorted it somewhat):
Makefile:721: Make_file.mk: Datei oder Verzeichnis nicht gefunden (file not found)
perl ../../../../src/components/test/Perl/generate_mk_files.pl test
perl ../../../../src/components/test/Perl/generate_c.pl ../../../../src/components/test/file.template
Therefore, make first complains that the include file is not found, then creates it and then also follows the rules of the included file.
Although I am happy that it works I wonder why. First, I thought that make loads the Makefile. During this step, Make_file.mk does not exists. Therefore it seems the Makefile is loaded more than once.
Further, the manual of Automake for include states:
Note that these fragments are read and interpreted by automake, not by
make.
Which is not what I see, since the included fragment does not exist during the execution of Automake.
My questions basically are:
Why does it work?
Is this the correct way to do this or should I use another approach, e.g. starting new instances of make within Makefile.
I don't really know Automake, but, from the GNU make manual :
If an included makefile cannot be found in any of these directories {standard includes directories} , a
warning message is generated, but it is not an immediately fatal
error; processing of the makefile containing the include continues.
Once it has finished reading makefiles, make will try to remake any
that are out of date or don’t exist. See How Makefiles Are Remade.
Only after it has tried to find a way to remake a makefile and failed,
will make diagnose the missing makefile as a fatal error.
If you want make to simply ignore a makefile which does not exist or
cannot be remade, with no error message, use the -include directive
instead of include, like this:
-include filenames…
This acts like include in every way except that there is no error (not even a warning) if any of the filenames (or any
prerequisites of any of the filenames) do not exist or cannot be
remade.
So basically, make cannot execute the recipe for remaking the include file before he has finished to parse the main Makefile. So it raises a warning, continue to read the Makefile, find the rule for remaking the included file, remake it, and then restart itself (that is explained in details in the How Makefiles Are Remade section).
Going back to the manual, it states there's two forms for automakes include mechanism:
include $(srcdir)/file
and
include $(top_srcdir)/file
neither of which match your include. So I'd imagine the include is actually run by the underlying make whatever that might be (e.g. GNU Make, though of course other make programs have this functionality as well).
Now for the questions:
Why does it work?
As explained in another answer, GNU Make will attempt to make a missing included makefile, before failing.
Is this the correct way to do this or should I use another approach, e.g. starting new instances of make within Makefile
Generating makefiles is one of the tasks autotools do, either through autoconf or automake. Going through multiple stages of "making makefiles" seems prone to error (and hard to maintain). Recursive make has similar problems.
The reason is that this include file is quite long.
automake include statements will happily paste together a large makefile out of smaller components.
Further in the real program it is not just only one file but several and the generation process for this file can change from time to time.
It's hard to recommend what to suggest to do in autotools based on how the "changes" are determined. Since it seems you're also using libtool adding/removing sources to libs (or entire libs) there can be effected by conditionals, variables, etc.

understanding data assigned to macros in a makefile

I have searched through this forum but am not able to find an answer to this question, still if I have missed it please excuse me and direct me to the same.
I am trying to understand makefiles and came across the makefile for the tcpreplay utility on Linux. There are lot of macros that have been defined with the value starting an ending in a #. What are these values, how are they used? A snippet:
ACLOCAL = #ACLOCAL#
AMTAR = #AMTAR#
AR = #AR#
AUTOCONF = #AUTOCONF#
AUTOGEN = #AUTOGEN#
AUTOHEADER = #AUTOHEADER#
This is a makefile template, likely for software built with a GNU configure script. When configure is run, the #NAME# placeholders are replaced with proper values as determined at runtime. E.g. #AR# will be the name (or path) of the archiver, /usr/bin/ar. You then have a proper Makefile that you can run with a make invokation. If an actual Makefile still contains #NAME# placeholders, there was an error in running configure.
You are very likely not looking at a file named Makefile but one named Makefile.in. The .in suffix indicating that this is input to configure.
You can find all the gory details in the GNU autoconf manual.

variable=#value# in Makefiles

I understand that # suppresses printing of a command in a Makefile...
http://www.gnu.org/software/make/manual/make.html#Echoing
... and I understand that $# is the target name...
http://www.gnu.org/software/make/manual/make.html#Automatic-Variables
... but I can't find any information on what a line like this might mean:
variable=#value#
I'm not trying to fix anything here, just trying to better understand Makefiles.
Update: The "Makefile Subsitutions" section of the GNU autoconf manual explains that it's a value that is substituted by autoconf.
Typically you find this in Makefile.in files, which are processed by configure (which are in turn generated by autoconf) scripts.
In that case #X# will be replaced by the value of a shell variable $X, if configure is told so. If it's not, no occurrence in the input file will be touched by configure, hence leaving the replaceable string as it is. If you ask me these instances indicate slips in the build system.

Evaluate automake variable only once

We are using automake & autoconf to build our multi-package software. I was wondering how to fill a variable with the output of e.g. shell-scripts once and reuse this, e.g. for needed include dirs
INCLUDES := -I`some-ext-config --incdir`
Using := instead of = here makes this variable filled once so some-ext-config will only be called once (AFAIK this comes from plain make). Of course INCLUDES is the depreciated cousin of AM_CPPFLAGS, but would I have used that one instead, the shell script would have been called for each compile.
Using INCLUDES instead of AM_CPPFLAGS is an acceptable solution for me (though I imagine there might be portability issues), but I have no solution for e.g. LDFLAGS for a libtool library
libmylib_la_LDFLAGS := `some-ext-config --ldflags` # will always be evaluated
What is the general solution inside automake if I want to make sure these external tools are not called multiple times? I would like to stay away from using an obvious AC_SUBST in configure.ac since we have to make sure our packages can be build both from subdirectories (some configure.ac in there) and with an recursive make from the top-level and a configure.ac there which shouldn't need to know too much about the different subprojects.
:= is GNU-make specific, so you are advised to use just = in automake. If you do not want to run the shell script everytime INCLUDES (or AM_CPPFLAGS, does not matter, it would occur with either), then run the script in configure.ac and use variable substitution via AC_SUBST. That is essentially what pkg-config would do — and come to speak of it, you could just use that instead of some-ext-config if there is a .pc file.
# configure.ac
libfoo_CPPFLAGS=$(some-ext-config --incdir);
libfoo_LIBS=$(some-ext-config --libs);
AC_SUBST([libfoo_CPPFLAGS])
AC_SUBST([libfoo_LIBS])
# Makefile.am
AM_CPPFLAGS = -Iwhatever ${libfoo_CPPFLAGS}
bin_PROGRAMS = foo
foo_LDADD = ${libfoo_LIBS}
This is a more lengthy explanation of what I suggested in a comment to jørgensen's answer.
I understand your top-level configure.ac must generate the makefiles of multiple sub-projects, and performs the required tests so that you don't have to run the configure in any subproject (a sub-configure serves only when you want to work on this particular sub-project).
In that case, you want to avoid duplicating as much stuff as possible from various configure.ac. I suggest you factor all the code of the sub-configure that must also be performed by the top-level configure in an m4 macro. This includes tests, AC_SUBSTS, and Makefile declarations.
For instance using only one-subproject. Here is a top-level ./configure.ac:
AC_INIT([toplevel], [1.0])
AM_INIT_AUTOMAKE([foreign -Werror])
SUB1_COMMON([sub1/]) dnl Stuff from the subproject
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
With ./Makefile.am:
ACLOCAL_AMFLAGS = -I sub1/m4
SUBDIRS = sub1
Now here is sub1/configure.ac for the sub-project:
AC_INIT([sub1], [1.0])
AM_INIT_AUTOMAKE([foreign -Werror])
AC_CONFIG_MACRO_DIR([m4])
SUB1_COMMON
AC_OUTPUT
With SUB1_COMMON defined in m4/common.m4:
AC_DEFUN([SUB1_COMMON],
[AC_SUBST([PYTHON3LIB], [`pkg-config --libs python3`])
AC_CONFIG_FILES([$1Makefile])])
And finally sub1/Makefile.am is just:
ACLOCAL_AMFLAGS = -I m4
# Build something.
...
The SUB1_COMMON contains all the code you want to share between the two configure.ac files, and use argument $1 to relocate the config files appropriately. In this example, the variable PYTHON3LIB will be defined regardless of which configure were run.

With autoconf/automake, how do I specify include file paths?

Let's say I want to have the generate makefile pass some specific header paths to g++.
What do I need to add to configure.ac or Makefile.am to specify this?
(note - I do not want to pass it in the CPPFLAGS with ./configure. I want those paths baked in before that step)
EDIT:
Specifically, I want to to include let's say /usr/include/freetype and /mypath/include.
I put AC_CHECK_HEADERS([freetype/config/ftheader.h]) and it passes, but doesn't seem to add it to the -I passed to g++.
I also did try adding CPPFLAGS=-I.:/usr/include/freetype:/mypath/include, but it screws up and puts -I twice, the first as -I. and it ignores the 2nd -I.
Since the question was about what to put in an automakefile, I would have thought AM_CPPFLAGS was the right variable to use to add includes and defines for all C/C++ compiles. See http://www.gnu.org/software/automake/manual/html_node/Program-Variables.html
Example:
AM_CPPFLAGS = -I/usr/local/custom/include/path
Hard coding paths into the package files is absolutely the wrong thing to do. If you choose to do that, then you need to be aware that you are violating the basic rules of building a package with the autotools. If you specify /mypath/include in your package files, you are specifying things specific to your machine in a package that is intended to work on all machines; clearly that is wrong. It looks like what you want is for your package (when built on your machine) to look for header files in /mypath. That is easy to accomplish without bastardizing your package. There are (at least) 3 ways to do it:
Use a config.site file. In /usr/local/share/config.site (create this file if necessary), add the line:
CPPFLAGS="$CPPFLAGS -I/mypath/include"
Now any package using an autoconf generated configure script with the default prefix (/usr/local) will append -I/mypath/include to CPPFLAGS and the headers in /mypath/include will be found.
If you want the assignment to be made for all builds (not just those to be installed in /usr/local), you can use this:
Put the same line specifying CPPFLAGS in $HOME/config.site, and set CONFIG_SITE=$HOME/config.site in the environment of your default shell. Now, whenever you run an autoconf generated configure script, the assignments from $HOME/config.site will be made.
Simply specify CPPFLAGS in the environment of your default shell.
All of these solutions have two primary advantages over modifying your build files. First, they will work for all autoconf generated packages (as long as they follow the rules and don't do things like assigning user variables such as CPPFLAGS in the build files). Second, they do not put your machine specific information into a package that ought to work on all machines.

Resources