u-config ("micro-config") is a small, highly portable pkg-config and pkgconf clone. It was written primarily for w64devkit and Windows, but can also serve as a reliable drop-in replacement on other platforms. Notable features:
-
A fraction of the size while retaining the core, user-level features of pkg-config and pkgconf.
-
Windows as a first-class supported platform.
-
Highly portable to any machine. Supports a variety of compilers and operating systems, ancient and new. Can be built without libc, which is handy for bootstrapping.
-
Trivial, fast build. No messing around with GNU Autotools, or any build system for that matter.
Each pkg-config is specialized to its surrounding software distribution, and so u-config is probably only useful to distribution maintainers.
As noted, u-config focuses on user-level features but deliberately lacks developer-level features. The goal is to support existing pkg-config based builds, not make more of them. In summary:
- Omits most
.pc
debugging features (--print-…
) - No special handling of "uninstalled" packages, and no attendant knobs
- Skips checks unimplemented by pkg-config (i.e.
Conflicts:
) - Less strict
.pc
syntax
It still supports the important pkg-config run-time environment variables:
PKG_CONFIG_PATH
PKG_CONFIG_LIBDIR
PKG_CONFIG_TOP_BUILD_DIR
PKG_CONFIG_SYSTEM_INCLUDE_PATH
PKG_CONFIG_SYSTEM_LIBRARY_PATH
PKG_CONFIG_ALLOW_SYSTEM_CFLAGS
PKG_CONFIG_ALLOW_SYSTEM_LIBS
See the pkg-config documentation for details. It also closely follows
pkg-config's idiosyncratic argument parsing — positional arguments are
concatenated then retokenzied — and its undocumented .pc
quote and
backslash syntax.
-
--newlines
: separates arguments by line feeds instead of spaces, which is sometimes useful like in the fish shell or when manually examining output. -
Handles spaces in
prefix
: Especially important on Windows where spaces in paths are common. Libraries will work correctly even when installed under such a path. (Note: Despite popular belief, and the examples in its own documentation, pkg-config was never designed for use in command substitution. It was designed foreval
, and spaces inprefix
will require implicit or expliciteval
.)
u-config compiles as one translation unit. Choose an appropriate platform
layer (*_main.c
) for your target then invoke your C compiler only that
source file. The "generic" platform is libc so it works everywhere, but
inherits the target's libc limitations (restricted path and environment
variable access, no automatic self-configuration, etc.).
$ cc -Os -o pkg-config generic_main.c
However, one of core goals is to be a reliable, native pkg-config for Windows, so it has a dedicated platform layer. This layer understands Unicode paths and environment variables — though keep in mind that it's probably interacting with tools that do not. It outputs arguments encoded in UTF-8 regardless of the system code page. Do not link a C runtime (CRT) in this configuration.
$ cc -Os -nostartfiles -o pkg-config win32_main.c
Or with MSVC:
$ cl /GS- /O2 /Os /Fe:pkg-config msvc_main.c
The Makefile documents compiler options for a more aggressively optimized GCC-based build.
The default search path tries to be useful, but the pkgconfig
directory
locations are unpredictable and largely distribution-specific. Once known,
use the macros below to hard code the correct paths into the binary. To
double check your configuration, examine pc_path
:
$ ./pkg-config --variable pc_path pkg-config
The pkg-config
package is virtual and need not exist as an actual .pc
file installed in the system. The pkg-config
make target automatically
grabs the search path from the system pkg-config
, and so could then be a
drop-in replacement for it.
$ make pkg-config # grabs system's pkg-config search path
The "generic" platform has several compile time configuration parameters. Each must be formatted as a C string with quotes. Relative paths will be relative to the run-time working directory, not the installation prefix, which is usually not useful.
-
PKG_CONFIG_PATH
: Like the run-time environment variable, but places these additional paths ahead of the standard search locations. If the standard search locations are insufficient, this is probably what you want. -
PKG_CONFIG_PREFIX
(default"/usr"
): The default prefix for the four standard search locations. -
PKG_CONFIG_LIBDIR
: Like the run-time environment variable, but fully configures the fixed, static search path. If set,PKG_CONFIG_PREFIX
is not used. If the environment variable is set at run time, it replaces this path. -
PKG_CONFIG_DEFINE_PREFIX
: Sets the default for--define-prefix
/--dont-define-prefix
. Defaults to true on Windows, false otherwise. You probably want the default. -
PKG_CONFIG_SYSTEM_INCLUDE_PATH
: Like the run-time environment variable but sets the static default. -
PKG_CONFIG_SYSTEM_LIBRARY_PATH
: Like the run-time environment variable but sets the static default.
Examples:
$ cc -DPKG_CONFIG_PREFIX="\"$HOME/.local\"" ...
$ cc -DPKG_CONFIG_PATH="\"$HOME/.local/lib/pkgconfig\"" ...
The "win32" platform always searches relative to pkg-config.exe
since
it's essentially the only useful behavior. It is rare for anything aside
from system components to be at compile-time-known absolute paths. The
default configuration assumes pkg-config resides in bin/
adjacent to
lib/
and share/
— a typical sysroot.
PKG_CONFIG_PREFIX
: A relative component placed before the "standard" search paths (lib/pkgconfig
,share/pkgconfig
). Either slash or backslash may be used to separate path components, but slash reduces problems.
Example, if just outside a sysroot which identifies the architecture:
$ gcc -DPKG_CONFIG_PREFIX=\"/$(gcc -dumpmachine)\" ...
While both are supported, u-config prefers slashes over backslashes in order to reduce issues involving backslash as a shell metacharacter.
linux_*_main.c
makes direct Linux system calls using assembly and does
not require libc. It compiles to a ~20kB static executable that will work
on any Linux distribution. It supports these configuration macros with the
same behavior as the generic platform.
PKG_CONFIG_LIBDIR
PKG_CONFIG_SYSTEM_INCLUDE_PATH
PKG_CONFIG_SYSTEM_LIBRARY_PATH
Suggested debug build, intended to be run under a debugger:
$ cc -g3 -Wall -Wextra -Wconversion -Wno-sign-conversion \
-fsanitize=undefined -fsanitize-trap PLATFORM_main.c
Enabling Undefined Behavior Sanitizer also enables assertions.
The test suite is a libc-based platform layer and runs u-config through
its entry point in various configurations on a virtual file system. Either
build and run test_main.c
as a platform, or use the suggested test
configuration in the Makefile (set EXE=.exe
on Windows):
$ make check
fuzz_main.c
is a platform layer implemented on top of AFL++. Fuzzer
input is supplied through a virtual file, and it exercises .pc
parsing,
variable expansion, and output processing. Its header documents suggested
usage.