NOTE: This page describes the internal structure of MRPT sources, which is intended for MRPT developers/contributors. More often, users will be interested in writting their own programs that use MRPT, as described here. NOTE 2: See also the Phyton script MRPT/scripts/bootstrap_new_lib.py which automates the creation of a new library in the MRPT source tree.
The MRPT source tree looks like this:
The part of interest here is the "libs" directory, where there are a number of libraries or "modules", all with a common structure, which is described here.
The name of all the libraries must be "mrpt-<name>", where <name> is a lowercase word describing the module. Examples are "slam", "base", or "vision". Note that the directories under "MRPT/libs/" are named "<name>", not "mrpt-<name>", while the library itself to be generated after building will be mrpt-<name>.dll (or .so for UNIX systems).
Each "module" mrpt-<name> must have, at least, these files and directories:
#include <mrpt/name.h> )#include <mrpt/name.h> )For template contents for each of the required files, please take a look at some of the simplest libraries, like "mrpt-topography" under MRPT/libs/topography. Note that this structure keeps the header files of each library separately, so the user of MRPT must specify the dependencies in his/her CMake configuration file, as described here.
If there are no complex conditional compiling options or any other complications, declaring an MRPT library is as simple as writing just the following in its CMakeListst.txt file:
#--------------------------------------------- # Macro declared in "DeclareMRPTLib.cmake": #--------------------------------------------- define_mrpt_lib( # Lib name name # Dependencies mrpt-base .... )
Notice that files matching the patterns *_LIN.cpp and *_WIN.cpp are automatically ignored when building under Windows or Linux/MacOS, respectively. For the usage of more advanced features, please refer to DeclareMRPTLib.cmake or the scripts for the existing libraries.
Each library "name" must have a header file to define the proper import/export pragmas needed by Visual C++ to compile DLLs and next import their symbols from a user program. Use as template any of the files in existing MRPT libraries, or this one, replacing "name" and "NAME" by their real values (case sensitive!):
#ifndef @NAME@_link_pragmas_H
#define @NAME@_link_pragmas_H
#include <mrpt/config.h>
#include <mrpt/utils/boost_join.h>
// ** Important! **
// In each mrpt library, search and replace:
// MRPT_XXX_EXPORT, MRPT_XXX_IMPORT
// @NAME@_IMPEXP, mrpt_xxx_EXPORTS
// If we are building the DLL (_EXPORTS), do not link against the .lib files:
#if !defined(mrpt_@name@_EXPORTS) && (defined(_MSC_VER) || defined(__BORLANDC__))
# if defined(_DEBUG)
# pragma comment (lib, BOOST_JOIN( BOOST_JOIN("libmrpt-@name@",MRPT_VERSION_POSTFIX),"-dbg.lib"))
# else
# pragma comment (lib, BOOST_JOIN( BOOST_JOIN("libmrpt-@name@",MRPT_VERSION_POSTFIX),".lib"))
# endif
#endif
/* The macros below for DLL import/export are required for Windows only.
Mostly all the definitions in this file are copied or at least topod
on the file wx/dlimpexp.h, written by Vadim Zeitlin and published
under the wxWindows licence.
*/
#if defined(MRPT_OS_WINDOWS)
/*
__declspec works in BC++ 5 and later, Watcom C++ 11.0 and later as well
as VC++ and gcc
*/
# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__GNUC__) || defined(__WATCOMC__)
# define MRPT_@NAME@_EXPORT __declspec(dllexport)
# define MRPT_@NAME@_IMPORT __declspec(dllimport)
# else /* compiler doesn't support __declspec() */
# define MRPT_@NAME@_EXPORT
# define MRPT_@NAME@_IMPORT
# endif
#elif defined(MRPT_OS_OS2) /* was __WXPM__ */
# if defined (__WATCOMC__)
# define MRPT_@NAME@_EXPORT __declspec(dllexport)
/*
__declspec(dllimport) prepends __imp to imported symbols. We do NOT
want that!
*/
# define MRPT_@NAME@_IMPORT
# elif defined(__EMX__)
# define MRPT_@NAME@_EXPORT
# define MRPT_@NAME@_IMPORT
# elif (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
# define MRPT_@NAME@_EXPORT _Export
# define MRPT_@NAME@_IMPORT _Export
# endif
#elif defined(MRPT_OS_APPLE)
# ifdef __MWERKS__
# define MRPT_@NAME@_EXPORT __declspec(export)
# define MRPT_@NAME@_IMPORT __declspec(import)
# endif
#elif defined(__CYGWIN__)
# define MRPT_@NAME@_EXPORT __declspec(dllexport)
# define MRPT_@NAME@_IMPORT __declspec(dllimport)
#endif
/* for other platforms/compilers we don't anything */
#ifndef MRPT_@NAME@_EXPORT
# define MRPT_@NAME@_EXPORT
# define MRPT_@NAME@_IMPORT
#endif
/* Macros that map to export declaration when building the DLL, to import
declaration if using it or to nothing at all if we are not compiling as DLL */
#if defined(MRPT_BUILT_AS_DLL)
# if defined(mrpt_@name@_EXPORTS) /* Building the DLL */
# define @NAME@_IMPEXP MRPT_@NAME@_EXPORT
# else /* Using the DLL */
# define @NAME@_IMPEXP MRPT_@NAME@_IMPORT
# endif
#else /* not making nor using DLL */
# define @NAME@_IMPEXP
#endif
#endif
The MRPT CMake scripts automatically recognize those files under the src directory with the pattern "*_unittest.cpp" as files for unit testing. MRPT uses the Google's gtest library to perform these tests. Note that the "*_unittest.cpp" files are not included in the "mrpt-<name>" library, but a new target "test-<name>" is automatically created which is invoked when doing a "make test". A typical content of a unit testing file is (see existing tests for more examples):
#include <mrpt/slam.h>
#include <gtest/gtest.h>
using namespace mrpt;
using namespace mrpt::utils;
using namespace std;
TEST(MyTestCaseName, ThisTestName)
{
double err;
// Do whatever...
EXPECT_EQ(0, err ) << "Differences were found when checking ...\n";
}