Autoconf and ./configure variables - autoconf

I have a little problem with autoconf, I know that you can use configure.ac to add some defines to configure.h, but is there a way to do something like this:
in one of my headers I have
#ifndef SIZE
#define SIZE 4
#endif
now I want to have an option that if I invoke
./configure
it creates makefile and the size is 4, but when someone does
./configure --block-size=num
the SIZE will be set to num, preferably I want to do this without config.h, I just want him to add something to makefile, so the compilation will be invoked with
-DSIZE=num

# configure.ac
AC_ARG_WITH([blocksize],
AS_HELP_STRING([The desired blocksize [[default: 4]]]),
[blocksize="$withval"], [blocksize=4])
my_CPPFLAGS="-DSIZE=$blocksize"
AC_SUBST([my_CPPFLAGS])
Quite simple.
# Makefile.am
AM_CPPFLAGS = ${my_CPPFLAGS}

Related

Clang recursive include path

I have a problem when including dependency folder as this isn't looking for headers recursively.
FOLDER STRUCTURE:
- main.cpp
- dependency
- sub1
- header1.h
- sub2
- header2.h
- root-header.h
main.cpp
#include "root-header.h"
#include "header1.h"
#include "header2.h"
int main() {
}
Command:
clang main.cpp -I"dependency"
Error:
fatal error: 'header1.h' file not found
The command only detects header.h inside dependency folder to one level, how to make the clang to recursively lookup for all headers inside dependency folder. Is there any compiler arguments to be added?
Thanks
The ISO/IEC 9899:2011 standard in section ยง6.10.2 explains the expected behavior of clang and other compilers:
# include <h-char-sequence> new-line
searches a sequence of implementation-defined places for a header identified uniquely by the specified sequence between the < and > delimiters, and causes the replacement of that directive by the entire contents of the header. How the places are specified or the header identified is implementation-defined.
You can modify the defined places by adding additional with the -I option, but a compiler should not search sub-directories.
You can work around this limitation in the spec by using make to compile a list of additional -I locations to add to you clang command. This is covered in #DanBonachea answer.
Instead, I'd advise you to change the includes to be compliant to the specification:
#include "sub1/header1.h"
#include "sub2/header2.h"
The conventional solutions are one of the following:
1. Change the include directives in the source code
This solution compiles with clang++ -Idependency main.cpp but modifies #include directives to include headers by subdirectory, eg:
#include "sub1/header1.h"
#include "sub2/header2.h"
This is obviously a modification to the code, so usually only makes sense if sub1 and sub2 are meaningful within the larger structure of the software (e.g. package names that are always the same). Or...
2. Use shell tools to traverse the directory and build the include path
This solution uses find to inject subdirectories on the include path, eg:
$ clang++ `find ./dependency -type d -exec echo -I'{}' \;` main.cpp
which scans to identify the subdirectories and adds them to the preprocessor include path.
Discussion
Both of these approaches should work with few changes with basically any C/C++ compiler on UNIX (incl Linux, macOS, WSL, etc).
Note the second approach above will involve some additional filesystem churn on every compilation, which might be noticeable if the number of subdirectories is very large. To be fair this cost is fundamental to that use case, and even if built-in support for recursive include existed in the compiler frontend, it would still need to perform a similarly expensive recursive directory traversal on every compilation to find all the files.
3. Amortize directory traversal
However we can improve upon the second solution if we assume all the headers that will be included from this directory structure have unique names. This is a reasonable assumption, because otherwise the unqualified #include directives inside the source files will be ambiguous, leading to orthogonal problems. With this assumption in hand, we can create a cache to amortize the cost of the dependency directory traversal as follows:
$ mkdir allheaders ; cd allheaders
$ find ../dependency -type f -exec ln -s '{}' . \;
Then compilation simply becomes:
$ clang++ -Iallheaders main.cpp
Or, if you additionally want to support a mix of option 1 and option 3 #include directives, then:
$ clang++ -Idependency -Iallheaders main.cpp
This approach could greatly accelerate compilation, because the preprocessor only needs to open one user directory and open the files by basename. The fact that the directory may contain a large number of headers (with some fraction potentially unused) should not significantly degrade performance, thanks to how filesystems work.
If we further assume the file names in the dependency directory change infrequently or never, then we only need to execute the directory traversal step once, and can amortize that cost against repeated compilation using the allheaders cache directory.

Pattern syntax %.3: man/libfoo.man in Automake with different base name

I wrote a library libfoo providing functions bar and baz.
I want the user to be able to find the same man-page (from mans/libfoo.man) when they call man libfoo, man bar and man baz (Similar to man fprintf, man sprintf all pointing to the same page.)
My current setup has the files mans/libfoo.man and Makefile.am
To 'tell' automake that I want to end up with the three man-pages I specified the dist_man3_MANS variable.
Makefile.am:
dist_man3_MANS = mans/libfoo.3 mans/bar.3 mans/baz.3
Coming from GNU make, I thought I could just write
%.3: mans/libfoo.man
ln -S libfoo.man $#
to create links temporarily and then let Automake install those accordingly, but Automake errors out with Makefile.am:115: warning: '%'-style pattern rules are a GNU make extension. I want to do it properly and take this warning seriously by not relying on GNU Make to be as portable as possible.
The Automake manual suggests to add a target
.man.3:
$(LN_S) $^ $#
but that just tells Automake that xx.man can be compiled to xx.3, requiring the base name to be the same. I don't want to carry around those xx.man files, so this approach does not work.
I could hack it in with putting a rule
dist_man3_MANS = mans/libfoo.3 mans/bar.3 mans/baz.3
$(dist_man3_MANS): mans/libfoo.man
$(LN_S) libfoo.man $#
but that seems like a dirty hack, because I am not giving it a recipe to compile .man to .3, but rather say: "Hey, you can create those files with this rule", which for this case may work coincidental.
I would follow the example from the Automake info page section Extending Automake Rules and do something along the lines of
LIBFOO_MAN_ALIASES = bar baz
install-data-hook:
set -e; \
cd $(DESTDIR)$(man3dir) && \
for manalias in $(LIBFOO_MAN_ALIASES); do \
$(LN_S) libfoo.3 $${manalias}.3; \
done
uninstall-hook:
cd $(DESTDIR)$(man3dir) && \
for manalias in $(LIBFOO_MAN_ALIASES); do \
rm -f $${manalias}.3; \
done
relying on AC_PROG_LN_S to make sure that $(LN_S) does something reasonable for the system (symlink, hardlink, copy) to create a file name which can be open(2)ed and read.
FTR, I have just taken a look at three different systems' man pages and found them using three different methods to make the fprintf(3) man page show the same man page as printf(3) does:
Debian 10 uses symlinks
Fedora 35 uses a /usr/share/man/man3/fprintf.3 file containing .so man3/printf.3 (while some other man pages use symlinks to achieve the same effect)
FreeBSD 13 uses hardlinks, and find /usr/share/man -type l does not find any symlinks on my relatively clean system. However, manually testing both symlinks and the .so man3/printf.3 method suggests that FreeBSD man(1) does not treat symlinks in any special way and therefore opens the symlinked man page, and it also interprets the .so command just like Fedora 35's man(1) does.
I do not know how portable each of those methods is. Each of these three methods could set up on make install by using an appropriate install-data-hook, but any man file which can be opened using open(2) appears to be work, and therefore $(LN_S) looks like a good bet.

When changing the comment of a .c file, scons still re-compile it?

It's said that scons uses MD5 signature as default decider to dertermine whether a source file needs re-compilation. E.g. I've got SConstruct as below:
Library('o.c')
And my o.c is:
$ cat o.c
/*commented*/
#include<stdio.h>
int f(){
printf("hello\n");
return 2;
}
Run scons and remove the comment line, run scons again. I expect that scons should not compile it again, but actually it's:
gcc -o o.o -c o.c
scons: done building targets.
If I change SConstruct file to add one line:
Decider('MD5').
Still same result.
My question is: how to make sure that for scons, when changing source file comments, they don't get re-built?
Thanks!
As you correctly stated, SCons uses the MD5 hashsum of a source file to decide whether it has changed or not (content-based), and a rebuild of the target seems to be required (since one of its dependencies changed).
By adding or changing a comment, the MD5 sum of the file changes...so the trigger fires.
If you don't like this behaviour, you can write and use your own Decider function which will omit comment changes to your likings. Please check section 6.1.4 "Writing Your Own Custom Decider Function" in the UserGuide to see how this can be done.

Create custom ./configure command line arguments

I'm updating a project to use autotools, and to maintain backwards compatibility with previous versions, I would like the user to be able to run ./configure --foo=bar to set a build option.
Based on reading the docs, it looks like I could set up ./configure --enable-foo, ./configure --with-foo, or ./configure foo=bar without any problem, but I'm not seeing anything allowing the desired behavior (specifically having a double dash -- before the option).
Any suggestions?
There's no way I know of doing this in configure.ac. You'll have to patch configure. This can be done by running the patching script in a bootstrap.sh after running autoreconf. You'll have to add your option to the ac_option processing loop. The case for --x looks like a promising one to copy or replace to inject your new option, something like:
--foo=*)
my_foo=$ac_optarg ;;
There's also some code that strips out commandline args when configure sometimes needs to be re-invoked. It'll be up to you to determine whether --foo should be stripped or not. I think this is probably why they don't allow this in the first place.
If it were me, I'd try and lobby for AC_ARG_WITH (e.g. --with-foo=bar). It seems like a lot less work.
in order to do that you have to add to your configure.ac something like this:
# Enable debugging mode
AC_ARG_ENABLE(debug,
AC_HELP_STRING([--enable-debug],[Show a lot of extra information when running]),
AM_CPPFLAGS="$AM_CPPFLAGS -DDEBUG"
debug_messages=yes,
debug_messages=no)
AC_SUBST(AM_CPPFLAGS)
AC_SUBST(AM_CXXFLAGS)
echo -e "\n--------- build environment -----------
Debug Mode : $debug_messages"
That is just a simple example to add for example a --enable-debug, it will set the DEBUG constant on the config.h file.
then your have to code something like this:
#include "config.h"
#ifdef DEBUG
// do debug
#else
// no debug
#endif

scons difference between ccflags and shccflags

What is the reason for having both a CCFLAGS and a SHCCFLAGS variable in the SCons environment?
I am trying to modify a large program build that I did not write myself. When I add the command:
env.Append(CCFLAGS=["-I%s" % amber_dir, "-DAMBER"])
the compiler runs without the flags I added. But when I do
env.Append(SHCCFLAGS=["-I%s" % amber_dir, "-DAMBER"])
the compiler adds my flags as wanted. Somewhere in SCons' innards, CCFLAGS are is not passed to SHCCFLAGS. But why have a CCFLAGS and a SHCCFLAGS to begin with?
This is taken from the SCons User's Guide: SCons Construction Variable
CCFLAGS
General options that are passed to the C and C++ compilers.
CPPFLAGS
User-specified C preprocessor options. These will be included in any
command that uses the C preprocessor, including not just compilation
of C and C++ source files via the $CCCOM, $SHCCCOM, $CXXCOM and
$SHCXXCOM command lines, but also the $FORTRANPPCOM, $SHFORTRANPPCOM,
$F77PPCOM and $SHF77PPCOM command lines used to compile a Fortran
source file, and the $ASPPCOM command line used to assemble an
assembly language source file, after first running each file through
the C preprocessor. Note that this variable does not contain -I (or
similar) include search path options that scons generates
automatically from $CPPPATH. See $_CPPINCFLAGS, below, for the
variable that expands to those options.
SHCCFLAGS
Options that are passed to the C and C++ compilers to generate
shared-library objects.
SHCCCOM
The command line used to compile a C source file to a shared-library
object file. Any options specified in the $SHCFLAGS, $SHCCFLAGS and
$CPPFLAGS construction variables are included on this command line.
The most interesting of the 4 mentioned above are the SHCCCOM and CPPFLAGS variables. Try your test again setting CPPFLAGS instead of CCFLAGS.
A general comment about the flags you are setting: with SCons, its generally better to set include paths with the CPPPATH variable, and to set defines with the CPPDEFINES. When using these variable, you dont need to include the -I, nor the -D flags, SCons will add it for you in a platform-independent manner. Here's an example:
env.Append(CPPPATH=amber_dir)
env.Append(CPPDEFINES='AMBER')
You'll need to test this to see if the SharedObject() and/or SharedLibrary() builders use those, I would imagine they would.
Answers to questions in comment below:
SHCCCOM is just used to see what the command line looks like, sometimes you may need to use it without using the SCons builders directly. SHCCFLAGS is a super-set of CPPFLAGS and others and should be used when you have flags that you only want to pass to SharedLibrary() or SharedObject(). CPPFLAGS applies to both static and shared compilations.

Resources