## 5.3 Details, custom compilation

Read this section if you have problems or want to know more. It is not necessary most of the time.
Most of the development of Gnucap was done on a PC running Linux. I have also compiled it successfully on several other systems, listed at the end of this file. Other users have ported it to several other systems. Some of the files are included in the distribution. They may not have been tested in the latest release. It should compile with any “standard” C++ compiler. It should produce no warnings when compiled with the switches in the supplied makefiles and g++, except those due to the system supplied header files being defective. It requires templates, but not exceptions.
All source files are in the src and modelgen directories. I use subdirectories for the .o files each supported machine. This makes it possible to install it on several different machines all sharing the same file system.
To avoid maintaining multiple versions of Makefiles, I have broken them up to parts that must be concatenated: Make1.*, Make2.*, Make3.*. In general, to make a Makefile for your system, cat one of each. See the Makefile for details. I have automated this for some systems. Just “make your-machine”, if it is one that is supported. In some cases, the Makefile will compile both a “release” and “debug” version. In these cases, type “make your-machine-release” or “make your-machine-debug” depending on which you want. This will make the appropriate Makefile, cd to where the .o's go and run make from there. For porting information for specific machines, read its `Make2.*` file.
I assume that make will follow “VPATH” to find the sources. This system makes it possible to manage several platforms on a single file system which may be NFS mounted to all the supported machines. If your make does not support VPATH, there are three options. The preferred method on unix based systems is to cd to where the .o's go and type `ln -s ../*.cc ../*.h .`. (The command ends with a dot.) This will set up links so the Makefiles will work as intended. In some cases we have set up the Makefile to do this automatically. The second method, which may be needed on systems that don't have symbolic links is to copy the .c and .h files to satisfy make. The third option, where you have only one computer, is to move the machine specific Makefile to the src directory and run make from there.
If you have g++ on a unix type system that is not directly supported, try to compile it by just typing `make`. In most cases this will do it, but you may get a few warnings. If it doesn't work, look in the file `md.h` for hints. Just plain `make` will build a guess at a release version, assuming a Linux-like system with GNU tools.
If you want a development version with additional debugging enabled, type `make debug`. This results in a significant speed penalty.
Then make the installation version, select the machine you have from the make file and make that. The machine specific versions will build in their own directory, have debugging code disabled, and options are set for best speed. The general purpose `make g++` builds a version that is optimized as much as it can be in the general case.
If you have a cfront-type compiler, called `CC`, and your system is not directly supported, try it first by typing `make CC`. Again, you may get a few warnings but it should work. Look in the file `md.h` for hints, if it doesn't work, or if the warnings look serious.
Since C++ is an evolving language, there are some known portability problems. All of them are due to compilers that do not implement the standard correctly. Since the problems will go away in time, I have chosen either not to burden the code with them, except where a few mainstream systems fail. All dependencies should be confined to the two files `md.h` and `md.cc`, if possible.
Here are some possible problems that are no longer supported:

bool
  The C++ language includes a type `bool`, which is not implemented in older compilers. Older compilers just use `int`, and fake it with a `typedef` or `#define`, neither of which work correctly.

Here are some problems that you will need to deal with creatively:

missing files or functions
  Another cause of a port to fail is missing header files or missing function prototypes. Sometimes missing functions can be a problem. The solution to these problems is to supply what is missing. The `md_*` files exist for this purpose. You should make a copy of the appropriate Make2.___ file, patch it to define something to identify the system, then patch the `md.h` and `md.cc` as appropriate. You should not use any `#ifdef`'s except in these file.
bad header files
  In some cases, the header files that come with the system or compiler are defective and generate warnings without anything wrong with the program being compiled. This slips by in the distribution because most developers compile with warnings off. Usually, these can be ignored.

Here are some problems that have work-arounds:

const
  C++ uses an abstract notion of constant, meaning that the external appearance of an object declared const must not change, but there can be internal changes like reference counters. The keyword `mutable` means that a member variable can change even if it is declared const. As a work around, we use CONST, which is either defined to nothing or const. For any good compiler, the line `#define CONST const` will give correct behavior. For a bad compiler, the line `#define CONST` will turn it off. There is no harm in treating all compilers as “bad” except for the loss of compile diagnostics.
complex
  The evolving standard shows complex to be a template class, so instead of having a type `complex`, there is `complex<double>`, `complex<float>`, and so on. Older compilers have only `complex`. The line `typedef std::complex<double> COMPLEX;` in `md.h` works for a correct compiler. You may need to change it of an older one.
template instantiation
  There are three common ways to instantiate templates in common use. Unfortunately, they are incompatible and none of the methods are available in all compilers. Gnucap requires templates, so will not work with many older compilers.
  Link time
    The entire program is compiled and linked without templates, resulting in some unresolved externals. The files defining the templates are compiled again to fill the need. This is the preferred way, if you have it. It is supported by CFRONT derivatives such as the Sun CC compiler. Define `LINK_TEMPLATES` to force it.
  Compile time
    All parts of templates must be compiled as if in-line, requiring all code to be in the .h file, or included by the .h file. Header files must include .cc files. The duplicates are supposed to be thrown away by the linker. This is the only style supported by Borland 3.1 or 4.0. It is supported inefficiently by the GNU compiler starting at version 2.6. Since no mainstream compiler requires this, and it is inefficient, it is no longer supported.
  manual
    Templates must be instantiated manually. This is the preferred way for the GNU and Microsoft compilers. It is a nuisance, but it generates the best code. Define `MANUAL_TEMPLATES` to force it.
template resolution
  The second inconsistency with templates is how the type matching is resolved. Some compilers require an exact match. Some will make trivial conversions, such as int to const int. The language definition allows for templates to be “specialized” by providing a specific implementation for a specific type, resorting to the template for others. Some compilers (Sun) do not support this. Since this is common, there are work arounds in the code for it in the simulator but not the model compiler. If you want to compile the model compiler, you will need to get a better C++ compiler.

The files starting with `plot` contain plotting drivers are generally bogus.
There should be NO non-portable code anywhere but the `md_*` files. If a fix is absolutely necessary elsewhere, `#define` some symbol in `md.h` and refer to it elsewhere. Then consider it to be temporary.