TWiki
>
Gaudi Web
>
UserGuide
>
HowToMigrateToGaudi21
(2009-09-03,
MarcoClemencic
)
(raw view)
E
dit
A
ttach
P
DF
---+!! How-To Migrate to Gaudi v21 %TOC% ---++ Introduction This twiki page is meant to provide instructions and, to some extent, the documentation for the changes between Gaudi v19/v20 and Gaudi v21. ---++ Interfaces ---+++ Rationale To extend a base component with the implementation of new interfaces, we have to provide an implementation of the method =IInterface::queryInterface=, which is almost always the same. A typical case looks like: %SYNTAX{ syntax="cpp" }% class MySpecialization: public MyBase, virtual public IMyFeature { public: /// Constructor MySpecialization(); /// Destructor virtual ~MySpecialization(); /// Implementation from IInterface virtual StatusCode queryInterface(const InterfaceID &riid, void **ppvInterface); /// Implementation from IMyFeature virtual StatusCode myMethod(); }; MySpecialization::MySpecialization():MyBase() { // ... do something } MySpecialization::~MySpecialization() { // ... do something } StatusCode MySpecialization::myMethod() { // ... do something return StatusCode::SUCCESS; } StatusCode MySpecialization::queryInterface(const InterfaceID &riid, void **ppvInterface) { if (ppvInterface == 0) return StatusCode::FAILURE; if (IMyFeature::interfaceId() == riid) { // sometimes is IID_IMyFeature *ppvInterface = (IMyFeature*)this; } else { return BaseClass::queryInterface(riid, ppvInterface); } addRef(); return StatusCode::SUCCESS; } %ENDSYNTAX% The implementation of =queryInterface= is (usually) a switch-like chain of =if= statements falling back on the base-class implementation. The implementation of such a method can be automated, in fact the =AlgTool= base class has a generic implementation based on a run-time list of implemented interfaces, so, when the base class is =AlgTool=, the example above becomes: %SYNTAX{ syntax="cpp" }% class MySpecialization: public AlgTool, virtual public IMyFeature { public: /// Constructor MySpecialization(); /// Destructor virtual ~MySpecialization(); /// Implementation from IMyFeature virtual StatusCode myMethod(); }; MySpecialization::MySpecialization():AlgTool() { declareInterface<IMyFeature>(this); } MySpecialization::~MySpecialization() { // ... do something } StatusCode MySpecialization::myMethod() { // ... do something return StatusCode::SUCCESS; } %ENDSYNTAX% The code for =AlgTool= specializations is shorter and less error-prone. The only draw-back that has not been removed is that the declaration of the implemented interfaces happens in two places: the =.h= file and the =.cpp= one, so you have to edit the two files in a consistent way. Another limitation of the current interface implementation is that it is not possible to have interfaces extending other interfaces. It is not a technical limitation (C++ allows it, of course), but it breaks the design principles of the framework. Each interface is identified by a numerical id (usually the a hash of the name) and a version (major and minor) that allow to tell if the component that we loaded from a library is compatible with the version of the interface that we used to compile our code. When an interface inherits from another and the base interface is changed, one should modify the version numbers of the derived interface, but it is simply impossible to keep track of those kind of chains. Using some specially crafted templated helper classes, a dedicated =InterfaceId= class and some "Boost::mpl" (Meta Programming Library) constructs, it is possible to make the compiler generate all the mechanical code that is needed, simplifying the maintenance of the components and allowing non-trivial interface hierarchies. ---+++ Implementation The implementation of the new interfaces infrastructure is based on the templated classes: $ =implements#<...>=: Used to write a class that does not have a concrete base class. $ =extends#<BASE, ...>=: Used to write a class that inherits from a concrete base class. $ =extend_interfaces#<...>=: Used to declare an interface that inherits from other interfaces. Due to the absence of variadic template arguments in C++, the classes have different names depending on the number of interfaces passed as templates, e.g.: * =implements1<IService>= * =extends2<AlgTool,ISpecial1,ISpecial2>= * =extend_interfaces1<INamed>= The other key element of the new infrastructure is the preprocessor macro =DeclareInterfaceID=, which expands to some common code. ---++++ Interface An interface declaration looks like: %SYNTAX{ syntax="cpp" numbered="true" }% class GAUDI_API IIncidentListener: virtual public IInterface { public: /// InterfaceID DeclareInterfaceID(IIncidentListener,2,0); /// Inform that a new incident has occurred virtual void handle(const Incident&) = 0; }; %ENDSYNTAX% Line 1 make the interface extend =IInterface= (one can extend other interfaces, like =INamed=). Line 4 declare the interface name and version. ---++++ Component base class %SYNTAX{ syntax="cpp" numbered="true" }% class GAUDI_API Algorithm: virtual public implements3<IAlgorithm, IProperty, IStateful> { public: // ... no queryInterface }; %ENDSYNTAX% Line 1 shows how to use the the =implements#<...>= helper to implements 3 interfaces. ---++++ Extension of a component %SYNTAX{ syntax="cpp" numbered="true" }% class GAUDI_API ConversionSvc: public extends2<Service, IConversionSvc, IAddressCreator> { public: // ... no queryInterface }; // Constructor ConversionSvc::ConversionSvc(...): base_class(...) {} %ENDSYNTAX% The first template argument of =extends#<...>= is the component base class, for the rest, it works exactly as =implements#<...>=. Line 6 shows how the constructor of the derived class must be written. =base_class= is a typedef to the actual base class (=extends#<...>=) that allows to avoid to repeat the list of interfaces in more than one place. ---+++ Migrating old code ---++++ Interfaces * If the interface inherits from more than one interface, it has to be modified to inherit from =extend_interfacesX<IInterface1,...>= (replacing X with the number of interfaces). * We must add the call to =DeclareInterfaceID= in the =public= section, close to the declaration of the class. * We must remove the static function =interfaceID= and all the references to the =IID_= static variable. Example: [[http://tinyurl.com/d5jbxs][IAlgorithm]]. ---++++ Component base class * Make the class inherit from =implements#<...>=. * Remove the implementation of =queryInterface=, =addRef= and =release= (unless non-trivial). ---++++ Extension of a component * Make the class inherit from =extends#<...>=. * Modify the constructor to call the constructor of =base_class=. * Remove the implementation of =queryInterface=, =addRef= and =release= (unless non-trivial). In case of AlgTool specializations, remove the "declareInterface" lines from the constructor. ---+++ Backward compatibility When Compiled with the macro =GAUDI_V20_COMPAT= defined, the old code will work in most cases. The only cases where it will break are when the =IID_= static constant variables are used directly. Those variables had to be removed to avoid conflicts. Replacing the =IID_= constants with calls to the static method =interfaceID()= will fix the user code in a backward compatible way (i.e. it works on both Gaudi v20 and v21 in compatibility mode). ---++ Symbol visibility ---+++ Rationale Since gcc 4.0 and on Windows it is possible to explicitly declare which are the symbol that should be visible from outside a library. The GCC Wiki has a good page about [[http://gcc.gnu.org/wiki/Visibility][symbol visibility]], so I'll not discuss it here. ---+++ Implementation The implementation is based on the [[https://savannah.cern.ch/patch/?2641][initial proposal]] by Sebastian Binet and the [[http://gcc.gnu.org/wiki/Visibility][gcc documentation]]. The visibility of symbols is declared using the macros =GAUDI_IMPORT=, =GAUDI_EXPORT=, =GAUDI_LOCAL=, =GAUDI_API= (=GaudiKernel/Kernel.h=): %SYNTAX{ syntax="cpp" }% #ifdef _WIN32 # define GAUDI_IMPORT __declspec(dllimport) # define GAUDI_EXPORT __declspec(dllexport) # define GAUDI_LOCAL #else # if defined(GAUDI_HASCLASSVISIBILITY) # define GAUDI_IMPORT __attribute__((visibility("default"))) # define GAUDI_EXPORT __attribute__((visibility("default"))) # define GAUDI_LOCAL __attribute__((visibility("hidden"))) # else # define GAUDI_IMPORT # define GAUDI_EXPORT # define GAUDI_LOCAL # endif #endif // Define GAUDI_API for DLL builds #ifdef GAUDI_LINKER_LIBRARY #define GAUDI_API GAUDI_EXPORT #else #define GAUDI_API GAUDI_IMPORT #endif %ENDSYNTAX% where GAUDI_HASCLASSVISIBILITY is defined for gcc >= 4 and not for CINT. Note that the visibility attributes in gcc make sense only if the source is compiled with the command line flag =-fvisibility=hidden=. In the linker libraries, the exported classes are declared as =GAUDI_API=: %SYNTAX{ syntax="cpp" }% class GAUDI_API Algorithm: virtual public implements3<IAlgorithm, IProperty, IStateful> { ... %ENDSYNTAX% while the exceptions are declared as =GAUDI_EXPORT=: %SYNTAX{ syntax="cpp" }% class GAUDI_EXPORT GaudiException: virtual public std::exception { ... %ENDSYNTAX% A special action is needed to compile on Windows: an environment variable is used to tell to the batch script that create the library if the symbols have to be exported automatically. ---+++ Migrating old code For component libraries, no operation is needed. For linker libraries we have to follow some simple rules: * we need to add =GAUDI_API= to the classes that have at least one method implemented in a .cpp * note that it is enough to export only the non-inline methods. * the classes that need a =dynamic_cast= (!DataObject etc.) must be exported as =GAUDI_API= (to use the same virtual table in all the libraries) * exception classes must be exported as =GAUDI_EXPORT= To be able to compile adapted code with the old version of Gaudi, one should add definitions for the macros =GAUDI_IMPORT=, =GAUDI_EXPORT=, =GAUDI_LOCAL=, =GAUDI_API= if not defined. E.g.: %SYNTAX{ syntax="cpp" }% #if defined(GAUDI_V20_COMPAT) && ! defined(GAUDI_API) #define GAUDI_API #define GAUDI_IMPORT #define GAUDI_EXPORT #define GAUDI_LOCAL #endif %ENDSYNTAX% ---+++ Backward compatibility For backward compatibility, the macros are declared empty and the command line option is not added when compiling in backward compatibility mode, so no action is needed in the user code. -- Main.MarcoClemencic - 19 Feb 2009
E
dit
|
A
ttach
|
Watch
|
P
rint version
|
H
istory
: r5
<
r4
<
r3
<
r2
<
r1
|
B
acklinks
|
V
iew topic
|
WYSIWYG
|
M
ore topic actions
Topic revision: r5 - 2009-09-03
-
MarcoClemencic
Log In
Gaudi
Gaudi Web
Create New Topic
Index
Search
Changes
Notifications
Statistics
Preferences
Public webs
Public webs
ABATBEA
ACPP
ADCgroup
AEGIS
AfricaMap
AgileInfrastructure
ALICE
AliceEbyE
AliceSPD
AliceSSD
AliceTOF
AliFemto
ALPHA
ArdaGrid
ASACUSA
AthenaFCalTBAna
Atlas
AtlasLBNL
AXIALPET
CAE
CALICE
CDS
CENF
CERNSearch
CLIC
Cloud
CloudServices
CMS
Controls
CTA
CvmFS
DB
DefaultWeb
DESgroup
DPHEP
DM-LHC
DSSGroup
EGEE
EgeePtf
ELFms
EMI
ETICS
FIOgroup
FlukaTeam
Frontier
Gaudi
GeneratorServices
GuidesInfo
HardwareLabs
HCC
HEPIX
ILCBDSColl
ILCTPC
IMWG
Inspire
IPv6
IT
ItCommTeam
ITCoord
ITdeptTechForum
ITDRP
ITGT
ITSDC
LAr
LCG
LCGAAWorkbook
Leade
LHCAccess
LHCAtHome
LHCb
LHCgas
LHCONE
LHCOPN
LinuxSupport
Main
Medipix
Messaging
MPGD
NA49
NA61
NA62
NTOF
Openlab
PDBService
Persistency
PESgroup
Plugins
PSAccess
PSBUpgrade
R2Eproject
RCTF
RD42
RFCond12
RFLowLevel
ROXIE
Sandbox
SocialActivities
SPI
SRMDev
SSM
Student
SuperComputing
Support
SwfCatalogue
TMVA
TOTEM
TWiki
UNOSAT
Virtualization
VOBox
WITCH
XTCA
Cern Search
TWiki Search
Google Search
Gaudi
All webs
Copyright &© 2008-2021 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
or Ideas, requests, problems regarding TWiki? use
Discourse
or
Send feedback