Including #foo preprocessor directives at compile time (GNU tools) - configure

I've currently run in such a problem, in fact caused by the package maintainer(s), who simply did not consider that a certain preprocessor definition was not available until version X of a certain toolkit package required in the dependencies (which is currently in testing stage). It was fixable by simply adding an additional #define to a header file in the base system, making the project compile fine again.
However, what if I had no root access to the system? Could I also add a #define new_macro "i am from the future" at compile time, e. g. to configure?
When reading myself through the matter, I thought that it might maybe work with the DEFS environment variable, but apparently this is not meant to be used for C preprocessor directives.
So can this be accomplished at all?

Thanks, but unfortunately a huge problem is the strings in quotes
Create a file, for example at ~/somedir/mycompiler with content:
#!/bin/sh
gcc -Dnew_macro="i am from the future" "$#"
add executable permissions chmod +x ~/somedir/mycompiler and then pass that as parameter to configure:
./configure CC="$HOME"/somedir/mycompiler ...
Configure script in turn will use that script to compile everything, passing -D everywhere, and quotes will be properly parsed by sh.

Related

Prepending custom dirs ($ZPFX/{include,libs}) to CPP..../LDFLAGS with use of config.site file of autotools?

I'm using a $CONFIG_SITE set to $ZPFX/share/config.site file containing:
CPPFLAGS="-I$ZPFX/include $CPPFLAGS"
LDFLAGS="-L$ZPFX/lib $LDFLAGS"
where $ZPFX variable is my custom user prefix, similar to ~/.local.
Now, the problem is that the system iconv.h (under path /usr/include) isn't found because of this, as only the above pre-set (with use of config.site) -I$ZPFX…/-L$ZPFX… are being passed to the test program, as the following lines from config.log are showing:
configure:21831: gcc -o conftest -g -O2 \
-I/home/q/.local/share/zinit/polaris/include \
-L/home/q/.local/share/zinit/polaris/lib \
conftest.c -lxml2 -liconv >&5
/usr/bin/ld: cannot find -liconv
collect2: error: ld returned 1 exit status
($ZPFX is expanded to its value, which is: /home/q/.local/share/zinit/polaris)
The Question: how to append (prepend) any custom ($ZPFX/… in my case) directories to CPPFLAGS/LDFLAGS, preserving their default values? So that my custom libraries are only given higher precedence, and not exclusivity?
What I've tried
As it can be seen, I've tried to prepend to the flags by appending any occurred values at the time of sourcing the config.site file, by "…$CPP…/$LDFLAGS" :
CPPFLAGS="-I$ZPFX/include $CPPFLAGS"
LDFLAGS="-L$ZPFX/lib $LDFLAGS"
However this has no effect.
I'm also waving between not-appending and appending any typically used system-libraries paths: /usr/include and /usr/lib{,64}, however I don't like the idea, because some system might use e.g.: /opt/… for main prefix, making such hack not working at all.
The documentation explains how configure scripts use CONFIG_SITE. The parts most relevant to your question are near the beginning:
If the environment variable CONFIG_SITE is set, configure uses its
value as a space-separated list of shell scripts to read [...].
Otherwise, it reads the shell script prefix/share/config.site if it
exists, then prefix/etc/config.site if it exists. [...]
Site files can be arbitrary shell scripts
You ask:
how to append (prepend) any custom ($ZPFX/… in my case) directories
to CPPFLAGS/LDFLAGS, preserving their default values? So that my
custom libraries are only given higher precedence, and not
exclusivity?
You need to read only a little between the lines to recognize that the mechanism by which configure scripts read site defaults must be via the . command. That the files may contain arbitrary shell code and that they can set shell variables within configure implies that they are going to be parsed and executed as shell code.
The docs also say what configure does by default when you do not provide CONFIG_SITE, so your site config can do that, too, if you wish. And that's what I would do, to start. Specifically, add this at the beginning of $ZPFX/share/config.site:
test -r "${prefix}/share/config.site" && . "${prefix}/share/config.site"
test -r "${prefix}/etc/config.site" && . "${prefix}/etc/config.site"
Now you have the same settings that configure would get when you don't define CONFIG_SITE at all. What remains is to insert your own additional settings, and the code already presented in the question ought to be fine for that:
CPPFLAGS="-I$ZPFX/include $CPPFLAGS"
LDFLAGS="-L$ZPFX/lib $LDFLAGS"
Additionally, you write:
I'm also waving between not-appending and appending any typically used
system-libraries paths: /usr/include and /usr/lib{,64}, however I
don't like the idea, because some system might use e.g.: /opt/… for
main prefix, making such hack not working at all.
I don't like that idea either.
In the first place, /usr/include, /usr/lib, etc. are not just commonly used, they are typical toolchain defaults. You pretty much never need to explicitly specify toolchain defaults, and trying to do so is more likely to cause harm than good. For example, it could cause breakage in cases such as you posit, where the defaults for the toolchain actually being used are different from the usual ones.
But in the second place, your remarks convey an incorrect perspective on what you're doing with site defaults. These are site-specific, which may mean machine specific or may mean more broadly specific to a group or organization, but any way around, you can set only your own site defaults, not those of other sites.
And that leads me to one final point: the site configuration is part of your site, not part of your project. Hopefully this is not a point of confusion for you, but I want to be sure it is clear. You should not be planning to distribute your site configuration file outside your own site, nor to rely on people wanting to build your project at other sites specifically to use a site configuration file to inject build settings.

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

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.

How to delay effect of "include" directive in Makefile.am until make (avoid "include" being seen by Automake)?

My Makefile.am includes a file (with various defined variables), for example:
include make.config
...
The problem is that this file is in turn generated by a tool (i.e. config.generator.sh) based on some input file (i.e. input.dat). The straightforward and wrong idea would be to add a rule to generate make.config:
make.config : input.dat
config.generator.sh input.dat > make.config
include make.config
...
Although this content is perfectly working makefile on its own without automake, the idea is doomed with automake. The make.config file is included by automake before I even have a chance to execute make (and it fails as the file is not yet generated):
automake: cannot open < make.config: No such file or directory
Is there a way to postpone effect of include directive until make is run (possibly by using another directive)?
There is probably a way to simply run arbitrary commands before any makefile generation is done (i.e. AC_CONFIG_COMMANDS*). But the question is more complicated because the config.generator.sh is supposed to use executables which are in turn also generated during the same build process (so there is a dependency chain which logically has to be managed by makefiles from the same project). The documentation simply confirms the logic without providing alternatives.
The solution is described in this email of Automake's mailing list.
The idea is to use include directives inside small regular "wrapper" makefile and include Automake-generated Makefile into it (note the upper case M). Because makefile is not an Automake template, the include works as expected triggering builds for non-existing files.
Note that:
By default make utility will search for makefile first (not for Makefile) making this approach working seamlessly.
It is still recommended to specify all rules inside Makefile.am and keep the "wrapper" makefile simple. The rules for non-existing files will naturally come from the generated Makefile anyway.
I've come across the same annoying problem today when moving my OCaml project to Autotools. My solution is to use autoconf's substitution to go around automake. For the above example, I'd add a substitution to configure.ac:
AC_SUBST([include_make_config], ["include make.config"])
and adjust Makefile.am, replacing the include directive with the autoconf variable reference:
make.config : input.dat
config.generator.sh input.dat > make.config
#include_make_config#
...
automake doesn't touch the #include_make_config# line so it gets carried over into the generated Makefile.in. When autoconf takes over, it substitutes the variable with include make.config in the final Makefile.
Note: I use this with OCaml's ocamldep dependency generator.

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