OSE - Makeit User Guide

Graham Dumpleton
Dumpleton Software Consulting Pty Limited
PO BOX 3150
Parramatta, 2124
N.S.W, Australia
email: grahamd@nms.otc.com.au

Table of Contents

Core Features
OSE - Makeit User GuideCore Features

Core Features

1 Introduction

Makeit is designed primarily to support development using the C and C++ programming languages. Therefore, makeit focuses on providing support for the creation of reusable libraries and executable programs. This chapter describes the core features of makeit supporting this type of development.

2 Makeit Subdirectory

Whenever you run makeit, all products of the build process, such as the library and programs produced, are placed by makeit into a subdirectory of the directory in which makeit is run. The name of the subdirectory created is derived from the name of the platform and the compilation variant being used.

An identifier for the platform being used is available in the MKTAG variable. The MKTAG variable is set by makeit and usually would not be overridden. The compilation variant in which makeit should operate is defined by setting the VARIANT variable. If you don't define the VARIANT variable, the default variant is used. If you define the VARIANT variable in the makefile, the definition must be included in the initialisation section.

The name of the subdirectory is formed by expanding

  $(MKTAG)_$(VARIANT)
If a Sun Sparc system is being used, the variable MKTAG is by default set by makeit to `SUN4'. If you do not define VARIANT, makeit will set it to `dbg'. The name of the subdirectory created under these circumstances will be `SUN4_dbg'.

The name of the makeit subdirectory may further be modified, by defining the variable MKPREFIX. If defined, the MKPREFIX variable would be defined when OSE is installed and you would not need to override it in your makefile. If you do define the MKPREFIX variable, the definition must appear in the initialisation section of your makefile. When defined, the name of the makeit subdirectory will be the expansion of:

  $(MKPREFIX)$(MKTAG)_$(VARIANT)
Setting MKPREFIX to `.mk_' would allow you to hide the name of the makeit subdirectory in a normal directory listing. If the name of the makeit subdirectory was already quite long, this would make the directory listing less cluttered.

As programs created by makeit are placed into the subdirectory, you will need to remember to prefix the name of the program with the name of the subdirectory, when you wish to run the program. For example:

  SUN4_dbg/two
If you need to use the name of the subdirectory in the makefile, the variable MK should be used. The variable MK has the value formed by expanding `$(MKTAG)_$(VARIANT)', or if MKPREFIX is defined, `$(MKPREFIX)$(MKTAG)_$(VARIANT)'. You should not override the value of MK. The value of the MK variable can only be used in the definitions or dependencies and rules sections of the makefile. The MK variable will not have a value while the initialisation section is being translated and so it should not be used in that section of the makefile.

By default, makeit will always create the subdirectory into which it will place the results of a build. If nothing is ever produced in a directory, this will result in an empty subdirectory being created. The creation of the subdirectory under all circumstances can be prevented by including the definition,

  NOMK := YES
in the initialisation section of the makefile. If you prevent creation, of the subdirectory when it is required, makeit will fail.

3 C Code

Support for the C programming language is enabled by listing `c' in the MODULES variable. All C code files must end with a `.c' extension. Any flags which you wish to pass to the C compiler, should be listed in the CFLAGS variable.

4 C++ Code

Support for the C++ programming language is enabled by listing any of `cc', `C', `c-cc', `cxx' or `cpp' in the MODULES variable. Which module you select, will depend on the extension used for C++ source files. The module names and the extension supported by a module are listed in the table below. Note that the C++ compiler you are using must support the extension in order for you to be able to use it.

-----------------
Module  Extension  
-----------------
cc      .cc        
C       .C         
c-cc    .c         
cxx     .cxx       
cpp     .cpp       
-----------------
If the directory contains C++ source files with different extensions, you can list more than one module. If the directory contains C source files and the `c' module is already being included, the `c-cc' module must not be included. Makeit does not support source files from two different languages with the same extension.

Despite which module is being used, if you wish to pass any flags to the C++ compiler, you should list them in the variable C++FLAGS.

4.1 Selecting a Compiler

When makeit is installed, it is configured to use a particular C++ compiler as the default. If more than one C++ compiler is available, it is possible for you to select the compiler to use. A compiler is selected by listing the identifying name for the compiler in the C++COMPILER variable. If the variable is set, the definition must be included in the initialisation section of the makefile. The following table lists the identifying names for those C++ compilers supported by makeit.

------------------------------------------
Compiler Tag  Vendor                        
------------------------------------------
ATT2.0        AT&T/USL (CFRONT)         
ATT2.1                                      
ATT3.0.?                                    
SUN2.1        Sun Microsystems              
SUN3.0.1                                    
SUN4.0                                      
HP3.?         Hewlett Packard               
EH-HP3.?                                    
DEC1.?        Digital Electric Corporation  
OS1.?         Object Design (ObjectStore)   
OS2.?                                       
OS3.?                                       
GNU2.?        GNU                           
CL1.1         CenterLine                    
CL2.0.?                                     
XL1.?         IBM                           
LC3.?         Lucid                         
SG3.0.?       Silicon Graphics              
------------------------------------------
The name for each compiler is made up from a tag identifying the compiler vendor and the version of the compiler. If for example, Sun C++ Version 3.0.1 is available, the following would be included in the makefile.

  C++COMPILER := SUN3.0.1
When a C++ compiler is selected, a C compiler suitable for use with that C++ compiler will also be selected. If it is required to override the C compiler which is used, the CC variable can be defined to the path of the C compiler you wish to use. The definition of the CC variable should be placed in the initialisation section of your makefile. For example:

  CC := /usr/5bin/cc
To identify, in code, which C++ compiler is being used, a preprocessor symbol identifying the compiler is defined by makeit when compiling all code files. This symbol is formed from the name listed in the C++COMPILER variable, with any occurrence of `.' replaced with an underscore.

For example, if Sun C++, Version 2.1 is being used, the following symbol is defined:

  CXX_SUN2_1
If a compiler represents a minor revision, the full version may not be incorporated into the name. If a minor revision is known to differ in an important way, an additional symbol to identify the compiler will be defined. For example, when Sun C++ Version 3.0.1 is being used, both of the following symbols are defined:

  CXX_SUN3_0
CXX_SUN3_0_1
In addition to defining a symbol identifying the version of the compiler, a symbol to identify just the vendor is defined. For example,

  CXX_OS
is defined for ObjectStore C++.

4.2 Separate Subdirectories for Compilers

If it is necessary to compile code in a directory with multiple C++ compilers, the name of the compiler can be encoded into the name of the makeit subdirectory. This option is selected by including,

  MAKEIT_OPTIONS := encode_compiler_name
in the makefile. The definition must occur in the initialisation section of your makefile. When defined, the name of the subdirectory created by makeit will have the tag identifying the compiler added to the end. For example, if Sun C++ 2.1 is being used, the name of the subdirectory created by makeit will be:

  SUN4_dbg.SUN2_1

5 Code File Types

By default, when you run makeit, it will compile all code files into object files and archive the object files into a library. A code file which is compiled to create an object file which is placed in the library, is refered to as a library code file.

To designate that selected code files should be compiled into executable programs, the names of the programs which will be produced, must be listed in the PROGRAMS variable. The name of each program is determined by dropping the language extension from the name of the code file compiled to generate the program. A code file which is compiled into an executable program is refered to as a program code file.

For example, if a directory contains the files `one.c' and `two.c', and the file `two.c' is a program code file, the PROGRAMS variable is set to:

  PROGRAMS := two
When you run makeit in this directory, it will compile the library code file `one.c' and archive the object file produced into a library, `lib.a', located in the makeit subdirectory. Makeit will then compile the program file `two.c' and link the object file produced with the library to create an executable program.

If a program code file, when compiled, should not be linked with the library, list the name of the program in the NOLIB variable. For example, if the program code file `four.c' were added to the directory, but it was not to be linked with the library, you would define:

  PROGRAMS := two four
NOLIB := three

6 Initiating a Build

To compile everything in a directory, you can run the makeit program with no arguments. Running makeit with no arguments is equivalent to running the command:

  makeit all
When the target `all' is supplied to makeit, makeit will compile each library code file into an object file and archive the object files into a library. Makeit will then compile each program code file and link the object file produced with the library to create a program executable. In addition, makeit will update any other auxiliary files in the directory.

You can have makeit only compile and build the library by running the command:

  makeit lib
To have makeit build both the library and the programs in the directory, you can run the command:

  makeit programs
In addition to directing makeit to build the complete library or all programs, makeit can be directed to compile individual files. Compilation of individual files is achieved by directing makeit to build the object file which is produced from a code file when compiled. For example, to compile the library code file `one.c' you would run the command:

  makeit one.o
Multiple code files can be compiled by listing more than one object file as the target. For example, if the directory contained two library code files, named `one.c' and `three.c', they both could be built by running:

  makeit one.o three.o
If an individual library code file is compiled, the object file created is not placed in the library immediately. Creation of the library will only occur, when a program that needs to be linked with the library is being built. Alternatively, you can force the library to be created by running the command:

  makeit lib
Individual program code files may be compiled by instructing makeit to build the object file, which would be produced by compiling that file. For example, to compile the program code file `two.c' you would run the command:

  makeit two.o
This will result in the object file for that program code file being produced. The object file will not be linked against the library to create an executable program. If it is required that an executable program be produced, the target name for makeit should be the name of the program. For example:

  makeit two
As the program object file must be linked against the library, the library will be built first. If none of the library code files have previously been compiled, this will result in makeit compiling all library code files first.

Multiple programs can be built at the same time by listing as the target, all the program names. For example, if the directory contained two program code files, named `two.c' and `four.c', you then could run the command:

  makeit two four
If a program listed in the NOLIB variable is used as the target to makeit, the library will not be created, even if other programs in the directory require it.

7 Preventing File Compilation

If a directory contains files that you want makeit to ignore, list the full name of the file in the EXCLUDE variable. For example,

  EXCLUDE := three.c
If you want makeit to ignore a number of files, where all match a specific pattern, you can list the pattern in the EXCLUDE variable. For example, to ignore all files with a suffix of `.test.c', you would define:

  EXCLUDE := %.test.c
The character `%', representing any characters, may only appear once in the pattern.

When you list a program code file in the EXCLUDE variable, and the program name still appears in the PROGRAMS variable, the EXCLUDE variable takes precedence. For example, if you list the file, `two.c' in the EXCLUDE variable, it will not be compiled, even if the name `two' also appears in the PROGRAMS variable.

8 Additional Flags

Working in a compilation variant results in certain flags being supplied automatically to compilers. The flags will be whatever is appropriate for the compiler to enable the required feature. This occurs without you having to know what flags are expected.

At times it will still be necessary for you to provide some additional flags. Makeit provides a number of variables which can be defined to pass flags onto the compilers. These variables correspond to the various phases of compiling an application. The core set of variables are CPPFLAGS, LDFLAGS and LDLIBS.

In addition to the core set, different programming languages or code generation tools will have their own set of variables. For example, flags specific to C compilers would be listed in the CFLAGS variable. Flags specific to C++ compilers are listed in the C++FLAGS variable.

Definitions for variables must be included in the definitions section of your makefile. For example:

  MODULES := c cc

include $(OSE_MAKEIT)/init.mk

PROGRAMS := two four

CFLAGS := -sb
C++FLAGS := -sb
LDLIBS := -lm

include $(OSE_MAKEIT)/modules.mk
Variables should not be overridden on the command line when makeit is run. For example, you should not say:

  makeit LDLIBS=-lansi
Defining a variable in this way will cause the value given to the variable in the makefile to be overridden, rather than the value being appended to that given to the variable in the makefile. If you have to provide additional flags from the command line, definitions within the makefile should be in the following form:

  override LDLIBS += -lm
Using this form will cause flags defined in the makefile to be added to those provided on the command line.

If all flags being assigned to a variable will not fit on one line, the continuation character can be used. The continuation character is the backslash, `\'. The character should appear as the last character in a line. The result is that the following line will be joined to the first line.

  override LDLIBS += \
-lm
The purposes of the core makeit variables are described in the following sections.

8.1 CPPFLAGS

Compilers and some code generation tools send code files through the C preprocessor before parsing the file. The CPPFLAGS variable can be used to define flags to be passed to the C preprocessor.

Flags which might appear in CPPFLAGS are, include file search paths and preprocessor symbol definitions. For example:

  CPPFLAGS := -I/usr/openwin/include -DNO_XVPS

8.2 LDFLAGS

Flags defined in LDFLAGS are passed on to the linker when generating program executables. The most common flag to be listed in LDFLAGS is one to define directories to search for libraries. For example:

  LDFLAGS := -L/usr/openwin/lib
Note that not all linkers use the `-L' flag for specifying library search directories. Some linkers expect the flag: '-Wl,-L'. If code is to be ported to one of these platforms, use the variable, LOPT.

  LDFLAGS := $(LOPT)/usr/openwin/lib
LOPT is set by makeit to the type of flag expected by the compiler being used. When LDFLAGS is supplied to the compiler or linker, it will precede the list of libraries to be linked. This allows the linker flags, which should apply to all libraries, to be listed in LDFLAGS. An example is the `-Bstatic' option to force linking of static libraries on Sun platforms.

  LDFLAGS := -Bstatic

8.3 LDLIBS

The LDLIBS variable should list any libraries and object files which must be linked with programs contained in the directory.

  LDLIBS := ../lib/libfoo.a -lX11 -lm /usr/lib/debug/malloc.o
Special linker flags may be included in LDLIBS if necessary.

  LDLIBS := -Bstatic -lX11 -Bdynamic -lm
Previously, libraries linked using the `-l' option, and those linked explicitly using a pathname were listed in separate variables. As of version 3.0 of OSE, the LOADLIBES variable, which was used to list explicit pathnames for libraries and object files should not be used. Libraries linked in either form, and object files, should now all be listed in the LDLIBS variable.

9 Excluding Object Files from the Library

By default, makeit recognises two types of code files, library code files and program code files. In some circumstances, a third type of code file can exist. This third type of file is compiled as if it is a library code file, but will not be archived into the library. The object files from these code files are still available for linking with programs. This situation can arise if multiple programs share code, but where the code is not to be exported in the library. For makeit to recognise this third type of code file, the full name of the file must be listed in the NONLIBSRC variable. For example, if the directory contains the file `five.c' which falls into this category, you would add the following to the definitions section of your makefile.

  NONLIBSRC := five.c
For these files to be compiled, you must create a dependency between the programs that use them and the object generated from the file. If the program being generated from the file, `four.c' required linking with the file, you would include in the dependencies and rules section of your makefile:

  $(MK)/four : $(MK)/five.o
The subdirectory named, using `$(MK)' must be included as shown. If not typed as shown, the file `five.c' will not be compiled and linked with the program generated from `four.c' as required.

10 Dependencies

Unaided, makeit can only determine the direct dependencies that exist between an object file and a code file, or a program and a code file. If code files contain header files, and a header file is changed, the code file will not be recompiled. For makeit to be able to compile code files correctly, when header files change, additional dependencies have to be supplied. This would usually require you to maintain a list of the dependencies which exist between files. In makeit, this process is automated. Instead of you having to add to a list of dependencies manually, the command, `makeit depend' is run when changes are made.

The result of the `depend' target is the creation of a dependency file. The contents of the dependency file are a list of the files used to compile each object file and program. If the dependency file exists, makeit will automatically include it and use it to calculate the targets which need to be rebuilt.

10.1 Dependency File

If not overridden, the name used for the dependency file is `DEPS.mk'. The file will list only header files as dependencies if they come from include directories relative to the source directory. This means that if `-I/usr/openwin/include' is used, any header files under the directory, `/usr/openwin/include' are not listed. Similarly, standard include files under `/usr/include' are not listed. Header files under a directory given by `-I../../include' would be listed though.

To override the name used for the dependency file, you should define the DEPFILE variable. To have all include files listed as dependencies, redefine the filter used to select files listed. The variable containing the description of the filter is DEPFILTER. The default filter is,

  sed -e `/ \/.*/d'
The default filter will delete all header files which have an absolute pathname. For all files to be listed, change the filter to `cat',

  DEPFILTER := cat
As a complete set of dependencies will list system header files, encode the name of the platform into the name of the dependency file,

  DEPFILE := DEPS.$(MKTAG).mk
If you do not incorporate the name of the platform into the name of the dependency file, you will need to delete the dependency file when you move from one platform to another. The reason is that the list of the system header files of each platform is likely to be different.

10.2 Automatic Dependency Generation

Makeit can be made to update the dependency file automatically. This feature is enabled by setting the AUTODEPEND variable to `YES' in the makefile,

  AUTODEPEND := YES
or on the command line when makeit is run,

  makeit AUTODEPEND=YES
The dependency file must still be created the first time by running, `makeit depend'. After that, makeit will recreate dependencies for any changed files automatically when it is run. Note that the recreation of dependencies can be time consuming. Therefore, automatic generation of dependencies is recommended for small projects only.

10.3 Library Dependencies

When libraries are listed in the LDLIBS variable, makeit will not try to create them if they do not already exist. If a library of the form `lib.a' does not exist, makeit will tell you that it cannot be found and will stop before it has done anything. Missing libraries of the form `-llib' will only be detected due to the program linker failing.

If libraries in the form `lib.a', or object files listed in LDLIBS are part of the same project, makeit can be instructed to create them. To have makeit create the missing libraries or object files if they are missing, you need to add a set of actions to your makefile to indicate how to create it.

For example, if an adjacent directory, `mylib', contains a library which needs to be linked with programs in your directory, you would include the following in the dependencies and rules section of your makefile.

  ../mylib/$(MK)/lib.a : ; $(MAKE) -C ../mylib lib
If you need to detect, prior to linking, that a library specified using `-l' option is missing, you need to add an explicit dependency between the programs being generated, and the library. You also need to specify the directory in which the library is located. For example:

  LDFLAGS := -L/usr/lib/X11
LDLIBS := -lX11

vpath %.a /usr/lib/X11

$(addprefix $(MK)/,$(PROGRAMS)) : -lX11
The `vpath' declaration and dependency, must be placed in the dependencies and rules section of your makefile. For more information on `vpath', you are directed to the GNU make documentation.

10.4 Generated Files

Code generators, such as Yacc and Lex, will often create header files which will be included into your code files. If these header files do not exist the first time that you try to update the dependencies, creation of the dependencies will fail. To ensure that a generated file, if it does not exist, is created before the dependencies are created, you must list the file as a dependent of the target `depend.setup'. For example:

  depend.setup :: $(MK)/parser.h

11 Cleaning Up

When work in a directory is complete, or space needs to be reclaimed, makeit can remove any products of the build that can be recreated. The two main targets for triggering the removal of items in a directory are `mostlyclean' and `clean'.

The `clean' target removes all files in the source directory which may have resulted from a failed build. The files removed include object files, core files and output files from profiling tools. In addition to cleaning up the working directory, the `clean' target completely removes the makeit subdirectory.

Note that only the subdirectory for the variant being used is removed. If multiple variants have been used, each will have to be cleaned individually. For example,

  makeit VARIANT=opt clean
makeit VARIANT=prf clean
makeit VARIANT=dbg clean
The `mostlyclean' target, as does the `clean' target, removes all files in the source directory that may have resulted from a failed build. The `mostlyclean' target does not remove the makeit subdirectory. Instead, the `mostlyclean' target only removes object files from the makeit subdirectory. The library and any program executables which have been created will be left in the makeit subdirectory. The `mostlyclean' target is intended only to reclaim space if it is required. Normally, the `clean' target would be used.