This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision | |||
|
arcs2:creating_a_component_library [2013/08/21 15:06] didier [Embedding components into a library] |
arcs2:creating_a_component_library [2013/08/21 16:08] (current) didier [Embedding components into a library] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== 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 | ||
| + | [[http://qt-project.org/doc/qt-5.1/qtcore/qobject.html|QObjects]] | ||
| + | with | ||
| + | specific [[http://qt-project.org/doc/qt-5.1/qtcore/signalsandslots.html|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: | ||
| + | <file cpp 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 | ||
| + | }; | ||
| + | </file> | ||
| + | The implementation of such components will not be a problem and will unfold quite naturally. | ||
| + | <file cpp 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; | ||
| + | } | ||
| + | </file> | ||
| + | |||
| + | ===== 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 [[http://arcs.ibisc.univ-evry.fr/doc/arcslibmaker.html|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 [[http://qt-project.org/doc/qt-5.1/qtdoc/qmake-manual.html|qmake tool]]). | ||
| + | <hidden click to display project file contents ''sample.pro''> | ||
| + | <code bash> | ||
| + | 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 | ||
| + | </code> | ||
| + | </hidden> | ||
| + | |||
| + | 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: | ||
| + | <file xml libsample.alx> | ||
| + | <library> | ||
| + | <headers> | ||
| + | <header name="sample.h"/> | ||
| + | </headers> | ||
| + | <components> | ||
| + | <component name="Loop"/> | ||
| + | <component name="DisplayInt"/> | ||
| + | </components> | ||
| + | </library> | ||
| + | </file> | ||
| + | |||
| + | 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''. | ||
| + | <hidden Click here to display ''alm_libsample.cpp''> | ||
| + | <code 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"); | ||
| + | } | ||
| + | </code> | ||
| + | </hidden> | ||
| + | ===== 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: | ||
| + | - prepare component source files; | ||
| + | - launch ''arcslibmaker''; | ||
| + | - edit XML files that were produced by ''arcslibmaker'' in order to tell what are the components; | ||
| + | - launch ''qmake'' to generate a ''Makefile'' under Unix like systems; | ||
| + | - compile the library using ''make''. | ||
| + | |||