Large multiple file programs

1.General principles

When using Mathemagix for the development of large mathematical programs which usually consist of lots of files, one should keep in mind one important design principle:

For any Mathemagix file my_program.mmx which is to be compiled into a binary, the set of all dependencies for my_program.mmx can be deduced from the source code in my_program.mmx.


For any Mathemagix file helper_program.mmx which is only to be compiled into an object file, the set of all dependencies for helper_program.mmx can be deduced from the source code in helper_program.mmx.

As a consequence of these principles, the compilation process for large projects is easy to understand: the programmer should just make sure to carefully include the correct include files for every individual file in the project. The compiler will then take care of determining the various dependencies and compiling the files in the project in the right order and in parallel whenever possible.

Notice that these rules are not satisfied in several other programming languages such as C or C++: in this case, there is usually a makefile for the project which describes the dependencies and all kinds of compiler and linker flags which are necessary for building the executable. Mathemagix on the other hand does not require any particular configuration or makefiles in order to compile multiple file projects. Also the number of command line options is strongly reduced with respect to languages such as C or C++.

In the case when some of the functionality of a Mathemagix program is imported from C++, the user should use the keywords cpp_include, cpp_flags and cpp_libs in order to specify the dependencies on the C++ code and the particular compiler and linker flags to be used in order to compile the C++ code. We refer to the chapter on interfacing with C++ for more details.

2.Inclusion of files

Other files can be included into a given Mathemagix file using the keyword include. Mathemagix provides three modes for the inclusion of other files: ordinary public inclusion, private inclusion and virtual inclusion.

2.1.Public inclusion

When including a file a.mmx into the file b.mmx using

include "a.mmx";

all public functions, classes and categories from the file a.mmx are made available in the file b.mmx. Moreover, for any chain of public inclusions b.mmx c_1.mmx c_n.mmx (we say that b.mmx is indirectly and publicly included by c_n.mmx), the public functionality of a.mmx is also available in c_n.mmx.

Public inclusions thus induce a dependency of b.mmx on a.mmx as well as of c_n.mmx on a.mmx for any file c.mmx which indirectly includes b.mmx. When building a large project in parallel, this means that both b.mmx and c.mmx will have to be recompiled whenever a change occurs in the public interface of a.mmx.

2.2.Private inclusion

In order to reduce the number of dependencies inside a large project, it is possible to use the mechanism of private inclusions whenever appropriate. When including a file a.mmx into the file b.mmx using

private include "a.mmx";

all public functions, classes and categories from the file a.mmx are made available in the file b.mmx. However, the functionality of a.mmx remains hidden for any other file c.mmx which directly or indirectly includes a.mmx (except when c.mmx includes a.mmx itself, or via some other file different from b.mmx, of course). On the other hand, if a.mmx indirectly and publicly includes a file A.mmx, then A.mmx remains an indirect (although private) inclusion of b.mmx, so all public functionality of A.mmx is also available in b.mmx.

In summary, a private inclusion of a.mmx in b.mmx still induces a dependency of b.mmx on a.mmx, but the transitivity of the inclusion relation is broken.

2.3.Virtual inclusion

When using the mechanism of private inclusion, we still introduce dependencies for the build process: whenever the public interface of the included file a.mmx changes, the file b.mmx where the inclusion occurred needs to be recompiled.

On some occasions, none of the functionality of a.mmx is actually needed in b.mmx or any other file which includes b.mmx (directly or indirectly). Indeed, it may happen that we just want to ensure that some initialization code present in a.mmx is executed before we start executing b.mmx. For instance, the file a.mmx might initialize some table which was declared in a file A.mmx which is included both by a.mmx and by b.mmx, and such that the code in b.mmx will only work correctly after initialization of this table.

Whenever the above situation occurs, we may perform a virtual inclusion of a.mmx into b.mmx

virtual include "a.mmx";

Virtual inclusions do not create any dependencies for the build process, but they do influence the list of files which need to be compiled and linked, as well as the order in which the various files of the project are executed (see section ? below).

2.4.Circular inclusions

Whatever inclusion modes are used, no circular chain of inclusions is allowed in Mathemagix.

In the case when some code in a file b.mmx depends on some code in the file a.mmx and vice versa, the programmer will have to explicitly include prototypes for the required functionality in one of the files. Class prototypes are declared using the syntax

class Simple_Class;
class Container (P_1: T_1, …, P_n: T_n);

Function prototypes are declared using the syntax

fun (arg_1: T_1, …, arg_n: T_n);

3.Order of execution

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License. If you don't have this file, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.