Symbian3/SDK/Source/GUID-CCE5DBCC-41D6-53D0-B929-ADB478B53F12.dita
changeset 13 48780e181b38
parent 8 ae94777fff8f
equal deleted inserted replaced
12:80ef3a206772 13:48780e181b38
    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:
    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:
    29 \src\example\MyDLLU.DEF(3) : _ZThn8_N7Derived3fooEv @2
    29 \src\example\MyDLLU.DEF(3) : _ZThn8_N7Derived3fooEv @2
    30 MAKEDEF WARNING: 1 export(s) not yet Frozen in \src\example\MyDLLU.DEF:
    30 MAKEDEF WARNING: 1 export(s) not yet Frozen in \src\example\MyDLLU.DEF:
    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 
    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 
    32 _ZThn8_N7Derived3fooEv @2        // this one is missing 
    32 _ZThn8_N7Derived3fooEv @2        // this one is missing 
    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_d0e10475_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 
    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_d0e10591_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 
    34 #define COUNT 1 
    34 #define COUNT 1 
    35 #endif 
    35 #endif 
    36 
    36 
    37 class Base 
    37 class Base 
    38 { 
    38 { 
    66 MInterface* fun2() { return new Derived; } 
    66 MInterface* fun2() { return new Derived; } 
    67 
    67 
    68 int MoreDerived::foo() { return iMoreDerived; } 
    68 int MoreDerived::foo() { return iMoreDerived; } 
    69 MoreDerived* fun3() { return new MoreDerived; } 
    69 MoreDerived* fun3() { return new MoreDerived; } 
    70 MInterface* fun4() { return new MoreDerived; }
    70 MInterface* fun4() { return new MoreDerived; }
    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_d0e10560_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)
    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_d0e10676_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)
    72     {
    72     {
    73     ...
    73     ...
    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>
    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>