Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Common Challenges to Porting Existing Code in C to BREW


riting—and maintaining—portable code is as much an art as it is the holy grail of many software companies. If your firm's success is based on a key algorithm for mobile computing (say, image or audio recognition), why not grow your market share by making your algorithm available for BREW? When you do, though, you'll face challenges. Often, the challenges are immediate and obvious, and how you solve them is part of how your company is successful, such as moving an application's user interface from one platform to another. At the heart of most technologies, however, are a few key algorithms nearly always written in mostly-portable C.

Moreover, once you've dealt with a few ports of such code to BREW, patterns emerge. Here are the four most common patterns I've observed, and how to deal with them.

Referencing Global and Static Variables
If you've written any code that actually runs on a BREW-enabled handset, you've already learned that BREW doesn’t have support global variables…or does it?

In point of fact, BREW doesn't support a read-write segment, that chunk of a program image where a compiler shoves the pre-initialized variables that you've indicated can change during program execution. The reasons for this are long and sticky, but the upshot is that if you're building your application using the ARM tool chain (using tools such as the BREW Builder or ARM ADS), you can't write things like this:

int gCounter = 0; static int thunk( void ) { return ++gCounter; }

Or this, for that matter:

static int thunk( void ) { static int gCounter = 0; return ++gCounter; }

How much of a problem this really poses depending on your application and what you want to do about it. The lack of a read-write segment (often called, simply, "the global variable problem") has been an issue to varying degrees at different times for a number of mobile platforms, including Palm OS and Symbian. As a result, many mobile solutions have been designed to accommodate this problem from the get-go, passing any data that would otherwise be global in a pointer to a structure on the heap:

typedef struct SContext { int counter; } SContext; static int thunk( SContext *p ) { return ( p ? ++p->counter : 0 ); }

This use of a context or state variable is still the best way to deal with the problem, because it promotes better organization for your code as well as fewer side effects. However, it's simply not practical if you're porting a large body of existing code, especially if you're going to be maintaining both the origin of the ported code and the resulting port. Fortunately, with the advent of GCC support for BREW, you now have two additional compiler options both based on GCC: Gnude and WinARM. Based on GCC 3.x and GCC 4.x respectively, the GCC tool chain can create "fix-up" code that allocates your global and static variables on the heap at run-time, letting you use your tried-and-true code without changes on BREW. Either of these tools poses some challenges; Qualcomm's support of GCC solutions for BREW has been more sound and fury, but a growing body of users (in a straw poll at the most recent BREW developer conference, nearly half the developers I asked told me they were using GCC-based tools) is stepping in to provide documentation and help. The binaries generated by the GCC tool chain can be larger than the tools available from ARM, but this is becoming less of a problem as handset capacities improve and open source developers put more effort into refining the WinARM tool chain. See the "Related Resources" box for more information on how to download and install either Gnude or WinARM.

Comment and Contribute





