Summary: Tips for creating SHIP, RETAIL and DEBUG builds, and various permutations of the environment flags WINCESHIP, WINCEDEBUG, COMPILE
DEBUG, and DISABLEOPTIMIZER.
SWITCHING BETWEEN DEBUG AND RETAIL CONFIGURATIONS
The Windows CE build system can compile your source code in three main configurations: DEBUG, RETAIL, and SHIP. This choice is controlled by a few key environment variables in your build window. These environment variables can be changed at any time, meaning you can target a specific component to be compiled DEBUG, while the rest of the system remains RETAIL.
This article explains how to use WINCEDEBUG, WINCESHIP, COMPILE
DEBUG, and DISABLEOPTIMIZER in various combinations. Understanding these flags can greatly aid in debugging and save valuable time for developers during bug investigations. This article is intended to highlight:
*Output library location. Will the libraries I build end up in \lib\ARMV4I\RETAIL or \lib\ARMV4I\DEBUG?
*Optimization. Was the optimizer enabled during my build? If so, some symbols may have been optimized out, making it impossible to set a watch in the debugger. Also, code paths that were optimized will cause discontinuities when single-stepping through the debugger.
*Debug Macros. Will I get DEBUGMSG/DEBUGCHK? Will I get RETAILMSG in addition? Will I get nothing?
SHIP BUILDS
To enable a ship build, the environment variable WINCESHIP must be set to 1, and WINCEDEBUG must be set to ‘retail’. Setting WINCESHIP causes the symbol SHIP_BUILD to be defined during compilation. In addition, the compiler’s optimizer is enabled. All code is complied to \RETAIL paths.
From a high level, \public\common\sdk\inc\dbgapi.h shows the basic debug macro characteristics of a ship build:
#ifdef SHIP_BUILD
#define ERRORMSG(cond,printf_exp) ((void)0)
#define RETAILMSG(cond,printf_exp) ((void)0)
#define DEBUGMSG(cond,printf_exp) ((void)0)
#define DEBUGLED(cond,parms) ((void)0)
#define DBGCHK(module,exp) ((void)0)
#define DEBUGCHK(exp) ((void)0)
#define DEBUGREGISTER(hMod) ((void)0)
#define RETAILREGISTERZONES(hMod) ((void)0)
// Note that later in dbgapi.h, ASSERT is defined as DBGCHK
#else // SHIP_BUILD
This shows that the standard mechanisms for handling messages/status and assertions are removed from source code, which we would expect in a shipping product. Always use caution with the message macros listed above, especially in timing sensitive components such as device drivers. Although you may not realize it, correct functionality of your driver may actually depend on the artificial delays introduced by message output. Also, any module has the ability to condition on the SHIP_BUILD define. As a result, ship builds can potentially have a far-reaching impact on execution. Microsoft recommends testing SHIP build configurations at least one month before shipping a product, if not sooner.
RETAIL BUILDS
To enable a full RETAIL build, the environment variable WINCESHIP must be cleared and WINCEDEBUG must be set to ‘retail’. Like SHIP builds, RETAIL builds contain optimized code. Again, all code is compiled to \RETAIL paths. Furthermore, dbgapi.h shows us that ERRORMSG, RETAILMSG, RETAILLED, and RETAILREGISTERZONES are now enabled. No ASSERT-like functions are enabled in RETAIL builds.
Retail builds are typically the target for testing. Only serious errors and critical status messages should use ERRORMSG/RETAILMSG, and otherwise code execution will closely mirror a SHIP build.
Retail builds contain optimized code, but you can override this setting. Set DISABLE_OPTIMIZER=1 and afterwards, any re-built modules will be unoptimized. This is useful for reproducing a bug where you want 1:1 parity in the debugger, but are not interested in DEBUGMSG/DEBUGCHK behavior.
DEBUG BUILDS
To enable a DEBUG build, the environment variable WINCESHIP must be cleared, and WINCEDEBUG must be set to ‘debug’. Code compiled in this configuration will not be optimized. All of the debugging macros from dbgapi.h are defined. All code will be compiled to \DEBUG directories.
DEBUG builds are the typical target for initial development. DEBUG builds will output messages from both RETAILMSG and DEBUGMSG (everything in dbgapi.h), for all zones that are enabled. For more information on debug zones, please see articles from the
CEBase team blog that appear at the bottom of the page.
A trace of
DEBUGMSGs can be the best currency when asking questions on newsgroups about errors. They provide a detailed description of what is happening in the system, which could help someone else isolate your problem quickly.
RETAIL BUILDS WITH TARGETED DEBUG COMPONENTS
Which is the right build for you? Most customers use SHIP builds because system behavior in a SHIP build is equivalent to what will run on the final product. However, as soon as we find a bug in our code, we need to think about making a RETAIL or DEBUG image.
There are trade-offs with DEBUG images as well. Again, they are perfect for initial development. However, many bugs that are timing-sensitive (race conditions) will no longer repro in a DEBUG build. DEBUG images are sometimes too large due to memory limitations on your platform, and they’re also slow. On the other hand, if your bug does reproduce in DEBUG there is a good chance that you will hit an ASSERT before the failure condition, or around the failure see a useful DEBUGMSG telling you what is wrong.
One of the most useful build configurations is a RETAIL build with targeted DEBUG components. In this configuration, WINCESHIP is clear, WINCEDEBUG=’retail’, and COMPILE
DEBUG=1. Setting COMPILEDEBUG=1 has the same effect as setting WINCEDEBUG=’debug’, except all libraries will be built to \RETAIL paths. The advantage here is the ability to target one library in DEBUG, and link with the existing libraries already in \RETAIL directories.
Say I want to debug only my USB Function MDD, but I am not interested in other libraries that comprise USBFN.DLL. I can browse to \public\common\oak\drivers\usbfn\controller\mdd, set COMPILE
DEBUG=1, ‘build’, and get a DEBUG version of the library in the \RETAIL directory (then I clear COMPILEDEBUG for good measure). Now I simply rebuild USBFN.DLL. When I boot my device, I’ll get full RETAIL behavior, until USBFN.DLL is loaded. Then I’ll have
DEBUGMSGs that were defined in the MDD only. (If I had changed WINCEDEBUG instead of COMPILE_DEBUG, I’d then have to go to \public\common\oak\lib\ARMV4I\debug, copy ufnmdd.lib and any other targets to ..\retail, and then rebuild USBFN.DLL, which is clumsier).
FURTHER READING
Debug Messages and Debug Zones in Windows CE_base/archive/2006/12/18/debug-messages-and-debug-zones-in-windows-ce.aspx
KITL and OAL Debug Messages in Windows CE6_base/archive/2006/12/22/kitl-and-oal-debug-messages-in-windows-ce6-0.aspx
Debug Zones Eliminating Excess Chatter_base/archive/2007/03/15/debug-zones-eliminating-excess-chatter.aspx
Go up to
Big Book of BSP
Thank you for contributing to this BSP Wiki. To ensure your comments and concerns receive proper exposure, include bspwiki""@""microsoft"".""com when providing feedback or topical suggestions.