From: Enar Väikene Date: Fri, 22 Jul 2011 13:53:40 +0000 (+0300) Subject: Written more tutorial files. X-Git-Url: https://vaikene.ee/gitweb/gitweb.cgi?a=commitdiff_plain;h=368818c22af812ac35f5ff69423522dbd54d37ed;p=evaf Written more tutorial files. --- diff --git a/www/highlight.css b/www/highlight.css new file mode 100644 index 0000000..d490944 --- /dev/null +++ b/www/highlight.css @@ -0,0 +1,20 @@ +/* Style definition file generated by highlight 3.3, http://www.andre-simon.de/ */ + +/* Highlighting theme: Kwrite Editor */ + +body.hl { background-color:#e0eaee; } +pre.hl { color:#000000; background-color:#e0eaee; font-size:10pt; font-family:'Courier New';} +.hl.num { color:#b07e00; } +.hl.esc { color:#ff00ff; } +.hl.str { color:#bf0303; } +.hl.pps { color:#818100; } +.hl.slc { color:#838183; font-style:italic; } +.hl.com { color:#838183; font-style:italic; } +.hl.ppc { color:#008200; } +.hl.opt { color:#000000; } +.hl.lin { color:#555555; } +.hl.kwa { color:#000000; font-weight:bold; } +.hl.kwb { color:#0057ae; } +.hl.kwc { color:#000000; font-weight:bold; } +.hl.kwd { color:#010181; } + diff --git a/www/pswgen02.html b/www/pswgen02.html new file mode 100644 index 0000000..021c93e --- /dev/null +++ b/www/pswgen02.html @@ -0,0 +1,23 @@ + + + + + + eVaf Tutorial - 02 - Preparations + + + + + + + + +

eVaf Tutorial

+ +

02 - Preparations

+ +

In the next section 03 - Generator Module we write the Generator module.

+ + + + diff --git a/www/pswgen03.html b/www/pswgen03.html new file mode 100644 index 0000000..056da8e --- /dev/null +++ b/www/pswgen03.html @@ -0,0 +1,334 @@ + + + + + + eVaf Tutorial - 03 - Generator Module + + + + + + + + + +

eVaf Tutorial

+ +

03 - Generator Module

+ +

In this section we write the Generator module. According to the specification, the Generator module has to + generate strong passwords in such a way that by feeding the module with the same input data we always get the + same password.

+ +

iGenerator interface

+ +

We start by defining the interface for the module. For this create the file igenerator.h in the + src/apps/pswGen/Generator directory:

+ +
/**
+ * @file src/apps/PswGen/Generator/igenerator.h
+ */
+#ifndef __PSWGEN_GENERATOR_IGENERATOR_H
+#  define __PSWGEN_GENERATOR_IGENERATOR_H
+
+#endif // igenerator.h
+ +

The interface class needs to be derived from QObject and we also need QString for input + data and generated passwords:

+ +
#include <QObject>
+#include <QString>
+ +

To avoid potential name collisions with other existing or future modules, we use the eVaf::PswGen + namespace for this application:

+ +
namespace eVaf {
+namespace PswGen {
+
+} // namespace eVaf::PswGen
+} // namespace eVaf
+ +

We call the interface class iGenerator: + +

class iGenerator : public QObject
+{
+    Q_OBJECT
+public:
+};
+ +

All the interface classes need a default constructor and an empty virtual destructor. Do not perform any actions + in these constructors and destructors. Instead, leave it up to the class that implements the interface.

+
/// Interface constructor
+iGenerator() : QObject() {}
+
+/// Empty virtual destructor
+virtual ~iGenerator() {}
+ +

Now we add the functionality to the interface and according to the specification we need two functions -- one that + generates passwords and another that returns the maximum length of the password:

+ +
virtual QString generatePassword(QString const & name, QString const & masterPassword, int length, uint flags = 0) const = 0;
+
+virtual int maxLength() const = 0;
+ +

I am training myself to use the style of writing declarations like "QString const &", which refers to a non-mutable QString object similar to "int maxLength() const", which is a function that does not modify the object's data members. Feel free to use the traditional way of writing "const QString &" if this looks weird to you.

+ +

The iGenerator interface needs to be visible for other modules and marked for export. We do this by creating the src/apps/PswGen/Generator/lib.h file, which defines the PSWGEN_GENERATOR_EXPORT macro:

+
/**
+ * @file src/apps/PswGen/Generator/lib.h
+ */
+#ifndef __PSWGEN_GENERATOR_LIB_H
+#  define __PSWGEN_GENERATOR_LIB_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(PSWGEN_GENERATOR_LIBRARY)
+#  define PSWGEN_GENERATOR_EXPORT Q_DECL_EXPORT
+#else
+#  define PSWGEN_GENERATOR_EXPORT Q_DECL_IMPORT
+#endif
+#endif // libgen.h
+ +

Then we include this new header file in our interface header file and modify the iGenerator class definition by adding + the PSWGEN_GENERATOR_EXPORT macro to it:

+
#include "lib.h"
+
+/// ...
+
+class PSWGEN_GENERATOR_EXPORT iGenerator : public QObject
+ +

This is pretty much all we need to add to the iGenerator interface and here is the final file:

+ +
/**
+ * @file src/apps/PswGen/Generator/igenerator.h
+ */
+
+#ifndef __PSWGEN_GENERATOR_IGENERATOR_H
+#  define __PSWGEN_GENERATOR_IGENERATOR_H
+
+#include "lib.h"
+
+#include <QObject>
+#include <QString>
+
+namespace eVaf {
+namespace PswGen {
+
+/// Password generator interface.
+class PSWGEN_GENERATOR_EXPORT iGenerator : public QObject
+{
+    Q_OBJECT
+
+public:
+
+    /// Interface constructor
+    iGenerator() : QObject() {}
+
+    /// Empty virtual destructor
+    virtual ~iGenerator() {}
+
+    /// Generates a strong password
+    virtual QString generatePassword(QString const & name, QString const & masterPassword, int length, uint flags = 0) const = 0;
+
+    /// Returns the maximum length of generated passwords
+    virtual int maxLength() const = 0;
+
+};
+
+} // namespace eVaf::PswGen
+} // namespace eVaf
+
+#endif // igenerator.h
+
+ +

As a final touch, we create a file called iGenerator with the following content:

+
#include "igenerator.h"
+ +

With this file in place other modules can use #include "Generator/iGenerator" instead of #include "Generator/igenerator.h" similar to other eVaf and Qt include files.

+ +

Generator module

+ +

Now we write the Generator module itself. The module class has to be derived from the Plugins::iPlugin interface class + with or without the Plugins::iPluginFactory factory class.

+ +

The Plugins::iPluginFactory factory class should be used when more than one plugins are implemented by the same + module. The factory class takes care of creating individual plugins whenever they are instantiated. This module implements only + one plugin and we opt to the implementation without the factory class.

+ +

Create the module.h header file in the src/apps/PswGen/Generator directory:

+ +
/**
+ * @file src/apps/PswGen/Generator/module.h
+ */
+#ifndef __PSWGEN_GENERATOR_MODULE_H
+#  define __PSWGEN_GENERATOR_MODULE_H
+
+#endif // module.h
+ +

As this is a simple module, we define all our class in this single header file. This includes the implementation + of the iGenerator interface and also the plugin itself. Se we need to include header files for the + iGenerator and iPlugin interfaces:

+ +
#include "igenerator.h"
+#include <Plugins/iPlugin>
+ +

We are going to put every public class in this module into the eVaf::PswGen::Generator namespace and private + classes into the eVaf::PswGen::Generator::Private namespace:

+ +
namespace eVaf {
+namespace PswGen {
+
+/// Module that generates strong passwords using cryptographic methods
+namespace Generator {
+
+/// Internal implementation of the Generator module
+namespace Internal {
+
+} // namespace eVaf::PswGen::Generator::Internal
+} // namespace eVaf::PswGen::Generator
+} // namespace eVaf::PswGen
+} // namespace eVaf
+ +

We call the class that implements the module simply Module. This is a public class and goes into the + eVaf::PswGen::Generator namespace. We however, do not need to export it as we did with the iGenerator + interface class, as this will be done by Qt.

+ +
class Module : public Plugins::iPlugin
+{
+    Q_OBJECT
+
+public:
+
+    Module();
+
+    virtual ~Module();
+
+}
+ +

The iPlugin interface has three abstract methods that we need to implement in our class -- init(), + done() and isReady(). Since this simple module is always ready, we can return true in the + isReady() function. More complex modules can use a private mReady variable, which they set to true + once all the initialization is done. + +

virtual bool init(QString const & args);
+
+virtual void done();
+
+virtual bool isReady() const { return true; }
+ +

We need the iGenerator interface object in this module and add it to the private members section: + +

private: // Members
+
+    /// iGenerator interface instance
+    Internal::GeneratorImpl * mGenerator;
+ +

As the Internal::GeneratorImpl class is not declared yet, we need to add this forward declaration before the + Module class:

+ +
namespace Internal {
+    class GeneratorImpl;
+} // namespace eVaf::PswGen::Generator::Internal
+ +

Then we can move forward and implement the iGenerator interface, which we already happened to call + GeneratorImpl. This class goes into the eVaf::PswGen::Generator::Internal namespace:

+ +
class GeneratorImpl : public iGenerator
+{
+    Q_OBJECT
+
+public:
+
+    GeneratorImpl();
+
+    virtual ~GeneratorImpl();
+
+    virtual QString generatePassword(QString const & name, QString const & masterPassword, int length, uint flags = 0) const;
+
+    virtual int maxLength() const;
+};
+ +

Here is the final module.h file:

+ +
/**
+ * @file src/apps/PswGen/Generator/module.h
+ */
+
+#ifndef __PSWGEN_GENERATOR_MODULE_H
+#  define __PSWGEN_GENERATOR_MODULE_H
+
+#include "igenerator.h"
+
+#include <Plugins/iPlugin>
+
+#include <QObject>
+#include <QString>
+
+namespace eVaf {
+namespace PswGen {
+
+/// Module that generates strong passwords using cryptographic methods
+namespace Generator {
+
+/// Internal implementation of the Generator module
+namespace Internal {
+    class GeneratorImpl;
+} // namespace eVaf::PswGen::Generator::Internal
+
+/// Plugins/iPlugin interface implementation.
+class Module : public Plugins::iPlugin
+{
+    Q_OBJECT
+
+public:
+
+    Module();
+
+    virtual ~Module();
+
+    virtual bool init(QString const & args);
+
+    virtual void done();
+
+    virtual bool isReady() const { return true; }
+
+
+private: // Members
+
+    /// iGenerator interface instance
+    Internal::GeneratorImpl * mGenerator;
+
+};
+
+namespace Internal {
+
+ /// iGenerator interface implementation.
+class GeneratorImpl : public iGenerator
+{
+    Q_OBJECT
+
+public:
+
+    GeneratorImpl();
+
+    virtual ~GeneratorImpl();
+
+    virtual QString generatePassword(QString const & name, QString const & masterPassword, int length, uint flags = 0) const;
+
+    virtual int maxLength() const;
+
+};
+
+} // namespace eVaf::PswGen::Generator::Internal
+} // namespace eVaf::PswGen::Generator
+} // namespace eVaf::PswGen
+} // namespace eVaf
+
+#endif // module.h
+ +

Continue implementing the Generator Module.

+ + + + diff --git a/www/pswgen04.html b/www/pswgen04.html new file mode 100644 index 0000000..df82cb0 --- /dev/null +++ b/www/pswgen04.html @@ -0,0 +1,306 @@ + + + + + + eVaf Tutorial - 04 - Generator Module + + + + + + + + + +

eVaf Tutorial

+ +

04 - Generator Module

+ +

Now we are going to implement all the classes declared in the module.h. Create the module.cpp file + in the src/apps/PswGen/Generator directory. We obviously include the module.h header file, but also + the QtCore header file for any non-GUI Qt classes.

+ +
/**
+ * @file src/apps/PswGen/Generator/module.cpp
+ */
+
+#include "module.h"
+
+#include <QtCore>
+ +

All the eVaf modules need to include version information. This is common for all the modules and we can simply + copy existing version info files from another eVaf module:

+ +
evaf/src/apps/PswGen/Generator $ cp ../../../plugins/SdiWindow/version.{h,rc} .
+ +

The version.h file contains version information for the module. The version.rc is for Windows + builds only and embeds the same version information into the dll or exe file. Modify the copied version.h + file for our new module. The version.rc file uses the values from the version.h and does not + need to be touched.

+ +
/**
+ * @file src/apps/PswGen/Generator/version.h
+ */
+#ifndef __PSWGEN_GENERATOR_VERSION_H
+#define __PSWGEN_GENERATOR_VERSION_H
+
+#include <version_rc.h>
+
+/**
+ * Module/library version number in the form major,minor,release,build
+ */
+#define VER_FILE_VERSION                0,1,1,1
+
+/**
+ * Module/library version number in the string format (shall end with \0)
+ */
+#define VER_FILE_VERSION_STR            "0.1.1.1\0"
+
+/**
+ * Module/library name (shall end with \0)
+ */
+#define VER_MODULE_NAME_STR             "PswGen\0"
+
+/**
+ * Module type (see version_rc.h for all the types)
+ */
+#define VER_MODULE_TYPE                 MT_GENERIC
+
+/**
+ * Module type in the string format (see version_rc for all the types)
+ */
+#define VER_MODULE_TYPE_STR             MT_GENERIC
+
+/**
+ * Original file name for windows (shall end with \0)
+ */
+#define VER_ORIGINAL_FILE_NAME_STR      "PswGen.dll\0"
+
+/**
+ * Description of the module/library (shall end with \0)
+ */
+#define VER_FILE_DESCRIPTION_STR         "Module that generates strong passwords using MD5 hashes.\0"
+
+#endif // version.h
+ +

Then include the version info file in the module.cpp file and use the VER_EXPORT_VERSION_INFO() macro + to export version information from the module. This macro defines a public function that all the eVaf modules export and + is used to collect version information from them. In your modules you only need to modify the version.h file and then + use the VER_EXPORT_VERSION_INFO() macro once somewhere in your code.

+ +
#include "version.h"
+
+VER_EXPORT_VERSION_INFO()
+ +

We make our life easier with several using namespace keywords:

+ +
using namespace eVaf;
+using namespace eVaf::PswGen;
+using namespace eVaf::PswGen::Generator;
+ +

The Module class needs to instantiate the iGenerator interface in the constructor. We also need to set + the QObject's name property to the name of the plugin by combining the name of the module with the name of the class. + While the application would work without the name property, it makes our life much easier if the name property is set.

+ +

Finally, we output an info message telling that the object was created. Every eVaf module and class is expected to + output info messages when they are created, destroyed, initialized or destroyed.

+ +
Module::Module()
+    : Plugins::iPlugin()
+{
+    setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
+
+    mGenerator = new Internal::GeneratorImpl;
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+ +

The EVAF_INFO macro comes from the Common/iLogger header file ane we need to include it:

+ +
#include <Common/iLogger>
+ +

The destructor should delete the iGenerator interface object, which we created in the constructor. The common + rule is that any resources allocated in the constructor shall be released in the destructor, preferrably in the opposite + order, ie. the first resource allocated in the constructor is released last in the destructor. + +

Module::~Module()
+{
+    delete mGenerator;
+
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+ +

We also need to implement init() and done() functions, which are used to initialize and finalize modules. + They are similar to the constructor and destructor with two major differences:

+
    +
  1. The init() function can fail and return false to indicate a failure. eVaf does not use exceptions and + this is the only way for a module to fail without terminating the whole application. A failed module will be disabled + and the rest of the application can still run if it can.
  2. +
  3. eVaf modules are loaded in two steps. At first, all the modules are created, which means that all the objects + are constructed. Only then will eVaf call init() functions meaning that when the init() function is + called, all the modules are already loaded and instantiated. Interfaces and resources from other modules that might be not + available when the object is created, are available when the init() function is called.
  4. +
+ +

The rule for init() and done() functions is the same than for constructors and destructors -- any resource + allocated in the init() function shall be released in the done() function and preferrably in the opposite + order.

+ +

This simple module needs no extra resources to be allocated and our init() and done() functions can be + the following:

+ +
bool Module::init(QString const & args)
+{
+    Q_UNUSED(args);
+
+    EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+    return true;
+}
+
+void Module::done()
+{
+    EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
+ +

We continue by implementing the iGenerator interface. There are no resources to be allocated in the constructor + and we just set the QObject's name property and output the info message.

+ +

We also register the iGenerator interface in the global registry so that other modules can query for it and + use our interface. This is done by using the Common::iRegistry interface, which we need to include:

+ +
#include <Common/iRegistry>
+ +

The GeneratorImpl class was declared in the eVaf::PswGen::Generator::Internal namespace, so we need + another using namespace keyword before the implementation of the class:

+ +
using namespace eVaf::PswGen::Generator::Internal;
+
+GeneratorImpl::GeneratorImpl()
+    : iGenerator()
+{
+    setObjectName(QString("%1.iGenerator").arg(VER_MODULE_NAME_STR));
+
+    Common::iRegistry::instance()->registerInterface("iGenerator", this);
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+GeneratorImpl::~GeneratorImpl()
+{
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+ +

Finally, we write the generatePassword function that does the actual job of the module.

+ +

We use the MD5 cryptographic hash function to calculate a hash value over the name and masterPassword values. + The result, which is a binary blob, needs to be convert into something that can be used as a password and we use base 64 encoding + for this and cut the result to the requested length:

+ +
QString GeneratorImpl::generatePassword(QString const & name, QString const & masterPassword, int length, uint flags) const
+{
+    Q_UNUSED(flags);
+
+    QByteArray inputString = QString("%1%2").arg(name).arg(masterPassword).toLatin1();
+    QCryptographicHash hash(QCryptographicHash::Md5);
+    hash.addData(inputString);
+    QByteArray result = hash.result().toBase64();
+    if (length > 0)
+        return result.left(length);
+    else
+        return result;
+}
+ +

We also know now the maximum length of the generated password, which is 24. Go back to the module.h header file and + modify the GeneratorImpl::maxLength() function:

+ +
virtual int maxLength() const { return 24; }
+ +

Here is the final module.cpp file:

+ +
/**
+ * @file src/apps/PswGen/Generator/module.cpp
+ */
+
+#include "module.h"
+#include "version.h"
+
+#include <Common/iLogger>
+#include <Common/iRegistry>
+
+#include <QtCore>
+
+VER_EXPORT_VERSION_INFO()
+Q_EXPORT_PLUGIN2(VER_MODULE_NAME_STR, eVaf::PswGen::Generator::Module)
+
+using namespace eVaf;
+using namespace eVaf::PswGen;
+using namespace eVaf::PswGen::Generator;
+
+Module::Module()
+    : Plugins::iPlugin()
+{
+    setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
+
+    mGenerator = new Internal::GeneratorImpl;
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+Module::~Module()
+{
+    delete mGenerator;
+
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+bool Module::init(QString const & args)
+{
+    Q_UNUSED(args);
+
+    EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+    return true;
+}
+
+void Module::done()
+{
+    EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
+
+using namespace eVaf::PswGen::Generator::Internal;
+
+GeneratorImpl::GeneratorImpl()
+    : iGenerator()
+{
+    setObjectName(QString("%1.iGenerator").arg(VER_MODULE_NAME_STR));
+
+    Common::iRegistry::instance()->registerInterface("iGenerator", this);
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+GeneratorImpl::~GeneratorImpl()
+{
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+QString GeneratorImpl::generatePassword(QString const & name, QString const & masterPassword, int length, uint flags) const
+{
+    Q_UNUSED(flags);
+
+    QByteArray inputString = QString("%1%2").arg(name).arg(masterPassword).toLatin1();
+    QCryptographicHash hash(QCryptographicHash::Md5);
+    hash.addData(inputString);
+    QByteArray result = hash.result().toBase64();
+    if (length > 0)
+        return result.left(length);
+    else
+        return result;
+}
+ +

Next -- 05 - Building Generator Module.

+ + + diff --git a/www/pswgen05.html b/www/pswgen05.html new file mode 100644 index 0000000..bc6b5d6 --- /dev/null +++ b/www/pswgen05.html @@ -0,0 +1,173 @@ + + + + + + eVaf Tutorial - 05 - Building Generator Module + + + + + + + + + +

eVaf Tutorial

+ +

05 - Building Generator Module

+ +

CMakeLists.txt

+ +

eVaf uses CMake as its build system and needs a file called CMakeLists.txt + in the src/apps/PswGen/Generator directory. Create the file and start editing it.

+ +

We use the TARGET variable to set the name of the module. This makes it easier to re-use the CMakeLists.txt + file in other modules and applications.

+ +
set(TARGET PswGen)
+ +

Then we include Qt include files and libraries. We also specify, that we do not want to include the QtGui module as this + module does not any classes from the QtGui module. By removing the QtGui module, we remove any graphical libraries as + dependencies for this module and it can be used in headless systems.

+ +
set(QT_DONT_USE_QTGUI TRUE)
+include(${QT_USE_FILE})
+ +

The next line adds the PSWGEN_GENERATOR_LIBRARY definition to the compiler (remember the lib.h file and + the PSWGEN_GENERATOR_EXPORT macro in the igeneraror.h file?): + +

add_definitions(-DPSWGEN_GENERATOR_LIBRARY)
+ +

Add all the eVaf include directories to the compiler. The variable eVaf_INCLUDE contains all the eVaf include + directories and is already initialized with proper values when this CMakeLists.txt file is processed.

+ +
include_directories(${eVaf_INCLUDE})
+ +

Then we initialize a variable with the names of all the eVaf modules that this module needs to be linked with. We only + need to specify the names of libraries without prefixes or suffixes like ".dll" or ".so". These libraries also become dependencies + of this module and will be built whenever we build this module.

+ +
set(eVaf_LIBRARIES CommonLib PluginsLib)
+ +

Collect all the source files that needs to be compiled:

+ +
set(SRCS
+    module.cpp
+)
+ +

Collect header files that need to be processed with the Qt meta-object compiler. Any header file that contains + class declarations with the Q_OBJECT keyword and/or signals and slots, needs to be included here. To avoid warnings + during the build, do not include here any other header files.

+ +
set(MOC_HDRS
+    igenerator.h
+    module.h
+)
+ +

The following line adds the Windows version info resource file to the list of source files:

+
if(WIN32)
+    set(SRCS ${SRCS} version.rc)
+endif(WIN32)
+ +

Process specified header files with the Qt meta-object compiler:

+ +
qt4_wrap_cpp(MOC_SRCS ${MOC_HDRS})
+ +

Put it all together and compile the module:

+ +
add_library(${TARGET} SHARED ${SRCS} ${MOC_SRCS})
+ +

Finally, link the module:

+ +
target_link_libraries(${TARGET} ${QT_LIBRARIES} ${eVaf_LIBRARIES})
+ +

And the final CMakeLists.txt file looks the following:

+ +
# src/apps/PswGen/Generator/CMakeLists.txt
+
+# Name of the target
+set(TARGET PswGen)
+
+# Qt modules
+set(QT_DONT_USE_QTGUI TRUE)
+include(${QT_USE_FILE})
+
+# Needed for exporting symbols from this library
+add_definitions(-DPSWGEN_GENERATOR_LIBRARY)
+
+# Include directories
+include_directories(${eVaf_INCLUDE})
+
+# Required eVaf libraries
+set(eVaf_LIBRARIES CommonLib PluginsLib)
+
+# Source files
+set(MOC_HDRS
+    igenerator.h
+    module.h
+)
+
+# Header files for the Qt meta-object compiler
+set(MOC_HDRS
+    igenerator.h
+    module.h
+)
+
+# Version info resource file for Windows builds
+if(WIN32)
+    set(SRCS ${SRCS} version.rc)
+endif(WIN32)
+
+# Run the Qt meta-object compiler
+qt4_wrap_cpp(MOC_SRCS ${MOC_HDRS})
+
+# Compile the module
+add_library(${TARGET} SHARED ${SRCS} ${MOC_SRCS})
+
+# Link the module
+target_link_libraries(${TARGET} ${QT_LIBRARIES} ${eVaf_LIBRARIES})
+ +

We also need CMakeLists.txt files in parent directory src/apps/PswGen. + In this file we add the PswGen directory to the list of include directories, which makes it possible to use + +

# src/apps/PswGen/CMakeLists.txt
+set(eVaf_INCLUDE ${eVaf_INCLUDE} ${SMAKE_SOURCE_DIR}/src/apps/PswGen)
+add_subdirectory(Generator)
+ +

Modify the CMakeLists.txt file in the src/apps directory and include the PswGen application:

+ +
# src/apps/CMakeLists.txt
+# ...
+add_subdirectory(PswGen)
+ +

Building the module

+ +

Now our module is included in the build system and we can try to compile it. Go to the eVaf root directory and create + a build directory:

+ +
evaf $ mkdir build
+evaf $ cd build
+ +

In the build directory, run cmake:

+ +
evaf/build $ cmake ..
+ +

If cmake finishes without errors, build the module with the make command:

+ +
evaf/build $ make PswGen
+ +

If you get compiler errors during the build, fix them. If the build finishes without errors, check the content of the + bin directory:

+ +
evaf/build $ ls bin
+libCommonLib.so*  libPluginsLib.so*  libPswGen.so*
+evaf/build $
+ +

As you can see, there are three libraries now. The libPswGen.so is our module and others are eVaf libraries + that our module needs in order to be run.

+ +

In the next section 06 - Storage Module we write the Storage module. + + +