Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Symbian OS Explained - Effective C++ Programming For Smartphones (2005) [eng].pdf
Скачиваний:
60
Добавлен:
16.08.2013
Размер:
2.62 Mб
Скачать

18

Compatibility

It is only the wisest and the very stupidest who cannot change

Confucius

I’ve devoted this chapter to compatibility, because it is an important aspect of software engineering. If you deliver your software as a set of interdependent components, each of which evolves independently, you will doubtless encounter compatibility issues at some stage.

For Symbian, most compatibility issues apply to dependent code, such as that belonging to third-party developers, which should ideally work equally well on products available today, and with future versions of Symbian OS. Compatibility must be managed carefully between major Symbian OS product releases. For developers delivering Symbian OS code that is not built into ROM, there is the additional complexity of managing compatibility between releases that are built on the same Symbian OS platform.

Let’s consider the basics of delivering a software library – a binary component which performs a well-defined task, such as a set of string manipulation functions or a math library. The software’s author typically publishes the component’s application programming interface (API) in the form of C++ header files (.h), which are used by a customer’s compiler, and an import library (.lib), which is used by a linker. Often these are also accompanied by written documentation that describes the correct way to use the library. The API presents, in effect, a contract that defines the behavior of the component to those that use it (its dependents).

Over time, the library may be expanded to deliver additional functionality, or it may be enhanced to remove software defects, make it faster or smaller, or conform to a new standard. These modifications may require changes to the API; in effect, the contract between the component and its dependents may need to be re-written. However, before doing this, the impact of those changes on any dependent code must be assessed. The nature and implications of a change must be well-understood because, when a library has a number of dependent components in a system, even an apparently simple modification can have a significant effect.

278

COMPATIBILITY

This is a fundamental issue of software engineering, and a number of techniques for writing extensible but compatible software have been developed. Many of the issues associated with compatibility lie outside the scope of this book, but an understanding of the basics will allow you to appreciate the factors which have shaped the evolution of Symbian OS. This chapter defines some of the basic terminology of compatibility. It then moves on to discuss some of the practical aspects, which will help you to develop code on Symbian OS which can be extended in a controlled manner without having a negative impact on your external dependents.

18.1Forward and Backward Compatibility

Compatibility works in two directions – forward and backward. When you update a component in such a way that other code that used the original version can continue to work with the updated version, you have made a backward-compatible change. When software that works with the updated version of your component also works with the original version, the changes are said to be forward-compatible.

Let’s look at an example: a software house releases a library (v1.0) and an application, A1. Later, it re-releases the library (v2.0) and also releases a second application, A2, which uses it. If original copies of A1 continue to work as they did previously with v2.0 of the library, the changes made were backward-compatible.

If the v1.0 version of the library is then reinstalled for some reason, and A2 continues to work with the older library as it did previously with v2.0, the changes were also forward-compatible. This is illustrated in Figure 18.1.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Library

 

 

 

 

 

 

 

 

 

 

 

 

Application

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A2

Backward

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(version 2.0)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Forward

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Compatible

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Compatible

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(Application A1

 

 

 

 

 

 

 

Update and

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(Application A2

works with

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

works with

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

version 2.0 of the

 

 

 

 

 

 

 

 

 

 

 

 

re-release

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

version 1.0 of the

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

library)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

library)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Application

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Library

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(version 1.0)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure 18.1 Forward and backward compatibility

Backward compatibility is usually the primary goal when making incremental releases of a component, with forward compatibility a desirable

SOURCE COMPATIBILITY

279

extra. Some changes cannot ever be truly forward-compatible, such as bug fixes, which by their nature do not work ”correctly” in releases prior to the fix.

There are different levels of compatibility: class-level and library-level. Maintaining compatibility at a class level means ensuring that, among other things, methods continue to have the same semantics as were initially documented, no publicly accessible data is moved, and the size of an object of the class does not change (at least, not when a client is responsible for allocating memory for it). To maintain library-level compatibility, you should ensure that the API functions exported by a DLL are at the same ordinal and that the parameters and return values of each are still compatible.

There are also degrees to which compatibility can be maintained. This can vary from not requiring anything of dependent code (i.e. it can run as it did previously when a new version of the component it uses is installed) to requiring it to be recompiled and/or re-linked. However, if dependent source code needs to be changed in any way in order to work with a new release of your component, the changes were incompatible. Pure and simple.

Maintaining backward compatibility is the primary goal of an incremental component release.

18.2 Source Compatibility

If you make a change to your component which forces any dependent code to be changed in order to recompile, the change is sourceincompatible.

//orchestra.h

//Version 1.0

...

class CInstrument : public CBase

{

public:

IMPORT_C static CInstrument* NewL(); IMPORT_C virtual CInstrument();

public:

IMPORT_C virtual void PlayL(); protected:

CInstrument(); void ConstructL();

private:

//...

};

280

COMPATIBILITY

Thus, the following change is source-incompatible if dependent code includes orchestra.h and uses class CInstrument:

//orchestra.h

//Version 2.0, renames a class

...

class CStringInstrument : public CBase

{

public:

IMPORT_C static CStringInstrument* NewL(); IMPORT_C virtual CStringInstrument();

public:

IMPORT_C virtual void PlayL(); protected:

CStringInstrument(); void ConstructL();

private:

//...

};

The only change between version 1.0 and version 2.0 is the change of class name from CInstrument to CStringInstrument. Any dependent binaries that built against version 1.0 and do not need to be recompiled will continue to work. It is only when the client code comes to be rebuilt against version 2.0 that it will be affected by source incompatibility (it must be modified to replace the CInstrument class with the new CStringInstrument class).

On Symbian OS, a typical source-incompatible change involves modifying the internals of a member function to give it the potential to leave when previously it could not do so. To adhere strictly to the naming convention, the name of the function must also be modified by the addition of a suffix L.

If you change your component and dependent components can recompile against the new version without the need to make any changes, it can be said to be source-compatible. An example of a source-compatible change is a bug fix to the internals of an exported function, which doesn’t require a change to the function definition itself.

18.3Binary Compatibility

Binary compatibility is achieved when one component, dependent on another, can continue to run without recompilation or re-linking after the component on which it depends is modified. The compatibility extends across compilation and link boundaries.

One example of a binary-compatible change is the addition to a class of a public, non-virtual function which is exported from the library with an ordinal1 that comes after the previous set of exported functions. A

1 As I described in Chapter 13, Symbian OS uses dynamic linking by ordinal, rather than function name matching, to reduce the size overhead of its export tables. However,