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.