Creating a component library

For this tutorial, we will only work at creating native ARCS components. We will describe how we design components and store them into libraries. To begin with, ARCS is heavily relying on Qt, so component description will share many similarities with the writing of customized QObjects with specific signals and slots. We will document the steps needed to produce a library like the sample one.

Designing components

We will write two components. The first one will be a Loop which take as a parameter an iteration number and that will execute its iterations. Each iteration will emit a signal indicating the current iteration. At the end, the component will emit a particular signal in order to indicate the loop is finished. The second component will receive an integer value and display it in console (component named DisplayInt). The declaration of these components should be as follows:

sample.h
#include <QObject> 
 
class Loop : public QObject // required public inheritance to QObject
{
  Q_OBJECT // Mandatory macro to create custom signals and slots
  public:
    // Constructor with a specific required signature
    Loop(QObject* parent=0) : QObject(parent) {} 
 
  public slots: // start of slot declarations
    void setIterations(int n); // gives the number of iterations to perform
 
  signals:      // start of signals declarations
    void newIteration(int i);  // signal emitted at each iteration
    void sendToken(QString s); // signal emitted at the end of the loop
};
 
class DisplayInt : public QObject
{
  Q_OBJECT
  public:
    DisplayInt(QObject* parent=0) : QObject(parent) {}
 
  public slots:
    void display(int i);      // slot that will display the integer passed as a parameter
};

The implementation of such components will not be a problem and will unfold quite naturally.

sample.cpp
#include "sample.h" // header declaring components
#include <iostream>
 
void Loop::setIterations(int n)
{
    for (int i=0; i < n; i++) 
    {
      std::cout << "[Loop] Emitting iteration " << i << std::endl;
      emit newIteration(i); // emit trigger the corresponding signal
    }
    emit sendToken("end");
}
 
void DisplayInt::display(int i)
{
  std::cout << "[DInt] Received integer " << i << std::endl;
}

Embedding components into a library

Once components are created, the library will be easy to make. You will have to run once the executable arcslibmaker (you may find more information on arcslibmaker manpage). If files were in a folder named sample, arcslibmaker will create a Qt project file named sample.pro that includes source files as well as special directives in order to compile the component library. Moreover, a file named libsample.alx will be generated and you will have to edit it. If necessary, you can also edit the project file (in this case, you may refer to the complete documentation of the qmake tool).

click to display project file contents sample.pro

click to display project file contents sample.pro

click to display project file contents sample.pro

win32-msvc* {
   TEMPLATE = vclib
 } else {
   TEMPLATE = lib
}
INCLUDEPATH += $$(ARCSDIR)/include
LIBS += -L$$(ARCSDIR)/lib -larcs
CONFIG += dll
QT = core
 
# source files to compile
HEADERS += sample.h
SOURCES += sample.cpp
 
# ARCS specific rules
ALXFILE = libsample.alx
OTHER_FILES += libsample.alx
arcslibrary.output = alm_${QMAKE_FILE_BASE}.cpp
arcslibrary.input = ALXFILE
arcslibrary.commands = arcslibmaker ${QMAKE_FILE_NAME}
arcslibrary.variable_out = SOURCES
QMAKE_EXTRA_COMPILERS += arcslibrary

First, we will have a look at the file libsample.alx which is a XML formatted document describing with a few markups component libraries. In this file, two sections will be of interest:

  • the headers section, where we will put which header files are declaring components;
  • the components section, where we will tell the actual components that the library will store.

Our library contains two components of types Loop and DisplayInt declared in a header file named sample.h. Therefore, our file libsample.alx should be edited as follows:

libsample.alx
<library>
  <headers>
    <header name="sample.h"/>
  </headers>
  <components>
    <component name="Loop"/>
    <component name="DisplayInt"/>
  </components>
</library>

Thanks to the rules automatically put in the project file, the utility arcslibmaker will be able to parse the file libsample.alx and generate C++ wrappers for the component library in a file named alm_libsample.cpp.

Click here to display alm_libsample.cpp

Click here to display alm_libsample.cpp

Click here to display alm_libsample.cpp

#include<arcs/arcslibtoolkit.h>
#include<QMetaType>
#include<sample.h>
 
extern "C" DLL_EXPORT void arcsLibraryRegister(ARCSComponentMap* cmap, ARCSFamilyMap* , ARCSTypeMap* )
{
  cmap->insert("Loop",new ARCSNativeComponentTemplate<Loop>());
  cmap->insert("DisplayInt",new ARCSNativeComponentTemplate<DisplayInt>());
}
 
extern "C" DLL_EXPORT void arcsLibraryUnregister(ARCSComponentMap* cmap, ARCSFamilyMap* , ARCSTypeMap* )
{
  delete cmap->take("Loop");
  delete cmap->take("DisplayInt");
}

Compiling the library

One call to qmake will generate the appropriate Makefile (or MS Visual studio projects). You will then be able to call make in order to compile the library.

The complete workflow

To sum it up, the complete workflow is as follows:

  1. prepare component source files;
  2. launch arcslibmaker;
  3. edit XML files that were produced by arcslibmaker in order to tell what are the components;
  4. launch qmake to generate a Makefile under Unix like systems;
  5. compile the library using make.