MIRA
Build System


Contents

Overview

The make system is based on CMake (http://www.cmake.org/).

With CMake the build process is specified in CMakeLists.txt files. Each directory of a source tree must contain such a CMakeLists.txt file.

Subdirectories must be specified using the ADD_SUBDIR(subdirectory) macro within the CMakeLists.txt of the parent directory. (Please note that subdirectories with the reserved names "tests" or "examples" are included in the associated configuration only (see Build). )

Build

The make system uses out-of-source builds in order to keep the source directories clean. It can be used to build the software in different configurations. The two major configurations are:

However, some additonal configurations are available for test cases, examples and advanced code analysis:

Please note: Once tests or examples have been built, they will be included in the associated debug or release configurations. e.g. if you have compiled the test cases with the test configuration, they will be rebuild (if necessary) if you are running the debug configuration.

In order to build the complete source tree in a certain configuration, go to the root directory of your project and type:

#> make <configuration>

e.g.

#> make release

CMake will be invoked automatically, hence a call of cmake . is not necessary and will fail, since in-source-builds are not allowed. The debug configuration is the default, so just make will build the debug configuration.

Where are my Binaries ?

The make system will create a separate build/<configuration> subdirectory, where all generated libraries, binaries and intermediate build files are stored. The subdirectories in build/<configuration> will have the same structure as the source tree and you will find the created binaries and libraries in the subdirectory that corresponds to the source directory containing the CMakeLists.txt for building that binary.

If e.g. your source files and the CMakeLists.txt are located in

examples/MyProgram/

the generated binaries for the debug, release and test builds will be located in the following subdirectories:

build/debug/examples/MyProgram/
build/release/examples/MyProgram/
build/test/examples/MyProgram/

Building Particular Targets

If you do not want to build all targets in a directory and all its subdirectories, you can specify the target you want to build. The target usually has the same name as the binary you are building (executable or library). To build a particular target only, type:

#> make <target>

To build a particular target in a particular configuration, type:

#> make <target>_<configuration>

E.g. if you have a binary called "MyProgram", you can build that target in debug configuration (the default) by typing:

#> make MyProgramm

To build it in the release configuration, you can type:

#> make MyProgramm_release

To see a list of all available targets type:

#> make help

Building Particular Packages

Similar to certain targets, the build system allows to build whole packages with all contained components.

#> make PACKAGE_<package name> (e.g. make PACKAGE_MyPackage)

To build it in the release configuration, you can type:

#> make PACKAGE_<package name>_release (e.g. make PACKAGE_MyPackage_release)

For building packages you can also use the miramk bash extension, that allows you to build all targets of a package without needing to cd into the source directory of that package. After activating the Mira Bash Extensions you just need to type:

#> miramk <package name> <build configuration> [make options]

For example:

#> miramk MyPackage release -j5

Using miramk

If you have sourced mirabash (see here) you can use the command miramk to build particular packages:

#> miramk MyPackage:release

Special targets

all

Specifying the target "all" explicitly is not necessary. make all is equivalent to make and - since the debug configuration is the default - this is equivalent to make debug. Similarly, make all_release is equivalent to make release

clean

The target "clean" can be used to remove the results of a previous build in order to prepare a clean rebuild. In order to remove all files that were generated by a debug build type:

#> make clean

or

#> make clean_debug

To remove all files that were created in a release configuration build, type:

#> make clean_release

install

make install installs all necessary files for a fully operational MIRA distribution into the installation directory. The installation path can be specified using DESTDIR, e.g.:

#> make DESTDIR=/path/to/somewhere/MIRA install

In order to create and install a release version of MIRA use:

#> make DESTDIR=/path/to/somewhere/MIRA install_release

Experimental

This special target performs a full CTest Experimental build. It checks out the latest version of MIRA from the repository, compiles all, runs all tests, and uploads the results to the CDash server.

#> make Experimental

How do I create my own component ?

The build process of each component (library or executable) is described by CMakeLists.txt files.

The component can depend on Packages. A dependency to a package can be specified by adding MIRA_REQUIRE_PACKAGE or MIRA_OPTIONAL_PACKAGE macros to its CMakeLists.txt file. The package name is specified as parameter, e.g.:

MIRA_REQUIRE_PACKAGE(MIRAFramework)

MIRA_OPTIONAL_PACKAGE should be used if the component does not strictly depend on that package, but can make use of its contents.

Additional, include paths that are necessary for building the component can be added using:

INCLUDE_DIRECTORIES(
path1
path2
path3
...
)

in the CMakeLists.txt file.

Creating a library component

To add a new target that creates a library, add

MIRA_ADD_LIBRARY(<LibraryName>
SHARED
PACKAGE <package>
EXPORT_SYMBOL <export-symbol>
SOURCE
SourceFile1.C
SourceFile2.C
...
QT_UIs
UIFile1.ui
UIFile2.ui
...
QT_MOCs
HeaderFile1.h
HeaderFile2.h
...
QT_QRCs
QRCFile1.qrc
QRCFile2.qrc
...
QT_TRs
trFile_en.tr
trFile_de.tr
...
QT_TR_SOURCES
HeaderFile1.h
SourceFile1.C
...
QT_TR_INCLUDES
IncludeDir1
IncludeDir2
...
LINK_LIBS
Lib1
Lib2
...
INSTALL_FILES
SourceFile1 DestDir1
SourceFile2 DestDir2
...
DONT_INSTALL
)

to your CMakeLists.txt.

In Linux this will create a shared library with the name lib<LibraryName>.so*, in Windows a <LibraryName>.dll will be created. Instead of SHARED also the options STATIC or MODULE can be used. Please use the cmake manual for more details on this.

If the library belongs to a package, the option PACKAGE can be used to define the owning package. The target library will get the version and cmake component information from the package management system.

PACKAGE, PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCH and PACKAGE_VERSION (aggregated number for comparison) will be added to the preprocessor as defines.

Note: These identifiers can be used to write version-aware code (in the most simple case, just able to output its version). However, keep in mind they describe the currently compiling target, they do not know about which package provides which file. Do not use them in header files (or anything to be included elsewhere).

When compiling on Windows, the EXPORT_SYMBOL will be added to the preprocessor as a define, which should be used for the handling of the DLL import/export macros. It is used to export classes and functions in DLLs. You need an extra header defining the EXPORT_SYMBOL like:

// file: MyExports.h
#ifndef _MIRA_MYEXPORTS_H_
#define _MIRA_MYEXPORTS_H_
#ifdef MIRA_WINDOWS
# ifdef MY_EXPORTS
# define MY_EXPORT __declspec(dllexport)
# else
# define MY_EXPORT __declspec(dllimport)
# endif
#else
# define MY_EXPORT
#endif
#endif

In your makefile you would then write:

MIRA_ADD_LIBRARY(MyLibrary
SHARED
PACKAGE MyPackage
EXPORT_SYMBOL MY_EXPORTS
....

and then you can export your classes and functions in your library as follows:

// file: MyHeader.h
#include <MyExports.h>
class MY_EXPORT MyClass
{
...
};
void MY_EXPORT myFunction();

All libraries (or target names) provided by LINK_LIBS will be linked to the new library.

The created library will be installed in the directory lib if not disabled by the parameter DONT_INSTALL.

The parameter INSTALL_FILES can be used to specify additional files, which should be install in the root directory.

All files must be specified with their relative path to the CMakeLists.txt file, e.g. src/MyProgram.C.

This macro works as alternative for the built-in ADD_LIBRARY macro. This macro performs the following steps:
-# Add the library as a new target using ADD_LIBRARY

  1. Setting library version if a version is specified by the owning package
  2. Define a symbol for the Windows DLL exports
  3. Link the library using the built-in TARGET_LINK_LIBRARIES
  4. Install optional other files to somewhere

Creating an executable component

To add a new target that creates an executable binary, add

MIRA_ADD_BINARY(<BinaryName>
PACKAGE <package>
SOURCE
SourceFile1.C
SourceFile2.C
...
QT_UIs
UIFile1.ui
UIFile2.ui
...
QT_MOCs
HeaderFile1.h
HeaderFile2.h
...
QT_QRCs
QRCFile1.qrc
QRCFile2.qrc
...
QT_TRs
trFile_en.tr
trFile_de.tr
...
QT_TR_SOURCES
HeaderFile1.h
SourceFile1.C
...
QT_TR_INCLUDES
IncludeDir1
IncludeDir2
...
LINK_LIBS
Lib1
Lib2
...
INSTALL_FILES
SourceFile1 DestDir1
SourceFile2 DestDir2
...
DONT_INSTALL
)

to your CMakeLists.txt.

This macro will compile and install a new binary.

The option PACKAGE can be used to define the owning package. The binary will get the cmake component information from the internal package management.

Like for library targets, PACKAGE, PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCH and PACKAGE_VERSION will be added to the preprocessor as defines.

All libraries (or target names) provided by LINK_LIBS will be linked to the new binary.

The created binary will be installed in the directory bin if not disabled by the parameter DONT_INSTALL.

The parameter INSTALL_FILES can be used to specify additional files, which should be install in the root directory.

All files must be specified with their relative path to the CMakeLists.txt file, e.g. src/MyProgram.C.

This macro works as alternative for the built-in ADD_EXECUTABLE macro. The macro perform the following steps:

  1. Add the binary as a new target using ADD_EXECUTABLE
  2. Handle Qt4 ui-Files, moc's and resources
  3. Link the library using the built-in TARGET_LINK_LIBRARIES
  4. Install optional other files to somewhere

Creating a Test Case

To add a new target that creates a test case binary, add

MIRA_ADD_TEST(<TestBinaryName>
PACKAGE <package>
SOURCE
SourceFile1.C
SourceFile2.C
...
QT_UIs
UIFile1.ui
UIFile2.ui
...
QT_MOCs
HeaderFile1.h
HeaderFile2.h
...
QT_QRCs
QRCFile1.qrc
QRCFile2.qrc
...
LINK_LIBS
Lib1
Lib2
...
)

to your CMakeLists.txt.

This macro works as alternative for the built-in ADD_TEST macros. The macro perform the following steps:

  1. Set the BOOST_TEST_DYN_LINK and BOOST_TEST_MODULE preprocessor flags
  2. Add the binary as a new target using ADD_EXECUTABLE
  3. Handle Qt4 ui-Files, moc's and resources
  4. Link the library using the built-in TARGET_LINK_LIBRARIES
  5. Add a test case using ADD_TEST

How can others use my components easily ?

Components can be assembled in a 'Package'' to make them usable by others. As described here, packages contain meta information such as dependencies to other packages and include directories.

In order to integrate your component into a package, you need to provide a package file.

This package file should contain all dependencies of your component, that others need when they are using it (include paths, etc.). Therefore, it may be necessary to move some INCLUDE_DIRECTORIES() macros from your CMakeLists.txt file into the package file. Since your own component also requires those dependencies, you need to require your own package in your CMakeLists.txt file using the MIRA_REQUIRE_PACKAGE macro.

How can I use the build system from an external project ?

The MIRA make scripts can also be used from external directories outside of the MIRA directories. If you want to use the make scripts in your own project, use the mirawizard tool to create a new project. Do not forget to add the root path to your project dir to the MIRA_PATH environment variable.

After that you can build your project similar to MIRA using the same features of the Make System described in this document.

Does mira support cross compile ?

The build system does support cross compile and is tested to work with cross compiling for Raspberry Pi. Please go to Cross Compiling for more information.

Important Predefined Variables

VariablePurposeExamples
${CMAKE_SOURCE_DIR}The root path of your current project.
/home/user/myproject/
${MIRA_EXTERNAL_DIR}The root path where all external 3rd party files should be located (downloaded, copied, etc.). This external path is located WITHIN your current project directory.
Note
This variable can be used in CMakeLists.txt etc, but never resolve it within a .package file: Package files are meant to be included from other packages, which can be installed in a different project directory, meaning MIRA_EXTERNAL_DIR will resolve to a path within that project (where the referenced 3rd party files are not located).
Use something like this instead:
GET_ASSOCIATED_MIRA_PATH( ${CMAKE_CURRENT_LIST_FILE} associatedMIRAPath )
SET(3RDPARTYLIB_ROOT_DIR "${associatedMIRAPath}/external/3rdPartyLib")
/home/user/myproject/external/
${MIRA_ROOT_DIR}The root path of the MIRA Core installation. This path does NOT point to your current project root. In Makefiles outside the MIRA Core directory, you should never write files within this directory, since it might be read-only, e.g. if it is located in /opt, etc.
/home/user/mira/
/opt/mira/