What is a module ?

A module consists of a shared library embedding a set of SolAR components as well as the corresponding factories to instantiate them. The management of modules is based on the XPCF third party providing a lightweight cross platform component framework. XPCF provides the following features to manage SolAR modules:

  • introspection to figure out which components are available in the module

  • separate implementation from interface to create the concrete implementation of a SolAR component and to bind it to an abstract SolAR and XPCF component interfaces.

  • component creation

Each module implementation is identified with a Universally Unique IDentifier (UUID) to nearly ensure the uniqueness of a component implementation when the system instantiates it.

As mentionned previoulsy, the third party XPCF can introspect the shared library of a module to obtain information about the embedded components and the interfaces they implement. Only, the introspection of a shared library requires to load it, what could become tricky when the shared library has been built on a different platform than yours (useful for authoring tools supporting cross-platform compilation such as Unity). For this reason, XPCF proposes to associate to each module a registry file in xml format that describes the module with:

  • the module UUID,

  • the components embedded in the module with their UUID,

  • the abstract component interfaces implemented by the components.

Thus, any system will be able to intropsect a module without the need to load the corresponding shared library.

Create a module with the wizard

Download QTCreator wizards for XPCF

Creating a new module from scratch can be a little bit tricky. To help you, a QTCreator wizard is available and will make the task much easier.
Start by installing this wizard by launching the install.bat on Windows (in your ${REMAKEN_PKG_ROOT}/packages/win-cl-14.1/xpcf/[version]/wizards) or install.sh on Linux (in your ${REMAKEN_PKG_ROOT}/packages/linux-gcc/xpcf/[version]/wizards).

You can also download the wizard on the following link:
https://github.com/SolarFramework/Tools/releases/download/XPCFWizard_2_3_4/XPCF_qtcreator_wizards.zip
Then unzip the downloaded file, and run the install.bat on Windows or the install.sh on Linux.

Create a SolAR module in QTCreator

Open QTCreator and create a new project (in File menu).

Select XPCF project and XPCF Module template and click on Choose button.

create an SolAR Module in QT
Figure 1. Create an SolAR Module in QT

Then, set the name of your module and its location (The creation a dedicated folder regrouping all module projects is recommended).

Set module project name in QT
Figure 2. Set module project name in QT

Next provide the details concerning your module. You can set a different name to the package for your module if you want to embed several modules in the same package. But by default, keep the same one. Also, you can define if you want to produce a static or a shared library. We highly recommend to use the shared library for modules. Also, for installation, all dependencies of your module can be copied in a recursive mode in your package folder. Thus, when you will deploy your module, you will be sure that all required third parties will be also deployed. For the link step, you can let the SolAR build pipeline find automatically the dependencies recursively. Finally, if you want to load your project in visual studio, check the box QTVS. Thus, you will be able to load the QTProject in visual studio via the plugin QTtVisual Studio Tools.

set module details in QT
Figure 3. Set module details in QT

Then, define your build system with qmake.

For the next step, you have to enter the directory where the xpcf binaries are located. Normally, you will find it in your <USER_HOME>, in the folder .remaken\packages\. You have also to set the namespace of your module. In order to have easy access to all your modules by completion when coding, we recommend to use the namespace SolAR::MODULES::MyModule for any module.

set XPCF version directory and namespace
Figure 4. Set XPCF version directory and namespace

Then, you have to choose your remaken rules. You can choose to use your own remaken rules, but when it is not necessary, we recommend to use the ones available in your <USER_HOME>/.remaken/rules folder (normally installed when you have installed SolAR).

remaken rules selection
Figure 5. Remaken rules selection

Next, choose your development kits. We recommend to use MSVC 2017 64bit on Windows or Clang on Linux.

Finally, no subproject to add here, if you want to add a version control, select it and click on the Finish button.

Your module is now created, you have just to configure it in QTCreator. Click on Projects in the left menu, select the developement kits of your choice, and click on Configure Project.

Configure Project
Figure 6. Configure your project

Five files have been created, the project file MyModule.pro, a C++ file MyModule_main.cpp, a header file MyModuleAPI.h defining the macro to export your interfaces, a packagedependencies.txt file to manage the dependencies of your module, and finally a bcom_MyModule.pc.in used by pkg_config to describe your module.

But let’s take a closer look at these files.

QTCreator project file

MyModule.pro
## remove Qt dependencies
QT       -= core gui
CONFIG -= qt

## global defintions : target lib name, version
INSTALLSUBDIR = SolARBuild
TARGET = MyModule
FRAMEWORK = $$TARGET
VERSION=X.X.X (1)

DEFINES += MYVERSION=$${VERSION}
DEFINES += TEMPLATE_LIBRARY
CONFIG += c++1z

include(findremakenrules.pri) (2)

CONFIG(debug,debug|release) {
    DEFINES += _DEBUG=1
    DEFINES += DEBUG=1
}

CONFIG(release,debug|release) {
    DEFINES += _NDEBUG=1
    DEFINES += NDEBUG=1
}

DEPENDENCIESCONFIG = shared install_recurse (3)

## Configuration for Visual Studio to install binaries and dependencies. Work also for QT Creator bby replacing QMAKE_INSTALL
PROJECTCONFIG = QTVS (4)

#NOTE : CONFIG as staticlib or sharedlib, DEPENDENCIESCONFIG as staticlib or sharedlib, QMAKE_TARGET.arch and PROJECTDEPLOYDIR MUST BE DEFINED BEFORE templatelibconfig.pri inclusion
include ($$shell_quote($$shell_path($${QMAKE_REMAKEN_RULES_ROOT}/templatelibconfig.pri)))  # Shell_quote & shell_path required for visual on windows

## DEFINES FOR MSVC/INTEL C++ compilers
msvc {
DEFINES += "_BCOM_SHARED=__declspec(dllexport)"
}

INCLUDEPATH += interfaces/

include (MyModule.pri)
#SOURCES +=     MyModule_main.cpp
#HEADERS +=     MyModuleAPI.h

unix:!android {
    QMAKE_CXXFLAGS += -Wignored-qualifiers
#    QMAKE_LINK=clang++
#    QMAKE_CXX = clang++
}

macx {
    DEFINES += _MACOS_TARGET_
    QMAKE_MAC_SDK= macosx
    QMAKE_CFLAGS += -mmacosx-version-min=10.7 -std=c11 #-x objective-c++
    QMAKE_CXXFLAGS += -mmacosx-version-min=10.7 -std=c11 -std=c++11 -O3 -fPIC#-x objective-c++
    QMAKE_LFLAGS += -mmacosx-version-min=10.7 -v -lstdc++
    LIBS += -lstdc++ -lc -lpthread
}

win32 {

    DEFINES += WIN64 UNICODE _UNICODE
    QMAKE_COMPILER_DEFINES += _WIN64
    QMAKE_CXXFLAGS += -wd4250 -wd4251 -wd4244 -wd4275 /Od
}

android {
    ANDROID_ABIS="arm64-v8a"
}
header_files.path = $${PROJECTDEPLOYDIR}/interfaces
header_files.files = $$files($${PWD}/interfaces/*.h*)

xpcf_xml_files.path = $${USERHOMEFOLDER}/.xpcf/SolAR
xpcf_xml_files.files=$$files($${PWD}/xpcf*.xml)

INSTALLS += header_files
INSTALLS += xpcf_xml_files

OTHER_FILES += \
    packagedependencies.txt \
    packagedependencies-linux.txt \
    packagedependencies-mac.txt \
    packagedependencies-win.txt \
    packagedependencies-android.txt

#NOTE : Must be placed at the end of the .pro
include ($$shell_quote($$shell_path($${QMAKE_REMAKEN_RULES_ROOT}/remaken_install_target.pri)))) # Shell_quote & shell_path required for visual on windows (5)
1 Set the version number of your module,
2 This .pri file has been installed by the wizard. It will allow to find the remaken folder depending on the OS you are using.
3 The dependencies of your module will be installed recursively. More details are available on the builddefs-qmake project on GitHub.
4 The installation of your module will also work with Visual Studio. Warning, in QTCreator, this will replace the usual QMAKE_INSTALL.
5 Place at the end the .pri file to install your module.

Package Dependencies file

As mentionned previously, SolAR framework provides developers with a build pipeline allowing among other things to easily manage dependencies (download, version management, packaging during deployment step, etc.).

To define the dependencies used by your pipeline, just add to your packagedependencies.txt a reference to the SolARFramework and to the third parties used by your module as shown below:

/.packagedependencies.txt

SolARFramework|0.8.0|SolARFramework|SolARBuild@github|https://github.com/SolarFramework/SolarFramework/releases/download
MyThirdParty1|x.x.x|MyThirdPaty1Folder|ThirdParty@github|https://github.com/MyGitHubProject/MyModule/releases/download (1)
MyThirdParty2#stable|x.x.x|MyThirdParty2Folder|conan|conan-center|shared|MyThirdParty2BuildOption (2)
1 Your third party is available in the release of your github project. To know how to package your third party, check the Third parties packaging page
2 Your third party can be directly downloaded using conan (for instance, from conan-center).

You will find bellow the syntax for each dependency (more information are available on the Remaken project on GitHub):

dependency_name|dependency_version|dependency_folder_name|dependency_path|dependency_download_url

XPCF and the build pipeline handle dependencies recursivity, meaning that you do not need to add the dependencies of the SolAR framework.

Your third parties, should be available in your <USER_HOME>/.remaken/packages/<yourCompiler>/ folder. To automatically download your dependencies, just run remaken where your packagedependencies.txt is located.

Numerous samples of packagedependencies.txt files can be found with the SolAR Modules you have surely installed on your machine.

MyModuleAPI.h

The file MyModuleAPI.h has been automatically created and it defines the macro MYMODULE_EXPORT_API you will have to place in front of each component interface to export them in your shared library.

MyModule_main.cpp

/MyModule_main.cpp

#include <xpcf/module/ModuleFactory.h>
#include <iostream>

namespace xpcf=org::bcom::xpcf;

/**
 *  @ingroup xpcfmodule
 */
/**
  * Declare module.
  */
 (1)
XPCF_DECLARE_MODULE("{5b066de7-2a9f-4dff-a730-ce82adafe2f6}","SolAR::MODULES::MyModule","MyModule module description");

/**
 * This method is the module entry point.
 * XPCF uses this method to create components available in the module.
 *
 * Each component exposed must be declared inside a xpcf::tryCreateComponent<ComponentType>() call.
 */
 (2)
extern "C" XPCF_MODULEHOOKS_API xpcf::XPCFErrorCode XPCF_getComponent(const xpcf::uuids::uuid& componentUUID,SRef<xpcf::IComponentIntrospect>& interfaceRef)
{
    xpcf::XPCFErrorCode errCode = xpcf::XPCFErrorCode::_FAIL;
    errCode = xpcf::tryCreateComponent<SolAR::MODULES::MyModule::componentType>(componentUUID,interfaceRef);
    if (errCode != xpcf::XPCFErrorCode::_SUCCESS) {
        errCode = xpcf::tryCreateComponent<SolAR::MODULES::MyModule::otherComponentType>(componentUUID,interfaceRef);
    }
    return errCode;
}

/**
  * The declarations below populate list of the components available in the module (it represents the module index).
  * XPCF uses this index to introspect the components available in a module, providing the ability to generate the configuration file skeleton from the code.
  */
(3)
XPCF_BEGIN_COMPONENTS_DECLARATION
XPCF_ADD_COMPONENT(SolAR::MODULES::MyModule::componentType)
XPCF_ADD_COMPONENT(SolAR::MODULES::MyModule::otherComponentType)
XPCF_END_COMPONENTS_DECLARATION

This .cpp file has three main goals:

1 It Declares the module to XPCF with a given UUID, a given namespace and a given name
2 It allows the XPCF component factory, thanks to the XPCF_getComponent method, to retrieve and create the component from its UUID
3 it declares the components embedded in the module

Each time you will want to embed a new component into the module, you will have to add its creation in the XPCF_getComponent method and to add it in the component declaration.

MyModule.pc.in file

The SolAR build pipeline can use pkg-config that helps to insert the correct compiler options on the command line so an application can use gcc -o test test.c pkg-config --libs --cflags glib-2.0 for instance, rather than hard-coding values on where to find glib (or other libraries). When you will install your module, this file will be directly copied to your binary folder <USER_HOME>/.remaken/packages/<yourInstallSubDir>/<yourCompiler>/<MyModule>/<MyModule_Version>.

The registry file

As mentionned previoulsy, a shared library has to be loaded for introspection, what is quite tricky when it has been built on a platform different from yours. For this reason, we always associate to a module a registry file describing information about the module itself and its components.

Create an xml file, name it xpcf_MyModule_registry.xml, and copy the following code in it (again replace MyModule with the name of your module):

xpcf_MyModule_registry.xml
<xpcf-registry>
<module uuid="MyModule_UUID" name="MyModule_Name" description="MyModule_Description" path="$REMAKEN_PKG_ROOT/packages/SolARBuild/win-cl-14.1/MyModule/MyModule_version/lib/x86_64/shared">
(1)
</module>
</xpcf-registry>
1 Copy and paste the module UUID, name and description defined in the file MyModule.cpp. Update the path by replacing MyModule by the name of your module and MyModule_version by the version number of your module defined in your .pro and in your CMakeLists.txt files.

This file is somewhat empty, but will be completed when adding components. It will be copied to the xpcf registry folder HOME_USER_/.xpcf/.