{: style="width:200px; float: right;"}
{: style="width:200px; float: right;"}
What this page is: a walk through every file sen package init generates, and what each line in
it is for. It is the reference to come back to when you want to know why something is in your
package, rather than a narrative to follow once.
If you have done the tutorials, you have already built one of these. Tutorial 1 walks the same ground as a story, with a smaller class and a running shell at the end. This page is the same territory laid out as reference: one section per generated file, in the order the build uses them.
Prerequisites: Sen installed and the activate script sourced, so that sen is on your PATH
and SEN_PREFIX is exported. See Getting Sen.
Ask Sen to create the skeleton for a package called "my_package", containing a class called "MyClass".
sen package init my_package --class MyClassInspect the contents of the newly-created folder:
my_package
├── CMakeLists.txt # (1)!
├── config.yaml # (2)!
├── src # (3)!
│ ├── my_class.cpp
│ └── my_class.h
└── stl # (4)!
└── my_package
├── basic_types.stl
└── my_class.stl # (5)!
- Tells CMake how to build your package.
- Tells the Sen kernel how to use your package.
- The implementation of your package.
- Contains the interface of your package.
- The class you implement.
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
project(my_package_project VERSION 0.0.1 LANGUAGES CXX C)
if(DEFINED ENV{SEN_PREFIX}) # (1)!
list(APPEND CMAKE_PREFIX_PATH "$ENV{SEN_PREFIX}/cmake") # (2)!
endif()
find_package(sen REQUIRED)
add_sen_package( # (3)!
TARGET
my_package
MAINTAINER
"<your name goes here>" # (4)!
VERSION
"0.0.1" # (5)!
DESCRIPTION
"<package description goes here>"
SOURCES
src/my_class.h
src/my_class.cpp
STL_FILES
stl/my_package/my_class.stl
stl/my_package/basic_types.stl
)
- The
SEN_PREFIXenvironment variable is exported by theactivatescript the installer writes. See Install. - This enables CMake to find the Sen package below.
- This function becomes automatically accessible once Sen is found.
- Replace the placeholders here and in
DESCRIPTIONwith your own details. Not mandatory, but helpful if you redistribute the package. - You can also use the CMake project version here.
This file defines a class with some properties, methods and events. A class can have several implementations, though this example provides one. You could also import an STL file from another repository or software asset and have this package implement it, in which case there is no STL file to write here.
import "stl/my_package/basic_types.stl" // (1)!
package my_package; // (2)!
class MyClass
{
var prop1 : string [static]; // (3)!
var prop2 : StructOfInts [writable]; // (4)!
var prop3 : MyVariant [writable, confirmed]; // (5)!
var prop4 : Vec2; // (6)!
var prop5 : i32 [writable]; // (7)!
// this method returns a + b
fn addNumbers(a: i32, b: i32) -> i32;
// this method returns message
fn echo(message: string) -> string;
// change some property
fn changeProps();
// fired when something happened
event somethingHappened();
// fired when something else happened
event somethingElseHappened(arg: i32) [confirmed];
}
- Brings in all the types defined in the
basic_types.stlfile (MyVariant,StructOfIntsandVec2). - Defines the namespace for the types defined in this file.
- Once defined for a given instance, does not change.
- Can be set by external callers. Sen generates a setter that's visible from the outside. This property goes over UDP.
- Similar to the previous property, but this one goes over TCP.
- This property is read-only from the outside. Its setter is generated on the base class, so your own implementation can change it, but it is not on the interface other objects hold.
- A plain counter. The
update()implementation below increments it on every cycle.
A header file for your class is not strictly needed (everything could go in a CPP file, but this keeps it tidy).
#pragma once
#include "stl/my_package/my_class.stl.h" // (1)!
// sen
#include "sen/kernel/component_api.h"
namespace my_package
{
class MyClassImpl: public MyClassBase // (2)!
{
public:
SEN_NOCOPY_NOMOVE(MyClassImpl) // (3)!
public:
using MyClassBase::MyClassBase;
~MyClassImpl() override = default;
public:
void update(sen::kernel::RunApi& runApi) override; // (4)!
protected: // (5)!
int32_t addNumbersImpl(int32_t a, int32_t b) override;
std::string echoImpl(const std::string& message) override;
void changePropsImpl() override;
};
} // namespace my_package
- For every STL file Sen will generate the equivalent C++ header.
MyClassBaseis generated by Sen. It contains helper functions and all the glue code. Understanding the generated code goes through what is in there and why.- This is a helper macro found in the Sen core library. It just disables the copy and move operations.
- This function shows how to evolve the state of your object.
- The methods are pure virtual in the parent class, so you must implement them.
#include "my_class.h"
namespace my_package
{
void MyClassImpl::update(sen::kernel::RunApi& /*runApi*/)
{
setNextProp5(getProp5() + 1); // here goes your update logic
}
int32_t MyClassImpl::addNumbersImpl(int32_t a, int32_t b)
{
return a + b;
}
std::string MyClassImpl::echoImpl(const std::string& message)
{
return message;
}
void MyClassImpl::changePropsImpl()
{
Vec2 val = getProp4();
val.x += 0.5f; // simply make some changes
val.y += 1.5; // to a property, to see the effect
setNextProp4(val);
}
SEN_EXPORT_CLASS(MyClassImpl) // (1)!
} // namespace my_package
- This exports the class implementation, so users can tell Sen to load the package and instantiate
MyClassImpls.
load:
- name: shell # (1)!
group: 2 # (2)!
open: [local.example] # (3)!
build:
- name: myComponent # (4)!
group: 3
freqHz: 30
imports:
- my_package # (5)!
objects:
- class: my_package.MyClassImpl # (6)!
name: myObject
bus: local.example # (7)!
prop1: some value # (8)!
- Load the shell, so there is something to look at.
- The shell runs in group 2, and your component in group 3.
- Automatically open this bus to see the created objects, so you do not have to open it by hand.
- This is the name of the component that Sen will build for us.
- Import your package so Sen can discover your implementation and instantiate your class.
- The name of the type that provides the implementation, defined in
my_class.cpp. - Your object will be published to this bus, which is why the shell auto-opens it.
prop1needs a value because it is static, and static properties require an initial value.
To build and run, follow the instructions sen package init printed:
# compile
cmake -S . -B build && cmake --build build
# tell the loader where the package is: bash or zsh
export LD_LIBRARY_PATH="$(pwd)/build/bin:$LD_LIBRARY_PATH"
# run
sen run config.yamlThe tool prints the equivalent for fish (set -xa LD_LIBRARY_PATH $(pwd)/build/bin) and for
PowerShell on Windows ($env:PATH = "$PWD\build\bin;$env:PATH").
Pointing the loader at build/bin is what running from the build tree looks like, and every package
in this repository runs that way. Taking the package anywhere else is a separate step:
add_sen_package writes no install rule, so you write your own for the library and for the
generated headers. Creating your own Conan package
walks through that, including how to get the generated headers out of GEN_HDR_FILES.
From this point you should be able to use the shell to inspect and interact with your object.
Stop the kernel with the shutdown command.
!!! note "Exit codes"
When the Sen executable finishes without error it returns zero, and prints a smiling face. If it
detects an error it can handle, it returns non-zero and prints a frowning one.
This is the reference route through Getting started. If you have not seen Sen run yet, the tutorials cover the same ground as a story.
The terms this page used without defining them, such as [static], [writable], [confirmed],
buses, groups and setNext, are explained in the manual. Main
concepts covers properties, buses and quality of service; the
mental model explains why a setter is called setNext; and the
Sen Type Language is the reference for everything inside an .stl file.
