Makefiles

Michael Himsolt

Makefiles

This section describes how Graphlet's configuration system can be used to add makefiles for modules. The source code distribution must be installed to take advantage of these features.
This section requires basic knowledge of how make programs work.

Overview of the configuration system

Graphlet uses GNU make for its configuration. This version of make has some features which are not normally present in make programs, such as extended macro processing and if...{then...{}else} structures. We chose GNU make over preprocessor based systems because the latter one would be harder to debug. One side effect of using GNU make is that we are using the name GNUmakefile instead of Makefile or makefile. This has the advantage that any other make program will not even try to source the file and report syntax errors, but will report that it could not find a make file and exit. We feel this is a cleaner approach and gives better error messages. Also, our coding standards require to use the name GNUmakefile for makefiles. All of Graphlet's configuration files are located in lib/graphlet/config. The default installation procedure copies the configuration system to Graphlet Installation Directory/lib/graphlet/config. The configuration system does not only determine the proper compiler flags and procedures for installing Graphlet on a particular system, but also provides a large set of predefined make variables and targets. To get access to the predefined variables and procedures, every GNUmakefile must include the file lib/graphlet/config/common. Since the information in common relies on information about the site installation, it can only be used with a source code distribution.

Anatomy of a GNUmakefile

An example for a GNUmakefile can be found in the algorithms module. A GNUmakefile must at least contain the following:
  1. Define of the variable MODULE: \begin{quote} MODULE = insert the name of the module here \end{quote} MODULE is the name of the module in which the GNUmakefile resides.
  2. Define the variable GRAPHLET_BASE_DIR: \begin{quote} GRAPHLET_BASE_DIR=insert the relative path to the toplevel of Graphlet \end{quote} GRAPHLET_BASE_DIR must be the relative path to the toplevel directory of Graphlet. For example, if your module is in src/mymodule, then set \begin{quote} GRAPHLET_BASE_DIR=../.. \end{quote}
  3. Define a standard target all which is executed when no arguments are given to make (which is usually the case): \begin{quote} all: lib\(MODULE).a \(SUBDIRS) \end{quote} This defines that the default actions are building the object libraries, and recursively traversing the subdirectories. For a module which has no default actions and no subdirectories, use
    .PHONY: all
    all:    
            Insert the actions for target all here
    
    The directive .PHONY: states that the following target(s) have no dependencies.
  4. Include the common configuration definitions: \begin{quote} include\(Graphlet_BASE_DIR)/lib/Graphlet/config/common \end{quote}

Standard Variables

SUBDIRS
The variable SUBDIRS holds a list of subdirectories. Most targets will recursively descend into subdirectories.
TCLFILES
TCLFILES is a list of Tcl files. This target index constructs a tclIndex file (for autoloading)
MYCFILES
MYCFILES is the list of C/C++ files which are not generated by a program (e.g. yacc or lex).
CFILES
CFILES is the list of all C/C++ files, including those which generated by a program (e.g. yacc or lex).
HFILES
HFILES is the list of C/C++ Header files. HFILES can be generated from MYCFILES as follows: \begin{quote} HFILES = \(CFILES:\ \end{quote}
  • You must assign values to both MYCFILES and CFILES.
  • The convention that there is a header file for each C++ file is essential for configuration system to work correctly.
  • Standard Targets

    it, all
    it and all must the default targets which are executed when no targets are given to make. Both targets it and all are required.
    install.local
    This target is used to perform installation operations which are specific for the local directory. \TBD{}.

    Modules

    This section describes how to design Graphlet modules. A module is a set of C++ and Graphscript files which implement one or several algorithms. The core of Graphlet itself is divided into three modules: Each module has a name, which must be unique throughout the Graphlet system. There are no restrictions on the name, but it is usually a good idea to choose a descriptive name. Later, the header files of a module name will be installed in a directory name\footnote{As a subdirectory of the Graphlet installation directory, e.g. /usr/local/include on UNIX systems.}, and its library will be installed under the name libname.a\footnote{On UNIX systems}. Graphlet uses the prefix gt_ for its names to prevent name clashes with other software packages. To avoid cluttering the system with too many libraries, modules should contain several algorithms, and should possibly further structured into submodules.

    Guidelines for adding C++ modules

    Example

    An example module can be found in the directory src/gt_algorithms in the Graphlet distribution.

    The Initialization File

    A module mod must provide its initialization code in a file named mod.cpp (respectively. mod.h). The following headers are required for module initialization files:

    The Initialization Procedure

    The initialization procedure for a module mod must be declared as follows:
    int GT_mod_init (Tcl_Interp* interp, GT_GraphScript* graphscript)
    
    where interp is the current Tcl interpreter, and graphscript is a pointer to the current Graphscript class. The initialization procedure must return TCL_OK if the initialization was successful, and TCL_ERROR otherwise.
  • The naming convention is necessary to use the standard initialization macros with application_init.
  • Initialization procedures must never make any assumptions on the sequence in which initialization procedures are called. The only valid assumption is that Graphlet's initializations are called before any algorithm modules are initialized.
  • Guidelines for adding Graphscript modules

    Placement

    During development, Graphscript files are best kept in the developers directory. This is best done with autoloading (see the Tcl documentation for details). For inclusion in the source code distribution, Graphscript files should be placed in the directory lib/graphscript within Graphlet, or in subdirectories of lib/graphscript.

    Filenames in lib/graphscript

    The filenames should reflect the name of the module:

    GNUmakefile modifications

    To add files to the Graphscript library, edit the file
     
      lib/graphscript/GNUmakefile
    
    and add the files to the list of files in the variable TCLFILES. It is also neccessary to re-create the Tcl index after new files were added or changed. This can be done with the following command: \begin{quote} gmake index \end{quote} where gmake is GNU make.
  • Subdirectories do not need to have their own GNUmakefile's. Instead, add all files to lib/graphscript/GNUmakefile. Remember to use relative paths.
  • Initialization

    There are two ways to initialize a Graphscript module:
    1. Tcl will execute any statements at the top level of a Tcl file when it loads the file. Put initialization code here.
    2. (Preferred) Implement an initialization procedure in Tcl (preferably called GT_init_name for module name) and execute that procedure in the initialization procedure of the C++ code. Here is an example:
      code = Tcl_Eval (interp, "GT_name_init");
      if (code == TCL_ERROR) {
          return code;
      }
      
      The Tcl initialization procedure should come at the end of the C++ module initialization, after all Graphscript commands have been installed.

    How to determine what is installed

    Before features are used which are implemented in an optional module, you need to check whether the module is present. Generally, Graphlet installations have the freedom to install or de-install any module. Therefore, it is illegal to make any a priory assumptions about installed modules. It is however possible to obtain information on whether a specific feature is installed:
    C++
    For each module name, Graphlet defines a preprocessor symbol GT_MODULE_NAME (note the capital letters). This can be used to write code which is only executed when a specific module exists:
    #ifdef GT_MODULE_NAME
      ... put code here that needs module name here ...
    #endif
    
    Graphscript
    Tcl goes even one step further than C++ and allows runtime testing for installed commands with info commands. Here is an example how to use that:
    if { [info commands cmd_name] != {} } {
      ... Put code here that needs command cmd_name ...
    }
    
    \begin{note} It is generally a good idea to add menu entries only for those commands which are actually installed. \end{note}

    Building Graphscript Interpreters

    For a quick take, copy and modify Graphlet's graphscript.cpp. After new Graphscript commands have been implemented, it is necessary to build a new interpreter which contains these new commands. Technically, this the same procedure as needed for a standard Tcl interpreter, with Graphscript as an additional module. \begin{note} Tcl/Tk now supports dynamic loading. We will change the initialization procedure at some point in the future to change support dynamic loading. Stay tuned. There should be no major problems unless you use global variables, in which case there will. \end{note}

    The main procedure

    Generally, a main procedure for a Graphscript interpreter should have the following form:
    int main (int argc, char **argv) 
    {
        return GT_GraphScript::gt_main (argc, argv, application_init);    
    }
    
    GT_GraphScript:gt_main is standard method which calls Tk's Tk_Main procedure (see the Tk documentation for details) and parses the command line in argc and argv for GraphScript specific options. application_init must be provided by the application and initializes Graphscript and algorithm modules.
  • It is legal to use the procedure Tk_main instead of GT_GraphScript:gt_main.
  • The procedure application_init

    Each interpreter must provide a procedure application_init which must have the following form:
    //
    // application_init (Tcl_interp* interp)
    //
    // interp is the current Tcl interpreter.
    //
    
    static int application_init (Tcl_Interp *interp)
    {
        //
        // Create a GraphScript handler.
        // For customization, replace the class GT_GraphScript
        // by a derived class.
        //
        
        GT_GraphScript* graphscript = new GT_GraphScript (interp);
        
        //
        // Initialize Tcl, Tk and GraphScript.
        //
        // code holds the Tcl return code.
        //
        
        int code = graphscript->application_init (interp);
    
        //
        // Check for an error. This step is mandatory.
        //
    
        if (code == TCL_ERROR) {
            return code;
        }
    
        //
        // Initialize other algorithm modules
        //
    
    #ifdef GT_MODULE_ALGORITHMS
        GT_ADD_MODULE(gt_algorithms)
    #endif
    
    #ifdef GT_MODULE_LSD
        GT_ADD_MODULE(gt_lsd)
    #endif GT_MODULE_LSD
        
    #ifdef GT_MODULE_GRID_ALGORITHMS
        GT_ADD_MODULE(gt_grid_algorithms)
    #endif GT_MODULE_LSD
        
        return code;
    }
    
  • We recommend the above syntax for the initialization of other modules, provided that these modules conform to the standards described in the module documentation.
  • Graphlet's configuration system automatically defines a macro GT_MODULE_NAME for each installed module name (note the capital letters).
  • The macro GT_ADD_MODULE is provided by Graphlet and performs all actions necessary to initialize a standard module. It will exit the procedure and return TCL_ERROR if the module initialization fails.
  • application_init must return a Tcl error code, that is TCL_OK for a successful return or TCL_ERROR otherwise.
  • Because Tcl is a C library, application_init must be a procedure or a static member function.
  • Linking the program

    \begin{WhoCanSkipThis} This section is meant as a guideline for developers who do not use the binary distribution. Developers who use the source code distribution may use Graphlet's configuration system to create makefiles. \end{WhoCanSkipThis} Link our code with the following libraries:
      Graphlet libraries
      MODULES -lgt_tcl -lgt_base where MODULES is the list of modules as used in application_init above.
      Tcl/Tk libraries
      -ltk -ltcl
      GTL libraries (release 3.4)
      -lP -lG -lL
      X11 and system libraries
      This depends on your operating system, flavor of X11 and local installation policy. Here are some recommendations:
      • On solaris systems (2.4/2.5), we recommend -L/usr/openwin/lib -lX11 -lsocket -lnsl -ldl -lm.
      • On SunOS systems (4.1.*), we recommend -L/usr/openwin/lib -lX11 -lm
      • On Linux systems, we recommend -L/usr/X11/lib -lX11 -ldl -lm
  • If you are linking with GTL 3.3.*, you need to add the library -lWx.
  • The order in which libraries are linked is important. We recommend to link libraries in the order indicated above.
  • \end{document}