Symbian3/SDK/Source/GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita
author Dominic Pinkman <Dominic.Pinkman@Nokia.com>
Wed, 31 Mar 2010 11:11:55 +0100
changeset 7 51a74ef9ed63
child 8 ae94777fff8f
permissions -rw-r--r--
Week 12 contribution of API Specs and fix SDK submission
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
7
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
     1
<?xml version="1.0" encoding="utf-8"?>
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
     2
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
     3
<!-- This component and the accompanying materials are made available under the terms of the License 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
     4
"Eclipse Public License v1.0" which accompanies this distribution, 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
     5
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
     6
<!-- Initial Contributors:
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
     7
    Nokia Corporation - initial contribution.
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
     8
Contributors: 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
     9
-->
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    10
<!DOCTYPE concept
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    11
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    12
<concept xml:lang="en" id="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12"><title>Exporting and Importing Classes</title><prolog><metadata><keywords/></metadata></prolog><conbody><p>This document discusses importing and exporting of classes. </p> <p>In particular this document describes: </p> <ul><li id="GUID-3F374F9D-1829-5E75-AAB4-1D653D9F42FC"><p>Class exporting rules: </p> <ul><li id="GUID-B9BF3994-3D41-5485-863E-6EA1C4017486"><p>DLL-derivation </p> </li> <li id="GUID-E9CCB315-097D-5F01-8E39-FDB6A2650BDE"><p>Non-sharable classes </p> </li> <li id="GUID-9AB46032-9EA5-5E5D-A210-8DEF3CD6E543"><p>The Simple Rule </p> </li> <li id="GUID-6B9127D2-8C6A-51B1-9415-D9546F224CB0"><p>Class impedimenta </p> </li> <li id="GUID-B75E2747-AC61-5CEB-81BC-9C81FB6F67B1"><p>Boundary cases where importing and exporting symbols are illegal, which some ABI compilers accept without warnings or errors </p> </li> </ul> </li> <li id="GUID-38EB4EAC-5CF2-5984-9698-5AD1FA299EAD"><p>The ARM ABI Thunk Offset Problem </p> </li> <li id="GUID-09EF7017-C160-5621-A7D9-7AE40E21305B"><p>The Shared DEF File Problem </p> </li> </ul> <p>The information described in this document is valid for RVCT 2.1 build 416 or later and for any compiler that is compliant with the ARM ABI v2.0 and higher. </p> <section><title>Definitions</title> <p id="GUID-884B1DF5-ECC8-5243-85B4-9B07BA52C58B"><b>Terminology and Background</b> </p> <ul><li id="GUID-DFD94FF3-2823-5853-B14C-62F416715ADC"><p>For all of this section it is assumed that the user intends to derive <b>class D</b> from <b>class C</b> and that both classes reside in different DLLs. </p> </li> <li id="GUID-F116357D-74A5-54CB-903D-4317D18A2FF3"><p>Class C is called <b>DLL-derivable</b>, if class D can be derived from C. </p> </li> <li id="GUID-6543650D-210E-5582-8EF6-EA408BE78E12"><p>Class C is called <b>non-sharable</b> if it is marked using _<i>_</i>  <i>declspec(notshared)</i> or using the macros NONSHARABLE_CLASS(x) or NONSHARABLE_ STRUCT(x). It is not possible to DLL-derive from a non-sharable class. Otherwise class C is called <b>sharable</b>. </p> </li> <li id="GUID-6BE83B98-8AFC-52C8-9356-44CA62F167E5"><p> <b>Class Impedimenta</b> are entities that are emitted by the compiler for any class, but do not have a direct representation in source. Examples of class impedimenta are: </p> <ul><li id="GUID-7DBEC962-29BE-56FF-AC1F-AB6141B7DFA9"><p>the class’s virtual table, or </p> </li> <li id="GUID-FBCB4F71-C878-5736-8783-C5D6011176DE"><p>a virtual table’s thunks, or </p> </li> <li id="GUID-867A206E-8FA6-5E06-A3C0-14C6BAE05652"><p>the class’s run-time type information </p> </li> </ul> <p>Class impedimenta are a key element of the ABI and are identified through ELF symbols. They play a crucial role in enabling polymorphism, RTTI and derivation. This means that they also play a key role in DLL-derivation. In fact, if the Class Impedimenta of class C are not exported, it is not possible to DLL derive from class C or in other words class C is non-sharable. </p> <p>This raises the interesting question as to how it is possible to export Class Impedimenta – and thus enable DLL-derivation – if they have no representation in source. The answer to this question is given in <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-3DA52D31-E3D7-5061-8D15-1F1D69AE2ED1">The Simple Rule – Sharable Classes</xref> section. </p> </li> <li id="GUID-F7071803-9F81-538C-8314-09FDF7CB0790"><p> <b>Non-callable exports</b> are Class Impedimenta that are exported. They are often used as synonym for Class Impedimenta in this document. </p> </li> <li id="GUID-F97952F0-0D14-5BE0-A990-1DD75480D9D8"><p>A <b>key function</b> is the first non-inline, non-pure virtual function of a class. </p> </li> </ul> <p><b>Symbian Conventions </b> </p> <p>Symbian defines macros for exporting and importing classes to hide implementation details: </p> <table id="GUID-E33F9AC8-DCD4-56AF-B6E4-6EAE28204A34"><tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/><tbody><row><entry><p> <b>Macro</b>  </p> </entry> <entry><p> <b>RVCT Implementation</b>  </p> </entry> </row> <row><entry><p>IMPORT_C <i>func-declaration</i>  </p> </entry> <entry><p>__declspec(dllimport)<i> func-declaration</i>  </p> </entry> </row> <row><entry><p>EXPORT_C <i>func-definition</i>  </p> </entry> <entry><p>__declspec(dllexport) <i>func-definition</i>  </p> </entry> </row> <row><entry><p>NONSHARABLE_CLASS(<i>x</i>) </p> </entry> <entry><p>class __declspec(notshared)<i/>  <i>x</i>  </p> </entry> </row> <row><entry><p>NONSHARABLE_STRUCT(<i>x</i>) </p> </entry> <entry><p>struct __declspec(notshared)<i/>  <i>x</i>  </p> </entry> </row> <row><entry><p> <i>class</i> NONSHARABLE <i>name struct</i> NONSHARABLE <i>name</i>  </p> </entry> <entry><p>__declspec(notshared) </p> <p>This macro does not yet exist in the Symbian platform source code. However all known ABI compliant compiler support the notations </p> <ul><li id="GUID-44F58960-1EE5-5134-8B9A-0FCBBBDE6DAA"><p>struct __declspec(notshared)<i/>  <i>x</i>  </p> </li> <li id="GUID-5C5BD85E-FB82-5E02-AE2A-7A1FDF502117"><p>class __declspec(notshared)<i/>  <i>x</i>  </p> </li> </ul> <p>which means that it is safe to define a simpler macro which does not require an argument. That macro could also be used in conjunction with templates. </p> </entry> </row> </tbody> </tgroup> </table> </section> <section id="GUID-A6382EAB-EEF5-56AC-B15E-B3740BB3C102"><title>Class Exporting Rules</title> <p>This section is a programmer’s summary of the Class Exporting Rules. </p> <p id="GUID-3C81E1FD-398F-55F3-B18A-AE4BB60EBAED"><b>Exporting Objects</b> </p> <p>A function, method of a class or data item is exported by marking its definition using the EXPORT_C macro. A function, method of a class or data item is imported by marking its declaration using the IMPORT_C macro. If an object is declared IMPORT_C and used in code, the linker will error if the definition of this object is not marked EXPORT_C. </p> <p>Although not required by the class exporting rules it is good practice to </p> <ul><li id="GUID-C5191DBB-6098-5301-8858-3B0F0FA15470"><p>Always mark all declarations of an exported object with IMPORT_C. </p> </li> <li id="GUID-142AEB30-4A89-52AB-91E9-7395FFBFD765"><p>Never mark objects that are not exported with IMPORT_C. </p> </li> </ul> <p id="GUID-3DA52D31-E3D7-5061-8D15-1F1D69AE2ED1"><b>The Simple Rule – Sharable Classes</b> </p> <p>The compiler will automatically export all<i>Class Impedimenta</i>, i.e. compiler implementation specific symbols of a class C such as <i>run-time-type-information</i> and <i>virtual tables</i>, that are required to enable DLL-derivation from class C. This means that all classes are by default <i>sharable</i>. </p> <p>The compiler will not export these symbols for classes that are marked as <i>non-sharable</i> using the macros NONSHARABLE_CLASS(<i>x</i>) or NONSHARABLE_STRUCT(<i>x</i>). Symbian requires that all classes that are derived from a non-sharable class are also marked non-sharable. </p> <p>Other methods or functions in classes are not automatically exported. They have to be explicitly exported as described in <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-3C81E1FD-398F-55F3-B18A-AE4BB60EBAED">Exporting objects</xref> section. Note that a class with virtual functions or virtual may not be DLL-derivable if the conditions in <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-7A65F9FF-DA65-54B2-A378-68C38675989B">Dll derivable classes</xref> section do not hold. </p> <p> <b>Example:</b> The following example shows the correct syntax to define a class as non-sharable: </p> <codeblock id="GUID-0B326A68-E896-5BC5-A444-57BC94F10ABE" xml:space="preserve">NONSHARABLE_CLASS(NonSharableClass) : public BaseClass … </codeblock> <p> <b>Note:</b> The Simple Rule has consequences in terms of how many entries are present in DEF files and for shared DEF files. See <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-E0F45E5F-F254-5D8B-A8E9-9D22C59DF2E4">The Shared DEF File Problem</xref> section for more details. </p> <p id="GUID-7A65F9FF-DA65-54B2-A378-68C38675989B"><b>DLL-Derivable Classes</b> </p> <p>The Simple Rule alone does not guarantee that the class C is DLL-derivable. Depending on the form of the class, additional conditions on exporting members of class C apply. This section outlines the conditions under which class C is DLL-derivable. </p> <p> <b>C has no Virtual Base</b>  </p> <p>For class C to be DLL-derivable, </p> <ul><li id="GUID-2D5ACE7B-0A15-5305-92ED-B7175B35D3EB"><p>Class C has to be sharable <b>AND </b>  </p> </li> <li id="GUID-5B62B475-1C69-5347-801B-4D13C4A72E33"><p>Every virtual function in C or C's bases that is not overridden in D needs to be <i>exported</i>  </p> </li> <li id="GUID-1683B0F7-0741-5224-884A-D3E8697A2051"><p>If the class C has no key function, i.e. it only has pure virtuals or inlined virtuals, all bases of C also have to be DLL-derivable. </p> </li> </ul> <p> <b>C has one or several Virtual Bases</b>  </p> <p>For class C to be DLL-derivable, </p> <ul><li id="GUID-C8B13C29-C1D0-5DC6-9E8D-28667E948E89"><p>Class C has to be sharable <b>AND</b>  </p> </li> <li id="GUID-5317D37C-51AF-569F-926E-5219775D6388"><p>Every virtual function in C or C's bases, virtual or otherwise, needs to be <i>exported</i>  <b>AND</b>  </p> </li> <li id="GUID-2D8BF597-94F4-55A0-A939-B405EBEF7C3B"><p>All bases of C, virtual or otherwise, have to be DLL-derivable </p> </li> </ul> <p>Note that link errors will occur if an attempt is made to DLL-derive a class from a base class that is not DLL-derivable. </p> <p><b>Boundary cases where Importing and Exporting Symbols is Illegal</b> </p> <p id="GUID-7CC0C991-DF72-5AD5-BD36-96BE67E215FE"><b>Static Symbols and Symbols in Anonymous Namespaces</b> </p> <p>The following code examples are illegal. But note that not all ABI compliant compilers produce an error or a warning in these situations. This is because the behaviour of export and import is neither defined by the C++ standard, nor is it defined by the ABI for the ARM Architecture. The ABI describes a binary interface and is not concerned with matters of syntax. </p> <p><b>Exporting/importing static symbols</b> </p> <p> <filepath> Foo.cpp </filepath>  </p> <codeblock id="GUID-6E1641ED-74FE-5549-8426-BFB6300F02EB" xml:space="preserve">static IMPORT_C int i; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    13
static EXPORT_C int j;</codeblock> <p><b>Exporting/importing symbols defined in anonymous namespaces</b> </p> <p> <filepath> Foo.cpp</filepath>  </p> <codeblock id="GUID-B328F310-FE43-5989-B059-069821E1BEFC" xml:space="preserve">namespace { // anonymous namespace
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    14
class CTest { 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    15
public: 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    16
    IMPORT_C CTest() { m = 0; }; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    17
    EXPORT_C int get() { return m; }; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    18
private: 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    19
    int m; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    20
};
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    21
}</codeblock> <p><b>Why is this illegal?</b> </p> <p>These patterns are illegal because they do not make sense. In fact it is impossible to write any C or C++ client code outside the compile unit in which the imports/exports are defined (e.g. Foo.cpp), that makes use of any statically defined object or an object defined in an anonymous namespace. </p> <p>This means that it is impossible that any of the exported symbols in the above examples can ever be used by client code that is in another DLL. </p> <p><b>What happens if I use these patterns?</b> </p> <p>The symbols that have been exported will appear in DEF files even though it is impossible to ever link against these symbols. Further the symbols contain a magic number. In the case of symbols in anonymous namespaces the symbol contains a filename and a magic number. For example: </p> <p> <codeph>_ZN30_GLOBAL__N__7_</codeph> <b>Foo_cpp</b> _<b>5b46ece4</b> <codeph>5CTestE</codeph> </p> <p>Where <codeph>Foo_cpp</codeph> is the filename and <codeph>5b46ece4</codeph> is the magic number. </p> <p>The ABI specifies that the magic number is unique. The creation of the magic number depends on the compiler. RVCT creates the magic number by computing a hash from the modification time-stamp of the source file and the top-level source directory. </p> <p>This means that in essence, the DEF file can never be frozen. If it is frozen, the Symbian toolchain will produce link errors, every single time the symbol changes. For RVCT this will happen every single time the source is changed, or when the user tries to build the source from a different source location than the person who froze the DEF file. Because the exported symbols can never be used, this is a trade-off without benefit. </p> <p><b>Classes in Anonymous Namespaces</b> </p> <p>Because of the <i>Simple Rule</i> (see <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-3DA52D31-E3D7-5061-8D15-1F1D69AE2ED1">The Simple Rule – Sharable Classes</xref>) any class or structure that is defined in an anonymous namespace will export its Class Impedimenta. This means that by default, the compiler exports symbols that can never be used and cause a series of problems (see <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-7CC0C991-DF72-5AD5-BD36-96BE67E215FE">Static Symbols and Symbols in Anonymous Namespaces</xref>). </p> <p>The ABI for the ARM architecture v2.0 specifies this behaviour, which is at the very least unintuitive, if not incorrect. </p> <p>The following code snippet will by default export the Class Impedimenta of the shown class and structure and thus gives rise to the problems described in <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-7CC0C991-DF72-5AD5-BD36-96BE67E215FE">Static Symbols and Symbols in Anonymous Namespaces</xref> section. Note that the exported Class Impedimenta can never be used by any client code. In fact by default, any class that is defined in an anonymous namespace is non-sharable. This is true, regardless of whether Class Impedimenta are exported or not. </p> <p> <b>Foo.cpp (incorrect)</b>  </p> <codeblock id="GUID-A17B8CE5-6F89-5C74-AC4F-B5A6BD2CA9FF" xml:space="preserve">namespace { // anonymous namespace 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    22
class CTest {…};
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    23
struct STest {…};
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    24
}</codeblock> <p>Thus, if you use anonymous namespaces, you must make sure to define them as non-sharable. For example: </p> <p> <filepath>Foo.cpp</filepath>  </p> <codeblock id="GUID-EEEBF8E8-9BAC-54D1-AE20-ADC97E15080D" xml:space="preserve">namespace { // anonymous namespace 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    25
class NONSHARABLE_CLASS(CTest)  {…};
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    26
struct NONSHARABLE_STRUCT(STest) {…};
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    27
}</codeblock> <p>This has no draw-backs and avoids any difficulties with frozen DEF files. If you have used anonymous namespaces incorrectly in the past, add the relevant NONSHARABLE macro and re-freeze your DEF file using <codeph>abld freeze
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    28
                –r armv5</codeph>. This will re-freeze the DEF file, leaving gaps where the removed exports would have been and thus does not affect binary compatibility. </p> <p><b>Auto-Exporting</b> </p> <p>The Simple Rule only covers compiler implementation specific data items that are required to enable DLL-derivation. However the compiler may also emit and export implementation specific functions. This process is called <i>auto-exporting</i>. This section describes under which circumstances the compiler auto-exports. Note that the compiler also may generate symbols for EABI library functions (these start with __cxa or __eabi). </p> <p><b>Constructors and Destructors</b> </p> <p>For each constructor/destructor in source, the compiler may create several instances of constructors/destructors in the object file, depending on how the constructor and destructors are used. If the constructor/destructor is exported, then all of the generated constructors/destructors are auto-exported. In such a case the following symbols may appear in your DEF file: </p> <p>_ZN…C1… complete object constructor </p> <p>_ZN…C2… base object constructor </p> <p>_ZN…C3… complete allocating constructor </p> <p>_ZN…D0… deleting destructor </p> <p>_ZN…D1… complete object destructor </p> <p>_ZN…D2… base object destructor </p> <p><b>Thunks</b> </p> <p>Under the C++ ABI <i>thunks</i> occur in the presence of multiple inheritance or virtual inheritance. They are used to adjust the <i>this</i> pointer of a class before calling virtual functions. Details can be looked up in the ABI. The export of a thunk is triggered, when a virtual function that needs a thunk is exported. Thunks have the form _ZTh… or _ZTv… </p> <p id="GUID-63FC4816-1807-5238-BB8F-644490A7A5F9"><b>Class Impedimenta</b> </p> <p>When checking DEF files non-callable exports and other compiler specific symbols may be present. The following list shows what some of these symbols mean: </p> <p>_ZTV… Virtual Table (VTABLE) </p> <p>_ZTI… Run-time Type Information (RTTI) </p> <p>_ZTT… Construction VTABLE </p> <p>_ZTh… Thunk emitted using multiple inheritance </p> <p>_ZTv… Thunk emitted using virtual inheritance </p> </section> <section><title>ARM ABI Thunk Offset Problem</title> <p><b>Symptoms of the ARM ABI Thunk Offset Problem</b> </p> <p>The "EABI Thunk Offset Problem" is the name that Symbian uses to describe a particular kind of build error which arises when multiple inheritance is used, and the size of a base class is changed. Here is an example of a typical symptom: </p> <codeblock id="GUID-F68AB56A-3ECF-55D8-91BA-83AD93CEF32E" xml:space="preserve">MAKEDEF ERROR: 1 Frozen Export(s) missing from object files:
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    29
\src\example\MyDLLU.DEF(3) : _ZThn8_N7Derived3fooEv @2
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    30
MAKEDEF WARNING: 1 export(s) not yet Frozen in \src\example\MyDLLU.DEF:
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    31
..\..\..\EPOC32\BUILD\src\example\group\MyDLL\ARMV5\MyDll{000a0000}.def(7) : _ZThn12_N7Derived3fooEv @6</codeblock> <p>This shows a problem with a frozen DEF file: the export at ordinal 2 is missing, and a new unfrozen export has been added at ordinal 6. When comparing the two symbols, they look suspiciously similar to each other, and to a third symbol in the DEF file: </p> <codeblock id="GUID-41EDE0BF-3A2F-5D76-A6B5-C4935A12CC29" xml:space="preserve">_ZN7Derived3fooEv @1 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    32
_ZThn8_N7Derived3fooEv @2        // this one is missing 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    33
_ZThn12_N7Derived3fooEv @6        // this one has appeared</codeblock> <p>The exports beginning with _ZTh are compiler generated functions called thunks (see <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-63FC4816-1807-5238-BB8F-644490A7A5F9">Class Impedimenta</xref>), and the information between _ZTh and the next underscore is the offset associated with the thunk. Our problem is that for some reason, the offset associated with the thunk has changed from –8 to –12 (the n denotes a negative offset). Note that there is another variant of this problem that involves thunks beginning with _ZTv. </p> <p>These generated functions are a feature of the Itanium C++ ABI, on which the ABI for the ARM architecture builds upon. Hence the name "ARM ABI Thunk Offset Problem". </p> <p><b>What causes this problem?</b> </p> <p>The problem is caused because the symbol name generated for the thunk contains an offset number. More details can be found in <xref scope="external" href="http://www.codesourcery.com/cxx-abi/abi.html">http://www.codesourcery.com/cxx-abi/abi.html</xref> under section 5.1.4. This offset may change, when the signature of the base class is changed. For example when a data member is added or removed. </p> <p>Another condition to trigger the problem needs to hold as well: multiple inheritance with virtual functions in more than one of the base classes. If this condition does not hold, the compiler will not generate a thunk and thus there is no problem. </p> <p>Note that this is always a Binary Compatibility break, which shows up as a change to symbols in DEF files. </p> <p><b>How do I fix it?</b> </p> <p>There are three choices to fix it: </p> <ol id="GUID-804A94CF-1A73-5640-B3B8-2DDFBEDD407A"><li id="GUID-955EC339-EC01-5989-B388-6D6BE285F14D"><p>The first option is to refreeze the DEF file: this would be OK if you are not maintaining a frozen interface, and your customers will in any case need to rebuild because of the Binary Compatibility break. The easiest way to refreeze is to delete all of the exports from your existing DEF file, build again, and then use "<i>abld freeze armv5</i> " to update the DEF file. After updating the DEF file, build again: this time it should build cleanly. </p> </li> <li id="GUID-9CE95A51-20BD-51B7-93D6-629FB97014FA"><p>The second option is to use the attached script to fix the ABI Thunk Offsets. It expects to read a build log containing the MAKEDEF errors and warnings and will modify the DEF file to replace each missing export with the corresponding unfrozen export. Run the script with no arguments to get further details. </p> <fig id="GUID-7C590699-C58D-5619-8FFA-1DE51A0D666F"><image href="GUID-377B04D8-4E8B-54C7-AE7F-8BD47CB81758_d0e9200_href.png" placement="inline"/></fig> <p>After fixing the DEF file, you will need to rebuild the DLL which uses the DEF file. </p> </li> <li id="GUID-22502314-4780-57B8-9D45-05470FA95757"><p>The last option is that you could change your mind about adding that extra member data. This will only be an option if it is your change which causes the problem: if your supplier has changed the size of a class that they own and caused this problem, then you are forced to change your DEF file. </p> <p>If you own the class which has the extra member data, it is worth noting that this change is likely to affect your customers as well. They will have to rebuild because of the BC break. Adding to this they will also see the ABI Thunk Offset Problem if they derive from your class. This includes simple inheritance from a class which shows the problem, if it re-implements any of the virtual functions which require thunks. </p> <p>When Symbian breaks compatibility in a way likely to cause this problem, the corresponding entry in the Compatibility Break spreadsheet will say "BC+ Break: Rebuild &amp; Check/Fix Def-File EABI Thunk Offsets". </p> </li> </ol> <p><b>Tell me the full details: What is a thunk? What causes its offset to change? </b> </p> <p>In a C++ class hierarchy involving both virtual functions and multiple inheritance, objects can be accessed as though they were several different types. A typical Symbian platform example would be a CBase-derived class which also derives from an M-class, perhaps to provide an <i>observer</i> interface: for example CCoeControl, which derives from both CBase and MObjectProvider. </p> <p>The virtual functions which can be called on an object depends on the type it currently appears to be.A CCoeControl object can be viewed as a CBase object, in which case it has one set of virtual functions, or as an MObjectProvider, in which case it has another. The compiler constructs separate <i>virtual tables</i> for each of the possible interfaces, and these tables contain information about how to convert back to the underlying CCoeControl object. When converting from a CCoeControl pointer to an MObjectProvider pointer, the compiler will adjust the value of the pointer, so that it points to the "MObjectProvider" part of the object, and not the full CCoeControl object. </p> <p>The MObjectProvider class defines a pure virtual function MopSupplyObject, which is implemented in CCoeControl. Even when the object is presenting it's MObjectProvider interface, the vtable must use the correct implementation of MopSupplyObject, which expects to be used in the context of a CCoeControl. The solution used by the compiler is to create a <i>virtual function override thunk</i> function which makes any necessary adjustments between the calling context (a pointer to MObjectProvider) and the execution context (a pointer to CCoeControl). </p> <p>This could have been implemented using the names of the two contexts, but instead the ABI uses the amount by which the <i>this</i> pointer needs to be adjusted to make the switch: this is the offset encoded in the name. </p> <p>Here is a small example: </p> <p> <b>eabi_thunk_offset_problem.cpp</b>  </p> <codeblock id="GUID-8ED84BFF-EDB0-5C54-8CE9-05F289231FF2" xml:space="preserve">#ifndef COUNT 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    34
#define COUNT 1 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    35
#endif 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    36
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    37
class Base 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    38
{ 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    39
public: 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    40
    int iBaseMember[COUNT]; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    41
    virtual ~Base(); 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    42
}; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    43
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    44
class MInterface 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    45
{ 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    46
public: 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    47
    virtual int foo(); 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    48
}; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    49
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    50
class Derived : public Base, public MInterface 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    51
{ 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    52
public: 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    53
    virtual int foo(); 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    54
    int iDerived; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    55
}; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    56
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    57
class MoreDerived : public Derived 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    58
{ 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    59
public: 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    60
    virtual int foo(); 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    61
    int iMoreDerived; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    62
}; 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    63
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    64
int Derived::foo() { return iDerived; } 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    65
Derived* fun1() { return new Derived; } 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    66
MInterface* fun2() { return new Derived; } 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    67
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    68
int MoreDerived::foo() { return iMoreDerived; } 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    69
MoreDerived* fun3() { return new MoreDerived; } 
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    70
MInterface* fun4() { return new MoreDerived; }
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    71
</codeblock> <p>Compile this with <i>armcc -S eabi_thunk_offset_problem.cpp</i> to get an assembly listing. Compile it again with an extra argument "-DCOUNT=2" to change the size of the base class, and compare the two files: there will be various differences in the code, but also differences in the _ZTh symbols - including the differences used in the "typical symptom" above. </p> <p>If you use virtual inheritance, then you may see another version of the problem. With virtual inheritance, there are two offsets involved and the thunk symbols will begin with _ZTv. The same symbol may appear in several thunks, each with different offsets. </p> </section> <section id="GUID-E0F45E5F-F254-5D8B-A8E9-9D22C59DF2E4"><title>The Shared DEF File Problem</title> <p><b>What is the Problem with Shared DEF Files?</b> </p> <p>The class exporting rules (see <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-A6382EAB-EEF5-56AC-B15E-B3740BB3C102">Class Exporting Rules</xref>) by default will generate non-callable exports for all classes that are not marked non-sharable in source. Say two DLLs, A and B share one DEF file, in effect implementing similar but different functionality towards the same public interface. Further say, no classes are marked non-sharable. Say there are some classes that are shared between DLL A and DLL B and that these classes have names of the form CShared&lt;xyz&gt;. Classes that are specific to DLL A have names of the form CA&lt;xyz&gt;, classes specific to DLL B have names of the form CB&lt;xyz&gt;. When DLL A is built, DEF file entries for non-callable exports from CShared&lt;xyz&gt; and CA&lt;XYZ&gt; are automatically added to the DEF file. When DLL B is built, exports from CShared&lt;xyz&gt; and CB&lt;XYZ&gt; are added. So in fact the DEF file would be the sum of all non-callable exports from CShared&lt;xyz&gt;, CA&lt;xyz&gt; and CB&lt;XYZ&gt;. It also will contain symbols from functions that are marked for export using EXPORT_C. However, this means that neither A or B can be linked. This is because when A is built, the code linking against the non-callable exports of CB&lt;XYZ&gt; do not exist in A and vice versa. </p> <fig id="GUID-E2B571A3-0463-5886-AD08-D50F0420EAF9"><image href="GUID-D205622E-FB0F-59C4-A039-B418B551CBFA_d0e9285_href.png" placement="inline"/></fig> <p><b>Use-cases for Fixing Shared DEF Files</b> </p> <p> <b>Use-Case 1:</b>  <b> Polymorphic “Plug-ins”</b>  </p> <p>Several DLLs are built using the same DLL interface (DEF file). Typically the DEF file has very few entries (1 or 2) and is maintained manually. This means that new functions are added by editing the shared DEF file. Also typically no import libraries are needed as the knowledge about the DLL interface is hard-coded into the client code of the "plug-in". The plug-ins do not have to be loaded at run-time. Some are always built but not always included in the ROM. </p> <p> <b>The Fix:</b>  </p> <ol id="GUID-A5D72F88-AF26-57FB-823F-7331992EB0F8"><li id="GUID-DE2A9DBD-EF23-56AA-997A-90B717406DBB"><p>If the shared DEF file is in \epoc32\include\def\EABI then locate the original DEF file by searching all BLD.INF files for the appropriate line in PRJ_EXPORTS </p> </li> <li id="GUID-1BE3AEA4-B629-5273-A370-DC3A9DABBA80"><p>Remove all non-callable exports that have caused warnings or errors from the original DEF file. </p> </li> <li id="GUID-CADA2F46-96C3-50DD-99AE-847D2EC70CFE"><p>Add NOEXPORTLIBRARY to all MMP files that share that component, ensuring that the build system does NOT try and re-freeze these automatically the next time you build. Otherwise the build system will re-introduce these non-callable exports. </p> </li> </ol> <p> <b>Note:</b>  </p> <p>If you want to use the re-freeze mechanism – say to add a new export, you have to temporarily remove NOEXPORTLIBRARY from the MMP file, then generate a new DEF file by re-building the component, re-freeze, possibly edit (to remove unwanted non-callable exports) and then insert the keyword NOEXPORTLIBRARY into the MMP file again. </p> <p> <b> Use-Case 2:</b>  <b> Polymorphic “Plug-ins” on which Other Components Depend</b>  </p> <p>This is very similar to use-case 1, except that some other component depends on one of the plug-ins. This means that an import library is required. </p> <p> <b>The Fix: </b> The build structure must be such that </p> <ul><li id="GUID-9B61065B-E448-5B32-910C-4F8356B30E63"><p>One MMP file generates the import library from the shared DEF file using the target type IMPLIB. It may be necessary to create a new MMP file which does this. </p> </li> <li id="GUID-4CB6CB0F-E690-5AAB-8B0C-1A6D64ECBC31"><p>All the other MMP files use NOEXPORTLIBRARY as described in use-case 1 </p> </li> </ul> <p> <b>Note:</b>  </p> <p>If you want to use the re-freeze mechanism – say to add a new export, you have to temporarily remove NOEXPORTLIBRARY from the MMP file, then generate a new DEF file by re-building the component, re-freeze, possibly edit (to remove unwanted non-callable exports) and then insert the keyword NOEXPORTLIBRARY into the MMP file again. </p> <p> <b>Use-Case 3:</b>  <b> Annotate Classes as Non-sharable</b>  </p> <p>Where a DEF file must be shared between components for whatever reason and none of the above use-cases can be applied, the build would fail for at least one component. An example of this may be a class MyPrivateClass that exists in the debug build (UDEV) of the OS, but not in the release build (UREL). </p> <p>In such a case all classes that should not contribute to the DEF file, i.e. that are really private to the implementation of a component, must be annotated in the source as NONSHARABLE_CLASS(X) or NONSHARABLE_STRUCT(X). As a result no non-callable exports will be generated for such a class. Say for example, class MyPrivateClass is truly private to a component that must share a DEF file with another component. Then it should be declared: </p> <codeblock id="GUID-8E236162-F6BA-5A77-9A50-8546C49A7FFC" xml:space="preserve">    NONSHARABLE_CLASS(MyPrivateClass)
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    72
    {
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    73
    ...
51a74ef9ed63 Week 12 contribution of API Specs and fix SDK submission
Dominic Pinkman <Dominic.Pinkman@Nokia.com>
parents:
diff changeset
    74
    };</codeblock> <p>This will prevent the compiler from exporting non-callables for MyPrivateClass. However this means that it is not possible to DLL-derive (for the definition of DLL-derive see <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-884B1DF5-ECC8-5243-85B4-9B07BA52C58B">Terminology and Background</xref>) from MyPrivateClass and that all classes derived from MyPrivateClass must also be marked non-sharable (see <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-884B1DF5-ECC8-5243-85B4-9B07BA52C58B">Terminology and Background</xref>). </p> <p> <b>Use-Case 4:</b>  <b> Optimisation</b>  </p> <p>A consequence of the Simple Rule (see <xref href="GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita#GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12/GUID-3DA52D31-E3D7-5061-8D15-1F1D69AE2ED1">The Simple Rule – Sharable Classes</xref>) is that some components may emit entries in their DEF files which are not needed. In the worst case the overhead is 8 bytes of ROM size per class (2 DLL entry points). In the typical case an increase of 4 bytes will occur and in some cases no increase at all. </p> <p>For code that is private to an implementation, i.e. where it is known that a class would never be used outside of that component, this footprint increase is unnecessary. In order to avoid the footprint increase mark all private classes (and classes derived from them) in the source as NONSHARABLE_CLASS(X) or NONSHARABLE_STRUCT(X) as described for use-case 3. </p> <p> <b> Use-Case 5:</b>  <b> The Build Tools Automatically Ignore Non-callable Exports</b>  </p> <p>For most components the build tools automatically ignore <b>all</b> non-callable exports. This is the case because the build tools know the situations when non-callable exports cannot be needed. Non-callable exports are only needed, if: </p> <ul><li id="GUID-BF53F4C7-14B3-5FEB-8CAE-F71383DFAB2E"><p>The target type is either DLL, EXEDLL or EXEXP and the MMP file has no NOEXPORTLIBRARY keyword </p> </li> <li id="GUID-622E7A6F-0618-5331-9AE8-E2ABDD7FA190"><p>If the MMP file contains the DEFFILE keyword and the MMP file has no NOEXPORTLIBRARY keyword </p> </li> </ul> <p>The reason for this is that target types, such as APP, always map directly onto one of the above use-cases. For example the target type APP is an example of use-case 1, i.e. the APP is a DLL that always has the same DEF file. However no other DLL but the APP loader will ever link against this binary, unless its MMP file contains the DEFFILE keyword. </p> <p> <b>Use-Case 6:</b>  <b> Best Practice</b>  </p> <p>Note that it is good practice to avoid unnecessary footprint increases by marking private classes as non-sharable as outlined in use-case 4. Further note, that at some point in the future Symbian may add this to the Symbian Coding Standards or withdraw tools support for some of the cases described above. </p> <p><b>Optimisation</b> </p> <p>This section discusses advantages of marking “private” classes as described in use-cases 4 and 6 in the previous section as non-sharable </p> <p>Reasons for Optimisation: </p> <ul><li id="GUID-50EBEA63-092D-5B01-8371-890947D05E57"><p>Small footprint saving </p> </li> <li id="GUID-509DD311-4E9E-5A32-8194-25F9DA554417"><p>DEF files are more “pretty”, i.e. they will have fewer entries for non-callable exports in it and may have fewer holes in them. </p> </li> <li id="GUID-7DD701A6-E55A-5ECD-B905-416281014E4D"><p>When changing code that is private to a module as described in use-case 4 and not marked non-sharable, DEF file changes are required when: </p> <ul><li id="GUID-CA989C12-3138-53F3-A5C0-7092A31E9867"><p>Renaming a private class </p> </li> <li id="GUID-835872C3-C047-57F8-9221-E356B2D09A5A"><p>Removing a private class </p> </li> <li id="GUID-20632617-A0DB-5DF5-9C39-EF14A39CC8DF"><p>Adding a private class </p> </li> </ul> <p>This makes it harder to maintain DEF files and will ultimately lead to less “pretty” DEF files when Binary Compatibility must be maintained. </p> </li> <li id="GUID-7B1CAE8B-3CB9-5782-AE6E-7B4AE2E2307E"><p>More non-sharable classes mean that it is less likely to have problems with shared DEF files as outlined in use-cases 1 and 2 in the previous section. </p> </li> </ul> <p> <b>When not to use Optimisation:</b>  </p> <p>It is not advisable to use optimisation in the following circumstances, as the build tools suppress non-callable exports automatically in these cases: </p> <ul><li id="GUID-0CD3582F-3976-599D-B1F1-A16C8025E50E"><p>The target type of the component containing private classes is neither DLL, EXEDLL nor EXEXP and no DEFFILE keyword is contained the components MMP file </p> </li> <li id="GUID-37D22C06-234B-57D8-9605-343E28EBB674"><p>The MMP file of the component contains the NOEXPORTLIBRARY keyword. </p> <p>If the NOEXPORTLIBRARY keyword has been introduced to work around problems introduced by shared DEF files and the Simple Rule it may be better to remove the NOEXPORTLIBRARY keyword and mark private classes as non-sharable instead. </p> </li> </ul> </section> </conbody></concept>