Skip to content

Use interfaces from an imported Sen-based project

This guide will focus on how to set up your project to consume interfaces from external packages. For this guide to be accurate, the package you consume should have followed the instructions described on the how to export interfaces in Sen-based projects guide.

How to consume Sen-based projects as CMake packages

To use an external project's interfaces you first need the project itself, and you consume it through CMake. Every Sen-based project is exported as a CMake package, and you can get that package in several ways: the Conan package manager, ZIP files, CMake installations, and so on. It does not matter which one you use. Every project ships a -config.cmake file, and the only requirement is that the directory containing it is on the CMAKE_PREFIX_PATH.

Setting the CMAKE_PREFIX_PATH depends on the method you choose to consume the package:

  • If you consume a Sen-based package via Conan, the CMAKE_PREFIX_PATH will be set automatically.
  • If you use ZIP files or CMake installations, you will need to provide the correct path to the directory before calling CMake's find package.

After ensuring that the project's CMake directory is added to the CMAKE_PREFIX_PATH variable, we can now call

find_package(my_project)

to add the consumed project to yours. Sen uses an independent CMake file for each dependency, so the recommendation is to follow the same architecture. You can check Sen's dependencies located in cmake/tps or the dependencies of any Sen-based project (e.g. a Sen-based gateway project) under cmake/deps for further detail.

Use external interfaces inside your project

After importing the external project into yours, you can use Sen's CMake tools to use the interfaces of an externally included project.

get_external_interfaces function

Sen's CMake utils implement the get_external_interfaces() function. This function receives the name of any Sen-based CMake target with an STL interface, and an installation dir, which should point to the directory where Sen is installed and being consumed externally:

get_external_interfaces(TARGET target_name INSTALLATION_DIR install_dir)
  • The TARGET argument will be the name of the desired CMake target who you want to obtain the interfaces from. The target name will stay the same as it is on the original project, preceded by its namespace. For example, if I want to obtain Sen's recorder component interfaces, I would call get_external_interfaces(TARGET sen::recorder ...).
  • The INSTALLATION_DIR argument is a variable that points to the actual directory where the imported package is located at compile time. If the CMake package of the consumed project was generated using the how to export interfaces in Sen-based projects guide, this variable should be set to *project_name*_INSTALL_DIR. If the variable is not set the function call will fail, showing possible solutions of the problem, ultimately leading to contact the maintainer of the consumed project.

Calling the get_external_interfaces function will add new CMake properties to the target that can later be used to generate code making use of Sen's CMake generation functions (sen_generate_cpp, sen_generate_package, add_sen_package, etc.).

Generating code using external interfaces

After calling get_external_interfaces, CMake will add additional properties to the given TARGET that were not present at the time of building. These two are always set:

  • INSTALL_BASE_PATH: Set BASE_PATH when generating the packages originally but adapted to point at the installation dir.
  • INSTALL_SEN_IMPORT_DIRS: The -i import search path the generator resolves stl imports through, pointing at the installation dir rather than the tree that built the package.

The rest are set only when the consumed component has files of that kind:

  • INSTALL_STL_FILES: List of paths to each of the component's STL files in the installation dir.
  • INSTALL_HLA_FOM_DIRS: List of paths to each of the component's defined HLA_FOM_DIRS in the installation dir.
  • INSTALL_HLA_MAPPINGS: List of paths to the component's HLA mapping files in the installation dir.
  • INSTALL_HLA_EXTENSIONS: List of paths to the component's HLA extension files in the installation dir.

You can use CMake's get_target_property function to fetch the value of these properties into local variables. With these variables filled, you will be able to call Sen's code generation functions with the files used to generate code on the original target. This allows replicating the generated code of the original package, but allowing it to be imported into your project, added as a dependency of your Sen Packages, etc.

Importing generated code

If the consumed project followed the how to export interfaces in Sen-based projects guide, you will be able to import the stl files in exactly the same way as they are imported in the original project. This applies to stl inclusions (import "stl/sen/components/recorder/recorder.stl"), CPP (#include "stl/sen/components/recorder/recorder.stl.h") or any language supported by Sen.

Note that you are not only limited to STL interfaces as HLA FOM files can also be exported in the same way.

Usage example

In this use case example, I have a component called Town. The town component resides in my project, but it wants to use the interfaces of the already created school component, present on the Sen project. The steps to follow would be:

1. Import Sen's CMake package by consuming it via Conan (or any other method to obtain packages) and call find_package accordingly.

2. In your project's CMake files, call the get_external_interfaces function with the adequate arguments:

  get_external_interfaces(TARGET sen::school INSTALLATION_DIR ${SEN_INSTALL_DIR})

3. Obtain both the stl files list and the BASE_PATH with get_target_property calls, storing them in local CMake variables:

  get_target_property(school_base_path sen::school INSTALL_BASE_PATH)
  get_target_property(school_stl_files sen::school INSTALL_STL_FILES)

4. Use the locally filled variables to generate the cpp code of the school interfaces:

sen_generate_cpp(TARGET sen_school_interfaces
                 BASE_PATH ${school_base_path}
                 STL_FILES ${school_stl_files})

NOTE: if the interfaces you are using depend on any other interfaces (e.g., Sen recorder interface depends on sen::db library interfaces), you need to generate them with a Sen code generation function that allows adding dependencies with the DEPS argument. These two functions are add_sen_component and add_sen_package.

5. After generating the code of the interfaces, you can use the obtained target sen_school_interfaces inside your Sen packages:

add_sen_package(TARGET town
                SOURCES ${town_sources}
                BASE_PATH ${town_source_dir}
                STL_FILES ${town_source_dir}/stl/sen/components/town/town.stl
                DEPS sen_school_interfaces)

With the interfaces as a dependency, you will be able to import their STL files in any file of your Sen package.

  • In STL files:
// town.stl file
import "stl/school/student.stl"

package town;

// What the schools we oversee last reported.
sequence<school.StudentStatus> StatusList;

class EducationCouncil
{
  var neededTaxIncome  : f32;
  var reportedStatuses : StatusList [confirmed];
}

Note what crosses the boundary here: school.StudentStatus is a value type, and value types are what properties can hold. A class such as school.Student cannot be a property type. To work with another package's objects you discover them at run time and hold them through the generated interface, as below.

  • In CPP files:
#include "stl/school/student.stl.h"

class EducationCouncilImpl: public EducationCouncilBase
{
  // some class implementation ...

private:
  // the students we are keeping an eye on, discovered at run time
  std::shared_ptr<sen::Subscription<school::StudentInterface>> students_;
};