Correct way of combining multiple components into a single app?

Hi all,

I have been spending quite some time with the legato framework and really like it so far. I have started building my own app and I have reached the point where my system is getting too big to have all functionality in one component, so I want to build an app using multiple (custom) components.

I have studied the following documents to help me in this process:
defFilesCdef.html
defFilesAdef.html
basicAppsIPC.html
basicAppsClientServer.html
basicAppsCompMulti.html

So what I gather from all this is that:

  • I need a .adef for my app that:
    – binds server interfaces to clients
    – defines my executable (s)
    – determines how many process my app will run
    – determines what components run in what process

  • I need a .cdef for every component:
    provides: api: describes what interface my component exposes (IPC server?)
    requires: api: describes what interface my component needs (IPC client?)
    – I need to have a .api file if I want to expose my component to other components

  • Placing functionally similar code in a single component is good for reusability/portability/security/debugging

What I managed so far is:

  • build an app
  • build multiple components
  • write a .api file
  • define the interface between two components using provides: and requires:

What I don’t understand now is how I bundle my components into an executable.

This page:
https://docs.legato.io/17_10/basicAppsClientServer.html
states that the example .adef defines two executables (myServer and myClient), like this:

executables:
{
myServer = ( greetServer )
myClient = ( greetClient )
}

processes:
{
run:
{
    (myServer)
    (myClient)
}
}

bindings:
{
myClient.greetClient.hello -> myServer.greetServer.hello
}

It then starts one instance of myServer and one instance of myClient , and binds myClient.greetClient.hello to myServer.greetServer.hello .

Okay, makes sense.

But then in: https://docs.legato.io/17_10/basicAppsCompMulti.html
Another .adef is defined, and in my eyes the only difference is the names of the executables:
But here it is stated that:

Now that we have componentized the client and server functionality, we are free to deploy those components to any executables we want without having to change the components at all. In fact, multiple components can be included in a single executable.

To demonstrate, we can put the two components greetClient and greetServer into the same executable. This is a simple change to helloWorld.adef like this:

executables:
{
    helloServer = ( greetServer )
    helloClient = ( greetClient )
}

processes:
{
    run:
    {
        (helloClient)
        (helloServer)
    }
}

bindings:
{
     helloClient.greetClient.hello -> helloServer.greetServer.hello
}

And in the MangOH redNodeSensorToCloud example there are even multiple components combined to a single executable. When I try to implement this on my project I get a “cannot find x binding” type or errors, after compiling and running the app on the target. I also don’t understand why you would event want to do this?

I don’t see the combining of multiple components into a single exe anywhere in the legato sample applications, so I’m wondering why this is done in mangoh examples. I also hope you understand my confusion and can provide some help/explanation or point me in the right direction.

Kind regards,

Stefan

Hi @langestefan,

Can you share your .cdef files here?

Also, do your source files (.c) which make calls to the hello.api functions include this?

#include "interfaces.h"

Cheers,
Raf

Hi raf,

Thanks for your response.

I have (atleast) this in every source file that makes calls to the api:
/* Includes */
#include “legato.h”
#include “interfaces.h”

This is my .adef:

sandboxed: true
start: manual

executables:
{
    //Connectivity_Bridge = ( EVENTSComponent BLEComponent) <-- this causes binding issues when the app runs but compiles fine
    
    events = ( EVENTSComponent) // <-- compiles & runs fine
    ble = ( BLEComponent) // <-- compiles & runs fine
}

processes:
{
    envVars:
    {
        LE_LOG_LEVEL = DEBUG
    }

    run:
    {
        ( events )
        ( ble )
    }
}

bindings:
{
	// Top level
	events.EVENTSComponent.ble -> ble.BLEComponent.ble
}

EVENTSComponent.cdef:

sources:
{
    events.c
}

requires:
{
	api:
    {
    	ble = ble.api
    }
}

BLEComponent.cdef:

sources:
{
    ble.c
}

provides:
{
    api:
    {
        ble = ble.api
    }
}

My ble.api file is in the toplevel directory. Can it also be placed in one of the component directories?

@langestefan, your “ble.api” file is well placed