Table of Contents
The configuration script is used by the
bt_config module to automatically configure a
source package. It is located inside the
Generic.bt
, splitted in two functions:
config
and config_init
. See
Chapter 8, Script files.
You may ask yourself why are configuration scripts needed at all. There are lots of different operating systems and machine types out there. Each system has its own features (and/or bugs) which can make your program unportable; furthermore, each system has several versions of itself which can show different behavior between them (even when they are expected to behave the same way). You may think that as you have coded your program in a portable way (following standards), it will work anyway. But that assumption is wrong, as things you expect to be present in a system may be missing beforehand. You will usually need to check for the presence of a compiler (and ensure it is good enough for your code), specific libraries, the size of variable types, architecture, etc.
Automatic configuration tries to solve most of the problems outlined above in an unattended way, addressed to the end user who may not know all the details about his system. The script issues several checks to detect system features and writes some output files used during the build to adjust commands to the actual system or to workaround problems. Checks are also used to detect missing dependencies and ask the system administrator to install them before continuing.
The bt_config module is the core utility to configure source packages. It provides a command line frontend, as we described in Chapter 4, Automatic package configuration, and lots of shell functions used to easily write a configuration script. These include predefined checks, functions to generate output files and functions to write diagnostic messages, between others.
The configuration script is a simple shell script that calls functions provided by the bt_config module. As such, it can include conditional sentences, loops, functions, or whatever else is supported by the standard shell[7], thus becoming extremely powerful. The script is parsed during runtime, which means that Buildtool must be present in the build system[8].
The script is divided in two blocks, each one contained in its own shell function:
The initialization block,
enclosed in the config_init
function. This is
parsed before the module analyzes command line arguments, therefore it
is used to define new customizable directories and features, change
their default values or even load extra configuration modules. No
checks can be placed here (if you do, unexpected results may
happen).
The configuration block, enclosed
in the config
function. This is parsed after the
module parses the initialization block and analyzes command line
arguments. This is the place where checks go, and where output is
generated.
The bt_config module provides two empty
functions for default, so you may omit any of them if not needed in a
particular script. Note that no code should be placed outside the
standard recognized functions. So you could have the following piece
of code inside Generic.bt
:
# Basic skeleton for a configuration script config_init() { # Initialization code goes here return } config() { # Checks and other configuration code go here return }
There are several standard functions to output diagnostic messages while the script is processed. You should not directly use commands like echo or printf, as they may make your script not work as expected (for example, stdout vs. stderr not beeing managed properly). Most of these functions will also take care to write proper information in the configuration log.
An error message is printed whenever a fatal condition happens in the configuration script (like not finding a required library). The message can contain information about what went wrong, how to fix it, suggestions, etc. After it is shown, the script aborts the configuration process.
bt_err line1 ... lineN
The bt_err
function is used to output error
messages. Each argument passed to it is treated as a different line,
as these messages are usually too long to fit on a single line. A
simple example:
bt_err "The required library foobar was not found." \ "You can download it from http://www.foobar.org/."
A warning message is printed whenever a non-fatal strange condition happens in the configuration script. The script is not aborted after the message is printed.
bt_warn line1 ... lineN
The bt_warn
function is used to output
warning messages. Each argument passed to it is treated as a
different line, as these messages are usually too long to fit on a
single line. A simple example:
bt_warn "The suggested library foobar was not found." \ "You should install it for optimal results."
A summary message is printed when the configuration finishes.
It may contain useful and important information that the user should
notice (like if some imporant hidden feature has been enabled or not).
These messages can be defined at any point inside the configuration
script, using the bt_msg_summary
function. The
configuration script will keep them in memory until it
finishes. The function syntax is:
bt_msg_summary message
If the message contains variable names, it should be surrounded by single quotes. This way, they will be evaluated when the script finishes only, thus showing the real value of a variable at the end of the script. An example:
bt_msg_summary 'The installation prefix is ${BT_PREFIX}'
Note that bt_config automatically adds some summary messages for consistency across packages, like the one shown above.
A check usually prints a message when it starts, like
checking for feature foobar...
, and a result
message when it finishes. There are two functions available to print
these two types of messages.
bt_msg_chk message
The bt_msg_chk
function is used to output a
message before the check starts. It automatically adds the
checking
word before the given message and the
ellipsis at its end.
bt_msg_result message
The bt_msg_result
function is used to
output the result of the check.
Here is an example on how to use these two functions during a check function:
bt_msg_chk "for program foobar" # All the stuff needed to detect the program. # The $res variable contains the 'yes' or 'no' word depending on the result. bt_msg_result "$res"
The configuration script can define new customizable directories and features to allow the user tune the package behavior. This is always done in the initialization block, as command line arguments recognized by the bt_config's frontend will be extended. Let's analyze them in detail.
Any directory used to install files or where your package expects to find files should be customizable by the end user. Paths must not be hardcoded in your program (assuming you do not have a very good reason to do so), but instead use variables that contain the values selected during configuration time. You will usually want to provide defaults to these values, though.
Directory values are stored in shell variables. All of them
start with the BT_DIR_
string for consistency. The
rest of the variable name matches the name used as a configuration
argument in the command line. For example, the directory holding
example files is customized with the [--dir-examples]
argument; therefore, its associated shell variable is
BT_DIR_EXAMPLES
. Even though, there is a minor
exception to this rule: the installation prefix is stored in the
BT_PREFIX
variable, as it is somewhat
special.
See Section 4.1.1, “Standard directories” for a complete list of standard customizable directories.
If you feel the real need to change a default value for a directory, you can do so in the initialization block, simply assigning a new value to the variable (note that this is discouraged, though, as it breaks consistency between packages).
You can also add new, non-standard customizable directories to
your script, and they will be made available to the user through the
command line. This is done using the bt_dir
function. Its synopsis:
bt_dir directory_name default_value comment
The function defines a new customizable directory, which can be
referenced by the name given in the directory_name
parameter, has a default value of default_value
and
an associated comment of comment
. Note that
the directory name omits the BT_DIR_
string.
An example: assume you need a directory to install pixmap files. You could define it with the following call:
bt_dir PIXMAPS '${BT_DIR_SHARE}/pixmaps' 'A directory holding pixmap files.'
Features allow the end user to manually select build details and characteristics during the configuration stage of a source package. These vary from forcing the package to use shared libraries to include optional support for a specific dependency (as OpenSSL).
Feature values are stored in shell variables. All of them start
with the BT_FEATURE_
string for consistency. The
rest of the variable name matches the name used as a configuration
argument in the command line. For example, the developer mode feature
is customized with the [--feature-developer] argument;
therefore, its associated shell variable is
BT_FEATURE_DEVELOPER
.
See Section 4.1.2, “Standard features” for a complete list of standard customizable features.
If you feel the real need to change a default value for a feature, you can do so in the initialization block, simply assigning a new value to the variable (note that this is discouraged, though, as it breaks consistency between packages).
You can also add new, non-standard customizable features to your
script, and they will be made available to the user through the
command line. This is done using the bt_feature
function. Its synopsis:
bt_feature feature_name default_value comment
The function defines a new customizable feature, which can be
referenced by the name given in the feature_name
parameter, has a default value of default_value
and
an associated comment of comment
. Note that
the feature name omits the BT_FEATURE_
string.
An example: assume you need a feature to enable or disable OpenSSL support. You could define it with the following call:
bt_feature OPENSSL 'yes' 'Whether to include OpenSSL support or not (yes/no).'
All standard configuration functions are grouped in
bt_config's core module, named
base.subr
. This module provides functions to
load external modules during configuration time, which can provide new
checks, support for other programming languages, etc. This makes
configuration scripts extensible and more powerful, as they can share
functions if needed.
Subroutine modules are loaded from the initialization block,
using the bt_subrload
function. This takes a
single argument, the module base name, without the path and without
any extension. Modules are searched in the list of directories
contained in the BT_PATH_SUBRS
environmental
variable (which is like the regular PATH
); it
includes the standard module directory by default, as given by the
site information target (see Section 2.2, “Site information”).
If a module is not located, the configuration process is aborted and the user is requested to install the package which provides it or fix the search path.
As an example, consider we want to load the module that provides checks to detect the X Window System:
bt_subrload 'x11'
See Section 11.8, “Standard subroutine modules” for a description of all
standard modules distributed together with Buildtool (excluding
base.subr
).
While the configuration script is executed, check results are stored in temporary variables. At the end of the script, these need to be stored on disk so that other Buildtool modules can use them. The bt_config module keeps two different lists of variables. Output files are generated based on one of the two lists, as described below:
This list contains all variable names that will be
used as substitution patterns in output files. They will be written
to the configuration environment file
(bt_config.env
).
This list contains all variable names that will be
stored in the configuration C/C++ header
(bt_config.h
) in the form of C preprocessor
defines.
It is often needed to substitute a pattern inside a source file with a check result or some dynamic string passed during the configure stage. Output files are files that receive this special treatment during automatic configuration.
The bt_generate_output
function is used to
generate output files. Its syntax:
bt_generate_output [files]
The function starts creating two files: the
bt_config.sed
configuration file and the
bt_output script. The former is used internally by
the later, so you shouldn't care about it; the only detail you should
know is that it is generated based on the substitution list. The
later is an auxiliary program used to really generate output files.
You must learn how this script works in order to understand how are
output files generated.
Output files will be very familiar to anybody who has ever
used the GNU autoconf utility. Although, be aware that you should try
to avoid the use of the bt_generate_output
function whenever possible, as Buildtool provides other (preferred)
methods to acquire the same results (e.g., through the
configuration environment file).
Anyway, there are some special cases where the use of output files is
unavoidable, like generating a dynamic C header file that needs to be
installed in the system (which cannot include
bt_config.h
).
bt_output takes file names as arguments.
Each name specifies a file that needs to be generated. To generate a
file, the script will look for a file with the same name as the one
that has to be created, but with an extra .in
suffix. If not found, the script will abort. If no file names are
passed, the script generates all files that were given to the
bt_generate_output
function (if any).
Most times it is better to call the function without arguments.
The rationale is: files should be created during the
build stage of the package, not during its
configuration; therefore, they can be removed during a soft clean and
regenerated later without problems. If you do this, you
must call the script using the
BT_OUTPUT
variable in logic files (when needed),
as its location may change in each build or other Buildtool versions.
Note, though, that logic files handle generation of files automatically
in most scenarios, so you should not have to call
bt_output directly.
The following code illustrates a sample logic file that generates an output file on the fly (do not worry if you do not understand it very well for now). In this specific example, the file to be generated is a C header that may include definitions dependant on the build host (like size of types):
# Sample logic file that uses bt_output. logic() { bt_target myprog target_myprog() { BT_TYPE=program BT_SOURCES=program.c specific.h } # The following is not really needed, as it is automatic. # It generates specific.h from specific.h.in. target_specific.h() { BT_TYPE=output } }
Let's look at another example that does the same but during
configuration time: a single call to the function that could generate
the src/specific.h
file, based on
src/specific.h.in
:
bt_generate_output src/specific.h
We are still missing how substitution patterns work. In fact,
it is very simple. A substitution pattern is a variable name present
in the substitution list surrounded by the @
character. That is, if the variable MYVAR
is in
the list, the input file can reference its value using the magic
string @MYVAR@
[9].
At last, to add a variable to the substitution list during
configuration time, you use the bt_subst
function. Its syntax:
bt_subst variables
All arguments are treated as independant variables and are added to the substitution list.
A configuration header is a regular C/C++ header file that is generated during the configuration stage of a package and contains macro definitions describing what features (other headers, functions, size types, etc.) are present or missing in the current system. This header file should be included by all C/C++ source files that form the package, so all of them can benefit from the generated header (which might include more complex things for compatibility). It cannot be included by other header files if they are going to be installed, as this will surely break your package.
Its contents are determined by the defines list, as we described above.
To generate a configuration header, always named
bt_config.h
, simply call the
bt_generate_configh
function at the end of the
configuration block of your script. For completeness, here is the
function syntax:
bt_generate_configh
All source files should include the header using the following syntax:
#include <bt_config.h>
Buildtool will take care to adjust the compiler include path so it locates the header file without problems inside the work directory (which may vary between different Buildtool versions).
You can freely add new values to the defines list to tune what is written to the configuration header. There are two functions available, whose description follows:
bt_define variable_name variable_value
This function takes a variables name and its value and adds them to the defines list. When the configuration file is written, variables tagged with this function will have their values surrounded by double quotes. This is usually useful for macros holding string values.
bt_define_unquoted variable_name variable_value
This function takes a variable name and its value and adds them to the defines list. When the configuration file is written, variables tagged with this function will have their values set to the macro result directly, without quotes. This is usually useful for macros holding numerical values.
As an example, consider the following calls:
bt_define MYNAME foobar bt_define_unquoted MYCONST 5
Which could result in the following lines in the configuration header:
#define MYNAME "foobar" #define MYCONST 5
Standard checks aim to support as many programming languages as possible. bt_config provides a rudimentary framework to make this easier, when it comes to manage languages that conflict between them. By conflicting languages we mean something like C and C++; both can share system headers, system libraries, but may need compilers from different vendors, each one with its own details, search paths, etc.
Almost all checks related to the compilation environment support both the C and the C++ language. Aside from these language dependant checks, there are a lot that are more generic (like program checks) and can be applied to any language. It is perfectly possible to write a configuration script suitable for a shell script project, a documentation project, a Perl project, etc. (and as configuration scripts are plain shell scripts, you can extend them as much as you want).
The interesting scenario here is the conflict between C and C++.
In a configuration script, there is always an active language whose
name is stored in the global variable Language
.
Many checks will use this variable's value to adapt their behaviour to
the adequate compiler.
The select language can be changed with the
bt_language_select
function. Its syntax:
bt_language_select language_id
The only parameter recognized by the function is the language
identifier that has to be selected. The C language is recognized with
the c
value, while C++ is recognized with the
cxx
value.
Most of the functions present in the
base.subr
module, the standard one, are used to
issue automatic checks for features of the build system. A check
executes several commands internally and sets the value of several
variables according to their results (which may in turn be added to
the substituion or defines lists); as a function, it usually returns a
boolean value[10]
indicating whether the check was successful or not.
Depending on the language you use to write your program, you will need several specific tools to build it. You can think that checking for the compiler or the interpreter is enough, but this is not usually true. The compiler will require extra checks to detect if it works, its vendor (to determine what flags are available), standard header files, standard libraries, etc.
To make things easy, there are some standard checks that automatically detect build environments. You must use them instead of calling the independant checks they execute if you want your configuration script to work properly with future versions of Buildtool.
bt_check_env
The bt_check_env
function checks for a
build environment based on the current language setting (Section 11.6, “Languages support”). See below for a description of all languages
supported.
bt_check_env_c
The bt_check_env_c
function detects the C
environment. It checks for the C compiler and its vendor name (see
Section 11.7.2.3, “C compiler”), the C preprocessor (see Section 11.7.2.4, “C/C++ preprocessor”), the linker (see Section 11.7.2.8, “C/C++ linker”), a set of standard headers (see Section 11.7.3.2, “Standard set of headers”) that are needed to build C code and how
to build libraries (see Section 11.7.5.1, “The library howto”).
If the developer mode is enabled, this function also checks for several warning flags and adds them to the standard compilation flags.
bt_check_env_cxx
The bt_check_env_cxx
function detects the
C++ environment. It checks for the C++ compiler and its vendor name
(see Section 11.7.2.5, “C++ compiler”), the C++ preprocessor (see
Section 11.7.2.4, “C/C++ preprocessor”), the linker (see Section 11.7.2.8, “C/C++ linker”) and a set of standard headers (see
Section 11.7.3.2, “Standard set of headers”) that are needed to build C++ code
and how to build libraries (see Section 11.7.5.1, “The library howto”).
If the developer mode is enabled, this function also checks for several warning flags and adds them to the standard compilation flags.
During the build of your program, you will usually need to execute several non-standard programs that may not be installed on the build system. You need to check for these programs during the configuration stage, so that if they are missing, you can tell it to the user.
There are several standard checks to detect very common programs. If you need something more special, there is a generic check available (in fact, all specific checks are based on the generic one).
bt_check_progs variable_name program_list [optional_path]
The bt_check_progs
function defines the
variable variable_name
to the full program path
if any of the names listed in program_list
is
found in the standard path, BT_PATH
, or in
optional_path
if given. The variable is
automatically added to the substitution list.
If variable_name
has a value before the
check is called, the program is not searched and the check always
succeeds (that is, the value is cached).
If no program from the list is found, the function returns false, otherwise true.
As an example, suppose you need to detect for a M4 macro processor (do not use this code; there is a specific check to search for this common program). It may be available with several names, like gm4 or m4. You could do the following:
if bt_check_progs BT_PROG_M4 "gm4 m4"; then :; else bt_err "A M4 macro processor is required." fi
Note that the program list is quoted. This is required as it is treated as a single argument to the function.
Also note that the variable name starts with the string
BT_PROG_
and is all uppercase. When checking for
programs, use this convention to keep consistancy across standard
checks and other packages.
bt_check_prog_awk
The bt_check_prog_awk
function searches for
an AWK interpreter, looking for the following standard names, in
order: gawk, nawk and
awk. The result is stored in the
BT_PROG_AWK
variable, which is added to the
substitution list.
Returns true on success, false if the program cannot be found.
bt_check_prog_cc
The bt_check_prog_cc
function searches for a
C compiler, looking for the following standard names, in order:
gcc, cc and
bcc. The result is stored in the
BT_PROG_CC
variable.
If the compiler is found, a test program is compiled to detect
the vendor name, which is later stored in the
BT_PROG_CC_NAME
variable. Its value may be any of:
gnu
, sunpro
or
unknown
. If the build fails, the configuration
process is stopped with a fatal error (the compiler or environment is
seriously broken).
The following variables are added to the substitution list:
BT_PROG_CC
, BT_PROG_CC_NAME
,
BT_FLAGS_CPP
and BT_FLAGS_CC
,
BT_LIBS
.
This function only returns on success.
Avoid using this function directly, if possible. Instead use build environments, see Section 11.7.1, “Checking for build environments”.
bt_check_prog_cpp
The bt_check_prog_cpp
function searches for
a C/C++ preprocessor. The result is stored in the
BT_PROG_CPP
variable, which is added to the
substitution list.
Returns true on success, false if the program cannot be found.
Avoid using this function directly, if possible. Instead use build environments, see Section 11.7.1, “Checking for build environments”.
bt_check_prog_cxx
The bt_check_prog_cxx
function searches for
a C++ compiler, looking for the following standard names, in order:
g++, c++,
gcc, CC, cxx
and cc++. The result is stored in the
BT_PROG_CXX
variable.
If the compiler is found, a test program is compiled to detect
the vendor name, which is later stored in the
BT_PROG_CXX_NAME
variable. Its value may be any
of: gnu
, sunpro
or
unknown
. If the build fails, the configuration
process is stopped with a fatal error (the compiler or environment is
seriously broken).
The following variables are added to the substitution list:
BT_PROG_CXX
, BT_PROG_CXX_NAME
,
BT_FLAGS_CPP
and BT_FLAGS_CXX
,
BT_LIBS
.
This function only returns on success.
Avoid using this function directly, if possible. Instead use build environments, see Section 11.7.1, “Checking for build environments”.
bt_check_prog_info
The bt_check_prog_info
function searches for
two different programs: makeinfo and
install-info, both included in the TeXinfo package.
The result is stored in the BT_PROG_MAKEINFO
and
BT_PROG_INSTALLINFO
variables respectively, which
are added to the substitution list.
Returns true on success, false if any of the two programs cannot be found.
bt_check_prog_lex
The bt_check_prog_lex
function searches for
a lexical analyzer generator, looking for the following standard
names, in order: flex and lex.
The result is stored in the BT_PROG_LEX
variable,
which is added to the substitution list.
Generated analyzers may require an associated library that
depends on the generator used. The library name can be found in the
BT_LIBS_LEX
variable, which is also added to the
substitution list.
Returns true on success, false if the program cannot be found.
bt_check_prog_ld
The bt_check_prog_ld
function searches for a
C/C++ linker program. The result is stored in the
BT_PROG_LD
variable, which is added to the
substitution list. The BT_FLAGS_LD
is added to the
list too.
Returns true on success, false if the program cannot be found.
Avoid using this function directly, if possible. Instead use build environments, see Section 11.7.1, “Checking for build environments”.
bt_check_prog_m4
The bt_check_prog_m4
function searches for a
M4 processor, looking for the following standard names, in order:
gm4 and m4. The result is
stored in the BT_PROG_M4
variable, which is added
to the substitution list.
Returns true on success, false if the program cannot be found.
bt_check_prog_make
The bt_check_prog_make
function searches for
a make utility, looking for the following names, in order:
gmake, bmake and
make. The path to it, if found, is stored in the
BT_PROG_MAKE
variable. Furthermore, the
BT_PROG_MAKE_TYPE
variable is set to the type of make
utility found, which can be one of bsd
,
gnu
or unknown
. Both variables are
added to the substitution list.
Returns true on success, false if the program cannot be found.
bt_check_prog_sh
The bt_check_prog_sh
function searches for a
shell interpreter, looking for the following standard names, in order:
ksh, pdksh,
sh, bash, and
zsh. The result is stored in the
BT_PROG_SH
variable, which is added to the
substitution list.
Returns true on success, false if the program cannot be found.
bt_check_prog_yacc [programs_list]
The bt_check_prog_yacc
function searches for
a LARL parser generator, looking for the following standard names, in
order: bison, byacc and
yacc. The result is stored in the
BT_PROG_YACC
variable, which is added to the
substitution list.
Some times you may want to avoid the detection of
bison. You can do this by passing a different set
of programs in the optional argument
programs_list
and skipping the tool you do not
want to be detected.
Returns true on success, false if the program cannot be found.
Header files are usually one of the most common problems when it comes to portability issues. They may be present on some systems, but missing on others, or even have different names. Therefore you must check for the presence of non-standard headers in your configuration script. When a header is found, a macro is defined in the configuration header, so you can then check it from inside your C or C++ code and include it or not.
The BT_INCLUDE_FILES
variable contains a list
of headers that are included in each test program compiled during the
configuration process.
bt_check_hdr header_name
The bt_check_hdr
function checks for a C or
C++ header, depending on the active language. Its name is given in
the header_name
argument. If the header is
found, the variable
BT_HAVE_HDR_<lang_name>_<parsed_name>
is defined and is added to the defines list.
parsed_name
is the name of the header you gave to
the function, converted to uppercase and with all special
(non-alphabetical) characters converted to underscores.
Returns true on success, false if the header cannot be found.
For example, if you needed to detect the
sys/soundcard.h
header, you could do:
bt_check_hdr sys/soundcard.h
This could define the macro
BT_HAVE_HDR_C_SYS_SOUNDCARD_H
in the configuration
header file if the check was successful.
bt_check_hdr_std
The bt_check_hdr_std
function checks for a
set of standard C and C++ (depending on the active language) required
to build many simple programs. These headers include:
stdio.h
, sys/types.h
,
sys/stat.h
, stdlib.h
,
string.h
and
unistd.h
[11].
All headers found during this check are added to the
BT_INCLUDE_FILES
variable. If the detection of
stdio.h
fails, the configuration process is
aborted, as the compiler is seriously broken.
Before detecting for other headers using
bt_check_hdr
, you should call this check. Even
though, avoid using this function directly. Instead use build
environments, see Section 11.7.1, “Checking for build environments”.
System functions are another focus of portability problems. While many of them are standard, they may not be present on ancient systems; the ones that are not standard should be emulated by the program itself or not used at all if not present in the build system.
bt_check_func function_name
The bt_check_func
function checks for a C
or C++ function, depending on the active language. Its name is given
in the function_name
argument. If the function
is found, the variable
BT_HAVE_FUNC_<lang_name>_<parsed_name>
is defined and is
added to the defines list. parsed_name
is the name
of the function you gave to the check, converted to uppercase and with
all special (non-alphabetical) characters converted to
underscores.
Returns true on success, false if the header cannot be found.
For example, if you needed to check for the presence of the
vfork
header, you could do:
bt_check_func vfork
And later, in your C code:
#include <bt_config.h> #ifdef BT_HAVE_HDR_C_UNISTD_H #include <unistd.h> #endif void sample_function() { #ifdef BT_HAVE_FUNC_C_VFORK /* code that uses vfork(2) */ #else /* code that does not use vfork(2) */ #endif }
Libraries are usually used during the development of a program to simplify the code, or to use code developed by a third party. You must check for the presence of the required libraries during the configuration stage of the package and notice the user if something goes wrong, so that linking does not fail in the build stage.
Aside from checking for the presence of libraries in the build system, you can be interested in creating and installing your own ones. Libraries are difficult to build in a portable way, as the process is not standard across systems nor compilers. Furthermore, some systems support static and shared libraries while others only support static.
bt_check_lib_howto
The bt_check_lib_howto
function helps you
in the process. It issues several checks to detect how to build
libraries in the current system and whether if static or shared types
are supported. The results are later used by
bt_logic to properly build and install
libraries.
This function is not described here for now, as it does many different things and is quite complex. Furthermore, it will likely change in a future.
Avoid using this function directly, if possible. Instead use build environments, see Section 11.7.1, “Checking for build environments”.
bt_check_lib library_name [function_name]
The bt_check_lib
function checks for a C or
C++ library, depending on the active language. Its name is given in
the function_name
argument. If no function
name is given and the library is found, the variable
BT_HAVE_LIB_<lang_name>_<parsed_name>
is defined and is
added to the defines list. parsed_name
is the name
of the library you gave to the check, converted to uppercase and with
all special (non-alphabetical) characters converted to
underscores.
If function name is not empty, then the semantics of the check
change. In this case, the given function is searched inside the given
library. If the function is found inside the library, the variable
BT_HAVE_FUNC_<lang_name>_<parsed_name>
is defined and is
added to the defines list. parsed_name
is the name
of the function you gave to the check, converted to uppercase and with
all special (non-alphabetical) characters converted to
underscores.
Returns true on success, false if the library (or function) cannot be found.
There are many other checks that do not fit other categories but are very useful during the configuration stage of your package. These are described in this section.
Some times you will need to know if a C or C++ (depending on the active language) type is present before building your code to workaround it.
bt_check_type type_name
The bt_check_type
function lets you detect
if a type exists. The variable
BT_HAVE_TYPE_<lang_name>_<parsed_name>
is defined and is
added to the defines list. parsed_name
is the name
of the type you gave to the check, converted to uppercase and with all
special (non-alphabetical) characters converted to underscores.
Returns true on success, false if the library (or function) cannot be found.
Some times you will need to know the size of a single type in bytes during build time to adapt your sources to it.
bt_check_sizeof type_name
The bt_check_sizeof
function lets you check
this on a type basis. The variable
BT_SIZEOF_<parsed_name>
is defined and is
added to the defines list; it is also set in the environment.
parsed_name
is the name of the type you gave to the
check, converted to uppercase and with all special (non-alphabetical)
characters converted to underscores.
Other times, you may need to define variables with a specific size, but without knowing which type they match.
bt_check_bits
The bt_check_bits
comes to simplify this
scenario. It checks for a bunch of signed and unsigned types and
defines useful macros according they size. Then the user does not
have to worry what type they really are, but only care about their
size.
The variables defined are: BT_TYPE_BITS8_S
,
BT_TYPE_BITS8_U
,
BT_TYPE_BITS16_S
,
BT_TYPE_BITS16_U
,
BT_TYPE_BITS32_S
,
BT_TYPE_BITS32_U
,
BT_TYPE_BITS64_S
and
BT_TYPE_BITS64_U
. The _S
suffix
stands for signed while _U
for unsigned. Macro
names are descriptive enough themselves. All of them are added to the
defines list, therefore they are present in the configuration header.
They are also set in the environment during configuration.
bt_check_host
The bt_check_host
function checks for two
different thigs. First, the host operating system name is checked and
is stored in the BT_HOST_OS
variable. After this,
an identificative string is constructed for the system (containing the
system name, its version and the machine name) and is stored in the
BT_HOST_TYPE
variable.
This function will check in a future the endianess of the build machine.
Usually, when buildtoolized libraries are installed, they will include a pkgflags file. This provides information about what compiler and linker flags are needed at build time to link against the given library.
bt_check_pkgflags cflags_variable ldflags_variable package_spec
The bt_check_pkgflags
checks, at
configuration time, for the flags provided by pkgflags files. The
first argument is the name of a variable that will store the compiler
flags while the second argument is the name of a variable that will
store the linker flags. The third argument is a package specification
that tells the bt_pkgflags module which library is
wanted and which version (see Chapter 15, Package flags).
As an example, suppose you want get the flags to build against
the foobar
library, and you need it to be at least
the 1.2 version:
if bt_check_pkgflags _cflags _ldflags foobar,ge,1.2; then BT_FLAGS_CPP="$BT_FLAGS_CPP $_cflags" BT_FLAGS_LD="$BT_FLAGS_LD $_ldflags" else bt_err "The foobar library is required. Install it and retry." fi
The GNU C/C++ compiler provides the special
__attribute__
keyword to help it while parsing
code, detecting some errors during build time. It may be a good idea
to use the keyword though it is not portable and will fail with other
different compilers.
bt_check_attribute
The bt_check_attribute
checks for the
presence of this keyword. If the check fails, an empty macro is
defined in the configuration header, which allows the code to build
with compilers not providing it. Therefore your code needs no
change.
Buildtool comes with some subroutine modules aside from the
standard base.subr
. They are separated because
they might be one day splitted from Buildtool's core, or because they
are not often used but imply a lot of code. Review Section 11.4, “Loading subroutine modules” to learn how to load modules.
The pkgconfig.subr
module provides an
interface to the pkgconfig utility, used mainly by
GNOME projects. As Buildtool provides a replacement,
bt_pkgflags, pkgconfig support
is provided as an optional module.
pkgconfig_check package_name version_spec
This function first checks for the pkg-config
program, and sets the PKGCONFIG_PROG
variable
pointing to it. If not found, it simply returns false.
After locating the utility, it executes it searching for the
given package and matching the version specification given. If
successful, PKGCONFIG_FLAGS_<parsed_name>_CC
and PKGCONFIG_FLAGS_<parsed_name>_LIBS
are
defined with the results of the call and added to the substitution
list. parsed_name
is the name of the package you
gave to the check, converted to uppercase and with all special
(non-alphabetical) characters converted to underscores.
The pthread.subr
module provides a
customizable feature and a check to detect a threading library on the
system.
pthread_feature
The pthread_feature
function defines a
customizable feature to allow the user tune if threading support has
to be enabled or not. The feature can take three values:
yes
, to force the detection of threading
(configuration will break if not found); no
, to
completely disable threads and auto
to leave
detection automatic (a check failure will not stop configuration).
This function should be used only once inside the initialization
block.
If this function is not called, the user is not able to tune threading support through the command line.
pthread_check
The pthread_check
function effectively
issues the threading detection if it was not disabled. It will try
several compiler flags and/or libraries. If any of the checks is
successful, the variable PTHREAD_FLAGS_LD
is set to
the flags needed for compilation and PTHREAD_LIBS
lists the required library (if applicable). Both variables are added
to the substitution list.
Returns true on success, false if the library (or function) cannot be found.
The x11.subr
module provides a customizable
feature and a some functions to detect the presence of the X Window
System on the system.
x11_feature
The x11_feature
function defines a
customizable feature to allow the user tune if X11 support has to be
enabled or not. The feature can take three values:
yes
, to force the detection of X11 (configuration
will break if not found); no
, to completely disable
X11 and auto
to leave detection automatic (a check
failure will not stop configuration). This function should be used
only once inside the initialization block.
If this function is not called, the user is not able to tune X11 support through the command line.
x11_check
The x11_check
function effectively issues
the X11 detection if it was not manually disabled. It will try
several standard directories when searching for include files and
libraries. Additional directories may be passed in the whitespace
separated lists provided in the X11_DIR_INCLUDE
and
X11_DIR_LIB
variables.
If X11 is found, X11_FLAGS_CPP
and
X11_FLAGS_LD
are defined with the required compiler
flags needed to compile and link programs against the X11 system.
Both variables are added to the substitution list.
Returns true on success, false if the library (or function) cannot be found.
x11_failure
The x11_failure
function can be used when
you need to inform the user that X11 was not found. It outputs a
consistant error message across packages and terminates the
configuration process, requiring user intervention to fix the
problems. Note that x11_check
will automatically
call this function in several situations, so make sure you are not
duplicating work.
[7] You must restrict yourself to portable shell code.
[8] No, we will not include a configure generator, in terms of GNU autoconf, as it defeats most of our goals.
[9] Just like in GNU autoconf.
[10] In shell scripting, a zero means true while anything different (usually one) means false.
[11] This list might be extended in future versions, but never shrinked.