Getting started in Qualcomm BREW development has its share of hurdles, but two in particular seem to discourage the small-scale (startup or academic) developers. The first is becoming an Authenticated BREW developer, the process of signing up for a Verisign certificate and signing Qualcomm’s developer agreement, required before you can have access to the Qualcomm BREW Extranet with its tools such as the BREW Signature File Generator and the BREW AppLoader. The second is obtaining a quality tool chain for the target hardware: Whereas the tools from ARM are first-rate, they’re also prohibitively expensive. (The lowest-cost option for the ARM tool chain costs more than the laptop I regularly use to run it!) Although GCC for ARM based on GCC 3.x is both supported by Qualcomm and widely available, its output is often larger, and it lacks support for Thumb, the small-footprint extension to the ARM architecture makes it difficult to create truly small binaries. Fortunately, with the advent of WinARM supporting both ARM7 and Thumb output, there’s a GCC-based solution for building binaries for BREW-enabled handsets. Although it won’t help you navigate Qualcomm’s legal agreement and get you access to the Qualcomm BREW Extranet, once you’re there it’s an excellent way to begin building your applications for evaluation on handsets.
Instructions to use WinARM for BREW aren’t hard to find—Ward Willats published a great HOWTO at http://brew.wardco.com/index.html back in May of 2006. It does, however, require some patience and tweaking of your makefile (even if you’ve previously used GCC) to get it right, so in the spirit of Qualcomm when supporting GCC 3.x, this article includes a custom make file that uses WinARM to build Qualcomm’s WhiteBoard developer sample. You can either use the instructions in this article and at Ward’s Web site to create your own make file, or begin with the WhiteBoard.mak available here.
To begin, you need a copy of WinARM. I downloaded mine, version 4.1.1, from http://gandalf.arubi.uni-kl.de/avr_projects/arm_projects/#winarm; the ZIP files at this link are pre-built and can be decompressed right to the directory where you want to install the tools. (I installed mine at the root of my boot drive, in c:WinARM). The advantage of using this release—besides that it’s precompiled and ready to go—is that it has no dependencies on cygwin. To install WinARM:
- Download the archive.
- Unpack the archive to a known location such as c:WinARM.
- Set the environment variables GCCHOME and GCCLIBPATH. GCCHOME should be set to the directory where you unpacked WinARM (for me, c:WinARM); GCCLIBPATH must be set to the lib directory inside your WinARM directory (for me, c:WinARMlib).
- Add c:WinARMbin to your PATH environment variable.
- Re-start any command line windows or command shells (say, in a text editor such as Emacs you may be using) to pick up the environment variable changes.
You also need Qualcomm’s support files for GCC, which requires you to have Qualcomm BREW Extranet access so you can download the files from the Qualcomm’s site. The archive contains two key things: a BREWelf2mod that can convert the ELF file from the linker to a mod file, and the GCCResolver.c file that contains definitions of memcpy and memset functions used by the GCC tool chain when creating the start-up code for your application. You will want to put GCCResolver.c someplace where you can get at it when you’re building your project, and of course the BREWelf2mod tool must be placed somewhere in your path. If you’re working with a team of developers, it’s best to powwow about where to put these so that everyone’s putting them in the same place, because they’re not linked to a specific BREW SDK version. I include the GCCResolver.c in my project just like any of my other source files, and by convention, I’ve put the BREWelf2mod command in my c:WinARMbin directory so I don’t have yet another directory with a single binary in my path.
Creating the Make File
Although I’m an old UNIX fan, I’m presently working in a shop that predominantly uses Microsoft Windows. Consequently, it’s nmake for me all the way—this keeps me from inflicting cygwin on my coworkers, and more closely matches the development environment directly supported by Qualcomm anyway. Because writing an make file for nmake from scratch is beyond the scope of this article, I offer the time-tested suggestion of finding one that works for someone else in another project and making it work to suit your needs. In my case, I began with an autogenerated make file for nmake and gcc 3.x using the Microsoft Visual Studio Plug-In for BREW available at https://brewx.qualcomm.com/bws/content/gi/products/vsaddins/3.0/220.127.116.11/web_install/install.htm. The make files generated by this tool are sufficient for small projects for single developers, but if you’re building a large project or cooperating with many developers who may have slightly different configurations, you’ll find quickly that you need to invest additional time in making a more capable make file for the handset.
Once you’ve created a basic make file, you must edit it as follows:
- Make sure the paths to the various build tools (the compiler and linker) are correct.
- Make sure the paths to the various build inputs (BREW SDK include files, BREW SDK source files, your source files, and so forth) are correct.
- Make sure the path to BREWelf2mod is correct.
- Make sure your target objects and input sources are correctly specified.
Step 2 is especially important—be sure you’re building the correct version of the SDK for your target handset. Class IDs for innocuous interfaces such as IFileMgr have been known to change in later versions of BREW; running with a binary built with a newer version of the SDK than the handset supports can cause crashes that look suspiciously similar to crashes caused by incorrect compiler options; often, your application just fails to launch and resets the handset.
Exactly how you do this depends on the make file you choose; if you’re lucky, the make file you start with is well-commented and this shouldn’t take very long. You can debug your make file at this point using the /N option to nmake, which executes your make file but does not execute the actual commands to build your application, letting you see what commands nmake thinks it needs to build your executable. Qualcomm’s make files are reasonably commented; be sure to check the values of the following environment variables: BREW_HOME, BREW_ADDINS, GCC_HOME, and GCC_LIBPATH.
Setting Compiler Options
When compiling C files for BREW using WinARM, you must specify the following options:
winarmbinarm-elf-gcc.exe -mlittle-endian -mcpu=arm7tdmi -mapcs-frame -fno-builtin -ffunction-sections -fshort-enums -D_DEBUG -DDYNAMIC_APP -I ... -o file.o -c file.c
The first argument specifies little-endian byte order, the default for most handsets (check your handset’s data sheet to be sure). The second specifies the ARM7 processor, and the third the standard mechanism for C stack frames. The fourth and fifth arguments specify that library functions should not be inlined (especially important, as you should be using BREW helper functions anyway) and that each function should be put in its own code segment, so that the linker can dead-strip unused functions. The last switch, -fshort-enums, tells the compiler to fit enumerations into the smallest number of bytes, and is good for saving some space in structures. Finally, if you’re compiling a debug build, be sure to include .D_DEBUG, and all applications should include .DDYNAMIC_APP. Of course, use the .I switch to specify your include paths, and the .o switch to declare the output file for the compilation.
Where you set these depends on the make file you’re using; in make files provided by Qualcomm, look at the CODE and INC variables.
Setting Linker Options
Linker options are a little tricker because you need to use a linker script that Ward’s helpfully crafted to ensure the proper ordering of all the object files in the project to create an ELF file that’s palatable to the BREWelf2mod converter. His web page has an excellent discussion of what’s necessary and why; the upshot is that the BREWelf2mod converter is very picky about the input ELF file, and if things aren’t just right, it gets hopelessly confused and creates multi-megabyte module files that aren’t likely to be executable anyway. Consequently, your linker command should look like this:
winarmbinarm-elf-ld.exe --script armelf.brew --emit-relocs --no-warn-mismatch -L winARMlibgccarm-elf4.1.1 -lgcc -o "file.elf" AEEAppGen.o file.o
The first argument tells the linker to pull in the linker script, about which I’ll say more in a moment. The second option is required, and tells the linker to output code relocation information; BREWelf2mod uses this information when creating the MOD file. The third is optional but a good idea, especially if you end up mixing ARM and Thumb code, and tells the linker not to warn about the different architectures being linked. Finally comes a list of what to link; the .L and .l options bring in the GCC library containing the application bootstrap glue, while the actual files being linked in this case are AEEAppGen.o and file.o to make the output file file.elf.
What happened to AEEModGen.o? If you’ve ever done any nosing around at the lowest levels of BREW development, you know how important this file is; it contains AEEMod_Load, the entry point for every application (and extension). Including AEEModGen.o is now the responsibility of the linker script, which also specifies the order of functions in the file (namely that AEEMod_Load must come first), and other details of the contents of the ELF file required by the BREWelf2mod utility.
In the make file with this article and most Qualcomm make files, check out the LINK_OBJS and LINK_CMD variables to configure the linker options.
Converting the ELF to a MOD
Converting the ELF file to a dynamic module is the purview of BREWelf2mod, and I’ve been successful doing this with two different versions of BREWelf2mod: the one included in the Microsoft Visual Studio Addins ZIP file I mentioned previously in this article, and the BREWelf2mod provided by Qualcomm dated 15 March 2004, a 52,248 byte executable.
In this article, I’ve shown you how to configure WinARM to compile C files for Qualcomm BREW in ARM architecture mode. With this knowledge and the resources at the end of this article, you should be able to modify your make file to build C++ files for ARM, or either C or C++ files for Thumb as well with just a few changes. There are many reasons you might choose WinARM, including compiler costs, the ability to debug using GDB on BREW 3.1.4 and later handsets, and the tool chain’s support for function pointer tables and global and static variables (recently also supported by Qualcomm with the ARM compiler via a newer BREWelf2mod utility). Regardless of your reasons, though, its good to know there’s another tool on the bench for building BREW applications.
- HOWTO Compile BREW applets with WinARM 4.1.0: http://brew.wardco.com/index.html
- WinARM: http://gandalf.arubi.uni-kl.de/avr_projects/arm_projects/#winarm
About the Author
Ray Rischpater is the chief architect at Rocket Mobile, Inc., specializing in the design and development of messaging and information access applications for today’s wireless devices. Ray Rischpater is the author of several books on software Development including eBay Application Development and Software Development for the QUALCOMM BREW Platform, both available from Apress, and is an active Amateur Radio operator. Contact Ray at [email protected]