| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- Binary Compatibility and wxWidgets
- ==================================
- 0. Purpose
- ----------
- This is a broad technote covering all aspects of binary compatibility with
- wxWidgets.
- 1. Releases
- -----------
- General overview of releases can be found in tn0012.txt, but for
- completeness the wxWidgets release version number is as follows:
- 2.6.2
- Where
- 2 6 2
- Major Minor Release
- (I.E. Major.Minor.Release).
- All versions with EVEN minor version component (e.g. 2.4.x, 2.6.x etc.)
- are expected to be binary compatible (ODD minors are development versions
- and the compatibility constraints don't apply to them). Note that by
- preserving binary compatibility we mean BACKWARDS compatibility only,
- meaning that applications built with old wxWidgets headers should continue
- to work with new wxWidgets (shared/dynamic) libraries without the need to
- rebuild. There is no requirement to preserve compatibility in the other
- direction (i.e. make new headers compatible with old libraries) as this
- would preclude any additions whatsoever to the stable branch. But see
- also section (4).
- 2. What kind of changes are NOT binary compatible
- -------------------------------------------------
- If its still up, the KDE guide is a good reference:
- http://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++
- The changes that are NOT binary compatible:
- - Adding a virtual function
- - Changing the name of a any function or variable
- - Changing the signature of a virtual function (adding a parameter,
- even a default one)
- - Changing the order of the virtual functions in a class
- ["switching" them, etc.]
- - Changing access privileges of a function: some compilers (among which MSVC)
- use the function access specifier in its mangled name. Moreover, while
- changing a private function to public should be compatible (as the old
- symbol can't be referenced from outside the library anyhow), changing a
- virtual private function to public is NOT compatible because the old symbol
- is referenced by the virtual tables in the executable code and so an old
- program compiled with MSVC wouldn't start up with a new DLL even if it
- doesn't use the affected symbol at all!
- - Adding a member variable
- - Changing the order of non-static member variables
- 3. Changes which are compatible
- -------------------------------
- - Adding a new class
- - Adding a new non-virtual method to an existing class
- - Adding a new constructor to an existing class
- - Overriding the implementation of an existing virtual function
- [this is considered to be backwards binary compatible until we find a
- counter example; currently it's known to work with Apple gcc at least]
- - Anything which doesn't result in ABI change at all, e.g. adding new
- macros, constants and, of course, private changes in the implementation
- 4. wxABI_VERSION and "forward" binary compatibility
- --------------------------------------------------
- As mentioned we do not support "forward" binary compatibility, that is the
- ability to run applications compiled with new wxWidgets headers on systems
- with old wxWidgets libraries.
- However, for the developers who want to ensure that their application works
- with some fixed old wxWidgets version and doesn't (inadvertently) require
- features added in later releases, we provide the macro wxABI_VERSION which
- can be defined to restrict the API exported by wxWidgets headers to that of
- a fixed old release.
- For this to work, all new symbols added to binary compatible releases must
- be #if'ed with wxABI_VERSION.
- The layout of wxABI_VERSION is as follows:
- 20602
- where
- 2 06 02
- Major Minor Release
- I.E. it corresponds to the wxWidgets release in (1).
- An example of using wxABI_VERSION is as follows for symbols
- only in a 2.6.2 release:
- #if wxABI_VERSION >= 20602 /* 2.6.2+ only */
- bool Load(const wxURI& location, const wxURI& proxy);
- wxFileOffset GetDownloadProgress();
- wxFileOffset GetDownloadTotal();
- bool ShowPlayerControls(
- wxMediaCtrlPlayerControls flags =
- wxMEDIACTRLPLAYERCONTROLS_DEFAULT);
- //helpers for the wxPython people
- bool LoadURI(const wxString& fileName)
- { return Load(wxURI(fileName)); }
- bool LoadURIWithProxy(const wxString& fileName, const wxString& proxy)
- { return Load(wxURI(fileName), wxURI(proxy)); }
- #endif
- 5. Workarounds for adding virtual functions
- -------------------------------------------
- Originally the idea for adding virtual functions to binary compatible
- releases was to pad out some empty "reserved" functions and then
- rename those later when someone needed to add a virtual function.
- However, after there was some actual testing of the idea a lot of
- controversy erupted. Eventually we decided against the idea, and
- instead devised a new method for doing so called wxShadowObject.
- wxShadowObject is a class derived from wxObject that provides a means
- of adding functions and/or member variables to a class internally
- to wxWidgets. It does so by storing these in a hash map inside of
- it, looking it up when the function etc. is called. wxShadowObject
- is generally stored inside a reserved member variable.
- wxShadowObject resides in include/wx/clntdata.h.
- To use wxShadowObject, you first call AddMethod or AddField with
- the first parameter being the name of the field and/or method
- you want, and the second parameter being the value of the
- field and/or method.
- In the case of fields this is a void*, and in the case of method
- is a wxShadowObjectMethod which is a typedef:
- typedef int (*wxShadowObjectMethod)(void*, void*);
- After you add a field, you can set it via SetField with the same
- parameters as AddField, the second parameter being the value to set
- the field to. You can get the field after you call AddField
- via GetField, with the parameters as the other two field functions,
- only in the case the second parameter is the fallback
- value for the field in the case of it not being found in the
- hash map.
- You can call a method after you add it via InvokeMethod, which
- returns a bool indicating whether or not the method was found
- in the hash map, and has 4 parameters. The first parameter is
- the name of the method you wish to call, the second is the first
- parameter passed to the wxShadowObjectMethod, the third is the
- second parameter passed to that wxShadowObjectMethod, and the
- fourth is the return value of the wxShadowObjectMethod.
- 6. version-script.in
- --------------------
- For ld/libtool we use sun-style version scripts. Basically
- anything which fits the conditions of being #if'ed via wxABI_VERSION
- needs to go here also.
- See 'info ld scripts version' on a GNU system, it's online here:
- http://www.gnu.org/software/binutils/manual/ld-2.9.1/html_node/ld_25.html
- Or see chapter 5 of the 'Linker and Libraries Guide' for Solaris, available
- online here:
- http://docsun.cites.uiuc.edu/sun_docs/C/solaris_9/SUNWdev/LLM/p1.html
- The file has the layout as follows:
- @WX_VERSION_TAG@.X
- Where X is the current Release as mentioned earlier, i.e. 2. This
- is following by an opening bracket "{", followed by "global:",
- followed by patterns matching added symbols, then followed by "}", and then
- the file is either followed by earlier Releases or ended by
- a @WX_VERSION_TAG@ block without the period or Release.
- The patterns used to specify added symbols are globbing patters and can
- contain wildcards such as '*'.
- For example for a new class member such as:
- wxFont wxGenericListCtrl::GetItemFont( long item ) const;
- the mangled symbol might be:
- _ZNK17wxGenericListCtrl11GetItemFontEl
- so a line like this could be added to version-script.in:
- *wxGenericListCtrl*GetItemFont*;
- Allow for the fact that the name mangling is going to vary from compiler to
- complier.
- When adding a class you can match all the symbols it adds with a single
- pattern, so long as that pattern is not likely to also match other symbols.
- For example for wxLogBuffer a line like this:
- *wxLogBuffer*;
- 7. Checking the version information in libraries and programs
- -------------------------------------------------------------
- On Sun there is a tool for this, see pvs(1). On GNU you can use objdump, below
- are some examples.
- To see what versions of each library a program (or library) depends on:
- $ objdump -p widgets | sed -ne '/Version References/,/^$/p'
- Version References:
- required from libgcc_s.so.1:
- 0x0b792650 0x00 10 GCC_3.0
- required from libwx_based-2.6.so.0:
- 0x0cca2546 0x00 07 WXD_2.6
- required from libstdc++.so.6:
- 0x056bafd3 0x00 09 CXXABI_1.3
- 0x08922974 0x00 06 GLIBCXX_3.4
- required from libwx_gtk2d_core-2.6.so.0:
- 0x0a2545d2 0x00 08 WXD_2.6.2
- 0x0cca2546 0x00 05 WXD_2.6
- required from libc.so.6:
- 0x09691a75 0x00 04 GLIBC_2.2.5
- To see what WXD_2.6.2 symbols a program uses:
- $ objdump -T widgets | grep 'WXD_2\.6\.2'
- 0000000000000000 g DO *ABS* 0000000000000000 WXD_2.6.2 WXD_2.6.2
- 00000000004126d8 DF *UND* 0000000000000177 WXD_2.6.2 _ZN19wxTopLevelWindowGTK20RequestUserAttentionEi
- To see what WXD_2.6.2 symbols a library defines:
- $ objdump -T libwx_based-2.6.so | grep 'WXD_2\.6\.2' | grep -v 'UND\|ABS'
- 0000000000259a10 w DO .data 0000000000000018 WXD_2.6.2 _ZTI19wxMessageOutputBest
- 00000000002599e0 w DO .data 0000000000000028 WXD_2.6.2 _ZTV19wxMessageOutputBest
- 000000000010a98e w DF .text 000000000000003e WXD_2.6.2 _ZN19wxMessageOutputBestD0Ev
- 0000000000114efb w DO .rodata 000000000000000e WXD_2.6.2 _ZTS11wxLogBuffer
- 0000000000255590 w DO .data 0000000000000018 WXD_2.6.2 _ZTI11wxLogBuffer
- 000000000011b550 w DO .rodata 0000000000000016 WXD_2.6.2 _ZTS19wxMessageOutputBest
- 00000000000bfcc8 g DF .text 00000000000000dd WXD_2.6.2 _ZN11wxLogBuffer5DoLogEmPKcl
- 000000000010a3a6 g DF .text 0000000000000153 WXD_2.6.2 _ZN19wxMessageOutputBest6PrintfEPKcz
- 00000000000c0b22 w DF .text 000000000000004b WXD_2.6.2 _ZN11wxLogBufferD0Ev
- 00000000000bfc3e g DF .text 0000000000000089 WXD_2.6.2 _ZN11wxLogBuffer5FlushEv
- 00000000000c0ad6 w DF .text 000000000000004b WXD_2.6.2 _ZN11wxLogBufferD1Ev
- 00000000000b1130 w DF .text 0000000000000036 WXD_2.6.2 _ZN11wxLogBufferC1Ev
- 00000000000c095c w DF .text 0000000000000029 WXD_2.6.2 _ZN19wxMessageOutputBestC1Ev
- 00000000000c08e8 w DF .text 000000000000003e WXD_2.6.2 _ZN19wxMessageOutputBestD1Ev
- 00000000002554c0 w DO .data 0000000000000038 WXD_2.6.2 _ZTV11wxLogBuffer
- 00000000000bfda6 g DF .text 0000000000000036 WXD_2.6.2 _ZN11wxLogBuffer11DoLogStringEPKcl
- 00000000000abe10 g DF .text 0000000000000088 WXD_2.6.2 _ZN14wxZipFSHandler7CleanupEv
- 8. Testing binary compatibility between releases
- ------------------------------------------------
- An easy way of testing binary compatibility is just to build wxWidgets
- in dll/dynamic library mode and then switch out the current library
- in question with an earlier stable version of the library, then running
- the application in question again. If it runs OK then there is usually
- binary compatibility between those releases.
- You can also break into your debugger or whatever program you want
- to use and check the memory layout of the class. If it is the same
- then it is binary compatible.
- (In GDB the command x/d will show addresses as pointers to functions if
- possible so you can see if the order of the functions in vtbl doesn't change.)
- Another way to check for binary compatibility is to build wxWidgets in shared mode
- and use the 'abicheck.sh --generate' script before doing your changes to generate
- the current ABI (if the 'expected_abi' file is not already in the repo).
- Then rebuild wxWidgets with your changes and use 'abicheck.sh' to compare the
- resulting ABI with the expected one.
- Note that the abicheck.sh script is in the "lib" folder.
- === EOF ===
- Author: RN
|