							Automatic Header File Generation
									  Cay S. Horstmann

									 mdgen Documentation

0. Purpose of the utility

This utility, for historical reasons called mdgen (module definition
generator), extracts header files from marked up source files.

The utility solves one problem: the separate maintenance of header and
implementation files. In C++, function and variable declarations and class
definitions must be contained in a header file, whereas the implementation
of functions and operations must be placed in an implementation file,
except of course for inline functions. Making a change means fixing two
files. This bothers some programmers a lot, others say `so what'. If
maintaining two sets of files isn't a problem for you, then don't use
mdgen. If it is, read on.

1. Running mdgen

To run mdgen, simply specify the source files you want to scan.

		mdgen date.cpp str.cpp hw*.cpp

This produces (or updates) files date.h, str.h, and hw*.h for all files
matching hw*.cpp.

2. The EXPORT tag

Unfortunately, mdgen is not smart enough to figure out what features to
extract from the source file into the header file. You have to tag all
exported features with the string EXPORT. In practice, this is not a great
problem--certainly less trouble than switching back and forth between edit
windows.

EXPORT is defined in setup.h as the empty string and has no influence on
the compilation.

3. Global variables and functions

Let us start with the easiest case: tagging global variables and functions.
Just prefix them with the tag EXPORT.

		EXPORT int days_per_month[12] = { 31, 28, ..., 31 };

		EXPORT istream& operator>>(istream& is, Date& date)
		{  // ...
		}

Then mdgen places the following lines into the header file:

		extern int days_per_month[12];

		extern istream& operator>>(istream& is, Date& date);


That is, the variable initializer and function body are ignored, and the
declaration is terminated with a semicolon.

You only tag the variables and functions that you want to export. As a
consistency check, see that all global variables and functions are either
tagged as EXPORT or static.

You benefit from the automatic extraction in two ways. You don't have to
type the declaration twice. And if you make a change in the function
definition, file, just run mdgen and let it update the header file for you.

4. Classes

Tag classes with EXPORT:

      EXPORT class Date
		{
		public:
			// ...
		};

The entire class definition is copied to the header file.

You may need to place a class declaration into the header file, either to
deal with circular dependencies or to avoid reading an entire header file.
Just tag the declaration.

		EXPORT class iostream;
		EXPORT class Time;

You only tag the class definitions, not the definitions of the
operations.

5. Other types

Unions, structures, typedef and enumerations are handled just like classes.
Tag them with the EXPORT token.

6. Inline functions

Inline functions must be copied to the header file since the inline
replacements may need to be carried out when compiling other modules.

Tag inline functions with EXPORT.

      EXPORT inline int Date::day() const
		//RETURNS:   the day of this date
		{ return _day; }

      EXPORT inline int Date::month() const
		//RETURNS:   the month of this date
		{ return _month; }

      EXPORT inline int Date::year() const
		//RETURNS:   the year of this date
		{ return _year; }

7. Constants

The handling of constants in C++ is murky. By default, global constants are
static, that is, not visible from other modules. This is to enable the
compiler to perform inline replacement on constants rather than using
memory lookups.

		const int DAYS_PER_YEAR = 365;

		y = d / DAYS_PER_YEAR; // compiles as d / 365

Integer constants can even be used at compile time!

		const int BUFFER_SIZE = 80;

		char buffer[BUFFER_SIZE];

This is different from C. In C, constants always occupy memory and they are
never evaluated at compile time.

Often, the value of such an `inline constant' needs to be visible to other
modules during compilation, and the definition must be placed in the header
file.

In C++, a constant that occupies storage and can be referenced from other
files must be declared and defined as extern const.

		extern const int days_per_month[12] = { 31, 28, ..., 31 };
		extern const Complex imag_unit = Complex(0, 1);

These are fairly rare.

Both cases are handled by mdgen. The tagged definitions 

      EXPORT const int DAYS_PER_YEAR = 365;
		EXPORT extern const int days_per_month[12] = { 31, 28, ..., 31 };

become

		const int DAYS_PER_YEAR = 365;
		extern const int days_per_month[12];

in the header file.

8. Templates

Templates of classes, operations, functions and variables must be copied to
the header file. Tag them with EXPORT.

      EXPORT template<class X> class Array
		/*PURPOSE:    smart array class template
			RECEIVES:   T - any type with copy construction and assignment
		*/
		{
		public:
			// ...
		};

      EXPORT template< class X >
		Array<X>::Array(const Array<X>& b)
		:  _low(b._low),
			_high(b._high)
		{  // ...
		}

9. Header file include directives

To copy an include directive, place a keyword EXPORT on the preceding line.

		EXPORT
		#include <iostream.h>

If the header file doesn't require the contents of iostream.h, except to
know that istream and ostream are classes, you can generate a more
efficient header file by exporting only the class declarations

		// no EXPORT
		#include <iostream.h>

		EXPORT class istream;
		EXPORT class ostream;

10. Miscellaneous preprocessor features

Occasionally, you need to include #ifdef or macros such as DECLARE(X, Y)
in a header file. Any code that is enclosed in between 

   #ifndef EXPORT
   ...
   #endif block.

is copied by mdgen into the header file.

11. Warts

Currently, mdgen is implemented as a compiled awk script. The script has
evolved for over five years and handles most cases smoothly. However, a few
ugly problems remain.

Default arguments must be part of the declaration of a function and not
repeated in the definition. For operations of a class, this is not a
concern since the operation declaration is inside the class and distinct
from the definition. But for global functions, a separate declaration must
be provided.

		EXPORT void display(Factory& f, Bool use_color = TRUE) // DON'T
		{  // ...
		}

Separate this into a declaration followed by a definition

		EXPORT void display(Factory& f, Bool use_color = TRUE);

		void display(Factory& f, Bool use_color)
		{  // ...
		}

This is dumb but fortunately rare.

The mdgen program cannot tell the difference between certain variable
definitions and functions. As a consequence, it will not remove the
initializer. Consider

		EXPORT Complex imag_unit(0, 1); // DON'T

Even many human readers must look twice to see that it is not a function
call. Instead, use

		EXPORT Complex imag_unit = Complex(0, 1); // OK

12. Double scan protection

The header files produced by mdgen are automatically protected against
double scanning. The entire file is surrounded by directives

		#ifndef DATE_H
		#define DATE_H
		// ...
		#endif

13. Error reporting

If you make a syntax error in an implementation file that causes a faulty
header file to be extracted, the compiler will report the error in the
source file, pointing to the actual offending line. The mdgen utility
places #line directives in the header file for this purpose.

If the compiler complains about syntax errors, fix the errors in the source
file and run mdgen again.

15. Interaction with `make' utilities

The mdgen utility respects time stamps of header files. If the changes in
date.cpp do not require a modification in date.h, the old date.h is not
changed. You can simply run

		mdgen *.cpp

to refresh all header files. You need not worry that the `make' or project
file triggers a complete recompile. If no change in a header files was
detected, it is not touched.

You can teach your `make' or project tool a dependency rule to
automatically invoke mdgen. For example, Borland `make' accepts the
following rule set:

		.cpp.obj:
			$(cc) -P $(copts) $<

		.asm.obj:
			$(asm) $<

		.cpp.h:
			mdgen $<

16. Installation as a tool

In Turbo/Borland C++, you can install mdgen as a tool that can be invoked
inside the integrated development environment. Follow these steps for
version 3. For version 4, the steps are similar.

In the "Options|Transfer" dialog, move the cursor to a blank entry and
select "Edit". Set the title to "~mdgen", the path to "mdgen", and the
command line to "$EDNAME $SAVE CUR". Remember to save your options.

To invoke mdgen, hit [Alt+Space] and type "m". The current window is
saved and run through mdgen.
