Question? Leave a message!

C++ Development for OOo: Tricks of the Trade

C++ Development for OOo: Tricks of the Trade 32
C++ Development for OOo: Tricks of the Trade Thorsten Behrens StarOffice/ Sun MicrosystemsThis Talk: • this is about OOo core programming. • the core: that's where the vast majority of both code and functionality is located, and it's is where to know your way around when things go wrong (i.e. you need to fix a bug or you want to add a feature that affects core functionality). 2What's the Matter With OOo • OOo is huge: 5.2 MSLOC, 4.6 MSLOC C++ (89), 23,000 C/C++ files (early 2.6 kernel: 4.3 MSLOC) • at its core, OOo is classic C++: classes inheritance, spread across a lot of shared libraries. • that gives us: a highly coupled beast, that takes a day to build from scratchCoupled In What Way • Separate compilation units ('cxx'files) are highly dependent on other files: e.g. header file vcl/window.hxx: 2552 (for 7127 of relevance) files that directly or indirectly depend on it about 1/3rd of OOo would need recompilation, when vcl/window.hxx changes.So, What's the Matter Again • nobody seriously wants to wait 3 hours to recompile after a single change • in contrast to the scholarly focus on encapsulation (which is about logical dependencies), a large C++ project like OOo also has to care about physical dependencies: transitive closure of OOo's dependency graph: 1,950,117 edges (from 7129 active compilation units), i.e.274 mean dependent files per compilation unit Break Dependencies, BruteForce • OOo is broken down into a bunch of modules, where each module ideally contains a delimited, cohesive area of functionality (e.g. VCL: GUI platform abstraction; SW: Writer) • each module provides a public interface via "exported headers": during build time, each module "delivers" headers to the global solver directory, which makes those headers visible to other modules. Break Dependencies (cont.) • switching off dependencies on headers taken from solver (by undefing MKDEPENDSOLVER) leaves only intramodule dependencies: now only 42 mean dependent files per compilation unit • this leads to the notion of "compatible" vs. "incompatible" changes – “compatible”: one does not need to recompile other modules (by hand) – “incompatible”: some, or all of the higher modules need rebuildsBreak Dependencies, the C++ Way • changing implementation should not require recompilation in other modules i.e. a class should be truly insulated • in a first step, reducing dependencies can be achieved via use forward decls instead of header inclusion wherever possible (ptr or reference to given type, return value) keep enums at the classes that use them (instead of putting them into a central enums.hxx) avoid default arguments they need full definitions, not only forward declaration ...Break Dependencies (cont.) • aforementioned list helps, but still leaves class internals exposed to client code • now, true insulation can be achieved by pimpl idiom (or handlebody idiom) abstract interface (protocol class) plus factoryWhat's a Pimpl, Anyway class MyClass public: someMethod(); someOtherMethod(); private: struct MyClassImpl; MyClassImpl mpImpl; ;Pimpl Vs. Abstract Interface • performance: pimpl is slightly faster than virtual functions calls on a protocol class • pimpl provides concrete classes, from which one can derive and that can be freely constructed (even on the stack) • protocol classes also remove linktime dependencies (see UNO) • but for both: overhead prohibitive, e.g. for lowlevel, frequently used classes with simple getter/setter methods when passing pimpled objects by value, consider to also COW (CopyOnWrite) them.Also Bad (When Used Large Scale) • nonlocal statics • passing userdefined types (class, struct, union) by value • COWed mass objects that need to be threadsafe • short and float at interfaces • automatic conversions • code is not warningfree • not being const as const can. • using exception specifications • ...What's Out There to Help You • boost::scopedptr for RAII • boost::sharedptr/boost::weakptr for ref counting • comphelper::servicedecl for UNO lib boilerplate avoidance • o3tl::cowwrapper, if you've pimpl already, and need COW on top • rtl::Static for providing ondemand created static objectsGdb or When All Else Fails • use most recent version (CVS) • hack to define ggdb instead of g • if gdb gives 'incomplete type' on classes that your code uses, try setting 'envcflags=femitclass debugalways' and rebuild the file(s) in question. • exercise the stuff you want to debug once,and only then attach gdb to the running office ('gdb soffice.bin PID'). that way, you workaround gdb's current inability to reliably set deferred breakpoints in demandloaded libs...Development Tools • • (X)Emacs Testing /testshl2cppunit • Vim delta • NetBeans/Eclipse • Code analysis • MSVC cvsstat gccxmloink • sloccount cpd bonsailxr UML cscope doxygen argo gcc dump options • build sourcenav for Emacs vi: • IFace design wrappers DialogDumpRecommended reading/links • OOo's list of literature • LargeScale C++ Software Design by John Lakos • C++ Coding Standards by Herb Sutter and Andrei Alexandrescu • Watch out for an update to OOo's coding guidelinesQA Thorsten Behrens