[DTrace-devel] [PATCH 5/5] build: add configure script

Kris Van Hees kris.van.hees at oracle.com
Thu Dec 21 18:49:19 UTC 2023


On Wed, Nov 29, 2023 at 04:08:29PM +0000, Nick Alcock wrote:
> This serves three purposes:
>  - let you bake configuration into build/config.* so that you don't
>    need to specify the same arguments to make repeatedly
>  - provide a somewhat familiar interface to builders
>  - provide more documentation for bits of the build configuration
>    which there was no place to document (notably Make variables
>    overridden by the user, which were documented only
>    intermittently in comments in the top-level GNUmakefile).
> 
> It is *not* generated by Autoconf but is a short and hopefully
> comprehensible shell script.
> 
> Internally it's fairly boring.
> 
> Overrides of makefile variables go into a new config-vars.mk, which is
> written as a unit, since their construction is very cheap and they don't
> need the variable-by-variable, test-by- test construction process used for
> variables that end up in config.{mk,h}.
> 
> Some of the help (for all the Makeconfig overrides) is printed by calling
> "make help-overrides", which ultimately derives it from the Makeconfig
> itself.  (Unfortunately I can't see a way to generate the actual
> write_config_var invocations from the same place, so there's still a bit of
> extra work to do when you add new Makeconfig tests.)
> 
> The rest of the "make help" -- and really most of the configure script -- is
> duplicative of stuff already in the GNUmakefile, but I can't see a way to
> automate its generation without ending up with *way* more automation than we
> have duplicated code here.
> 
> In the GNUmakefile, the biggest impact is making all the paths normal
> recursively evaluated variables, so that they can pick up
> configure-generated paths (which are defined later), and moving most of the
> rest of the non-configure-modified variables down below the inclusion of
> config-vars.mk.  This gives the desired properties for defaulting:
> 
>  - doing nothing causes the assignments in the Makefile to kick in
>  - defining stuff via configure causes them to be overridden by
>    further assignments in the config-vars.mk (which values are then
>    picked up by the moved-down assignments
>  - passing stuff on the make command line does what that normally
>    does, and suppresses the corresponding in-makefile variable
>    assignments, both in GNUmakefile itself and in config-vars.mk,
>    thus overriding both the defaults and configure-generated paths
> 
> Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
> ---
>  GNUmakefile |  76 +++++++++++++++------------
>  README.md   |  15 ++++--
>  configure   | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 202 insertions(+), 38 deletions(-)
>  create mode 100755 configure
> 
> diff --git a/GNUmakefile b/GNUmakefile
> index 619b709bf78e..c39aa0d2b587 100644
> --- a/GNUmakefile
> +++ b/GNUmakefile
> @@ -26,22 +26,10 @@ $(if $(subst sparc64-linux,,$(subst aarch64-linux,,$(subst x86_64-linux,,$(ARCHO
>  $(if $(filter %-linux,$(ARCHOS)),, \
>      $(error "Error: DTrace only supports Linux"))
>  
> +# Variables overridable by the command line and configure scripts.
> +
>  CFLAGS ?= -O2 -Wall -pedantic -Wno-unknown-pragmas
>  LDFLAGS ?=
> -BITNESS := 64
> -NATIVE_BITNESS_ONLY := $(shell echo 'int main (void) { }' | gcc -x c -o /dev/null -m32 - 2>/dev/null || echo t)
> -ARCHINC := $(subst sparc64,sparc,$(subst aarch64,arm64,$(subst x86_64,i386,$(ARCH))))
> -INVARIANT_CFLAGS := -std=gnu99 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 $(if $(NATIVE_BITNESS_ONLY),-DNATIVE_BITNESS_ONLY) -D_DT_VERSION=\"$(VERSION)\"
> -CPPFLAGS += -Iinclude -Iuts/common -Iinclude/$(ARCHINC) -I$(objdir)
> -
> -export CC = gcc
> -override CFLAGS += $(INVARIANT_CFLAGS)
> -PREPROCESS = $(CC) -E
> -export BPFC = bpf-unknown-none-gcc
> -
> -BPFCPPFLAGS += -D$(subst sparc64,__sparc,$(subst aarch64,__aarch64__,$(subst x86_64,__amd64,$(ARCH))))
> -BPFCFLAGS ?= -O2 -Wall -Wno-unknown-pragmas
> -export BPFLD = bpf-unknown-none-ld
>  
>  # The first non-system uid on this system.
>  USER_UID=$(shell grep '^UID_MIN' /etc/login.defs | awk '{print $$2;}')
> @@ -83,30 +71,52 @@ KERNELARCH := $(subst sparc64,sparc,$(subst aarch64,arm64,$(subst x86_64,x86,$(A
>  
>  # Paths.
>  
> -prefix = /usr
> +prefix ?= /usr
>  export objdir := $(abspath build)
> -LIBDIR := $(prefix)/lib$(BITNESS)
> -INSTLIBDIR := $(DESTDIR)$(LIBDIR)
> -BINDIR := $(prefix)/bin
> -INSTBINDIR := $(DESTDIR)$(BINDIR)
> -INCLUDEDIR := $(prefix)/include
> -INSTINCLUDEDIR := $(DESTDIR)$(INCLUDEDIR)
> -SBINDIR := $(prefix)/sbin
> -INSTSBINDIR := $(DESTDIR)$(SBINDIR)
> -UDEVDIR := $(prefix)/lib/udev/rules.d
> -INSTUDEVDIR := $(DESTDIR)$(UDEVDIR)
> -SYSTEMDUNITDIR := $(prefix)/lib/systemd/system
> -INSTSYSTEMDUNITDIR := $(DESTDIR)$(SYSTEMDUNITDIR)
> -DOCDIR := $(prefix)/share/doc/dtrace-$(VERSION)
> -INSTDOCDIR := $(DESTDIR)$(DOCDIR)
> -MANDIR := $(prefix)/share/man/man8
> -INSTMANDIR := $(DESTDIR)$(MANDIR)
> -TESTDIR := $(prefix)/lib$(BITNESS)/dtrace/testsuite
> -INSTTESTDIR := $(DESTDIR)$(TESTDIR)
> +LIBDIR = $(prefix)/lib$(BITNESS)
> +INSTLIBDIR = $(DESTDIR)$(LIBDIR)
> +BINDIR = $(prefix)/bin
> +INSTBINDIR = $(DESTDIR)$(BINDIR)
> +INCLUDEDIR = $(prefix)/include
> +INSTINCLUDEDIR = $(DESTDIR)$(INCLUDEDIR)
> +SBINDIR = $(prefix)/sbin
> +INSTSBINDIR = $(DESTDIR)$(SBINDIR)
> +UDEVDIR = $(prefix)/lib/udev/rules.d
> +INSTUDEVDIR = $(DESTDIR)$(UDEVDIR)
> +SYSTEMDUNITDIR = $(prefix)/lib/systemd/system
> +INSTSYSTEMDUNITDIR = $(DESTDIR)$(SYSTEMDUNITDIR)
> +DOCDIR = $(prefix)/share/doc/dtrace-$(VERSION)
> +INSTDOCDIR = $(DESTDIR)$(DOCDIR)
> +MANDIR = $(prefix)/share/man/man8
> +INSTMANDIR = $(DESTDIR)$(MANDIR)
> +TESTDIR = $(prefix)/lib$(BITNESS)/dtrace/testsuite
> +INSTTESTDIR = $(DESTDIR)$(TESTDIR)
>  TARGETS =
>  
>  DTRACE ?= $(objdir)/dtrace
>  
> +# configure overrides (themselves overridden by explicit command-line options).
> +
> +-include $(objdir)/config-vars.mk
> +
> +# Variables derived from the above.
> +
> +BITNESS := 64
> +NATIVE_BITNESS_ONLY := $(shell echo 'int main (void) { }' | gcc -x c -o /dev/null -m32 - 2>/dev/null || echo t)
> +ARCHINC := $(subst sparc64,sparc,$(subst aarch64,arm64,$(subst x86_64,i386,$(ARCH))))
> +
> +INVARIANT_CFLAGS := -std=gnu99 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 $(if $(NATIVE_BITNESS_ONLY),-DNATIVE_BITNESS_ONLY) -D_DT_VERSION=\"$(VERSION)\"
> +CPPFLAGS += -Iinclude -Iuts/common -Iinclude/$(ARCHINC) -I$(objdir)
> +
> +export CC = gcc
> +override CFLAGS += $(INVARIANT_CFLAGS)
> +PREPROCESS = $(CC) -E
> +export BPFC = bpf-unknown-none-gcc
> +
> +BPFCPPFLAGS += -D$(subst sparc64,__sparc,$(subst aarch64,__aarch64__,$(subst x86_64,__amd64,$(ARCH))))
> +BPFCFLAGS ?= -O2 -Wall -Wno-unknown-pragmas
> +export BPFLD = bpf-unknown-none-ld
> +
>  all::
>  
>  # Include everything.
> diff --git a/README.md b/README.md
> index 01bdf8173562..f3b0c5b7df1b 100644
> --- a/README.md
> +++ b/README.md
> @@ -191,7 +191,7 @@ sudo make install
>  
>  Some distributions install the BPF gcc and binutils under different names.  You
>  can specify the executables to use using the **BPFC** and **BPFLD** variables.
> -E.g. on Debian you would use:
> +E.g. on Debian you could use:
>  
>  ```
>  make BPFC=bpf-gcc BPFLD=bpf-ld
> @@ -209,11 +209,16 @@ make KERNELS="5.16.8"
>  as long as the source tree that kernel was built with remains where it was
>  when that kernel was installed.
>  
> -See the GNUmakefile for more options (building translators against multiple
> -different kernels at once, building against kernel sources found in
> -different places, building against a kernel built with O=, etc.)
> +See `./configure --help`, `make help`, and the top-level GNUmakefile for a
> +full list of options (building translators against multiple different
> +kernels at once, building against kernel sources found in different places,
> +building against a kernel built with O=, installing in different places,
> +etc.)
>  
> -'make help' might also be of interest.
> +Some of the options (e.g., those specifying paths) may need to be specified
> +when installing as well as when building.  To avoid this, you can use the
> +configure script: it bakes variable settings into the makefile so that they
> +persist across multiple invocations, including `make install`.
>  
>  ## 3. Testing
>  
> diff --git a/configure b/configure
> new file mode 100755
> index 000000000000..187884a92067
> --- /dev/null
> +++ b/configure
> @@ -0,0 +1,149 @@
> +#!/bin/bash
> +# Allow user overrides of configuration options.
> +#
> +# Oracle Linux DTrace.
> +# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
> +# Licensed under the Universal Permissive License v 1.0 as shown at
> +# http://oss.oracle.com/licenses/upl.
> +
> +set -e
> +
> +write_make_var()
> +{
> +    local val="$(printf "%s" "$2" | sed 's,^.*=,,')"
> +
> +    [[ ! -d build ]] && mkdir -p build
> +
> +    if [[ ! -f build/config-vars.mk ]]; then
> +        echo 'Writing build/config-vars.mk'
> +        echo '# This file is automatically generated.' > build/config-vars.mk
> +    fi
> +
> +    printf '%s=%s\n' $1 "$val" >> build/config-vars.mk
> +}
> +
> +write_config_var()
> +{
> +    local val="$(printf "%s" "$2" | sed 's,^.*=,,')"
> +
> +    if [[ ! -d build/.config ]]; then
> +       mkdir -p build/.config
> +       touch build/.config/dir.stamp
> +        echo 'Writing build/config.{h,mk}'

This is a confusing message because it is not accurate.  The script is actually
writing to build/.config/config.$1.{h,mk}.

> +    fi
> +
> +    case $val in
> +        no) printf '# HAVE_%s undefined\n' $1 > build/.config/config.$1.mk
> +            printf '/* #undef HAVE_%s */\n' $1 > build/.config/config.$1.h;;
> +        yes|'') printf 'HAVE_%s=y\n' $1 > build/.config/config.$1.mk
> +                printf '#define HAVE_%s 1\n' $1 > build/.config/config.$1.h;;
> +    esac
> +}
> +
> +rm -f build/config-vars.mk
> +rm -rf build/.config

This is problematic because if I simply want to invoke configure --help to get
the help output, I do not necessarily want my previous config to get deleted.
Surely, some options like --help should *not* have any side effects like that.

In fact, ideally, I would prefer a failed configure run (if that is in fact
even possible with this tiny script) to leave any previous config in place.
I.e. only replace any existing config if configure is successful.

Right now, nothing that I see can cause a failure - which is also interesting
because that means if I have something wrong in my tree and e.g. config-vars.mk
is not writable, it does not seem an error will be reported.  In this version,
obviously, the rm statements above would yield an error but since they really
shouldn't be there IMHO, once they are removed, failing commands do not seem
to be considered - i.e. no error checking.

> +
> +help()
> +{
> +	cat >&2 <<'EOF'
> +Installation paths:
> +
> +--prefix=/usr					Prefix of all installed paths
> +--objdir=build					Build directory
> +--libdir=PREFIX/lib64				Library directory
> +--bindir=PREFIX/sbin				Binary directory
> +--sbindir=PREFIX/sbin				Alias for --bindir
> +--includedir=PREFIX/include			#include directory
> +--mandir=PREFIX/share/man/man8			Manpage directory
> +--udevdir=PREFIX/lib/udev/rules.d		udev rules directory
> +--systemd-unit-dir=PREFIX/lib/systemd/system	systemd unit directory
> +--docdir=PREFIX/share/doc/dtrace		Documentation directory
> +--testdir=LIBDIR/dtrace/testsuite		Testsuite install directory
> +
> +Options relating to the user environment (may need customization on
> +some systems, see GNUmakefile)
> +
> +--user-uid=UID			The first non-system uid on the system
> +--dumpcap-group=GROUP		Group one must run as to invoke $DUMPCAP
> +--unpriv-uid=UID		A uid suitable for unprivileged processes;
> +				may be negative
> +--unpriv-home=/run/initramfs	Non-writable directory to use as $HOME for
> +				unprivileged processes
> +
> +Options relating to kernels (for local builds against a running kernel
> +built locally, none of these should be needed):
> +
> +--kernels="6.1 6.2 6.3"		Space-separated list of kernel versions to
> +				produce translators for
> +--kernel-mod-dir=DIR		Directory used to search for kernel build trees
> +--kernel-src-dir=DIR		Source location of kernel tree for local builds
> +--kernel-obj-dir=DIR		O= passed to local kernels built with O=
> +
> +Options controlling the compiler (pass on the command line):
> +
> +CC				C compiler (may be a cross-compiler)
> +CPP				Preprocessor, by default $(CC) -E
> +CPPFLAGS			Preprocessor flags
> +CFLAGS				Compiler flags
> +LDFLAGS				Linker flags
> +BPFC				Cross-compiler to BPF
> +BPFCPPFLAGS			BPF C preprocessor flags
> +BPFCFLAGS			BPF C compiler flags
> +BPFLD				BPF linker
> +
> +EOF
> +	make help-overrides
> +        cat >&2 <<'EOF'
> +If passed to configure as command-line arguments, all the variables
> +above stick for future make invocations until "make clean".
> +
> +EOF
> +}
> +
> +for option in "$@"; do
> +    case "$option" in
> +        --help) help; exit 1;;
> +	--prefix=*) write_make_var prefix "$option";;
> +        --objdir=*) write_make_var objdir "$option";;
> +        --libdir=*) write_make_var LIBDIR "$option";;
> +        --bindir=*) write_make_var BINDIR "$option";;
> +        --sbindir=*) write_make_var SBINDIR "$option";;
> +        --includedir=*) write_make_var INCLUDEDIR "$option";;
> +        --udevdir=*) write_make_var UDEVDIR "$option";;
> +        --systemd-unit-dir=*) write_make_var SYSTEMDUNITDIR "$option";;
> +        --docdir=*) write_make_var DOCDIR "$option";;
> +        --mandir=*) write_make_var MANDIR "$option";;
> +        --testdir=*) write_make_var TESTDIR "$option";;
> +        CC=*) write_make_var CC "$option";;
> +        CPP=*) write_make_var PREPROCESS "$option";;
> +        CFLAGS=*) write_make_var CFLAGS "$option";;
> +        CPPFLAGS=*) write_make_var CPPFLAGS "$option";;
> +        LDFLAGS=*) write_make_var LDFLAGS "$option";;
> +        BPFC=*) write_make_var BPFC "$option";;
> +        BPFCPPFLAGS=*) write_make_var BPFCPPFLAGS "$option";;
> +        BPFCFLAGS=*) write_make_var BPFCFLAGS "$option";;
> +        BPFLD=*) write_make_var BPFLD "$option";;
> +        --user-uid=*) write_make_var USER_UID "$option";;
> +        --dumpcap-group=*) write_make_var DUMPCAP_GROUP "$option";;
> +        --unpriv-uid=*) write_make_var UNPRIV_UID "$option";;
> +        --unpriv-home=*) write_make_var UNPRIV_HOME "$option";;
> +        --kernels=*) write_make_var KERNELS "$option";;
> +        --kernel-mod-dir=*) write_make_var KERNEL_MOD_DIR "$option";;
> +        --kernel-src-dir=*) write_make_var KERNEL_SRC_DIR "$option";;
> +        --kernel-obj-dir=*) write_make_var KERNEL_OBJ_DIR "$option";;
> +        HAVE_ELF_GETSHDRSTRNDX=*) write_config_var HAVE_ELF_GETSHDRSTRNDX "$option";;
> +        HAVE_LIBCTF=*) write_config_var HAVE_LIBCTF "$option";;
> +        HAVE_STRRSTR=*) write_config_var HAVE_STRRSTR "$option";;
> +        HAVE_LIBSYSTEMD=*) write_config_var HAVE_LIBSYSTEMD "$option";;
> +        HAVE_FUSE_LOG=*) write_config_var HAVE_FUSE_LOG "$option";;
> +        HAVE_LIBFUSE3=*) write_config_var HAVE_LIBFUSE3 "$option";;
> +        HAVE_FUSE_NUMA=*) write_config_var HAVE_FUSE_NUMA "$option";;
> +        HAVE_CLOSE_RANGE=*) write_config_var HAVE_CLOSE_RANGE "$option";;
> +        HAVE_GETTID=*) write_config_var HAVE_GETTID "$option";;

Have you considered introducing options for these list --with-* and --without-*,
especially for things like libctf, libsystemd, and fuse?  The others relate to
functions that we have our own implementation for if the libraries do not 
provide one (or we cannot verify they do), so perhaps something lihe
--with-own-* or --without-own-* could apply?

That seems to be more configure-like and more consistent?  Or allow both?

> +	*) echo "Unknown option $option" >&2
> +           exit 1;;
> +    esac
> +done
> +
> +exit 0
> +
> -- 
> 2.42.0.271.g85384428f1
> 
> 



More information about the DTrace-devel mailing list