Scconfig developer documentation

0. Introduction

Scconfig is a Simple C Configuration tool, a minimalistic autotools replacement licensed under the LGPL2 (for more details please refer to COPYING).

Instead of depending on shell scripts, scconfig is entirely implemented in ANSI C (C89), thus it requires only a standard C compiler to run. The reason for this is that writing complex shell scripts (which are self-contained, so one doesn't need a full featured system with m4 and other extras to generate is not very easy using only the very portable subset of the shell.

Some exotic systems may still fail compiling and running scconfig. The rule of thumb for those systems is simple: where scconfig fails, most probably the application being configured would fail too.

Scconfig consists of the following main parts:

  1. a database
  2. simplified API for some file manipulation and compiling
  3. internal dependencies
  4. logging
  5. a file generator "template system"

1. The database

To keep things simple, scconfig implements a database that represents detected data in key-value pairs, where keys are actually long and look more like paths in a filesystem. Accessing the database is a simple get(key) or put(key, value). For more information abour the API please read db.txt , about the standard key names tree.txt .

2. File manipulation and compiling

The strenght of shell scripting is running commands and looking at files are much simpler than in C. To overcome this drawback, scconfig provides an extremly simple API for the following common operations.

File operations:

Compile and run operations:

File listing:

3. Internal dependencies

Most tests for detecting libs will require the C compiler to be detected first, but sometimes libs need to be detected before other libs can be detected. To solve this problem, each detection routine hardwires its own dependencies and those dependencies are resolved in a recursive manner, on demand. This means there is no fixed order of detections, but just as with Makefiles, the software works out the minimum set of things to be done before the real target can be reached. When writing a new detection subroutine, adding a dependency for the C compiler is as easy as inserting the following line in the C code:
	require("cc/cc", logdepth, fatal);
where logdepth is an integer for indenting the log properly (recursion may be confusing without indentation), fatal is either 0 or 1 indicating whether failure of the dependency is a fatal condition.

4. Logging

Scconfig provides simple calls for dumping log messages in the central log file. Further calls are provided to merge other log files into the central log. In practice this means error messages and warnings of test compilations end up in the log file, not in the standard error or standard output.

Instead, the standard error and output are reserved for informing the user about the progress of configuration.

5. File generation

After detecting necessary libs, compilers, tools, everything is in a big tree of key-value pairs. This is not directly useful for the software we are trying to configure. To let detected settings take effect, configure systems usually create Makefiles, config.h files, shell scripts, etc. Scconfig doesn't try to do all these itself, instead the user needs to add the C code to write those files.

Scconfig helps generating files by providing an optional minimalistic template system that allows the user to process template files into output files. While processing, simple if-then-else constructions, switches, regex substitutions, for loops (with lists), variables can be used. Template files can include other template files (even conditionally) so that a modular template system can be built. This option does not cost any external dependency and the template language implementation is small (less than 1600 sloc, or 50 kilobytes, in C).

6. Cross compilation

Some projects may want to crosscompile. This means the compilation is done on a host system while the output of the process is for a different target system. Scconfig fully supports this by splitting the database tree between host and target. When host and target are the same (not crosscompiling), they are "symlinked" so no CPU or memory is wasted. For more details, please read host_target.txt