# Compile an mlpack program

Once an mlpack application has been developed, it is easy to compile it into a
standalone program.  On this page, compilation is performed via the command-line
on a standard Linux or OS X system; if this is not your environment, see also:

 * [Cross-compile to a Raspberry Pi 2](../embedded/crosscompile_armv7.md)
 * [Deploy mlpack on Windows](deploy_windows.md)

## Simple command-line compilation

Assuming that mlpack and its dependencies are [installed on the
system](install.md), an mlpack program can be compiled just like any other C++
program:

```sh
g++ -std=c++17 -O3 -o mlpack_program mlpack_program.cpp -larmadillo -fopenmp
```

The command above uses [gcc](https://gcc.gnu.org/) to compile the program
`mlpack_program.cpp` in C++17 mode with optimizations, using OpenMP for
parallelization.  It is expected that `mlpack_program.cpp` has the `int main()`
function defined.

For more complex applications that have multiple source files, it can often be
easier to develop a simple [`Makefile`](https://www.gnu.org/software/make/manual/html_node/Simple-Makefile.html).

The [examples repository](https://github.com/mlpack/examples) contains several
standalone C++ projects, each of which have `Makefile`s.  These can be adapted
for any project, and are especially useful if any extra include directories or
library directories need to be specified.  (This might be the case if, for
instance, mlpack or any dependencies are not installed to standard locations.)

 * [Example adaptable `Makefile`](https://github.com/mlpack/examples/blob/master/cpp/neural_networks/mnist_cnn/Makefile)

A full list of compiler options to configure the build is beyond the scope of
this simple documentation, but
[this simple list](https://gist.github.com/g-berthiaume/74f0485fbba5cc3249eee458c1d0d386)
has a handful of commonly-used gcc/clang options.

### Configuring mlpack with compile-time definitions

Several compilation options can control the behavior of an mlpack program.
These can be specified directly on the command line, or at the top of the
program (before including mlpack or Armadillo!).

| ***Command-line option*** | ***Code option*** | ***Meaning*** |
|---------------------------|-------------------|---------------|
|*Speed and debugging.* |||
| `-DNDEBUG` | `#define NDEBUG` | Remove all debugging checks.  This can result in slightly faster code, but with no error checking! |
| `-DARMA_NO_DEBUG` | `#define ARMA_NO_DEBUG` | Remove all Armadillo error checking.  *Warning:* if there are errors in your code, you are more likely to get a segfault instead of an exception! |
|---------------------------|-------------------|---------------|
|*Output.* |||
| `-DMLPACK_COUT_STREAM=std::cout` | `#define MLPACK_COUT_STREAM std::cout` | Set the default output stream.  (Defaults to `std::cout`.) |
| `-DMLPACK_CERR_STREAM=std::cerr` | `#define MLPACK_CERR_STREAM std::cerr` | Set the default error stream.  (Defaults to `std::cerr`.) |
| `-DMLPACK_PRINT_INFO` | `#define MLPACK_PRINT_INFO` | Print information messages (`[INFO ]`) during program execution. |
| `-DMLPACK_PRINT_WARN` | `#define MLPACK_PRINT_WARN` | Print warning messages (`[WARN ]`) during program execution. |
| `-DMLPACK_SUPPRESS_FATAL` | `#define MLPACK_PRINT_FATAL` | Do not print `[FATAL]` messages during program execution. |
| `-DENS_PRINT_INFO` | `#define ENS_PRINT_INFO` | Print informational messages from [ensmallen](https://www.ensmallen.org/) optimizers. |
| `-DENS_PRINT_WARN` | `#define ENS_PRINT_WARN` | Print warning messages from [ensmallen](https://ensmallen.org/) optimizers. |
|---------------------------|-------------------|---------------|
|*Functionality.* |||
| `-DMLPACK_ENABLE_ANN_SERIALIZATION` | `#define MLPACK_ENABLE_ANN_SERIALIZATION` | Allow neural network layers to be serialized. |
| `-DMLPACK_NO_STD_MUTEX` | `#define MLPACK_NO_STD_MUTEX` | Disable mutexes inside mlpack; use this if your system has no support for `std::mutex` and has only one core.  You may also need to define `ARMA_DONT_USE_STD_MUTEX` for Armadillo. |
|---------------------------|-------------------|---------------|
|*Configuration.* |||
| `-DMLPACK_USE_SYSTEM_STB` | `#define MLPACK_USE_SYSTEM_STB` | Use the version of STB available on the system instead of the version bundled with mlpack.  If set, make sure `stb_image.h`, `stb_image_write.h`, and `stb_image_resize2.h` are available. |
| `-DMLPACK_DONT_USE_SYSTEM_STB` | `#define MLPACK_DONT_USE_SYSTEM_STB` | Force usage of the bundled version of STB.  Only necessary if mlpack was [configured](install.md#cmake-options) with `USE_SYSTEM_STB=ON`. |

***Note:*** If your code serializes (saves or loads) mlpack neural networks, the
`MLPACK_ENABLE_ANN_SERIALIZATION` option must be enabled.  This option is not
enabled by default because it can cause compilation time to increase
significantly, but it is necessary for any code that serializes neural networks.

## Linking without the Armadillo wrapper

Armadillo, by default, requires linking against the runtime library
`libarmadillo.so` (or `libarmadillo.dylib` or `armadillo.dll` on non-Linux
systems).  This library is a convenience library that internally contains all of
the symbols necessary from lower-level libraries (e.g.
[OpenBLAS](https://www.openblas.net/),
[SuperLU](https://portal.nersc.gov/project/sparse/superlu/),
[ARPACK](https://www.arpack.org/),
[HDF5](https://www.hdfgroup.org/solutions/hdf5/), and so on).
When the wrapper library is used, linking against Armadillo means simply typing
`-larmadillo` instead of linking against all of Armadillo's dependencies.

In some situations this is not preferable, and it is therefore possible via the
[`ARMA_DONT_USE_WRAPPER` macro](https://arma.sourceforge.net/docs.html#config_hpp)
to avoid the Armadillo runtime library and link directly against Armadillo's
dependencies.

When the Armadillo wrapper library is not being used, a compilation command will
need to be adjusted.  For instance, the example of the previous section would
need to be changed to:

```
g++ -DARMA_DONT_USE_WRAPPER -std=c++17 -O3 -o mlpack_program mlpack_program.cpp -lopenblas -fopenmp
```

Some notes on the command above:

 * Here, `ARMA_DONT_USE_WRAPPER` is specified on the command line instead of in
   `mlpack_program.cpp` (or otherwise in the Armadillo
    [configuration](https://arma.sourceforge.net/docs.html#config_hpp)).

 * OpenBLAS is used for BLAS/LAPACK support.  But, other options include ACML,
   reference LAPACK/BLAS, Intel MKL, and so forth.

 * In some programs, especially if sparse matrix support or HDF5 support is
   used, it may be necessary to link against other libraries (e.g. `-lSuperLU
   -lhdf5`, etc.).  The precise set of libraries to link against depends on the
   code being used and the system configuration, but it should be easy enough to
   use any linker errors to figure out what libraries need to be linked against.

## Using mlpack in another CMake project

For complex C++ projects, a build system like CMake may be in use.  Adding
mlpack as a dependency to a C++ project is straightforward.  The following CMake
code will require mlpack and its dependencies to be available:

```cmake
# Find mlpack and its dependencies.
find_package(Armadillo REQUIRED)
find_package(cereal REQUIRED)
find_package(ensmallen REQUIRED)
find_package(mlpack REQUIRED)

include_directories("${ARMADILLO_INCLUDE_DIRS}" "${CEREAL_INCLUDE_DIR}"
    "${ENSMALLEN_INCLUDE_DIR}" "${MLPACK_INCLUDE_DIR}")

# Targets should link against ${ARMADILLO_LIBRARIES}.
```

If the relevant files are not available on the system to find those four
packages, they can be downloaded from the
[models](https://github.com/mlpack/models) repository:

 * [`models/CMake` directory](https://github.com/mlpack/models/tree/master/CMake)

The following files in that directory are necessary (and can be added to the
CMake files for the project):

 * [`ARMA_FindACML.cmake`](https://github.com/mlpack/models/blob/master/CMake/ARMA_FindACML.cmake)
 * [`ARMA_FindACMLMP.cmake`](https://github.com/mlpack/models/blob/master/CMake/ARMA_FindACMLMP.cmake)
 * [`ARMA_FindARPACK.cmake`](https://github.com/mlpack/models/blob/master/CMake/ARMA_FindARPACK.cmake)
 * [`ARMA_FindBLAS.cmake`](https://github.com/mlpack/models/blob/master/CMake/ARMA_FindBLAS.cmake)
 * [`ARMA_FindCBLAS.cmake`](https://github.com/mlpack/models/blob/master/CMake/ARMA_FindCBLAS.cmake)
 * [`ARMA_FindCLAPACK.cmake`](https://github.com/mlpack/models/blob/master/CMake/ARMA_FindCLAPACK.cmake)
 * [`ARMA_FindLAPACK.cmake`](https://github.com/mlpack/models/blob/master/CMake/ARMA_FindLAPACK.cmake)
 * [`ARMA_FindMKL.cmake`](https://github.com/mlpack/models/blob/master/CMake/ARMA_FindMKL.cmake)
 * [`ARMA_FindOpenBLAS.cmake`](https://github.com/mlpack/models/blob/master/CMake/ARMA_FindOpenBLAS.cmake)
 * [`FindArmadillo.cmake`](https://github.com/mlpack/models/blob/master/CMake/FindArmadillo.cmake)
 * [`FindEnsmallen.cmake`](https://github.com/mlpack/models/blob/master/CMake/FindEnsmallen.cmake)
 * [`Findcereal.cmake`](https://github.com/mlpack/models/blob/master/CMake/Findcereal.cmake)
 * [`Findmlpack.cmake`](https://github.com/mlpack/models/blob/master/CMake/Findmlpack.cmake)

<!-- TODO: improve this so that it is simpler in the future! -->
