C++ Dependency Handling

Ein sehr primitiver Ansatz für ein Dependency Injection in C++

 

-------------basis und factory-------------------
struct BaseModule;
struct ModuleFactory;

/*basis für alle module*/
struct BaseModule
{
    BaseModule(){}
    virtual ~BaseModule(){}

 /* Default creator wenn dependencies */
  template<class ModuleClass>
  static void create(
              ModuleFactory &factory,
              ModuleClass *&module
                 )
  {
      module= new ModuleClass();
  }
};
/* Simple list of modules */

struct BaseModuleList : map<const type_info*,BaseModule*>
{

  void add(BaseModule *_ptr )
  {
    add(typeid(*_ptr),_ptr);
  }
  void add(const type_info &_type , BaseModule *_ptr )
  {
    cout << "Adding module " << _type.name()<< endl;
    ASSERT(count(&_type)==0 || at(&_type)==NULL || at(&_type)==_ptr );
    insert( make_pair(&_type,_ptr) );
  }

  BaseModule* get(const type_info &_type )
  {
    iterator it = find( &_type );
    if ( it!=end() )
      return it->second;
    if (it->second==NULL)
      throw logic_error(string("Circular module dependency detected. Creation of Module ")+ _type.name()+" needs a module which need this module to create.");
    return NULL;
  }
};
/*factory*/
struct ModuleFactory
{

  ModuleFactory(BaseModuleList &modules)
  :modules(modules)
  {}

  BaseModuleList &modules;

/*gebe reference auf Module zurück*/
 template<class B>
  B& get()
  {
    //already present ? Search in modulelist, throw an exception if we request on recursive same type.
    B *module = dynamic_cast<B*>(modules.get( typeid( B ) )) ;

    if (module)
      return *module;

    //Special : um circular dependencies zu erkennen, markieren wir jetzt den zu erstellenden typ indem wir einen NULL Pointer adden.
    modules.add(typeid(B),NULL);
    //Sollte jetzt ein Module , dass von dem Modul benötigt wird,erzeugt wird, auf dieses Modul dependen, gibt es einen Fehler/exception beim get()

    B::create(*this,module);    //TODO: detect circular dependencies !!!! this will cann recursivly get() below...
    modules.add(module);
    return *module;
  }  
};
/*specialize get für eine modulelist */
 template<>
 inline
 BaseModuleList& ModuleFactory::get<BaseModuleList>()
 {
   return modules;
 }
/* special to get ModuleFactory */
template<>
  inline
  ModuleFactory& ModuleFactory::get<ModuleFactory>()
  {
    return *this;
  }


-------------------------------------------------
Header von A 
 
class Module_B; //dependency bleibt in der Implementierung
class Module_C;
class Module_A : public BaseModule
{
    Module_A(Module_B&,Module_C&);
}
template<>
void BaseModule::create<Module_A>(ModuleFactory &factory,Module_A *&module);

-------------------------------------------------
Header von B

class Module_B : public BaseModule
{
}

--------------------------------------------------------------
Header von C

class Module_C : public BaseModule
{
}

-------------------------------------------------

Implementierung von A

include Module_A
include Module_B //muss nur hier B und C kennen, da es sie benutzt
include Module_C

template<>
void BaseModule::create<Module_A>(ModuleFactory &factory,Module_A *&module)
{
  module= new Module_A(factory.get<Module_B>(),factory.get<Module_C>()); //erzeugt A, und reicht B und C hinein... 
}

------------------------------------------------
Beispiel start in einer main.cpp:

    BaseModuleList modules;
    ModuleFactory modulefactory(modules);
    modulefactory.get<Module_A>(); //wenn noch nicht vorhanden beginnt erzeugung von A,B,C

    /* Init Modules */

    for (BaseModuleList::iterator it=modules.begin();it!=modules.end();++it)
    {
        (*it)->init();
    }


Eine mögliche erweiterung sind folgende BOOST PP Kombination um aus einer dependency Liste FactoryFunktion und Constructor zu bauen.

/** Basemodule implementation helper Macros
 *  prefix: BIH_
 *
 *  Helps implementing Factory Creation Function, Construtor out of a Dependecy Sequence list
 *
 *  BIH_DEFINE_FACTORY( baseclassname, dependencylist )
 *    defines a factory function for class baseclassname using dependencylist dependencylist
 *  sample:
 *         #define ModuleA_DEPENDENCY_LIST (DependencyTest)
 *         BIH_DEFINE_FACTORY(ModuleA,ModuleA_DEPENDENCY_LIST)
 *
 * BIH_DEFINE_CONSTRUCTOR(baseclassname, dependencylist )
 *   declare a matching constructor
 * sample:
 *        BIH_DEFINE_CONSTRUCTOR(ModuleA,ModuleA_DEPENDENCY_LIST);
 *
 *
 * BIH_DEFINE_CONSTRUCTOR_IMPL(baseclassname, dependencylist )
 *   implementation of a matching constructor
 * sample:
 *        BIH_DEFINE_CONSTRUCTOR_IMPL(ModuleA,ModuleA_DEPENDENCY_LIST)
 *        {
 *        }
 *    allows extension , to extend initialization list, use special macro or add ,
 *    empty dependency list works not on  BIH_DEFINE_CONSTRUCTOR_IMPL, because of empty list after :
 *
 */

#define BIH_MACRO_DEP1(r, data, elem)  (factory.get<elem>())
#define BIH_MACRO_DEP2(r, data, elem)  (elem &BOOST_PP_CAT(_,elem))
#define BIH_MACRO_DEP3(r, data, elem)  (BOOST_PP_CAT(M_, elem)( BOOST_PP_CAT(_,elem) ))
#define BIH_MACRO_DEP4(r, data, elem)  elem& BOOST_PP_CAT(M_, elem);

#define BIH_DEFINE_FACTORY(BASECLASS,DEPS)  \
    template<>                \
    void BaseModule::create(ModuleFactory &factory,BASECLASS *&module) \
    { \
      module= new BASECLASS( BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(BIH_MACRO_DEP1,,DEPS))); \
    }

#define BIH_DEFINE_CONSTRUCTOR(BASECLASS,DEPS)  \
    BASECLASS( BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(BIH_MACRO_DEP2,,DEPS)))

#define BIH_DEFINE_CONSTRUCTOR_IMPL(BASECLASS,DEPS)  \
    BASECLASS:: BIH_DEFINE_CONSTRUCTOR(BASECLASS,DEPS)  \
    : BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(BIH_MACRO_DEP3,,DEPS)) \

#define BIH_DEFINE_DEP_MEMBER(DEPS)  BOOST_PP_SEQ_FOR_EACH(BIH_MACRO_DEP4,,DEPS)


Ming & Precompiled Header

Gcc unterstützt Precompiled Header. Die Nutzung mit MinGW ist im Prinzip genauso einfach.

Durch einen bekannten Bug crasht ab und zu der Linker. Derzeit gibt es nur zwei Möglichkeiten. Auf Precompiled Header verzichten oder sie auf mehre Header verteilen. dabei ist drauf zu achten das man die Header nicht gegenseitig included ;) , aber dennoch Abhängigkeiten erfüllt sind.

Ich nutze derzeit ein common_stl.h , common_boost.h common_win32.h .

gesplittet wird der erste bei mit 75MB und boost 322MB. Ein einzelnen precompiled Header von 176MB crasht dagegen.

 

Ming & Precompiled Header weiterlesen

Mingw Compiler

Ziel

Diese Anleitung erhebt keinen Anspruch auf Vollständigkeit, aber vielleicht findet der eine oder andere einen Nutzen daran.

Ziel ist es eine kompakte redistributable Toolchain mit dem MinGW Compiler zu erstellen. Diese Toolchain integriert die Standard Tools cmake und boost library.

Alle Pfade beziehen sich auf ein „Root“ Verzeichnis. Ich persönlich bevorzuge ein kurzen Pfad wie D:\MINGW, aber dies ist am Ende irrelevant.

Alternativ kann man sich das komplette Paket auch direkt hier herunterladen.

Vorbereitung

TODO: notizen formulieren

Create Root DIR  c:\mingw32 and d:\mingw64
(Zwei getrennte Verzeichnisse aufgrund einiger Header die derzeit noch inkompatibel sind. Irgendwann sollte ein Verzeichnis ausreichen)

 

Download

URL:

http://mingw-w64.org/doku.php

Deep link auf zip files

ml.exe is Microsoft Assembler
a common Download added to Mingw/bin Directory.
its needed by boost Build.

32Bit Version: URL:
64Bit :  im Windows PSDK enthalten…
es wird nur ml64.exe benötigt um boost atomic zu bauen.

Erstellen wir uns eine mingw-w64.bat

SET MINGW=D:\MINGW64
set PATH=%MINGW%\bin;%PATH%
„C:\Windows\system32\cmd.exe“

Sie erleichtert das weitere arbeiten, wenn die System Umgebungsvariablen nicht angepasst werden sollen.

 

Boost bauen

Für eine andere Boost Version die Anleitung einfach mit anderer Version ausführen.

Download & Extract

d:\mingw64\boost_1_58_0  (350MB)
Download Boost1.57

Nun müßen wir noch boost JAM einmalig bauen. Dafür  im  Verzeichnis boost_1.58.0/  „bootstrap.bat gcc“  ausführen.
Dies sollte b2.exe im aktuellen Verzeichnis erzeugen.

Der nächste Schritt ist, die Buildkonfiguration zu erstellen bzw. zu bearbeiten:

\boost_1_5?_0\project-config.jam

import option ;
#Abort on Error
option.set keep-going : false ;
#Choosing GCC as Toolchain.
using gcc ;

boost_1.58.0/

b2  –layout=tagged variant=debug,release address-model=64 link=static threading=multi runtime-link=static –prefix=%MINGW% –libdir=%MINGW%\lib\boost\ –includedir=%MINGW%\include\ –build-dir=build.dir  –without-mpi –build-type=minimal

Die 64 sollte durch 32 ersetzt werden wenn wir die 32Bit Version bauen wollen. Leider bin ich beim versuch beide Versionen zu bauen gescheitert, da Mingw derzeit einige Header unterschiedlich hat bei 32/64 und so zwei getrennte Verzeichnisse benötigt.
Aber dies ist kein großen Hindernis, nur eines in das ich keine Zeit investieren wollte.

TIP: die Kommandozeile in eine build.bat archivieren. Fürs das nächste mal.

Nach einen build, noch ein install ausführen (selbe Kommandozeile) und schwups ist boost in include/boost und lib/boost kopiert.

Nach dem alles erfolgreich gebaut wurde können wir das boost_1.57 verzeichnis komplett entfernen, was 1-2 GB einspart.

CMAKE

Binary:
http://www.cmake.org/files/v2.8/cmake-3.1.0-win32-x86.zip

Source: (not recommend)

bin nach bin, share nach share … doc nach  doc …

Doxygen & Graphviz

Doxygen,graphviz,dot,mscgen is in d:\MinGW.tc\3rdparty\doxygen\bin
The Directory contains minimal files optimized for usage with doxygen.
To Use graphviz in total, download the graphviz Package.

 

Eclipse CDT und MinGW

Updates

Aufgrund Nachfrage: Notiz aktueller Versionsnummern, zum Zeitpunkt des Eintrages.
[UPDATE]
Eclipse Platform 4.6.0.I20150916-2000
CDT 8.8.0.201509291003
Papyrus UML 1.2.0.201509301002

http://download.eclipse.org/eclipse/updates/4.6milestones/
http://download.eclipse.org/tools/cdt/releases/8.8
http://download.eclipse.org/eclipse/updates/4.6
Allgemeine URLs:
http://download.eclipse.org/releases/mars
Nachfolger von mars: Neon M2 (June 2016)
http://download.eclipse.org/releases/neon

Installation

Eclipse Runtime eclipse-platform-4.5M5a-win32-x86_64.zip entpacken.

update_sites.xml importieren (Beispiel)

Install CDT Development Tools

Toolchain Configuration

Add MINGW Compiler to the PATH, Eclipse auto discover will work.

Setting Window/Preferences
C/C++ / Build / Settings on TAB „Discovery“
Entry „CDT GCC Build-in Compiler Settings MinGW [Shared]“
Change Command by prefix
{COMMAND} with ${MINGW_HOME}\bin\
Sample:

${MINGW_HOME}\bin\${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"

 

Now Eclipse should found your MinGW Compiler on start by Automatic Compiler discovery. And now the CDT indexer
will find all symbols, because now _cplusplus symbol is found and used.

Windows/Preference/C++/Build/Environment
Add PATH with points to gcc PATH=D:\mingw64\bin

This will enable autodetection of MINGW Toolchain and will define MINGW_HOME Variables

C/C++ File Types:
Add *.tcc as c++ header for mingw

This helps the indexer to index STL headers.

Create new project

New Project
Makefile Project with Existing Code
Toolchain for Indexer Settings: MingW (will only be shown ig mingw gcc was found in PATH)

Add Include Directory to Eclipse Index Settings.
(Mingw is added from autodetection already)
Project Settings / C/C++ General / Preprocess Include Paths / CDT User Settings Entries

ADD ${MINGW_HOME}/include (File System path , Built-in , System Headers

C/C++ Build / Make file generation / and untick „Generate Make files automatically“.
In additionally you may have to set the Build location also to ${ProjDirPath}

C/C++ Build / Tool Chain Editor / Current Builder = Gnu Make Builder

(default build ist „make“ bis eigene make targets definiert wurden, dafür kann optional make tool auf mingw32-make gesetzt werden.)
(Project Option C/C++ Build) Build Command = mingw32-make[Leerzeichen]

Create New Target:
cmake
Make Target:
Build Command:cmake -G „MinGW Makefiles“

all

FAQ

 

Beim Build wird Default/sources.mk u.s.w. erzeugt oder es erscheint ein Fehler das sie fehlen

Siehe „Create project“
–> C/C++ Build –> Make file generation –> and untick „Generate Make files automatically“

Beim build kommt make command not found

–> C/C++ Build –> Default build command auf mingw32-make setzen

Bei jeden Build Tool Java Nullpointer Exception fehler : fehler interner Builder

–> -> C/C++ Build / Tool Chain Editor / Current Builder   von Internal auf Gnu Make Builder umstellen.

Indexer findet STL Header files wie <map> <vector> nicht:

Project sollte auf MinGW Toolchain konfiguriert sein, dies geht aber nur wenn gcc von Eclipse im Pfad gefunden wird
Dafür den pfad IN eclipse erweitern, oder vor Start definieren
–> C/C++ Build –> Tool Chain Editr –>  Current toolchain : „MinGW GCC“

Daraufhin sollte in

–> C/C++ General Preprocessor Include path –> Setting Entries –> Unterpunkt
CDT GCC Built-in Compiler Settings MinGW [Shared] beim aufklappen sollten
viele MINGW spezifische Pfade konfiguriert sein (Show buildin values)
z.b.
d:/MINGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include
u.s.w.

Indexer findet spezielle STL Klassen wie string nicht:

Im MingW headern sind einige STL header in Dateien mit Endung tcc enthalten. Diese werden per Default nicht von Eclipse indexiert.

Einfache Lösung: in den Eclipse Projektweiten Einstellungen .tcc als file-type c++Header hinzufügen.

Indexer findet third-party Header wie <boost/>  nicht

–> C/C++ General Preprocessor Include path –> Setting Entries –> Unterpunkt CDT User Settings Entries
${MINGW_HOME}/include adden (Filesyste,system header adden!)

 

 

Messaging

 

Ein Sammelsurium zum Thema Messaging aus Entwicklersicht. Zusammengetragene Informationen und Links die kontinuierlich erweitert werden.

Noch ein Hinweis am Rande:
Weder Reihenfolge noch Umfang sind eine Bewertung ;)

Protobuf

Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler.Protocol buffers are just an interchange format. They could easily be used for RPC – and, indeed, they do have limited support for defining RPC services – but they are not tied to any one RPC implementation or protocol.(q)

Site: https://developers.google.com/protocol-buffers/
Code: https://github.com/google/protobuf

  • Codegenerator
  • Definition von Services, aber nicht weit von allen Generatoren unterstützt
  • generierte Strukturen/Nachrichten haben einfaches Interface und sind generell nutzbar, nicht nur als Message.
  • Trennung von Format und Semantik
  • Generierter Code ist sehr einfach, benötigt aber viel aus der libprotobuf library

Msgpack

Serialisierungsformat

 

AMQP

AMQP (Advanced Message Queuing Protocol) ist ein Standard im Messaging-Bereich. Er definiert nicht etwa ein API, sondern ein Netzwerkprotokoll, das von Messaging-Lösungen zum Übertragen der Nachrichten genutzt wird.

RabbitMQ

ASN.1

  • Beschreibt Syntax von Datenstrukturen unabhängig ihres Encodings
  • Verschiedene Encodings: DER/BER ..

Apache Thrift

  • http://thrift.apache.org/

 

JSON

  • sehr einfaches Format
  • lesbar

 

XMPP

 

  • Wikipedia Extensible_Messaging_and_Presence_Protocol
  • Grundform bassiert auf XML, Es gibt aber auch optimierte Formen, ähnlich BinaryXML.
  • Definiert nicht nur Messaging, sondern mittels Extensions Definitionen verschiedenste Standards, Von Datenübertragung über Rechtemanachment,pub/sub Bus, Routing u.s.w.
  • Oft noch unter dem Jabber bekannt.
  • Obwohl es primär für Instant Messaging bekannt ist, kann es dennoch mehr als ein „Chat“-Protokoll sein.

 WAMP

 

http://www.wamp.org

Ein Websocket Publish/Subscribe RPC Protokoll Server/Client/Router. Variable serialisierung(json,msgpack) und variable Transporte (WebSocket,RawTCP,Pipes)