1179860b2SJed Brown<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"> 2179860b2SJed Brown<book id="BuildSystemManual" lang="en"> 3179860b2SJed Brown 4179860b2SJed Brown<bookinfo> 5179860b2SJed Brown<title>ASE BuildSystem Manual</title> 6179860b2SJed Brown<authorgroup> 7179860b2SJed Brown<author> 8179860b2SJed Brown<firstname>Matthew</firstname> 9179860b2SJed Brown<othername>G.</othername> 10179860b2SJed Brown<surname>Knepley</surname> 11179860b2SJed Brown</author> 12179860b2SJed Brown</authorgroup> 13179860b2SJed Brown<date>July, 2005</date> 14179860b2SJed Brown<releaseinfo>Release tag ???</releaseinfo> 15179860b2SJed Brown</bookinfo> 16179860b2SJed Brown 17179860b2SJed Brown<chapter id="Introduction"> 18179860b2SJed Brown<title>Introduction</title> 19179860b2SJed Brown 20179860b2SJed Brown<para>The BuildSystem from ASE is intended to be a Python replacement for the GNU autotools. It actually encompasses 21179860b2SJed Brownsomewhat more, as it supports integrated version control and automatic code generation. However, the most useful 22179860b2SJed Browncomparisons will come from <command>autoconf</command>, <command>make</command>, and <command>libtool</command>. The 23179860b2SJed Brownsystem is not designed to be monolithic. Thus each component may be used independently, meaning logging, configuration, 24179860b2SJed Brownand build are all separate modules which do not require each other. This allows a user to incremenetally adopt the most 25179860b2SJed Brownuseful portions of the package.</para> 26179860b2SJed Brown 27179860b2SJed Brown</chapter> 28179860b2SJed Brown 29179860b2SJed Brown<chapter id="Configure"> 30179860b2SJed Brown<title>Configure</title> 31179860b2SJed Brown 32179860b2SJed Brown<sect1 id="Configure-Design-Sketch"> 33179860b2SJed Brown<title>Configure Design Sketch</title> 34179860b2SJed Brown 35179860b2SJed Brown<para>The system is based upon an autonomous unit, objects of class <classname>config.base.Configure</classname>, which 36179860b2SJed Brownare responsible for discovering configuration information for a particular package or purpose. The only interface which 37179860b2SJed Brownmust be supported is the <methodname>configure</methodname> method, as shown below. Support for lower-level operations 38179860b2SJed Brownsuch as compiling and linking will be discussed in section ???.</para> 39179860b2SJed Brown 40179860b2SJed Brown<classsynopsis language="python"> 41179860b2SJed Brown<ooclass> 42179860b2SJed Brown<classname>Configure</classname> 43179860b2SJed Brown</ooclass> 44179860b2SJed Brown<methodsynopsis> 45179860b2SJed Brown<void/><methodname>configure</methodname><methodparam><parameter>self</parameter></methodparam> 46179860b2SJed Brown</methodsynopsis> 47179860b2SJed Brown</classsynopsis> 48179860b2SJed Brown 49179860b2SJed Brown<para>This collection of configure objects is managed by a <classname>config.base.Framework</classname> object. As we 50179860b2SJed Brownwill see in section ???, the framework manages all dependecies between modules and output of configure information. The 51179860b2SJed Brownframework is itself a subclass of <classname>config.base.Configure</classname> for which the 52179860b2SJed Brown<methodname>configure</methodname> method manages the entire configuration process. In order to associate a module with 53179860b2SJed Brownthe given framework, it also provides the <methodname>require</methodname> method, discussed in section ???. Thus, the 54179860b2SJed Brownminimal framework interface is given by:</para> 55179860b2SJed Brown 56179860b2SJed Brown<classsynopsis language="python"> 57179860b2SJed Brown<ooclass> 58179860b2SJed Brown<classname>Framework</classname> 59179860b2SJed Brown</ooclass> 60179860b2SJed Brown<ooclass> 61179860b2SJed Brown<classname>config.base.Configure</classname> 62179860b2SJed Brown</ooclass> 63179860b2SJed Brown<methodsynopsis> 64179860b2SJed Brown<void/><methodname>require</methodname> 65179860b2SJed Brown <methodparam><parameter>self</parameter></methodparam> 66179860b2SJed Brown <methodparam><parameter>moduleName</parameter></methodparam> 67179860b2SJed Brown <methodparam><parameter>depChild</parameter></methodparam> 68179860b2SJed Brown <methodparam><parameter>keywordArgs</parameter><initializer>{}</initializer></methodparam> 69179860b2SJed Brown</methodsynopsis> 70179860b2SJed Brown<methodsynopsis> 71179860b2SJed Brown<void/><methodname>configure</methodname><methodparam><parameter>self</parameter></methodparam> 72179860b2SJed Brown</methodsynopsis> 73179860b2SJed Brown</classsynopsis> 74179860b2SJed Brown 75179860b2SJed Brown<para>This design allows user modules to be seamlessly integrated into the framework without changing the paradigm, or 76179860b2SJed Browneven any of the original code. Modules can be specified on the command line, or left in special directories. Although it 77179860b2SJed Brownis common to derive from <classname>config.base.Configure</classname>, the only necessity is that the user provide a 78179860b2SJed Brown<methodname>configure</methodname> method for the framework to execute.</para> 79179860b2SJed Brown 80179860b2SJed Brown<para>The framework does provide the traditional output mechanisms from <command>autoconf</command>, namely 81179860b2SJed Brown<methodname>#define</methodname> statements and file substitutions, to which we add make variables and 82179860b2SJed Brownrules. However, the preferred interaction mechanism is to use member variables directly from the configure objects. This 83179860b2SJed Brownis illustrated in section ???</para> 84179860b2SJed Brown 85179860b2SJed Brown</sect1> 86179860b2SJed Brown 87179860b2SJed Brown<sect1 id="Running-configure"> 88179860b2SJed Brown<title>Running configure</title> 89179860b2SJed Brown 90179860b2SJed Brown<para>The first step in running configure is to show the help: 91179860b2SJed Brown<screen> 92179860b2SJed Brown<prompt>bash$</prompt> <command>framework.py -help</command> 93179860b2SJed Brown<computeroutput> 94179860b2SJed BrownPython Configure Help 95bebe2cf6SSatish Balay Comma separated lists should be given between [] (use \[ \] in tcsh/csh) 96179860b2SJed Brown For example: --with-mpi-lib=\[/usr/local/lib/libmpich.a,/usr/local/lib/libpmpich.a\] 97179860b2SJed Brown---------------------------------------------------------------------------------------- 98179860b2SJed BrownScript: 99179860b2SJed Brown --help : Print this help message current: 1 100179860b2SJed Brown --h : Print this help message current: 0 101179860b2SJed BrownFramework: 102179860b2SJed Brown --configModules : A list of Python modules with a Configure class current: [] 103179860b2SJed Brown --ignoreCompileOutput : Ignore compiler output current: 1 104179860b2SJed Brown --ignoreLinkOutput : Ignore linker output current: 1 105179860b2SJed Brown --ignoreWarnings : Ignore compiler and linker warnings current: 0 106179860b2SJed Brown --doCleanup : Delete any configure generated files (turn off for debugging) current: 1 107179860b2SJed Brown --with-alternatives : Provide a choice among alternative package installations current: 0 1080aa1f76dSSatish Balay --with-executables-search-path : A list of directories used to search for executables current: [] 1090aa1f76dSSatish Balay --with-packages-search-path : A list of directories used to search for packages current: [] 110179860b2SJed Brown --with-batch : Machine uses a batch system to submit jobs current: 0 111179860b2SJed Brown</computeroutput> 112179860b2SJed Brown</screen> 113179860b2SJed BrownThe options shown will depend upon the modules loaded with <option>-configModules</option>. For instance, we will 114179860b2SJed Brownnormally load the compiler module, which reveals the host of optios controlling preprocessors, compilers, and linkers. 115179860b2SJed Brown<screen> 116179860b2SJed Brown<prompt>bash$</prompt> <command>framework.py -configModules=[config.compilers] -help</command> 117179860b2SJed Brown<computeroutput> 118179860b2SJed BrownPython Configure Help 119bebe2cf6SSatish Balay Comma separated lists should be given between [] (use \[ \] in tcsh/csh) 120179860b2SJed Brown For example: --with-mpi-lib=\[/usr/local/lib/libmpich.a,/usr/local/lib/libpmpich.a\] 121179860b2SJed Brown---------------------------------------------------------------------------------------- 122179860b2SJed BrownScript: 123179860b2SJed Brown --help : Print this help message current: 1 124179860b2SJed Brown --h : Print this help message current: 0 125179860b2SJed BrownFramework: 126179860b2SJed Brown --configModules : A list of Python modules with a Configure class current: [] 127179860b2SJed Brown --ignoreCompileOutput : Ignore compiler output current: 1 128179860b2SJed Brown --ignoreLinkOutput : Ignore linker output current: 1 129179860b2SJed Brown --ignoreWarnings : Ignore compiler and linker warnings current: 0 130179860b2SJed Brown --doCleanup : Delete any configure generated files (turn off for debugging) current: 1 131179860b2SJed Brown --with-alternatives : Provide a choice among alternative package installations current: 0 1320aa1f76dSSatish Balay --with-executables-search-path : A list of directories used to search for executables current: [] 1330aa1f76dSSatish Balay --with-packages-search-path : A list of directories used to search for packages current: [] 134179860b2SJed Brown --with-batch : Machine uses a batch system to submit jobs current: 0 135179860b2SJed BrownCompilers: 136179860b2SJed Brown --with-cpp=<prog> : Specify the C preprocessor 137179860b2SJed Brown --with-cc=<prog> : Specify the C compiler 138179860b2SJed Brown --with-cxx=<prog> : Specify the C++ compiler 139179860b2SJed Brown --with-fc=<prog> : Specify the Fortran compiler 140179860b2SJed Brown --with-64-bit-pointers=<bool> : Use 64 bit compilers and libraries current: 0 141179860b2SJed Brown --CPP=<prog> : Specify the C preprocessor 142179860b2SJed Brown --CPPFLAGS=<string> : Specify the C preprocessor options current: 143179860b2SJed Brown --CXXPP=<prog> : Specify the C++ preprocessor 144179860b2SJed Brown --CC=<prog> : Specify the C compiler 145179860b2SJed Brown --CFLAGS=<string> : Specify the C compiler options current: 146179860b2SJed Brown --CXX=<prog> : Specify the C++ compiler 147179860b2SJed Brown --CXXFLAGS=<string> : Specify the C++ compiler options current: 148179860b2SJed Brown --CXX_CXXFLAGS=<string> : Specify the C++ compiler-only options current: 149179860b2SJed Brown --FC=<prog> : Specify the Fortran compiler 150179860b2SJed Brown --FFLAGS=<string> : Specify the Fortran compiler options current: 151179860b2SJed Brown --LD=<prog> : Specify the default linker 152179860b2SJed Brown --CC_LD=<prog> : Specify the linker for C only 153179860b2SJed Brown --CXX_LD=<prog> : Specify the linker for C++ only 154179860b2SJed Brown --FC_LD=<prog> : Specify the linker for Fortran only 155179860b2SJed Brown --LDFLAGS=<string> : Specify the linker options current: 156179860b2SJed Brown --with-ar : Specify the archiver 157179860b2SJed Brown -AR : Specify the archiver flags 158179860b2SJed Brown -AR_FLAGS : Specify the archiver flags 159179860b2SJed Brown --with-ranlib : Specify ranlib 160179860b2SJed Brown --with-shared-libraries : Enable shared libraries current: 1 161179860b2SJed Brown --with-shared-ld=<prog> : Specify the shared linker 162179860b2SJed Brown --with-f90-header=<file> : Specify the C header for the F90 interface, e.g. f90_intel.h 163179860b2SJed Brown --with-f90-source=<file> : Specify the C source for the F90 interface, e.g. f90_intel.c 164179860b2SJed Brown</computeroutput> 165179860b2SJed Brown</screen> 166179860b2SJed BrownThe syntax for list and dictionary option values is identical to Python syntax. However, in some shells (like 167179860b2SJed Brown<command>csh</command>), brackets must be escaped, and braces will usually have to be enclosed in quotes.</para> 168179860b2SJed Brown 169179860b2SJed Brown<para>The modules indicated with <option>-configModules</option> are located using <envar>PYTHONPATH</envar>. Since 170179860b2SJed Brownspecifying environment variables can be inconvenient and error prone, it is common to provide a driver which alters 171179860b2SJed Brown<varname>sys.path</varname>, as is done for PETSc. In fact, the PETSc driver 172179860b2SJed Brown<itemizedlist> 173179860b2SJed Brown <listitem><para>Verifies <envar>PETSC_ARCH</envar></para></listitem> 174179860b2SJed Brown <listitem><para>Checks for invalid Cygwin versions</para></listitem> 175179860b2SJed Brown <listitem><para>Checks for RedHat 9, which has a threads bug</para></listitem> 176179860b2SJed Brown <listitem><para>Augments <envar>PYTHONPATH</envar></para></listitem> 177179860b2SJed Brown <listitem><para>Adds the default PETSc configure module</para></listitem> 178179860b2SJed Brown <listitem><para>Persists the configuration in <filename>RDict.db</filename></para></listitem> 179179860b2SJed Brown <listitem><para>Handles exceptions</para></listitem> 180179860b2SJed Brown</itemizedlist> 181179860b2SJed Brown</para> 182179860b2SJed Brown 183179860b2SJed Brown</sect1> 184179860b2SJed Brown 185179860b2SJed Brown<sect1 id="Adding-a-module"> 186179860b2SJed Brown<title>Adding a module</title> 187179860b2SJed Brown 188179860b2SJed Brown<para>As we discussed in the introduction, all that is strictly necessary for a configure module, is to provide a class 189179860b2SJed Brownnamed <classname>Configure</classname> with a method <methodname>configure</methodname> taking no arguments. However, 190179860b2SJed Brownthere are a variety of common operations, which will be illustrated in the sections below.</para> 191179860b2SJed Brown 192179860b2SJed Brown <sect2 id="Using-other-modules"> 193179860b2SJed Brown <title>Using other modules</title> 194179860b2SJed Brown 195179860b2SJed Brown <para>We will often want to use the methods or results of other configure modules in order to perform checks in our 196179860b2SJed Brownown. The framework provides a mechanism for retrieving the object for any given configure module. As an example, 197179860b2SJed Brownconsider checking for the <methodname>ddot</methodname> function in the BLAS library. The relevant Python code would 198179860b2SJed Brownbe 199179860b2SJed Brown<programlisting> 200179860b2SJed Brownimport config.base 201179860b2SJed Brown 202179860b2SJed Brownclass Configure(config.base.Configure): 203179860b2SJed Brown def __init__(self, framework): 204179860b2SJed Brown config.base.Configure.__init__(self, framework) 205179860b2SJed Brown self.compilers = self.framework.require('config.compilers', self) 206179860b2SJed Brown self.libraries = self.framework.require('config.libraries', self) 207179860b2SJed Brown return 208179860b2SJed Brown 209179860b2SJed Brown def configure(self): 210179860b2SJed Brown return self.libraries.check('libblas.a', 'ddot', otherLibs = self.compilers.flibs, 211179860b2SJed Brown fortranMangle = 1) 212179860b2SJed Brown</programlisting> 213179860b2SJed BrownThe <methodname>require</methodname> call will return the configure object from the given module, creating it if 214179860b2SJed Brownnecessary. If the second argument is given, the framework will ensure that the returned configure object runs 215179860b2SJed Brown<emphasis>before</emphasis> the passed configure object. Notice that we can use the returned object either to call 216179860b2SJed Brownmethods, like <methodname>check</methodname> from <classname>config.libraries</classname>, or use member variables, such 217179860b2SJed Brownas the list of Fortran compatibility libraries <methodname>flibs</methodname> from 218179860b2SJed Brown<classname>config.compilers</classname>. 219179860b2SJed Brown</para> 220179860b2SJed Brown 221179860b2SJed Brown<para>The underlying implementation in the framework uses a directed acyclic graph to indicate dependencies among 222179860b2SJed Brownmodules. The vertices of this graph, configure objects, are topologically sorted and then executed. Moreover, child 223179860b2SJed Brownobjects can be added to the framework without respecting the dependency structure, but this is discouraged.</para> 224179860b2SJed Brown 225179860b2SJed Brown </sect2> 226179860b2SJed Brown 227179860b2SJed Brown <sect2 id="Adding-a-test"> 228179860b2SJed Brown <title>Adding a test</title> 229179860b2SJed Brown 230179860b2SJed Brown <para>A user could of course perform all tests in the object's <methodname>configure</methodname> method, but the base 231179860b2SJed Brownclass provides useful logging support for this purpose. Consider again the BLAS example, which will now become, 232179860b2SJed Brown<programlisting> 233179860b2SJed Brown def checkDot(self): 234179860b2SJed Brown '''Verify that the ddot() function is contained in the BLAS library''' 235179860b2SJed Brown return self.libraries.check('libblas.a', 'ddot', otherLibs = self.compilers.flibs, 236179860b2SJed Brown fortranMangle = 1) 237179860b2SJed Brown 238179860b2SJed Brown def configure(self): 239179860b2SJed Brown self.executeTest(self.checkDot) 240179860b2SJed Brown return 241179860b2SJed Brown</programlisting> 242179860b2SJed BrownPassing our test module to the framework, 243179860b2SJed Brown<screen> 244179860b2SJed Brown<prompt>docs$</prompt> <command>PYTHONPATH=`pwd` ../config/framework.py --configModules=[examples.blasTest]</command> 245179860b2SJed Brown</screen> 246179860b2SJed Brownwe produce the following log output in <filename>configure.log</filename>. Notice that it not only records the method and module, but the method doc string, 247179860b2SJed Brownall shell calls, and any output actions as well.</para> 248179860b2SJed Brown<screen> 249179860b2SJed Brown<computeroutput> 250179860b2SJed Brown================================================================================ 251179860b2SJed BrownTEST checkDot from examples.blasTest(/PETSc3/sidl/BuildSystem/docs/examples/blasTest.py:10) 252179860b2SJed BrownTESTING: checkDot from examples.blasTest(/PETSc3/sidl/BuildSystem/docs/examples/blasTest.py:10) 253179860b2SJed Brown Verify that the ddot() function is contained in the BLAS library 254179860b2SJed Brown Checking for functions ['ddot'] in library ['libblas.a'] ['-lfrtbegin', '-lg2c', '-lm', 255179860b2SJed Brown '-L/usr/lib/gcc-lib/i486-linux/3.3.5', '-L/usr/lib/gcc-lib/i486-linux/3.3.5/../../..', 256179860b2SJed Brown '-lm', '-lgcc_s'] 257179860b2SJed Brownsh: gcc -c -o conftest.o -fPIC conftest.c 258179860b2SJed BrownExecuting: gcc -c -o conftest.o -fPIC conftest.c 259179860b2SJed Brownsh: 260179860b2SJed Brownsh: gcc -o conftest -fPIC conftest.o -lblas -lfrtbegin -lg2c -lm 261179860b2SJed Brown -L/usr/lib/gcc-lib/i486-linux/3.3.5 -L/usr/lib/gcc-lib/i486-linux/3.3.5/../../.. -lm -lgcc_s 262179860b2SJed BrownExecuting: gcc -o conftest -fPIC conftest.o -lblas -lfrtbegin -lg2c -lm 263179860b2SJed Brown -L/usr/lib/gcc-lib/i486-linux/3.3.5 -L/usr/lib/gcc-lib/i486-linux/3.3.5/../../.. -lm -lgcc_s 264179860b2SJed Brownsh: 265179860b2SJed BrownDefined HAVE_LIBBLAS to 1 in config.libraries 266179860b2SJed Brown</computeroutput> 267179860b2SJed Brown</screen> 268179860b2SJed Brown 269179860b2SJed Brown </sect2> 270179860b2SJed Brown 271179860b2SJed Brown <sect2 id="Checking-for-headers"> 272179860b2SJed Brown <title>Checking for headers</title> 273179860b2SJed Brown 274179860b2SJed Brown <para>Often, we would like to test for the presence of certain headers. This is done is a completely analogous way to 275179860b2SJed Brownthe library case, using instead the <classname>config.headers</classname> module. Below, we test for the presence of the 276179860b2SJed Brown<command>curses</command> header. 277179860b2SJed Brown<programlisting> 278179860b2SJed Brownimport config.base 279179860b2SJed Brown 280179860b2SJed Brownclass Configure(config.base.Configure): 281179860b2SJed Brown def __init__(self, framework): 282179860b2SJed Brown config.base.Configure.__init__(self, framework) 283179860b2SJed Brown self.headers = self.framework.require('config.headers, self) 284179860b2SJed Brown return 285179860b2SJed Brown 286179860b2SJed Brown def checkCurses(self): 287179860b2SJed Brown 'Verify that we have the curses header' 288179860b2SJed Brown return self.headers.check('curses.h') 289179860b2SJed Brown 290179860b2SJed Brown def configure(self): 291179860b2SJed Brown self.executeTest(self.checkCurses) 292179860b2SJed Brown return 293179860b2SJed Brown</programlisting> 294179860b2SJed BrownRunning this test 295179860b2SJed Brown<screen> 296179860b2SJed Brown<prompt>docs$</prompt> <command>PYTHONPATH=`pwd` ../config/framework.py --configModules=[examples.cursesTest]</command> 297179860b2SJed Brown</screen> 298179860b2SJed Brownproduces the following log output.</para> 299179860b2SJed Brown<screen> 300179860b2SJed Brown<computeroutput> 301179860b2SJed Brown================================================================================ 302179860b2SJed BrownTEST checkCurses from examples.cursesTest(/PETSc3/sidl/BuildSystem/docs/examples/cursesTest.py:9) 303179860b2SJed BrownTESTING: checkCurses from examples.cursesTest(/PETSc3/sidl/BuildSystem/docs/examples/cursesTest.py:9) 304179860b2SJed Brown Verify that we have the curses header 305179860b2SJed BrownChecking for header: curses.h 306179860b2SJed Brownsh: gcc -E conftest.c 307179860b2SJed BrownExecuting: gcc -E conftest.c 308179860b2SJed Brownsh: # 1 "conftest.c" 309179860b2SJed Brown# 1 "<built-in>" 310179860b2SJed Brown# 1 "<command line>" 311179860b2SJed Brown# 1 "conftest.c" 312179860b2SJed Brown# 1 "confdefs.h" 1 313179860b2SJed Brown# 2 "conftest.c" 2 314179860b2SJed Brown# 1 "conffix.h" 1 315179860b2SJed Brown# 3 "conftest.c" 2 316179860b2SJed Brown# 1 "/usr/include/curses.h" 1 3 4 317179860b2SJed Brown# 58 "/usr/include/curses.h" 3 4 318179860b2SJed Brown# 1 "/usr/include/ncurses_dll.h" 1 3 4 319179860b2SJed Brown# 59 "/usr/include/curses.h" 2 3 4 320179860b2SJed Brown# 99 "/usr/include/curses.h" 3 4 321179860b2SJed Browntypedef unsigned long chtype; 322179860b2SJed Brown# 1 "/usr/include/stdio.h" 1 3 4 323179860b2SJed Brown# 28 "/usr/include/stdio.h" 3 4 324179860b2SJed Brown# 1 "/usr/include/features.h" 1 3 4 325179860b2SJed Brown# 295 "/usr/include/features.h" 3 4 326179860b2SJed Brown# 1 "/usr/include/sys/cdefs.h" 1 3 4 327179860b2SJed Brown# 296 "/usr/include/features.h" 2 3 4 328179860b2SJed Brown# 318 "/usr/include/features.h" 3 4 329179860b2SJed Brown#... 330179860b2SJed Brown... W* win,int* y, int* x, _Bool to_screen); 331179860b2SJed Brownextern _Bool mouse_trafo (int*, int*, _Bool); 332179860b2SJed Brownextern int mcprint (char *, int); 333179860b2SJed Brownextern int has_key (int); 334179860b2SJed Brownextern void _tracef (const char *, ...) ; 335179860b2SJed Brownextern void _tracedump (const char *, WINDOW *); 336179860b2SJed Brownextern char * _traceattr (attr_t); 337179860b2SJed Brownextern char * _traceattr2 (int, chtype); 338179860b2SJed Brownextern char * _nc_tracebits (void); 339179860b2SJed Brownextern char * _tracechar (int); 340179860b2SJed Brownextern char * _tracechtype (chtype); 341179860b2SJed Brownextern char * _tracechtype2 (int, chtype); 342179860b2SJed Brown# 1203 "/usr/include/curses.h" 3 4 343179860b2SJed Brownextern char * _tracemouse (const MEVENT *); 344179860b2SJed Brownextern void trace (const unsigned int); 345179860b2SJed Brown# 4 "conftest.c" 2 346179860b2SJed Brown 347179860b2SJed BrownDefined HAVE_CURSES_H to 1 in config.headers 348179860b2SJed Brown</computeroutput> 349179860b2SJed Brown</screen> 350179860b2SJed Brown 351179860b2SJed Brown<para>Alternatively, we could have specified that this header be included in the list of header files checked by default.</para> 352179860b2SJed Brown<programlisting> 353179860b2SJed Brownimport config.base 354179860b2SJed Brown 355179860b2SJed Brownclass Configure(config.base.Configure): 356179860b2SJed Brown def __init__(self, framework): 357179860b2SJed Brown config.base.Configure.__init__(self, framework) 358179860b2SJed Brown self.headers = self.framework.require('config.headers, self) 359179860b2SJed Brown self.headers.headers.append('curses.h') 360179860b2SJed Brown return 361179860b2SJed Brown 362179860b2SJed Brown def checkCurses(self): 363179860b2SJed Brown 'Verify that we have the curses header' 364179860b2SJed Brown return self.headers.haveHeader('curses.h') 365179860b2SJed Brown 366179860b2SJed Brown def configure(self): 367179860b2SJed Brown self.executeTest(self.checkCurses) 368179860b2SJed Brown return 369179860b2SJed Brown</programlisting> 370179860b2SJed Brown 371179860b2SJed Brown<para>In addition, the base class does include lower level support for preprocessing files. The 372179860b2SJed Brown<methodname>preprocess</methodname> method takes a code string as input and return a tuple of the 373179860b2SJed Brown<command>(stdout,stderr,error code)</command> for the run. The <methodname>outputPreprocess</methodname> method returns 374179860b2SJed Brownonly the standard output, and <methodname>checkPreprocess</methodname> returns true if no error occurs.</para> 375179860b2SJed Brown 376179860b2SJed Brown </sect2> 377179860b2SJed Brown 378179860b2SJed Brown <sect2 id="Checking-for-libraries"> 379179860b2SJed Brown <title>Checking for libraries</title> 380179860b2SJed Brown 381179860b2SJed Brown <para>We have already demonstrated a test for the existence of a function in a library. However the 382179860b2SJed Brown<methodname>check</methodname> method is much more general. It allows the specification of multiple libraries and 383179860b2SJed Brownmultiple functions, as well as auxiliary libraries. For instance, to check for the <methodname>MPI_Init</methodname> and 384179860b2SJed Brown<methodname>MPI_Comm_create</methodname> functions in MPICH when the Fortran bindings are active, we would use: 385179860b2SJed Brown<programlisting> 386179860b2SJed Brown self.libraries.check(['libmpich.so', 'libpmpich.so'], ['MPI_Init', 'MPI_Comm_create'], 387179860b2SJed Brown otherLibs = self.compilers.flibs) 388179860b2SJed Brown</programlisting> 389179860b2SJed BrownAs in the BLAS example, we can also turn on Fortran name mangling. The caller may also supply a function prototype and 390179860b2SJed Browncalling sequence, which are necessary if the current language is C++. 391179860b2SJed Brown</para> 392179860b2SJed Brown 393179860b2SJed Brown<para>It is also necessary at some times to determine whether a given library is a shared object. This can be 394179860b2SJed Brownaccomplished using the <methodname>checkShared</methodname> method, as we demonstrate with the MPICH library in a call 395179860b2SJed Browntaken from the MPI configure module in PETSc. 396179860b2SJed Brown<programlisting> 397179860b2SJed Brown self.libraries.checkShared('#include <mpi.h>\n', 'MPI_Init', 'MPI_Initialized', 398179860b2SJed Brown 'MPI_Finalize', checkLink = self.checkMPILink, 399179860b2SJed Brown libraries = self.lib) 400179860b2SJed Brown</programlisting> 401179860b2SJed BrownThe theory for the check is that a shared object will have only one copy of any global variable. Thus functions such as 402179860b2SJed Brown<methodname>MPI_Initialized</methodname> will render consistent results across other libraries. The test begins by 403179860b2SJed Browncreating two dynamic libraries, both of which link the given library. Then an executable is constructed which loads the 404179860b2SJed Brownlibraries in turn. The first library calls the initizlization functions, here <methodname>MPI_Init</methodname>, and the 405179860b2SJed Brownsecond library calls the initialization check function, here <methodname>MPI_Initialized</methodname>. The check 406179860b2SJed Brownfunction will return true if the given library is a shared object. This organization is shown in figure ???</para> 407179860b2SJed Brown<para> 408179860b2SJed Brown<inlinemediaobject> 409179860b2SJed Brown<imageobject><imagedata fileref="sharedLibraryCheck" format="EPS"/></imageobject> 410179860b2SJed Brown<imageobject><imagedata fileref="sharedLibraryCheck" format="JPG"/></imageobject> 411179860b2SJed Brown<!-- <textobject><phrase>A diagram of the link structure for the shared library test</phrase></textobject> --> 412179860b2SJed Brown</inlinemediaobject> 413179860b2SJed Brown</para> 414179860b2SJed Brown 415179860b2SJed Brown <para>The lower level interface to compiling and linking in the base class mirrors that for preprocessing. The 416179860b2SJed Brown<methodname>outputCompile</methodname> and <methodname>checkCompile</methodname> methods function in the same way. The 417179860b2SJed Browncode is now broken up into four distinct sections. There are includes, the body of <methodname>main</methodname>, and a 418179860b2SJed Brownpossible replacement for the beginning and end of the <methodname>main</methodname> declaration. The linking methods, 419179860b2SJed Brown<methodname>outputLink</methodname> and <methodname>checkLink</methodname>, are exactly analogous.</para> 420179860b2SJed Brown 421179860b2SJed Brown <para>There are also some convenience methods provided to handle compiler and linker flags. The 422179860b2SJed Brown<methodname>checkCompilerFlag</methodname> and <methodname>checkLinkerFlag</methodname> try to determine whether a given 423179860b2SJed Brownflag is accepted by the processor, while <methodname>addCompilerFlag</methodname> and 424179860b2SJed Brown<methodname>addLinkerFlag</methodname> will do that check and add any valid flag to the list of default flags.</para> 425179860b2SJed Brown 426179860b2SJed Brown </sect2> 427179860b2SJed Brown 428179860b2SJed Brown <sect2 id="Checking-for-executables"> 429179860b2SJed Brown <title>Checking for executables</title> 430179860b2SJed Brown 431179860b2SJed Brown <para>The <methodname>getExecutable</methodname> method is used to locate executable files. For instance, this code 432179860b2SJed Brownwould allow us to locate the <command>valgrind</command> binary. 433179860b2SJed Brown<programlisting> 434179860b2SJed Brown self.getExecutable('valgrind') 435179860b2SJed Brown</programlisting> 436179860b2SJed BrownIf the program is found, a member variable of the same name will be set in the object to the program name, and a make 437179860b2SJed Brownmacro defined to it as well. We can opt for these to contain the full path by using the <option>getFullPath</option> 438179860b2SJed Brownargument. In addition, we can change the name of the member variable and macro using the <option>resultName</option> 439179860b2SJed Brownargument. 440179860b2SJed Brown</para> 441179860b2SJed Brown 442179860b2SJed Brown<para>We also have control over the search path used. If we give no arguments, the default path from the environment is 443179860b2SJed Brownused. This can be overridden with a new path using the <option>path</option> argument, either as a Python list or a 444179860b2SJed Browncolon separated string. Furthermore, the default path can be added to this custom path using the 445179860b2SJed Brown<option>useDefaultPath</option> argument. For instance, this call 446179860b2SJed Brown<programlisting> 447179860b2SJed Brown self.getExecutable('valgrind', path=['/opt/valgrind-1.0'], getFullPath=1, 448179860b2SJed Brown useDefaultPath=1, resultName='grinder') 449179860b2SJed Brown</programlisting> 450179860b2SJed Brownwill check for <command>valgrind</command> first in <filename>/opt/valgrind-1.0</filename> and then along the default 451179860b2SJed Brownpath. If found in the first location, it will set <varname>self.grinder</varname> to 452179860b2SJed Brown<filename>/opt/valgrind-1.0/valgrind</filename> as well as define <envar>GRINDER</envar> to the same value in makefiles. 453179860b2SJed Brown</para> 454179860b2SJed Brown 455179860b2SJed Brown <para>As in the cases of preprocessing, compiling, and linking, the lower level operations are also exposed. The 456179860b2SJed Brown<methodname>checkRun</methodname> method takes in a code string and returns true if the executable runs without 457179860b2SJed Brownerror. The <methodname>outputRun</methodname> method returns the output and status code. Both methods us the safe 458179860b2SJed Brownexecution routine <methodname>config.base.Configure.executeShellCommand</methodname> which accepts a timeout. Moreover, 459179860b2SJed Brownthere commands can run in the special batch mode described in section ???.</para> 460179860b2SJed Brown 461179860b2SJed Brown </sect2> 462179860b2SJed Brown 463179860b2SJed Brown <sect2 id="Output-results"> 464179860b2SJed Brown <title>Output results</title> 465179860b2SJed Brown 466179860b2SJed Brown <para>The BuildSystem configure includes the traditional output methods employed by <command>autoconf</command> to 467179860b2SJed Brownenable communication with <command>make</command>. Individual configure modules use the 468179860b2SJed Brown<methodname>addDefine</methodname> method to add C <methodname>#define</methodname> statements to a configuration header 469179860b2SJed Brownand the <methodname>addSubstitution</methodname> to setup substitution rules for specified files. For instance, to 47015ac2963SJed Brownactivate the parmetis package, we might provide 471179860b2SJed Brown<programlisting> 472179860b2SJed Brown self.addDefine('HAVE_PARMETIS', 1) 473179860b2SJed Brown</programlisting> 474179860b2SJed Brownand then for the make process 475179860b2SJed Brown<programlisting> 476179860b2SJed Brown self.addSubstitution('PARMETIS_INCLUDE', ' '.join([self.libraries.getIncludeArgument(i) 477179860b2SJed Brown for i in self.include])) 478179860b2SJed Brown self.addSubstitution('PARMETIS_LIB, ' '.join([self.libraries.getLibArgument(l) 479179860b2SJed Brown for l in self.lib])) 480179860b2SJed Brown</programlisting> 481179860b2SJed Brown</para> 482179860b2SJed Brown 483179860b2SJed Brown<para>The actual output of this data is controlled by the framework. The user specifies the header file using the 484179860b2SJed Brown<varname>header</varname> field of the framework, and then the file is created automatically during the configure 485179860b2SJed Brownprocess, but can be output at any time using the <methodname>outputHeader</methodname> method. Furthermore, the 486179860b2SJed Brown<methodname>addSubstitutionFile</methodname> method can be used to tag a file for substitution, and also specify a 487179860b2SJed Browndifferent file for the result of the substitution.</para> 488179860b2SJed Brown 4894eb7a547SBarry Smith<para>In the <command>autoconf</command> approach, separating the defines and substitutions for different packages 490179860b2SJed Brownbecomes troublesome, and in some cases impossible to maintain. To help with this, we have introduced 491179860b2SJed Brown<emphasis>prefixes</emphasis> for the defines and substitutions. The are strings, unique to each module, which are 492179860b2SJed Brownprepended with an underscore to each identifier defined or substituted. These are set on a per object basis using the 493179860b2SJed Brown<varname>headerPrefix</varname> and <varname>substPrefix</varname> members. For instance, in our 49415ac2963SJed Brownparmetis example, if we instead used the code 495179860b2SJed Brown<programlisting> 496179860b2SJed Brown self.headerPrefix = 'MATT' 497179860b2SJed Brown self.addDefine('HAVE_PARMETIS', 1) 498179860b2SJed Brown</programlisting> 499179860b2SJed Brownin our configuration header we would see 500179860b2SJed Brown<programlisting> 501179860b2SJed Brown #ifndef MATT_HAVE_PARMETIS 502179860b2SJed Brown #define MATT_HAVE_PARMETIS 1 503179860b2SJed Brown #endif 504179860b2SJed Brown</programlisting> 505179860b2SJed BrownNote that the value of the prefix is used at output time, not at the time that the define or substitution is set. 506179860b2SJed Brown</para> 507179860b2SJed Brown 508179860b2SJed Brown<para>Another extension of the old-style output mechanisms adds more C structure to the interface. The 509179860b2SJed Brown<methodname>addTypedef</methodname> method allows a typedef from one typename to another, which in 510179860b2SJed Brown<command>autoconf</command> is handled by a define. Likewise <methodname>addPrototype</methodname> can add a missing 511179860b2SJed Brownfunction prototype to a header. Since these are C specific structures, they are output into a separate configuration 512179860b2SJed Brownheader file, which is controlled by the <varname>cHeader</varname> member variable.</para> 513179860b2SJed Brown 514179860b2SJed Brown<para>Extending in a different direction, we allow makefile structures to be specified directly rather than through 515179860b2SJed Brownsubstitutions. Using <methodname>addMakeMacro</methodname>, we can add variable definitions to the configuration 516179860b2SJed Brownmakefile, whereas <methodname>addMakeRule</methodname> allows the user to specify a make target, complete with 51715ac2963SJed Browndependencies and action. As an example, we will replace our parmetis example from above with the following code 518179860b2SJed Brown<programlisting> 519179860b2SJed Brown self.addMakeMacro('PARMETIS_INCLUDE', ' '.join([self.libraries.getIncludeArgument(i) 520179860b2SJed Brown for i in self.include])) 521179860b2SJed Brown self.addMakeMacro('PARMETIS_LIB, ' '.join([self.libraries.getLibArgument(l) 522179860b2SJed Brown for l in self.lib])) 523179860b2SJed Brown self.addMakeRule('.c.o', '', ['${CC} -c -o $@ -I${PARMETIS_INCLUDE} $<']) 524179860b2SJed Brown self.addMakeRule('myApp', '${.c=.o:SOURCE}', ['${CC} -o $@ $< ${PARMETIS_LIB}']) 525179860b2SJed Brown</programlisting> 526179860b2SJed Brownwhich will produce 527179860b2SJed Brown<programlisting> 52815ac2963SJed Brown PARMETIS_INCLUDE = -I/home/knepley/petsc-dev/externalpackages/parmetis/build/Darwin-x86_64/include 52915ac2963SJed Brown PARMETIS_LIB = -L/home/knepley/petsc-dev/externalpackages/parmetis/build/Darwin-x86_64/lib -lparmetis -lmetis 530179860b2SJed Brown</programlisting> 531179860b2SJed Brownin the file specified by the <varname>makeMacroHeader</varname> member variable, and 532179860b2SJed Brown<programlisting> 533179860b2SJed Brown myApp: ${.c=.o:SOURCE} 534179860b2SJed Brown ${CC} -i $@ $< ${PARMETIS_LIB} 535179860b2SJed Brown</programlisting> 536179860b2SJed Brownin the file specified by the <varname>makeRuleHeader</varname> member variable.</para> 537179860b2SJed Brown 538179860b2SJed Brown<para>The above output methods are all specified on a per configure object basis, however this may become confusing in a 539179860b2SJed Brownlarge project. All the prefixes and output filenames would have to be coordinated. A common strategy is to use the 540179860b2SJed Brownframework for coordination, putting all the output into the framework object itself. For instance, we might have 541179860b2SJed Brown<programlisting> 542179860b2SJed Brown self.framework.addDefine('HAVE_PARMETIS', 1) 543179860b2SJed Brown</programlisting> 544179860b2SJed Brownwhich would allow the define to appear in the headre specified by the framework with the framework prefix. 545179860b2SJed Brown</para> 546179860b2SJed Brown 547179860b2SJed Brown </sect2> 548179860b2SJed Brown 549179860b2SJed Brown</sect1> 550179860b2SJed Brown 551179860b2SJed Brown<sect1 id="Configuring-batch-systems"> 552179860b2SJed Brown<title>Configuring batch systems</title> 553179860b2SJed Brown 554179860b2SJed Brown<para>It is not uncommon for large clusters or supercomputing centers to have a batch execution policy, making it 555179860b2SJed Browndifficult for configure to execute the few tests that depend on executing code, rather than compiling and linking it. To 556179860b2SJed Brownhandle this case, we provide the <option>--with-batch</option> argument. The code to be run is collected in a single 557179860b2SJed Brownexecutable which the user must submit to the system. This executable produces a <emphasis>reconfigure</emphasis> script 558179860b2SJed Brownwhich may then be run to fully configure the system.</para> 559179860b2SJed Brown 560179860b2SJed Brown<para>When configure is run with the <option>--with-batch</option> option, the following message will appear. 561179860b2SJed Brown<screen> 562179860b2SJed Brown<prompt>petsc-dev$</prompt> <command>./config/configure.py --with-batch</command> 563179860b2SJed Brown</screen> 564179860b2SJed Brownproduces the following log output. 565179860b2SJed Brown<screen> 566179860b2SJed Brown<computeroutput> 567179860b2SJed Brown================================================================================= 568*a8cf87e0SJunchao Zhang Since your compute nodes require use of a batch system or mpiexec you must: 569179860b2SJed Brown 1) Submit ./conftest to your batch system (this will generate the file reconfigure) 570179860b2SJed Brown 2) Run "python reconfigure" (to complete the configure process). 571179860b2SJed Brown================================================================================= 572179860b2SJed Brown</computeroutput> 573179860b2SJed Brown</screen> 574179860b2SJed BrownThe user must then execute the <filename>conftest</filename> binary, and then run the <command>python 575179860b2SJed Brownreconfigure</command> command. 576179860b2SJed Brown</para> 577179860b2SJed Brown 578179860b2SJed Brown<para>If a user defined test relies upon running code, he may make it suitable for a batch system. The 579179860b2SJed Brown<methodname>checkRun</methodname> method takes the <option>defaultArg</option> argument which names a configure option 580179860b2SJed Brownwhose value may substitute for the outcome of the test, allowing a user to preempt the run. For instance, the 581179860b2SJed Brown<methodname>config.types.checkEndian</methodname> method contains the code 582179860b2SJed Brown<programlisting> 583179860b2SJed Brown if self.checkRun('', body, defaultArg = 'isLittleEndian'): 584179860b2SJed Brown</programlisting> 585179860b2SJed Brownwhich means the <option>isLittleEndian</option> option can be given to replace the output of the run. However, this does 586179860b2SJed Brownthe require the user to supply the missing option.</para> 587179860b2SJed Brown 588179860b2SJed Brown<para>To automate this process, the test should first check for batch mode. Using the 589179860b2SJed Brown<methodname>addBatchInclude</methodname> and <methodname>addBatchBody</methodname> methods, code can be included in the 590179860b2SJed Brownbatch executable. We return to the endian test to illustrate this usage. 591179860b2SJed Brown<programlisting> 592179860b2SJed Brown if not self.framework.argDB['with-batch']: 593179860b2SJed Brown body = ''' 594179860b2SJed Brown /* Are we little or big endian? From Harbison & Steele. */ 595179860b2SJed Brown union 596179860b2SJed Brown { 597179860b2SJed Brown long l; 598179860b2SJed Brown char c[sizeof(long)]; 599179860b2SJed Brown } u; 600179860b2SJed Brown u.l = 1; 601179860b2SJed Brown exit(u.c[sizeof(long) - 1] == 1); 602179860b2SJed Brown ''' 603179860b2SJed Brown if self.checkRun('', body, defaultArg = 'isLittleEndian'): 604179860b2SJed Brown endian = 'little' 605179860b2SJed Brown else: 606179860b2SJed Brown endian = 'big' 607179860b2SJed Brown else: 608179860b2SJed Brown self.framework.addBatchBody( 609179860b2SJed Brown ['{', 610179860b2SJed Brown ' union {long l; char c[sizeof(long)];} u;', 611179860b2SJed Brown ' u.l = 1;', 612179860b2SJed Brown ' fprintf(output, " \'--with-endian=%s\',\\n",\ 613179860b2SJed Brown (u.c[sizeof(long) - 1] == 1) ? "little" : "big");', 614179860b2SJed Brown '}']) 615179860b2SJed Brown # Dummy value 616179860b2SJed Brown endian = 'little' 617179860b2SJed Brown</programlisting> 618179860b2SJed BrownThe batch body code should output configure options to the <varname>output</varname> file descriptor. These are 619179860b2SJed Browncollected for the new configure run in the <filename>reconfigure</filename> script. 620179860b2SJed Brown</para> 621179860b2SJed Brown 622179860b2SJed Brown</sect1> 623179860b2SJed Brown 624179860b2SJed Brown</chapter> 625179860b2SJed Brown 626179860b2SJed Brown<chapter id="Build"> 627179860b2SJed Brown<title>Build</title> 628179860b2SJed Brown 629179860b2SJed Brown<para>The build operation now encompasses the configure, compile, link, install, and update operations.</para> 630179860b2SJed Brown 631179860b2SJed Brown<sect1 id="Running-make"> 632179860b2SJed Brown<title>Running make</title> 633179860b2SJed Brown 634179860b2SJed Brown<para>All options for both configuration and build are given to <filename>make.py</filename>. Thus, the simplest build 635179860b2SJed Brownis merely 636179860b2SJed Brown<screen> 637179860b2SJed Brown<prompt>petsc-dev$</prompt> <command>./make.py</command> 638179860b2SJed Brown</screen> 639179860b2SJed BrownThe help is also given by <option>-help</option>, but this time it will also include build switches. 640179860b2SJed Brown<screen> 641179860b2SJed Brown<prompt>petsc-dev$</prompt> <command>./make.py -help</command> 642179860b2SJed Brown<computeroutput> 643179860b2SJed BrownScript Help 644179860b2SJed Brown----------- 645179860b2SJed BrownScript: 646179860b2SJed Brown --help : Print this help message current: 1 647179860b2SJed Brown --h : Print this help message current: 0 648179860b2SJed BrownMake: 649179860b2SJed Brown -forceConfigure : Force a reconfiguration current: 0 650179860b2SJed Brown -ignoreCompileOutput : Ignore compiler output current: 1 651179860b2SJed Brown -defaultRoot : Directory root for all packages current: ../.. 652179860b2SJed Brown -prefix : Root for installation of libraries and binaries 653179860b2SJed BrownSIDLMake: 654d5b43468SJose E. Roman -bootstrap : Generate the bootstrap client current: 0 655179860b2SJed Brown -outputSIDLFiles : Write generated files to disk current: 1 656179860b2SJed Brown -excludeLanguages=<languages> : Do not load configurations from RDict for the given languages current: [] 657179860b2SJed Brown -excludeBasenames=<names> : Do not load configurations from RDict for these SIDL base names current: [] 658179860b2SJed Brown</computeroutput> 659179860b2SJed Brown</screen> 660179860b2SJed Brown</para> 661179860b2SJed Brown 662179860b2SJed Brown</sect1> 663179860b2SJed Brown 664179860b2SJed Brown<sect1 id="Makers"> 665179860b2SJed Brown<title>Makers</title> 666179860b2SJed Brown 667179860b2SJed Brown<para>The build operation now encompasses configure, compile, and link operations, which are coordinated by objects of 668179860b2SJed Brownclass <classname>maker.Maker</classname>. This object manages: 669179860b2SJed Brown<itemizedlist> 670179860b2SJed Brown <listitem><para>configuration,</para></listitem> 671179860b2SJed Brown <listitem><para>build,</para></listitem> 672179860b2SJed Brown <listitem><para>install, and</para></listitem> 673179860b2SJed Brown <listitem><para>project dependencies</para></listitem> 674179860b2SJed Brown</itemizedlist> 675179860b2SJed BrownAll options, no matter which component they are intended for, are given uniformly to <filename>make.py</filename>. 676179860b2SJed Brown</para> 677179860b2SJed Brown 678179860b2SJed Brown <sect2 id="SIDLMaker"> 679179860b2SJed Brown <title>SIDLMaker</title> 680179860b2SJed Brown 681179860b2SJed Brown<para>This is a subclass which handles source generation from SIDL.</para> 682179860b2SJed Brown 683179860b2SJed Brown </sect2> 684179860b2SJed Brown 685179860b2SJed Brown</sect1> 686179860b2SJed Brown 687179860b2SJed Brown<sect1 id="Builders"> 688179860b2SJed Brown<title>Builders</title> 689179860b2SJed Brown 690179860b2SJed Brown<para>The build operation now encompasses the configure, compile, and link operations.</para> 691179860b2SJed Brown 692179860b2SJed Brown</sect1> 693179860b2SJed Brown 694179860b2SJed Brown<sect1 id="LanguageProcessors"> 695179860b2SJed Brown<title>LanguageProcessors</title> 696179860b2SJed Brown 697179860b2SJed Brown<para>The build operation now encompasses the configure, compile, and link operations.</para> 698179860b2SJed Brown 699179860b2SJed Brown</sect1> 700179860b2SJed Brown 701179860b2SJed Brown<sect1 id="Interaction-with-Configure"> 702179860b2SJed Brown<title>Interaction with Configure</title> 703179860b2SJed Brown 704179860b2SJed Brown<para>The pickled configure is loaded by Maker, and then the config.compile objects are jacked into the Builder.</para> 705179860b2SJed Brown 706179860b2SJed Brown</sect1> 707179860b2SJed Brown 708179860b2SJed Brown</chapter> 709179860b2SJed Brown 710179860b2SJed Brown</book> 711