System Definition .sdef

This topic provides details about Legato's System Definition files.

See howToSecurity for details on how to howToSecuritySandboxConfigSample and understand app and process limits.

.sdef files can contain these sections:

Search Paths

These sections are used to specify directories in which mksys should look for the various files that make up your system.

Note
mksys allows the command line arguments -i or --interface-search to also specify the interface search path(s). For backwards compatability, all other search paths fall under the command line arguments -s or --source-search. To add multiple search paths simply add multiple instances of -i or -s to your command.

When building systems that are intended to be inherited by other projects it is recommended to use the search paths within your included .sdef file. This way each individual subsystem can be added to a top level .sdef file without forcing the user to append many search paths to their command line when running mksys.

interfaceSearch

The interface search is used to find the .api files referenced in your system, your applications, and the components that make up your applications.

To allow components to be relocated in the build host file system, components should not specify interface file search paths outside of their own directories. To separate interfaces from implementation, interfaces should be kept outside of components. This can be accomplished by adding interface search directory paths to the interfaceSearch section in the .sdef file.

This way components can be kept in a components directory, and interfaces can be kept within an interface directory. Keeping these API files seperated from compoents can make it easier to share between clients and servers, as well as between seperate server implementations.

So, for example, in a Legato system definition there would be a interface search paths setup for the APIs offered by Legato itself under default.sdef:

interfaceSearch:
{
    $LEGATO_ROOT/interfaces                 // Directory contianing
    $LEGATO_ROOT/interfaces/modemServices   // Directory containing Legato modem services APIs.
}

In your sdef, after defining LEGATO_ROOT you can include Legato's search paths and append your own.

#include "$LEGATO_ROOT/default.sdef"

interfaceSearch:
{
    $CURDIR/interfaces   // Directory containing custom interfaces belonging to this system.
}

Now your components and applications can find all of your custom APIs as well as those that come with Legato.

Note
CURDIR is a mktools managed variable. CURDIR always refers to the directory that your .def file is residing in. So, if your def file is in ~/myProject/mySystem.sdef then CURDIR would be the full path to the def's directory: /home/username/myProject/ See Environment Variables for more details on the automatic variables.

For example, inside of one of your Component.cdef files:

requires:
{
    api:
    {
        le_sms.api       // Make use of one of the modem service APIs.
        myCustomApi.api  // Also, make use of your own custom APIs.
    }
}

appSearch

This search path is used when specifiing apps in your .sdef's apps: section. Instead of having to specify a full path to your applications, you can specify locations for where they should be found.

appSearch:
{
    $CURDIR/applications  // Search for apps in a subdirectory of the directory that holds your
                          // .sdef or .sinc file.
}

componentSearch

Use the componentSearch to add your paths to the directories that the build system uses to find your components.

componentSearch:
{
    $CURDIR/components  // Search for components in a subdirectory of the directory that holds your
                        // .sdef or .sinc file.
}

This way, when you are defining your applications executables within an executables: section you do not need to specify the full path to your component's executables. For example, your application executable is composed of two components, mainComp and helperComp. Using a component search path, you can easily share helperComp between different executables and different applications.

executables:
{
    myExe = ( mainComp helperComp )
}

moduleSearch

The section moduleSearch is for adding to the module search path. This search path is used when specifing modules in your .sdef's kernelModules: section. Instead of having to specify a full path to your kernel modules, you can specify locations for where they should be found.

For example:

moduleSearch:
{
    // My example modules are found in this directory.
    $LEGATO_ROOT/drivers/example
}

// In the kernel modules section, you no longer need to give a full path to your mdef files.  The
// mktools will search through all of your paths given in the moduleSearch section.
kernelModules:
{
    // Include my sample module in the build.
    example.mdef
}

apps

An apps: section declares one or more apps to be deployed to the target system.

apps:
{
webserver
}

This looks for an app definition file called webserver.adef and includes it in the system. You can also optionally include the .adef extension.

Alternatively you can include the full path and adef extension on the declaration and bypass the app search paths.

apps:
{
/full/path/to/my/app/webserver.adef
}

In addition to including applications in source for to your system builds. You can also add binary application packages.

Binary app packages are apps distributed without their source code. You include these apps in your .sdef file apps: section just like .adef files.

apps:
{
webserver.wp85.app
}

Binary app files are named for the target architecture they are built against. This way it's hard to mix up builds for incompatible target architectures. The same pathing and search rules apply to binary apps as do for .adef files.

The apps: section can override limits and other app settings.

Here's a code sample to deploy a web server limiting its share of the CPU under heavy load to 500 (see cpuShare):

apps:
{
webServer
{
cpuShare: 500
}
}

Any of the following subsections can be used in an .sdef apps: section, and will override the .adef setting for all processes in that app:

maxPriority

maxPriority

Sets the maximum priority level the app it permitted to use.

Acts as a ceiling only. Lowers the priority level if an app would otherwise be allowed to use a higher priority. It won't raise the priority level for any processes in the app.

Here's a code sample where a process in the app's .adef is configured to start at high priority, and the .sdef section for that app has maxPriority set to medium so the process will start at medium priority.

apps:
{
foo
{
maxPriority: high
}
}

Another process in the same .adef configured to start at low priority will still start at low priority.

preloaded

Indicates whether or not an app must be preloaded onto the target device separately from the rest of the system.

If you are not sure whether or not you need this feature, you probably don't. Use of this feature is intended for very specific use cases. It is encouraged that delta updates of systems be used instead, whenever practical.

The legato AF supports being installed in a read-only partition, mounted as /mnt/legato in the target file system. Writeable files will be kept in another file system mounted as /legato in the target file system.

If the read-only partition must be updated, but there are other (possibly very large) apps in the writeable file system, it may be impossible to deliver an update containing the apps over-the-air at the same time that the read-only partition is updated.

Usually, the read-only partition does not need to be updated, but in some cases, it may be desireable, and this feature can help.

For example, a customer has a giant app containing pictures and audio files. In the factory, the framework and a few apps are loaded into the read-only /mnt/legato, and other apps, including the huge app, are installed in the writeable /legato. Later, when the device is in the field, a change needs to be made to both the modem firmware and the Legato framework, and must be delivered together, as a single FOTA (firmware over the air) update. A new system is built using mksys. But, the resulting system update file is too large to fit in the FOTA update image (and likely very expensive to deliver over the air to hundreds of thousands of devices). Fortunately, the audio files don't need to be updated at the same time, and the audio app can be marked "preloaded" in the .sdef file to exclude it from the system update file. After the FOTA update, the new system will use the audio file that already exists on the target's writeable file system.

apps:
{
modemService
audioService
dataConnectionService
controller
userInterface { preloaded: true }
}

After you have built the new system, verify that the app that was marked "preloaded" in the .sdef file has the same MD5 hash as the app that is actually installed on the target. You can do this by comparing the contents of the symlink in /legato/systems/current/apps/ on the target with the contents of the symlink in the staging/apps/ directory of the system's build directory on the build host.

$ ssh root@192.168.2.2 'readlink /legato/systems/current/apps/userInterface'
/legato/apps/a60357d912ff3b4b28e080580b34fff3
$ readlink build/wp85/system/staging/apps/userInterface
/legato/apps/a60357d912ff3b4b28e080580b34fff3

If these are different, then something has changed that has resulted in the built version of your app to be different in the context of your new system. If you continue to install your new system on the target, the "preloaded" app will not start. But, if you find yourself in this situation, and you are absolutely certain that the version of the preloaded app that is on your target is still compatible with the new system you are about to install, and you can't afford to install the new version of your app, then you have another option: Change the "true" in your "preloaded: true" statement in your .sdef file to the MD5 hash of the old version of the app installed on your target.

apps:
{
modemService
audioService
dataConnectionService
controller
userInterface { preloaded: a60357d912ff3b4b28e080580b34fff3 }
}

bindings

Lists IPC bindings that connect apps’ external IPC interfaces. They're listed in the extern section of their .adef files. Each binding connects one client-side interface to one server-side interface.

Interfaces use the app name and the interface name, separated by a period (‘.’). The two bound-together interfaces are separated by an arrow ("->").

For example,

apps:
{
vavController
thermostat
airHandlerProxy
}
 
bindings:
{
// Connect the VAV controller to the thermostat
vavController.temp -> thermostat.temp
vavController.setpoint -> thermostat.setpoint
 
// Connect the VAV controller to the supply air duct temperature sensor
vavController.ductTemp -> ductTemperatureSensor.temp
 
// Hook up the VAV control outputs to the damper actuators.
vavController.supplyDamper -> supplyAirDamper.damper
vavController.returnDamper -> returnAirDamper.damper
 
// Use a network proxy to request duct temperature changes from the Air Handling Unit.
vavController.airHandler -> airHandlerProxy.airHandler
}

For security reasons, binding between apps is never performed unless explicitly specified in the .sdef or .adef files.

buildVars

Build environment variables can be defined inside the .sdef file using "buildVars:" sections. This will define variables in the build tools' process environment at build time.

buildVars:
{
    PRODUCT_VERSION = "0.2.3 - beta"
    HARDWARE_REV = 4
    DEBUG = 1
}

These are defined using "name = value" pairs, where the value can be a quoted string and may contain the values of other environment variables that were previously defined.

All buildVars: sections will be evaluated before processing any other sections. So, even if a buildVars: section appears after another section that uses it, the variables will be available in that other section.

Note
This is necessary to allow the sharing of components between apps. If two apps contained the same component, but each app were built with a different set of environment variables, it would be hard to tell which set of environment variables were used to build the shared component, and the component may behave in an unexpected way for one of the apps.
apps:
{
    $APP_PATH
}

buildVars:
{
    APP_PATH = path/to/app
}

Within the buildVars: sections, the order of the definitions matters.

buildVars:
{
    X = foo  // X is now "foo"

    X = bar  // X has been changed to "bar"

    X = foo${X}  // X has been changed to "foobar"

    X = "$X baz" // X has been changed to "foobar baz"
}

cflags

Provides a way to specify command-line arguments to pass to the compiler when compiling C source code files. These flags will be added to the flags specified on the command-line and in other definition files.

Flags are separated by whitespace.

cflags:
{
-g -O0
-DDEBUG=1
}

cxxflags

Provides a way to specify command-line arguments to pass to the compiler when compiling C++ source code files. These flags will be added to the flags specified on the command-line and in other definition files.

Flags are separated by whitespace.

cxxflags:
{
-std=c++0x
-g -O0
}

ldflags

Linker flags provide a way to specify command-line arguments to pass to the compiler when linking C/C++ object (.o) files together into a component shared library (.so) file. These flags will be added to the flags specified on the command-line and in other definition files.

Flags are separated by whitespace.

ldflags:
{
-Lfoo/bar
}

kernelModules

The optional kernelModules: section declares a list of kernel modules to be bundled and installed with Legato.

Each entry represents a path to the .mdef definition file that describes how the module is installed on the target.

This code sample shows the section declaring the "/path/to/kernel/module/hello.mdef" be bundled with Legato:

kernelModules:
{
/path/to/kernel/module/hello
}

The kernel modules listed in this section are loaded in alphabetical order and removed in reverse alphabetical order by the Legato system. If a module depends on one or more other modules, then the order in which the modules are installed and removed takes the dependencies into consideration. Dependencies are added by adding the modules to the requires: kernelModules: section of the .mdef for the kernel module that depends on them.

commands

To make a command-line tool available to a root user who is logged-in to a shell on a target device tty (e.g., through secure shell [ssh] or a serial console):

  1. Build an app containing the executable.
  2. Add the executable to the "commands:" section of the .sdef file.

Each entry in the commands section looks like this:

commandName = appName:/path/to/exe

The path to the executable must be an absolute path within the application's read-only installed files. For example, if the executable is a script that was bundled into the app "myApp" to appear at "/usr/share/exe" inside the myApp's sandbox at runtime, then the command would be specified as

commandName = myApp:/usr/share/exe

If the executable is built using an "executables" section in a .adef file, then the executable will appear in the app's bin directory. For example,

apps:
{
myTools // This app's .adef builds an exe called "led" that can be used to turn LEDs on and off.
}
 
commands:
{
led = myTools:/bin/led // When I login via ssh, I can run "led 1 on" to turn on LED 1.
}
Warning
When the command runs, it runs with the full privileges of the user that runs it. If you login as root and run a command, the command executes with root user privileges.

externalWatchdogKick

If your system is hooked up to an external watchdog (e.g.; wp85 is externally hooked up to Linux's Softdog) the internal watchdog daemon will "kick" the external watchdog at a specified time as long as all watched processes and apps are running and have successfully "kicked" the internal watchdog.

The externalWatchdogKick sets the interval for the internal watchdog daemon to kick the external watchdog. If no external watchdog exists then externalWatchdogKick will have no effect on the system.

If this section is not specified then the default of 30 seconds will be used.

Example:

externalWatchdogKick: 120000 // Configure external watchdog kick to 2mins