3 <title>Maintaining Binary Compatibility
</title>
6 <h1>Binary Compatibility in
3 Easy Steps!
<hr></h1>
8 <h2>An Introduction
</h2>
9 In the early days of the OpenBeOS project, a debate raged concerning one of the projects
10 primary goals: maintaining binary compatibility with BeOS R5. The idea was that the
11 only way an effort to rewrite BeOS would be successful was if folks could continue
12 running the apps they already had. Certainly, a lot of software available for BeOS is
13 open source or actively maintained -- these apps could just be recompiled if necessary.
14 Others -- PostMaster, gobe's Productive suite and a few other crucial apps -- weren't
15 likely to get rebuilt, either because the original author had stopped maintainance
16 without being kind enough to release the source, or because it just wouldn't be
17 commercially feasible.
<p>
18 Some said that we were crazy; that it couldn't be done. Thankfully, cooler heads
19 prevailed and we're well on our way to a binary compatible clone of R5.
<p>
21 "But wait!" you cry.
"How did the cooler heads which prevailed know that the holy grail
22 of binary compatibility was achievable?" I'm so glad you asked! Keeping reading and be
23 enlightened, Grasshopper.
<p>
26 There are three basic issues that have to be addressed to ensure binary compatibility:
29 <b>Names must be identical
</b><br>
30 This includes class and structure names as well as public, protected and global
31 function and variable names.
34 <b>Object sizes must be identical
</b><br>
35 Classes must contain the same number of bytes of data; global variables must
36 be the same size. Maybe BGlobalVar should've been an
<code>int32
</code>
37 instead of an
<code>int16
</code>, but we're stuck with it now.
40 <b>Virtual function table layout must be identical
</b><br>
41 The most cryptic and confusing aspect of maintaining binary compatibility.
42 The issue essentially boils down to this: for any given class, there must
43 be the same number of virtual functions, declared in the same order as the
48 <h2>The Nitty Gritty
</h2>
49 "Good grief!" you say.
"How on earth do I keep all this stuff straight?" Ah,
50 Grasshopper, it is easier that you might imagine. Just follow these steps, and you
51 should be binary compatible in no time!
54 <b>Make a copy of the appropriate Be header file
</b><br>
55 This is now your header file. You may need to change a thing or two, but what
56 you can (or will need to) change is quite limited, and discussed below.
59 <b>Implement public, protected and virtual functions
</b><br>
60 In the course of doing this, you may discover that there are some private
61 non-virtual function declarations that you just don't use. Feel free to axe
62 them! Since they're private, nobody using the class will miss them, and
63 because they're not virtual, they don't effect the vtable layout. Conversely,
64 if you find a need to add some private, non-virtual functions, go right ahead
65 (for the very same reasons).
68 <b>Make sure you don't change the number of bytes used for data
</b><br>
69 There are two situations that can make this seem difficult. First, there
70 may be data members that you don't use in your reimplementation. You can
71 just leave them (safe, but a little messy) or you can add the extra members'
72 bytes to the class's
"unused" data array. An example will make this clear.
<br>
73 Let's say we have a class BFoo:
<br>
89 The Be engineers that originally wrote this BFoo purposely added some data
90 padding in the form of an array of
2 <code>int32
</code>s (they did this with
91 most classes in the API). Now let's suppose in your implementation, you
92 really didn't need
<code>fQux
</code>. You can add
<code>fQux
</code>'s bytes
93 into
<code>fUnused
</code>:
<br>
106 Nothing could be easier! An additional twist that should be noted is that
107 data member order must also be preserved. In much the same way as existing
108 apps will
"look" for virtual functions in a specific place in the vtable,
109 so will they
"look" for data members in a specific place in an object.
<br>
110 "But what if I don't need <code>fZig</code>, either?" you wonder.
"It's only
111 one byte, not four like an <code>int32</code>!" Have no fear! Just rename it
112 "<code>fUnusedChar</code>" and be done with it.
<p>
114 The second situation that can make preserving object size tricky is if there
115 aren't
<i>enough
</i> bytes of data available. Building on our cheesy BFoo
116 example, let's suppose that rather than getting rid of
<code>fQux
</code> and
117 <code>fZig
</code>, you actually needed to
<i>add
</i> another
4
118 <code>int32
</code>s worth of data:
<code>fNewData1
</code> through
119 <code>fNewData4
</code>. The original implementation of BFoo has two extra
120 <code>int32
</code>s which we can use, but that leaves us two
<code>int32
</code>s
121 short. What to do? The easiest thing is to create a data structure to hold
122 your new data and convert one of the
<code>fUnused
</code> items into a pointer
138 _BFooData_* fNewData;
152 fNewData = new _BFooData_;
160 Voila! More data without making the class bigger. Make sure you're cleaning up
161 your new (dynamically allocated) data in the destructor.
<b>NOTE:
</b> this trick
162 will only work if the class originally had a destructor! Adding a destructor
163 after the fact won't work for existing apps (since they won't call it), leading
164 to memory leaks. Fortunately, there are very few instances in the BeAPI where a
165 class doesn't have a destructor already declared.
169 And there you have it: Binary Compatibility in
3 Easy Steps!
<br>
170 Questions, comments, or corrections? Please let
171 <a href=
"mailto:erik@cgsoftware.com">me
</a> know!
<br>
174 <!-- The obligatory SourceForge plug -->
176 <small>The OpenBeOS project is hosted by:
</small><br><br>
177 <a href=
"http://sourceforge.net">
178 <img src=
"http://sourceforge.net/sflogo.php?group_id=33869&type=1" width=
"88" height=
"31" border=
"0" alt=
"SourceForge Logo">
182 <small>Copyright
© 2001-
2002
183 <a href=
"http://www.openbeos.org">OpenBeOS
</a> Project
</small>