oconfigure

oconfigure is a configuration system for writing portable C-language software with OpenBSD features and functions. It allows easy porting to Linux (glibc and musl), FreeBSD, NetBSD, Mac OS X, DragonFlyBSD, and OmniOS (illumos). Other systems may also be supported: please let me know if they are.

The system consists of three files that need to be included in your source code: a configure script, a tests.c file used by the script to probe for OpenBSD features, and a compats.c source file providing all compatibility functions. The configure script outputs Makefile.configure and config.h when run, which must be integrated into your system. In full:

  1. copy configure, compats.c, and tests.c into your source tree, or grab files from a cloned repository or downloaded release
  2. run ./configure to create Makefile.configure and config.h
  3. include Makefile.configure at the top of your Makefile (BSD or GNU make) and add compats.c to be linked into your binary or library
  4. reference compatibility functions by adding #include "config.h" as the first inclusion in your sources

oconfigure is used on a fair amount of software written with OpenBSD as a basis, such as kcgi, lowdown, etc.

Usage

The central part of oconfigure is the configure script. It repeatedly compiles different parts of the tests.c file to test for OpenBSD-compatible features like pledge(2) or strlcpy(3). It also detects compiler operation, such as which flag to use for linking shared libraries. The results are output as a header file, config.h, for inclusion in your sources; and a make(1) fragment, Makefile.configure, for your build system.

Run the script as ./configure or sh ./configure, depending upon whether it's executable. It can be run in parallel mode as ./configure -jn, where n is the number of processors or zero for all. Key-value pairs may be passed into the script to affect feature testing, such as for cross-compiling or overload libraries.

📚 See Configuration options and environment for general details and libbsd for specific libbsd instructions.

The generated Makefile.configure will contain key-value pairs used for building software with make(1). The following example shows how to include and use Makefile.configure. It uses BSD make style. The compats.c is distributed with oconfigure, while Makefile.configure and config.h are generated by the configure script.

include Makefile.configure
# Require zlib, just to make things interesting.
LDADD_PKG != pkg-config --libs zlib || echo "-lz"
CFLAGS_PKG != pkg-config --cflags zlib || echo ""

LDADD += $(LDADD_PKG)
CFLAGS += $(CFLAGS_PKG)

# Build the main binary with the compatibility functions.
main: main.o compats.o
	$(CC) -o $@ main.o compats.o $(LDFLAGS) $(LDADD)

# Install into BINDIR in the the DESTDIR fake root.
install:
	mkdir -p $(DESTDIR)$(BINDIR)
	$(INSTALL_PROGRAM) main $(DESTDIR)$(BINDIR)

# All sources depend on the generated config.h.
main.o compats.o: config.h

clean:
	rm -f main main.o compats.o

📚 See Shared libraries for building shared libraries and Static binaries for building static binaries.

Next, how must the software be modified to use compatibility? It depends on whether the code is testing for a feature, like looking for pledge(2) or capsicum(4), or using an OpenBSD function like strlcpy(3) that has a compatibility shim in oconfigure.

In general, using an OpenBSD-specific feature without compatibility requires a conditional guard; while using an OpenBSD-specific feature with compatibility might require a header guard.

📚 See Features for a full list of feature tests and compatibility functions.

#include "config.h" /* required inclusion */
#if HAVE_ERR /* sometimes err.h exists, sometimes not */
# include <err.h>
#endif
#include <stdio.h>
#include <unistd.h>

int main(void) {
#if HAVE_PLEDGE /* do we have pledge? */
	if (pledge("stdio", NULL) == -1)
		err(1, NULL); /* compat provides this */
#endif
	warnx("hello, world!"); /* compat provides this */
	return 0;
}

The #if HAVE_ERR statement draws from config.h to see if the err.h header file exists. If it does, use it; otherwise, the source will use the compatibility in config.h. After those lines, the warn() and err() functions will resolve. The #if HAVE_PLEDGE is a feature test, so what's within will only be compiled if pledge() was detected.

Acknowledgements

This framework was inspired by mandoc’s configure script written by Ingo Schwarze.

Tables and appendices

The following sections are for specific use cases and documentation.

Features

What follows is a description of the feature tests and compatibility provided by config.h and compats.c when included into your sources. Each is linked to the test and compatibility source, where applicable.

Compatibility functions

arc4random(), …

Tests and compatibility for arc4random(3) functions in stdlib.h, defining HAVE_ARC4RANDOM with the result.

#if HAVE_ARC4RANDOM
# include <stdlib.h> /* arc4random, arc4random_buf... */
#endif

The compatibility functions provide the same quality (via the same source) as OpenBSD, using the host’s getentropy() function for seed.

Source: compat, test

blf_enc(), blf_dec(), …

Tests and compatibility for blf_enc(3) functions including the raw block functions (not documented on OpenBSD, but still in the public API).

#if HAVE_BLOWFISH
# include <blf.h> /* blf_enc ... */
#endif

Source: compat, test

b64_ntop(), b64_pton()

Tests and compatibility for these functions, which do not have manpages on OpenBSD despite existing and being usable. On some systems, the functions are only declared, but not defined. To avoid superfluous inclusions, their usage should be guarded:

#if HAVE_B64_NTOP
# include <netinet/in.h>
# include <resolv.h>
#endif

Some systems (Linux only?) with HAVE_B64_NTOP need -lresolv during linking. If so, LDADD_B64_NTOP is defined in Makefile.configure to -lresolv. Otherwise, it is empty.

Since these functions are always poorly documented, the following demonstrates usage for b64_ntop(), which translates src into an encoded NUL-terminated string dst and returns the string length or -1. The dstsz is the maximum size required for encoding.

srcsz = strlen(src);
dstsz = ((srcsz + 2) / 3 * 4) + 1;
dst = malloc(dstsz);
if (b64_ntop(src, srcsz, dst, dstsz) == -1)
	goto bad_size;

b64_pton() reverses this situation from an encoded NUL-terminated string src into the decoded and NUL-terminated string dst (it’s common not to need the NUL-terminator for the decoded string, which is meant to be binary). The dstsz is the maximum size required for decoding.

srcsz = strlen(src);
dstsz = srscsz / 4 * 3;
dst = malloc(dstsz + 1); /* NUL terminator */
if ((c = b64_pton(src, dst, dstsz)) == -1)
	goto bad_data;
dst[c] = '\0'; /* NUL termination */

Source: compat, test

crypt_newhash(), …

Tests and compatibility for the crypt(3)-replacing functions crypt_newhash(3) and crypt_checkpass(3) functions, defining HAVE_CRYPT_NEWHASH with the result.

The portability functions only provide bcrypt() functionality.

Source: compat, test

htole32(), be32toh(), …

On most operating systems (Linux, OpenBSD), endian.h provides the POSIX.1 endian functions, e.g., htole32(3), be32toh(3), etc. On FreeBSD, however, these are in sys/endian.h. Mac OS X and SunOS have their own functions in their own places.

The required invocation to use the endian functions is:

#if HAVE_ENDIAN_H
# include <endian.h>
#elif HAVE_SYS_ENDIAN_H
# include <sys/endian.h>
#elif HAVE_OSBYTEORDER_H
# include <libkern/OSByteOrder.h>
#elif HAVE_SYS_BYTEORDER_H
# include <sys/byteorder.h>
#endif

Compatibility for the Mac OS X and SunOS functions to the usual htole32() style is provided. To make this easier, the COMPAT_ENDIAN_H is also defined:

#include COMPAT_ENDIAN_H

This will paste the appropriate location.

Source: test

err(), warn(), …

Tests for the err(3) functions, defining HAVE_ERR variable with the result.

Provides compatibility functions if not found. The functions are for err(), errx(), errc(), warn(), warnx(), warnc(), and the variable-argument versions of each.

#if HAVE_ERR
# include <err.h>
#endif

The err.h header needs to be guarded to prevent systems using the compatibility functions for failing, as the header does not exist.

It’s worth noting that glibc defines many of these functions, but misses the errc() and warnc() variations. oconfigure considers it all or nothing, so will not define HAVE_ERR in this case.

Source: compat, test

explicit_bzero()

Tests for explicit_bzero(3) in string.h, defining HAVE_EXPLICIT_BZERO with the result.

#include <string.h> /* explicit_bzero */

Provides a compatibility function if not found. The compatibility function will use memset_s, if found. HAVE_EXPLICIT_BZERO shouldn’t be directly used in most circumstances.

Source: compat, test

fts_open(), fts_read(), …

Tests for fts_open(3) functions in fts.h, defining HAVE_FTS with the result.

#if HAVE_FTS
# include <sys/types.h>
# include <fts.h> /* fts_open(3) et al. */
#endif

The fts.h header needs to be guarded to prevent systems using the compatibility functions for failing, as the header does not exist.

Provides compatibility functions if not found.

Source: compat, compat, test

getprogname()

Tests for getprogname(3) in stdlib.h, defining HAVE_GETPROGNAME with the result.

#include <stdlib.h> /* getprogname */

Provides a compatibility function if not found. The compatibility function tries to use __progname, program_invocation_short_name, or getexecname(). If none of these interfaces may be found, it will emit a compile-time error. HAVE_GETPROGNAME shouldn’t be directly used in most circumstances.

Source: compat, test, test, test, test

INFTIM

Tests for the INFTIM macro value in poll(2), defining HAVE_INFTIM with the result.

#include <poll.h> /* INFTIM */

Provides a compatibility value if not found. Since a compatibility value is provided, HAVE_INFTIM shouldn’t be directly used in most circumstances.

Source: test

MD5Init(), MD5Update(), …

Tests for the standalone md5(3) functions, defining HAVE_MD5 with the result.

If not found, provides a full complement of standalone (i.e., not needing any crypto libraries) MD5 hashing functions. These are MD5Init, MD5Update, MD5Pad, MD5Transform, MD5End, and MD5Final. The preprocessor macros MD5_BLOCK_LENGTH, MD5_DIGEST_LENGTH, and MD5_DIGEST_STRING_LENGTH are also defined.

These differ ever-so-slightly from the OpenBSD versions in that they use C99 types for greater portability, e.g., uint8_t instead of u_int8_t.

If using these functions, you’ll want to guard an inclusion of the system-default. Otherwise a partial md5.h may conflict with results, or a missing md5.h may terminate compilation.

#if HAVE_MD5
# include <sys/types.h>
# include <md5.h>
#endif

On some systems (FreeBSD or those with Guillem Jover’s libmd) with HAVE_MD5, you’ll also need to add -lmd when you compile your system, else it will fail with undefined references.

The LDADD_MD5 value provided in Makefile.configure will be set to -lmd if it’s required. Otherwise it is empty.

Source: compat, test

memmem()

Tests for memmem(3) in string.h, defining HAVE_MEMMEM with the result.

#include <string.h> /* memmem */

Provides a compatibility function if not found. Since a compatibility function is provided, HAVE_MEMMEM shouldn’t be directly used in most circumstances.

Source: compat, test

memrchr()

Tests for memrchr(3) in string.h, defining HAVE_MEMRCHR with the result.

#include <string.h> /* memrchr */

Provides a compatibility function if not found. Since a compatibility function is provided, HAVE_MEMRCHR shouldn’t be directly used in most circumstances.

Source: compat, test

WAIT_ANY

Tests for WAIT_ANY in waitpid(2), defining HAVE_WAIT_ANY with the result.

#include <sys/wait.h> /* WAIT_ANY, WAIT_MYPGRP */

Provides a compatibility value for both WAIT_ANY and WAIT_MYPGRP if not found. Since a compatibility function is provided, HAVE_WAIT_ANY shouldn’t be directly used in most circumstances.

Source: test

mkfifoat()

Tests for the mkfifoat(3) function, defining HAVE_MKFIFOAT with the result.

Provides a compatibility function if not found. This is not a direct replacement, as the function is not atomic: it internally gets a reference to the current directory, changes into the “at” directory, runs the function, then returns to the prior current. Upon errors, it makes a best effort to restore the current working directory to what it was.

Source: compat, test

mknodat()

Tests for the mknodat(3) function, defining HAVE_MKNODAT with the result.

Provides a compatibility function if not found. This is not a direct replacement, as the function is not atomic: it internally gets a reference to the current directory, changes into the “at” directory, runs the function, then returns to the prior current. Upon errors, it makes a best effort to restore the current working directory to what it was.

Source: compat, test

PATH_MAX

Tests for the PATH_MAX variable in limits.h, defining HAVE_PATH_MAX with the result.

#include <limits.h> /* PATH_MAX */

If not found, defines the PATH_MAX macro to be 4096. Since a compatibility value is provided, HAVE_PATH_MAX shouldn’t be directly used in most circumstances.

Source: test

readpassphrase()

Tests for the readpassphrase(3) function, defining HAVE_READPASSPHRASE with the result. The readpassphrase.h header inclusion needs to be guarded for systems that include it by default; otherwise, the definitions are provided in the generated config.h:

#if HAVE_READPASSPHRASE
# include <readpassphrase.h>
#endif

Provides a compatibility function if not found. If using this function, makes sure you explicitly zero the passphrase buffer as described in readpassphrase(3).

Source: compat, test

reallocarray()

Tests for reallocarray(3) in stdlib.h, defining HAVE_REALLOCARRAY with the result.

#include <stdlib.h> /* reallocarray */

Provides a compatibility function if not found. Since a compatibility function is provided, HAVE_REALLOCARRAY shouldn’t be directly used in most circumstances.

Source: compat, test

recallocarray()

Tests for recallocarray(3) in stdlib.h, defining HAVE_RECALLOCARRAY with the result.

#include <stdlib.h> /* recallocarray */

Provides a compatibility function if not found. Since a compatibility function is provided, HAVE_RECALLOCARRAY shouldn’t be directly used in most circumstances.

Source: compat, test

scan_scaled(), fmt_scaled()

Tests for OpenBSD’s scan_scaled(3), defining HAVE_SCAN_SCALED if it was found.

#if HAVE_SCAN_SCALED
# include <util.h>
#endif

Provides compatibility functions if not found. If this is required, the LDADD_SCAN_SCALED variable in Makefile.configure will be set to the required library (-lutil).

Source: compat, test

SHA256Init(), SHA256Update(), …

Tests for the standalone sha2(3) functions, defining HAVE_SHA2 with the result. This was previously provided as HAVE_SHA2_H, which still works as an alias for HAVE_SHA2.

If not found, provides a full complement of standalone SHA2 hashing functions. These are SHA256Init(), SHA256Transform(), SHA256Update(), SHA256Pad(), SHA256Final(), SHA256End(), SHA256File(), SHA256FileChunk(), and SHA256Data(). The preprocessor macros SHA256_BLOCK_LENGTH, SHA256_DIGEST_LENGTH, and SHA256_DIGEST_STRING_LENGTH are also defined.

The SHA2 functions and macros are provided for SHA256, SHA384, and SHA512. So for example the SHA512Final() function is also provided.

If using these functions, you’ll want to guard an inclusion of the system-default. Otherwise a partial sha2.h may conflict with results, or a missing sha2.h may terminate compilation.

#if HAVE_SHA2
# include <sys/types.h>
# include <sha2.h>
#endif

On some systems (such as those with Guillem Jover’s libmd) with HAVE_SHA2, you’ll also need to add -lmd when you compile your system, else it will fail with undefined references.

The LDADD_SHA2 value provided in Makefile.configure will be set to -lmd if it’s required. Otherwise it is empty.

Source: compat, test

strlcat()

Tests for strlcat(3) in string.h, defining HAVE_STRLCAT with the result.

#include <string.h> /* strlcat */

Provides a compatibility function if not found. Since a compatibility function is provided, HAVE_STRLCAT shouldn’t be directly used in most circumstances.

Source: compat, test

strlcpy()

Tests for strlcpy(3) in string.h, defining HAVE_STRLCPY with the result.

#include <string.h> /* strlcpy */

Provides a compatibility function if not found. Since a compatibility function is provided, HAVE_STRLCPY shouldn’t be directly used in most circumstances.

Source: compat, test

strndup()

Tests for strndup(3) in string.h, defining HAVE_STRNDUP with the result.

#include <string.h> /* strndup */

Provides a compatibility function if not found. Since a compatibility function is provided, HAVE_STRNDUP shouldn’t be directly used in most circumstances.

Source: compat, test

strnlen()

Tests for strnlen(3) in string.h, defining HAVE_STRNLEN with the result.

#include <string.h> /* strnlen */

Provides a compatibility function if not found. Since a compatibility function is provided, HAVE_STRNLEN shouldn’t be directly used in most circumstances.

Source: compat, test

strtonum()

Tests for strtonum(3) in stdlib.h, defining HAVE_STRTONUM with the result.

#include <stdlib.h> /* strtonum */

Provides a compatibility function if not found. Since a compatibility value is provided, HAVE_STRTONUM shouldn’t be directly used in most circumstances.

Source: compat, test

LIST_HEAD(), TAILQ_HEAD(), …

Tests for the queue(3) header, sys/queue.h. Defines HAVE_SYS_QUEUE if found. To use these macros, make sure to guard inclusion:

#if HAVE_SYS_QUEUE
# include <sys/queue.h>
#endif

Provides all of the queue macros if not. This uses TAILQ_FOREACH_SAFE as a basis for determining whether the header exists and is well-formed. This is because glibc provides a skeleton sys/queue.h without this critical macro.

Source: compat, test

SPLAY_INIT(), RB_INIT(), …

Tests for the tree(3) header, sys/tree.h. Defines HAVE_SYS_TREE if found. To use these macros, make sure to guard inclusion:

#if HAVE_SYS_TREE
# include <sys/tree.h>
#endif

Provides all of the tree macros if not found.

Source: compat, test

timingsafe_bcmp()

Tests for the timingsafe_bcmp(3) functions in string.h, defining HAVE_TIMINGSAFE_BCMP with the result.

#if HAVE_TIMINGSAFE_BCMP
# include <string.h> /* timingsafe_bcmp... */
#endif

If not found, provides compatibility functions.

Source: compat, test

Feature tests

Capsicum

Tests for FreeBSD’s Capsicum subsystem, defining the HAVE_CAPSICUM variable with the result.

#if HAVE_CAPSICUM
# include <sys/resource.h>
# include <sys/capsicum.h>
#endif

The guard is required for systems without these headers.

crypt()

On OpenBSD, passwords are managed primarily through crypt_newhash(3) and friends. However, the old crypt(3) function is still used in portable applications. Even though it’s not very portable.

This tests for crypt(3), defining HAVE_CRYPT with the result.

On many systems with HAVE_CRYPT, you’ll also need to add -lcrypt when you compile your system, else it will fail with undefined references. The LDADD_CRYPT value provided in Makefile.configure will be set to -lcrypt if it’s required. Otherwise it is empty.

Source: test

landlock

Tests for Linux’s landlock) LSM. Defines HAVE_LANDLOCK if found.

This test does not mean that the module is enabled. You’ll need to perform a run-time check for landlock_restrict_self()’s return value in your sources.

To actually use Landlock, you’ll need to modify your system’s LSM at boot time.

Source: test

libsocket

On IllumOS-based distributions, all socket functions (bind(2), listen(2), socketpair(2), etc.) require linking to the -lsocket and -lnsl libraries.

If this is required, the LDADD_LIB_SOCKET variable in Makefile.configure will be set to the required libraries.

minor(), major(), …

major(2), minor(2), and makedev(2) all live in different places on different systems.

#if HAVE_SYS_MKDEV_H
# include <sys/types.h> /* dev_t */
# include <sys/mkdev.h> /* minor/major/makedev */
#elif HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h> /* minor/major/makedev */
#else
# include <sys/types.h> /* minor/major/makedev */
#endif

This can be made much easier as follows, where COMPAT_MAJOR_MINOR_H is set to one of the above. sys/types.h may be included twice.

#include <sys/types.h>
#include COMPAT_MAJOR_MINOR_H
pledge()

Test for pledge(2), defining HAVE_PLEDGE with the result. Does not provide any compatibility.

#include <unistd.h> /* pledge */

The HAVE_PLEDGE guard is not required except around the function invocation.

Source: test

sandbox_init()

Tests for sandbox_init(3), defining HAVE_SANDBOX_INIT with the result. Does not provide any compatibility.

Source: test

seccomp

Tests for Linux’s prctl(2) function, which is the gateway for seccomp(2). This defines several variables:

  • HAVE_SECCOMP_HEADER: Compile-time support exists for seccomp.
  • SECCOMP_AUDIT_ARCH: If HAVE_SECCOMP_HEADER is set, this is set to the architecture used for seccomp operations (e.g., AUDIT_ARCH_ARM). If this is not set and HAVE_SECCOMP_HEADER is set, seccomp is enabled in the kernel but the hardware architecture is not known by oconfigure. Please create an issue or pull request with your uname -m and hardware profile.
  • HAVE_SECCOMP_FILTER: Set if both HAVE_SECCOMP_HEADER and SECCOMP_AUDIT_ARCH are set.

This test does not mean that the sandboxing is enabled. You’ll need to perform a run-time check for prctl()’s return value in your sources.

Source: test

SOCK_NONBLOCK

Tests for socketpair(2) in sys/socket.h supporting the SOCK_NONBLOCK mask as found on OpenBSD. Defines the HAVE_SOCK_NONBLOCK variable.

#if HAVE_SOCK_NONBLOCK
	socketpair(AF_UNIX, flags|SOCK_NONBLOCK, 0, fd);
#else
	socketpair(AF_UNIX, flags, 0, fd);
	fcntl(fd[0], F_SETFL, 
	fcntl(fd[0], F_GETFL, 0)|O_NONBLOCK);
	fcntl(fd[1], F_SETFL, 
	fcntl(fd[1], F_GETFL, 0)|O_NONBLOCK);
#endif

The guard is not required only around the variable usage, not header inclusion. However, the above example could have the fcntl.h header guarded by !HAVE_SOCK_NONBLOCK.

Source: test

systrace

Tests for the deprecated systrace(4) interface. Defines HAVE_SYSTRACE if found. Does not provide any compatibility.

This function is never “found”.

Source: test

termios

Tests for whether termios(4) exists, defining HAVE_TERMIOS with the result, specifically with the use case of testing terminal widths via ioctl(2) and TIOCGWINSZ (which must also exist). Does not provide any compaibility.

Source: test

unveil()

Test for unveil(2), defining HAVE_UNVEIL with the result. Does not provide any compatibility.

#include <unistd.h> /* unveil */

The HAVE_UNVEIL guard is not required except around the function invocation.

Source: test

Configuration options and environment

The following key-value pairs may be passed into the configure script to either affect feature testing, choice of environment (via the compiler), or simply be passed unchanged into the generated Makefile.configure. They may subsequently be used by the including Makefile for portably building software.

Tools…

AR: static library archiver

Uses system defaults (dictated by make) or as overridden by the environment. Be careful: used to determine build-time environment (cross-compiling).

CC: C compiler

Uses system defaults (dictated by make) or as overridden by the environment. If not provided, cc, clang and gcc are tested before giving up. Be careful: used to determine build-time environment (cross-compiling).

Flags…

CFLAGS: C compiler flags

Used for compiling objects. Uses system defaults (dictated by make) or as overridden by the environment. Defaults to having -g -W -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter. Be careful: used to determine build-time environment (cross-compiling).

CPPFLAGS: C preprocessor flags

Used for pre-compiling objects. Disregarded if found in the environment.

LDADD: -l libraries and flags usually used for linking binaries

Disregarded if found in the environment.

LDFLAGS: -L linker flags used for linking

Disregarded if found in the environment. Be careful: used to determine build-time environment (cross-compiling).

LDLIBS: -l libraries and flags usually used for linking shared libraries

LIBADD is sometimes used for this. Disregarded if found in the environment.

LINKER_SOFLAG: linker flag to create shared libraries

Defaults to -shared or -dynamiclib, depending on whether non-Apple. Determined by invoking the compiler. Disregarded if found in the environment.

LINKER_SONAME: linker command used to create shared libraries

Defaults to -soname or -install_name, depending on whether non-Apple. Determined by invoking the compiler. Disregarded if found in the environment.

LINKER_SOSUFFIX: suffix for shared libraries

Defaults to so or dylib, depending on whether non-Apple. Determined by invoking the compiler and switching on LINKER_SOFLAG. Disregarded if found in the environment.

Directories…

DESTDIR: install directory fake root

Prefixed to all install directories during installation. Not otherwise affecting install directories. Disregarded if found in the environment.

INCLUDEDIR: install directory for header files

Defaults to PREFIX/include. Disregarded if found in the environment.

BINDIR: install directory for binaries

Defaults to PREFIX/bin. Disregarded if found in the environment.

LIBDIR: install directory for libraries

Defaults to PREFIX/ib. Disregarded if found in the environment.

MANDIR: install directory for manpages

Defaults to PREFIX/man. Disregarded if found in the environment.

PREFIX: directory for default install directories

Defaults to /usr/local. Disregarded if found in the environment.

SBINDIR: install directory for system binaries

Defaults to PREFIX/sbin. Disregarded if found in the environment.

SHAREDIR: install directory for shared files

Defaults to PREFIX/share. Disregarded if found in the environment.

Any extra key-value assignment pairs are passed unchanged and unquoted, one per line, to the generated Makefile.configure.

libbsd

For Linux users with libbsd installed, oconfigure can be instructed to use libbsd exclusively as follows:

./configure LDFLAGS=$(pkg-config --libs libbsd-overlay) \
	CFLAGS=$(pkg-config --cflags libbsd-overlay)

For new versions of libbsd, this will pull in the library for all compatibility replacements instead of those within compats.c.

Shared libraries

For shared library generation, the LINKER_SONAME, LINKER_SOFLAG, and LINKER_SOSUFFIX variables are set in the generated Makefile.configure to assist in Mac OS X portability. To further complicate issues, the order of suffix parts in Mac OS X is different from every other system.

Generating a shared library version 3 named lib from lib.c might look like in your Makefile:

lib.o: lib.c
	$(CC) -fPIC -o lib.o -c lib.c

.if $(LINKER_SOSUFFIX) == "dylib"
SUFFIX = 3.$(LINKER_SOSUFFIX)
.else
SUFFIX = $(LINKER_SOSUFFIX).3
.endif

lib.$(SUFFIX): lib.o
	$(CC) $(LINKER_SOFLAG) -o lib.$(SUFFIX) \
		-Wl,$(LINKER_SONAME),lib.$(SUFFIX) lib.o

lib.$(LINKER_SOSUFFIX): lib.$(SUFFIX)
	ln -sf lib.$(SUFFIX) $@

The choice of -fPIC or -fpic is left for the user.

The suffix and flag only apply to shared libraries: dynamically-loaded libraries use -shared and so on all Unix-like systems.

Static binaries

Static libraries may be built on all platforms, but Mac OS X does not allow creating static binaries. The LDADD_STATIC variable is set in the generated Makefile.configure to either be -static on conforming systems or empty on Mac OS X.

lib.o: lib.c
	$(CC) -fPIC -o lib.o -c lib.c

lib.a: lib.o
	$(AR) rcs lib.a lib.o

test: lib.a
	$(CC) $(LDADD_STATIC) -o test lib.a