autosetup 0.7.1

autosetup v0.7.1 has been released.

Changes since v0.7.0

Major improvements:

Minor changes and bug fixes:

  • autosetup-find-tclsh will now build jimsh0 in the current directory
  • pkg-config: invocation of -print-sysroot is now correct
  • config.guess, config.sub: update to 2021-06-03
  • cc-check-tools: fix when command includes args
  • define-push: simplifies define management

Handling CFLAGS

One question that comes up quite often is, “What is the right way of handling CFLAGS within autosetup (also autoconf, automake, etc.) and the Makefiles for the best user experience?” – stack overflow. automake spends some time on this – 26.6 Flag Variables Ordering however it doesn’t answer all the questions that we might want answered. Below is my attempt to untangle the confusion and provide a canonical best way to handle CFLAGS with autosetup and make (or similar).

One fundamental consideration is that CFLAGS (and CPPFLAGS, CXXFLAGS) are all user-specified and the user’s wishes should be respected above all else. This means that overwriting the user’s settings by changing CFLAGS or adding additional flags after the user’s settings is not acceptable. With this in mind, let’s look at all the points where flags to the C compiler could be specified.

First the user can provide flags in the environment or on the command line to configure that we will name (1) and (2).

$ CFLAGS=-Dd1 ./configure CFLAGS=-Dd2

Next the user can provide flags in the environment or on the commandline to make or equivalent that we will name (3) and (4).

$ CFLAGS=-Dd3 make CFLAGS=-Dd4

Finally if no explicit CFLAGS are provided by the user, use -g -O2, which we will name (0).

In addition, configure may wish to add additional flags based on configure tests or user options, but these should not affect CFLAGS.

# If supported, add this flag to compiler flags
cc-check-flags -std=c99

And also we may we wish to add to CFLAGS within the makefile based on settings. (This example could have been done in auto.def instead - it is just indicative). Simlarly this should not affect the user’s CFLAGS settings.

ifeq(@SHARED@,1)
# Except we don't want to append to CFLAGS
CFLAGS += -dynamic
endif

Now what behaviour provides the best user experience? It is reasonable for (2) to override (1), especially as CFLAGS may simply be set in the environment, so the explicit setting on the command line should take precedence. Similarly, (4) should override (3) for similar reasons. It is also clear that (4) should take precedence over (1) and (2) as this is a later phase. One thing that is not entirely clear is whether (3) should override (2). For simplicity we will say it should as otherwise we would need to distiguish beteen (1) and (2) in the Makefile. Finally, for CFLAGS all of (1) - (4) should override (0). Now as we said that the user’s selection is the highest precedence, our command line should clearly be.

cc <other-flags> $CFLAGS -c ... -o ...

With the user’s selection last, overriding other flags that we will discuss shortly, and where CFLAGS is defined as below, where the notation means that the first value that is set is chosen.

CFLAGS := (4) || (3) || (2) || (1) || (0)

Note that CPPFLAGS can be specified by the user in all the same ways, except that there is no default if not specified. The ordering between CFLAGS and CPPFLAGS is not clear, but we may as well follow the gnu make approach:

# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

So then we have:

cc <other-flags> $CFLAGS $CPPFLAGS -c ... -o ...

Now we only need to decide how configure-derived flags are set and made available to make. While most autosetup checks don’t do anything with CFLAGS by default (it is up to the auto.def developer to make the flags available), cc-check-flags unfortunately (as of autosetup 0.7.0) modifieds CFLAGS. This is not OK as CFLAGS is a user value, and should not be touched by autosetup. Therefore, as of autosetup 0.7.1, cc-check-flags now adds to AS_CFLAGS instead (autosetup CFLAGS). This makes the recommendation of how to handle CFLAGS in auto.def simple. All flags are added to AS_CFLAGS (or AS_CPPFLAGS or AS_CXXFLAGS). e.g.

# Adds to AS_CFLAGS
cc-check-flags -std=c99
# Add profiling if selected
if {[opt-bool profiling]} {
	define-append AS_CFLAGS -pg
}

And finally we need to determine how flags can be added in the Makefile. It is simplest if we use the same AS_CFLAGS as autosetup. e.g.

ifeq(@SHARED@,1)
AS_CFLAGS += -dynamic
endif

Now the only remaining challenge is to ensure that the Makefile implements our desired command line:

cc $(AS_CFLAGS) $(AS_CPPFLAGS) $CFLAGS $CPPFLAGS -c ... -o ...

We could start by trying this:

CFLAGS += @AS_CFLAGS@ @AS_CPPFLAGS@ @CFLAGS@ @CPPFLAGS@

However this does not work as these will take precedence over the user flags. As there is no way to prepend flags, we could try the cumbersome:

override CFLAGS := @AS_CFLAGS@ @AS_CPPFLAGS@ $(CFLAGS)

But my preference is for the simpler solution to either take over the implicit rule entirely, or replace the compile line. Therefore in gnu make we can do:

# Use configure versions if not set during make
CFLAGS ?= @CFLAGS@
CPPFLAGS ?= @CPPFLAGS@
CFlAG
# ensure we get the ordering we need
COMPILE.c = $(CC) @AS_CFLAGS@ @AS_CPPFLAGS@ $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

(Note that we could changed to CFLAGS = @CFLAGS@ if we wanted to ignore (3))

Alternatively replace the rule entirely:

# This may be gnu make only
%.o: %.c
        $(CC) @AS_CFLAGS@ @AS_CPPFLAGS@ $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@

# This may work better for bsd make
.c.o:
        $(CC) @AS_CFLAGS@ @AS_CPPFLAGS@ $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@

This is implemented in examples/typical/Makefile.in If you have a suggestion why one Makefile approach is better than the others, please make a comment on this page.

autosetup 0.7.0

autosetup v0.7.0 has been released.

Changes since v0.6.9

Major improvements:

  • options: improved option handling, consistency and documentation

Minor changes and bug fixes:

  • Avoid adding duplicates to $CONFIGURE_OPTS and $AUTO_REMAKE
  • pkg-config: Improve cross compiling support, identify dependency issues, pkg-config-get-var
  • cc: $CXX is set to the empty string if not found rather than false
  • Add support for Tcl 8.7

autosetup 0.6.9

autosetup v0.6.9 has been released.

As there has been no release notes for a while, here are the changes since v0.6.2

Major improvements:

  • make-template: Support nesting, better conditionals, @define and @include
  • Make it possible to use a system-installed autosetup. e.g. autosetup –sysinstall=/usr/local
  • Add initial pkg-config support
  • Add an extensible init system with autosetup –init=<type>

Minor changes and bug fixes:

  • define-append now ignores empty values
  • define-append: improved check for duplicates
  • cc-shared: always use -fPIC
  • cc-shared: Add support for RPATH
  • cc-shared: Add $STRIPLIBFLAGS
  • system: add support for –runstatedir
  • system: add abs_top_srcdir and abs_top_builddir
  • options-defaults provides a way to change the default options from auto.def
  • Never honor prefix for /var, honor only if != /usr for /etc
  • make-template: Don’t write file if unchanged
  • Allow $autosetup_tclsh to select the preferred tclsh
  • Add cc-path-progs
  • cc: drop empty -cflags, -includes, -libs
  • cc: tests should use LIBS and LDFLAGS
  • opt-bool: allow boolean options multiple times
  • opt-bool: accepts -nodefault option
  • cc-lib: add cc-check-alloca and cc-signal-return-type
  • Fix cc-check-members for members of structs
  • Set srcdir to a fully qualified path
  • Add support for undefine
  • Allow –init and –install to be combined
  • Update config.{sub,guess} from automake-1.15
  • Add ‘cctest -nooutput 1’ to consider any compiler output as an error

Incompatibilities introduced:

  • Syntax of @if statements has changed in make-template
  • Remove –with-xxx and –without-xxx synonyms
  • opt-val now returns a list

Automatic autoconf migration tool

Although autosetup configurations are generally easy to create, developers moving a complex project from autoconf to autosetup may still find it tedious to create the auto.def configuration file.

To simplify migration from autoconf, autosetup includes a migration tool which will automatically convert a configure.in or configure.ac file to an auto.def file.

Consider the following migration of tinytcl:

$ cd tinytcl
$ ~/src/autosetup.git/migrate-autoconf
Migrating configure.ac to auto.def
Created auto.def. Now edit to resolve items marked XXX
$ ~/src/autosetup.git/autosetup --install
Installed autosetup v0.6.2 to autosetup/
I see configure, but not created by autosetup, so I won't overwrite it.
Use autosetup --init --force to overwrite.
$ ./autosetup/autosetup --init --force
I will overwrite the existing configure because you used --force.

Now the migrated auto.def can be edited. Before editing it looks something like this:

# Created by migrate-autoconf - fix items marked XXX

use cc cc-lib

options {
    shared=0         =>  {Build a shared library}
    history=0        =>  {Enable history support}
    debug=0          =>  {Enable debugging command: cmdtrace}
    fork=1           =>  {Do not use fork (no exec, etc.)}
    syslog=0         =>  {Build the syslog extension}
}

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.


# XXX autosetup automatically substitutes all define'd values
#     In general, simply 'define' the value rather than using a shell
#     variable and AC_SUBST.
#
# XXX AC_SUBST TARGET_PLATFORM $ac_cv_host

# Checks for programs.

# XXX TINYTCL_IS_STATIC=1
if {[opt-bool shared]} {
    # XXX if test "x$enableval" = "xyes" ; then
    msg-result "* creating shared library"
    # XXX TINYTCL_IS_STATIC=
    # XXX fi
}
# XXX AC_SUBST TINYTCL_IS_STATIC $TINYTCL_IS_STATIC
...

After editing, auto.def looks more like:

...
define TARGET_PLATFORM [get-define host]

define TINYTCL_IS_STATIC 1
if {[opt-bool shared]} {
    msg-result "* creating shared library"
    define TINYTCL_IS_STATIC 0
}
...

The final edited version is available at in the autosetup repository as auto.def.edited along with additional examples.

Note that migrate-autoconf only understands a common subset of autoconf macros and uses various heuristics to perform the migration. Nonetheless, migrate-autoconf can significantly speed up migration from autoconf.

Fossil adopts autosetup

Recently the Fossil SCM has been adopted by Tcl/Tk as a replacement for CVS. Now the Tcl-based autosetup has been adopted as the development configuration system for Fossil.

Fossil is similar to many open source projects that are required to support a number of different platforms. The obvious approach is to use autoconf and possibly automake, but many people find that approach frustrating.

Some of the immediate benefits of autosetup are support for cross compilation and easily allowing Fossil to be build with different options.

See All News Articles »