All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Create a Basic Component

This is how to create a basic component, written in C, that just prints "Hello World." when the process it is in starts up.

First, create a directory: the directory name will become the component name.

$ mkdir helloComp

Next, create a file called "Component.cdef" in the helloComp directory. The build tools look for this file.

$ gedit helloComp/Component.cdef

Our minimalist Component.cdef file contains only a "sources:" section, listing our C source code file ("hi.c").

sources:

    hi.c
Note
The build tools figure out what language the source code is written in by looking at the filename extension. So, because our file "hi.c" ends in ".c", the build tools will try to use a C compiler to compile it into a library when it gets included in an executable.

Now we create our implementation file "hi.c":

$ gedit helloComp/hi.c

It should contain the following:

#include "legato.h"
COMPONENT_INIT
{
LE_INFO("Hello world.\n");
}

This looks very similar to the original C "hello, world" program from Kernighan's and Richie's "The C Programming Language", except that:

  • #include <stdio.h> is replaced with #include "legato.h"
  • main() is replaced with COMPONENT_INIT

In fact, legato.h will include stdio.h, along with a bunch of other system headers and Legato framework headers. This reduces the amount of time you have to spend including header files to get access to the functions and data types you need.

The COMPONENT_INIT macro is used to identify your component initializer. Every component must have a component initializer.

By using component initializers instead of having each component implement their own main() function, we make it possible to run multiple components in the same executable, and even share a thread between those components. The main thread of the process (the main() function that is auto-generated by the build tools) will automatically call the component's initializer at the appropriate time in the start-up sequence of the process, based on the inter-dependencies between components. If component A is used by component B, then component A's initializer will be run before component B's initializer. Therefore, component B can safely call the API functions of component A, knowing that component A has already been initialized. This of course won't work if both components depend on each other (directly or indirectly through other components). That is one of the reasons why such dependency loops are not permitted between components. The framework will detect inter-component dependency loops at build time and terminate the build.

Component initializers don't take any parameters and don't return anything, but they must always return ; unless they experience a fatal error, in which case they must terminate the process with a non-zero exit code (which can be done using LE_FATAL(), LE_ASSERT(), etc. ).

Note
If a component's initializer doesn't return, the process will not be able to finish initializing all the components that have been deployed to it and the process's main thread will never process any events that are queued to it.

In our "Hello World" example, we just use our component initializer to print "Hello world." to the log using LE_INFO().

Now let's package this into an application by creating an application definition:

$ gedit hi.adef

that looks like this inside:

executables:

    helloWorld ( helloComp )

processes:

run: (helloWorld)

And then build it like this:

$ mkapp hi.adef -t wp7

And install on target like this:

$ instapp hi.wp7 192.168.1.2
Note
Your installed application's output will not appear on the terminal you used to install the application. It will go into the syslog buffer on the target device, which can be viewed using logread.

Copyright (C) Sierra Wireless, Inc. 2014. All rights reserved. Use of this work is subject to license.