Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

The Windows CE Build Process


Dr. Dobb's Journal August 1998: The Windows CE Build Process

Aspi is a developer for Cruise Technologies and can be contacted at [email protected].


Windows CE is an operating system that can be separated into any number of components, which may or may not be bundled with each other. Consequently, when you create a unique hardware platform and use Windows CE as the operating system, you can pick and choose from the available components what to include in your custom version of Windows CE. The Windows CE build process specifies which components should go into a custom version, which is then built in the form of a binary file. The components and build process are available from Microsoft in a development kit called the "Windows CE Embedded Toolkit" (ETK) that runs on Windows NT. The ETK currently comes with three CD-ROMs. One contains the Windows CE SDK and Visual C++ toolkit for CE. The other two have the ETK, which allows you to integrate your drivers with the kernel, write a Hardware Adaptation Layer (HAL) for your hardware, and create a custom version of Windows CE for your board. If you are developing applications, you work with CD #1. If you are developing hardware for CE, you work with CDs #2 and #3.

Because of the need to create a flexible build process, Microsoft has created an extensive and complex build process that lets you specify how a custom version of Windows CE must be built for a specific hardware platform.

Typically, after new hardware is designed and available, you choose one of the demo projects in the Windows CE ETK and modify it to suit your needs. This approach of treating the build process as a black box is fraught with the potential for mistakes. These mistakes result in unpredictable problems, like the hardware being unable to boot or software exceptions in certain modules. Such problems can, quite simply, be the result of bad builds.

The Structure of the ETK

In this article, I'll focus on the CEPC platform of the Windows CE Alder preview ETK. The Alder preview has been distributed to developers by Microsoft on numerous occasions, and the retail version is available commercially. The CEPC platform was created to let you build a version of Windows CE that will run on an x86 PC -- including that old, outdated 486 PC sitting in the corner of your office.

While you wait for hardware to become available, the CEPC represents your best chance to get software development going and begin your software prototyping. Alternatively, you can get a hardware reference platform for the processor you are using in your hardware (like the 821ADS board for the PowerPC 821), or buy the ODO development platform used by Microsoft. ODO is the name of the development board used by the Microsoft developers for Windows CE, hence the ODO_prefix to some of the variables you will come across in the build process. The ODO platform, designed by Hitachi, can accept different CPUs and change its hardware configuration by switching Field Programmable Arrays (FPGAs). (In case you aren't familiar with the TV series Deep Space 9, "Odo" is a character who is a shapeshifter; hence the name.)

Files installed by the ETK can be categorized into several groups:

  • Windows CE components provided by Microsoft. These are files that Microsoft gives you in binary form. This represents the CE kernel and other standard components like TCP/IP, the graphical windows and event system (GWES), dial-up networking, and the like. These files live under \Wince\Public\Common.
  • Platform-specific files. The CEPC platform files, provided in the \Wince\Platform\CEPC directory, include display, audio, keyboard, mouse, and serial port drivers. Other components under CEPC include utilities to download code and a CEPC boot loader. The \Wince\Platform\CEPC\Inc directory stores header files available to all platform-specific modules.
  • Project-specific files. Consider, for example, an ETK project called demo6. The project-specific files for demo6 are in \Wince\Public\Demo6. Project-specific files tell the build process which platform-specific files to include in the build. When a particular project is being built, the files that comprise the project are collected under the project-specific directory as well. When your build is complete, this directory is populated with all the files you need to create your custom build.

When creating a custom build, you should not make any changes to files under \Wince\Public\Common. These are Microsoft-supplied files. If you think you absolutely need to change a file under this directory tree, rethink your strategy: It will simplify your life when Microsoft upgrades become available.

If you are an old hand at embedded systems, you may be wondering, "What happens if the processor on my platform changes? Does this merit a new platform directory tree?" The answer is yes and no. The Microsoft build process creates processor-specific directories under the platform-specific directory tree to handle different processors in the same platform. Having said that, in these days of highly integrated embedded processors, a change in processor will probably merit a change in platform. The point is that it doesn't always have to be that way.

Anatomy of the Build Process

The flexibility of the build process is provided in terms of being able to specify which of the available components will make it into the Windows CE build you are trying to create. Accounting for the highly limited Windows NT command shell language, Microsoft has created a build process by using makefiles, batch files, and custom utilities.

Let's say you are building demo6. You do this by typing:

C:> demo6.bat

C:> blddemo

The blddemo batch file calls a combination of the batch files, makefiles, and custom utilities. These different build methods need a way to communicate. For example, a batch file may set a certain option so that a particular component may be included. Later in the build process, a custom utility that is putting together the binary image of the custom build may need to know which components have been included. This communication is carried out using environment variables. This is an important point. Look through the Microsoft documentation and learn about all the possible environment variables that you can set to modify the demo6 build. Later, when developing a build of your own platform, you will have the opportunity to create your own environment variables.

Table 1 lists some examples of environment variables you can set to control the CEPC build. Some of these variables are set by the file demo6.bat. Some environment variables, when set, tell the build process when not to include components. (For example, ODO_NOKEYBD is set to indicate that the build must not contain a keyboard driver.)

Windows CE Modules and Components

A particular functionality in Windows CE is called a "module" -- the kernel, networking, graphical windowing system, flash file system, and so on. Modules are further broken down into components, units that make up the functionality in a module. The subdivision of modules into smaller units lets OEMs include only what is absolutely necessary for their hardware build. On an embedded system, where space is at a premium, this is a welcome feature. This process of selecting components that go into making Windows CE is called "generating the system."

A word of caution: The components you select may not mix and match. If this happens, you will usually get a trace such as Windows CE KernelInit when running Windows CE. If you get no more traces, your software has expired and the problem may be in the way you have mixed and matched the Windows CE components.

Microsoft has not detailed which components can be safely mixed and matched. However, there are some canned configurations that demonstrate how components can be combined. These configurations live under the \Wince\Public\CONFIG* directories. Demo6 is based on the configuration provided in CONFIG4. Hence the environment variables with the CONFIG4_ prefix modify the canned configuration copied over from the CONFIG4. (You can read more about it in the online ETK documentation under the topic "The Public Config Directories.")

At this point, I'll present an overview of how the build process cobbles together a Windows CE binary image. The binary image, called "nk.bin," is placed along with other related files, in the \Wince\Release directory.

Setting-up Your Environment

The first step in the build process is to run a batch file called "Wince.bat," which sets up environment variables that locate your installation, its various directories, and your platform. Wince.bat, which is in \Wince\Public\Common\Oak\Misc, takes the command-line arguments Wince.bat cputype cpu os project platform. For example, the CEPC build requires that Wince.bat be invoked with the arguments Wince.bat x86 i486 CE WBT CEPC.

Wince runs a developer-specified batch file called "Setenv.bat," which it looks for in the predefined directory \Wince\Developr. It also runs a platform-specific batch file called "<Platform>.bat" from \Wince\Platform\<Platform>, and a project-specific batch file called "<Project>.bat" from \Wince\Public\<Project>. These batch files let you set platform- and project-specific environment variables.

Table 2 is a sampling of what Wince.bat sets internally for the demo6 CEPC build.

Generating the Windows CE System

When Wince.bat runs the demo6.bat file, environment variables are set up that specify the configuration you want. Among other things, these variables specify the type of drivers that get built into your platform. Windows CE components are set in a file called "Cesysgen.bat," which lives in the \Public\<Project>\Oak\Misc directory. Listing One rovides a few lines from the Cesysgen.bat file used with demo6.

The environment variables in Cesysgen.bat take a list of the names of components that go into a build of Windows CE. Cesysgen sets the environment variables CE_MODULES, COREDLL_COMPONENTS, FILESYS_COMPONENTS, GWES_COMPONENTS.

How does Cesysgen.bat get invoked? To create a build, you run a file called "Blddemo.bat." This file runs another batch file called "Sysgen.bat." This batch file's job is to pull together the Windows CE system and copy it to an appropriate place. Recall that the Windows CE system consists of selectable Windows CE components. Blddemo.bat and Cesysgen.bat are both project-specific files; for example, with each new project, you will have to modify or create new versions of these files. This is a good reason to understand what goes on inside these files.

After Cesysgen.bat executes, the components that will go into the Windows CE "system" have been specified by the environment variables set in that file. Blddemo now calls on the services of a Makefile located in \Wince\Public\Common\Cesysgen to build these components. These components are built as executables, DLLs, or static libraries from existing binaries (and some source code) shipped by Microsoft. They are then integrated with your modules to produce the final binary image that will run on your hardware.

The Makefile that Blddemo invokes does a number of things. For instance, it generates custom Windows CE modules like coredll, filesys, and other modules related to networking, infrared support, audio support, and so on. It copies them all into appropriate locations. Components are copied into \Wince\Public\demo6\cesysgen\target. Components that are created as static libraries are copied into \Wince\Public\demo6\cesysgen\lib. Sysgen.bat invokes the Makefile with the sysgen target. This target does everything the Makefile can do. Although beyond the scope of this article, reading and understanding this Makefile can be extremely educational.

There is one interesting target in the Makefile -- the include target. This target invokes a tool called "Cefilter" on the Windows CE include files. Cefilter parses the header files and leaves out portions of the files that are not relevant to your build. How does it do that? Recall the environment variables set in Cesysgen.bat. Cefilter uses these variables to find out which CE components are included in your build. It then determines which portions of the header files to exclude for your build. Cefilter is called to parse all the Microsoft-supplied header files in the Oak\Inc, Ddk\Inc, and Sdk\Inc directories under \Wince\Public\Common. The newly created custom header files are then copied into similarly named directories under \Wince\Public\demo6\cesysgen. These are pruned header files that should be included by your modules when they get built.

The Cefilter is also responsible for selecting the Windows CE modules that get included in your build. Where does Cefilter get these directions? From a file called Common.bib in \Wince\Public\Common\Oak\Files. Consider the example in the Common.bib file (Listing Two).

The @CESYSGEN directive tells Cefilter to look for an environment variable called CE_MODULES; if this variable contains the name GWES in its list of components, go ahead and include the following lines in the build. The conditional is closed by the @CESYSGEN ENDIF statement. In this particular case, if the environment variable CE_MODULES contains the component GWES in its list, the file gwes.exe is included in the build. The attributes NK and SH specify that the file goes into the NK section of memory and that the file's system (S) and hidden (H) attributes must be set. NK is the section in ROM where the binary image of the build is loaded.

Similar directives await Cefilter in the file Common.reg as well. This particular file is a representation of the initial registry that is part of the Windows CE build. Needless to say, the registry entries get pruned based on what you need in your custom build. Shrinking the registry in this way saves bytes in ROM.

Building Platform-Specific Drivers

Once Blddemo finishes running Sysgen.bat, it turns its attention to building drivers under the \Wince\Platform\Cepc directory. Recall that this directory contains code specific to the platform you are building. A large portion of this code consists of drivers specific to your hardware platform. These may include (but are not limited to) display, keyboard and mouse, touch-panel, and audio drivers. Drivers are found in the \Wince\Platform\<platform>\Drivers directory. However, Blddemo doesn't build everything under this directory. It picks and chooses which drivers it needs to build by looking at the environment variables you set in the <project>.bat file, in our case demo6.bat.

To build a particular driver, Blddemo first changes its working directory to the driver directory. It then invokes the command build -cfs. When this command returns, Blddemo looks for a file called Build.err in the current directory. If one exists, there were errors during the build, and Blddemo informs users that an error has occurred and executes the pause shell command. You can choose to continue by pressing any key, but you would be well advised to press Ctrl-C and check the errors in Build.err. Warnings are placed in a file called Build.wrn. A log of everything is made in a file called Build.log.

All the platform-specific stuff that gets built is copied into \Wince\Platform\<platform>\Target directory. Subdirectories under this directory reflect the CPU type and CPU you are building for. This lets you use multiple CPUs without changing platforms.

Drivers and platform-specific modules aren't all that Blddemo builds. It can also run through your project directory looking for applications to build. Applications may reside in the directory \Wince\Project\<project>\Oak\Src. In the case of demo6, two applications, "etcha" and "simple," are built. Modules built under the project directory are placed in \Wince\Project\<project>\Oak\Target.

Creating the Binary Image

Assuming Blddemo is successful in running through all your code and building your platform- and project-specific modules, it calls a batch file called Buildrel.bat. Buildrel focuses on copying built modules from the numerous directories they reside in and puts them all in the release directory, namely, \Wince\Release. Buildrel deletes everything under \Wince\Release before it begins copying. If you make any temporary changes to files in the \Wince\Release directory to test out something quickly, the changes will be lost when Buildrel is invoked the next time.

As the final step in the build process, Blddemo calls the Makeimg.exe utility, which looks at the release directory and parses several BIB files to create a ROM image that you can use to run on your hardware. Binary Image Builder (BIB) files contain directives to Makeimg on what platform-specific components need to be added to the build. The BIB files you need to know about include common.bib, a platform-specific BIB file called "Platform.bib," and a project-specific BIB file called "Project.bib." As a rule of thumb, modules that reside under the Platform directory are added to the build via Platform.bib. Modules that reside under the Public directory are added to the build via Project.bib. When Makeimg runs, it combines all of these BIB files and creates one common BIB file called "Ce.bib." Makeimg then calls the Windows CE binary ROM builder Romimage.exe, which parses Ce.bib and constructs a ROM image called Nk.bin. You can look at the output of Makeimg to determine which components have been added to Nk.bin. Makeimg will produce errors and abort if it discovers that it cannot find a module in the release directory that it needs to add to the binary. The final BIB file that warrants your attention is called "Config.bib," and it specifies how the memory on your hardware is laid out.

A similar fate awaits registry files. You can decide the initial registry that Windows CE will boot with via files with the .REG extension. You have already been introduced to the Common.reg file in the discussion on Cefilter. Platform-specific registry entries are specified in a file named <Platform>.reg. Project-specific registry entries may be specified in, you guessed it, <Project>.reg. Makeimg combines these files into a single file called Reginit.ini.

Makeimg performs some other bookkeeping. It performs localization functions depending on the setting of the COUNTRY environment variable. It also combines the database files Common.db, Project.db, and Platform.db to create a Initobj.ini. Initobj.ini is used to initialize the object store when Windows CE starts up. The RAM file-system files Common.dat, Project.dat, and Platform.dat are combined into Initobj.dat, which is used to initialize the RAM file system.

You can find more details on the workings of the Makeimg utility under the topic "How Makeimg.exe works" in the Windows CE online help.

Adding Modules to the Build Process

The process of adding your module to the build process is straightforward. You create a file called Sources in your directory. In Sources, you specify a SOURCES variable and set it to all the source files that comprise your module. I'll step through a sample SOURCES file (see Listing Three) to illustrate all the things you need to do. A makefile should be added to your module directory containing the line !include <makefile.def>.

Makefile.def is the master Makefile that all modules use. Using a common Makefile unifies the functionality that all modules will use. For example, Makefile.def sets up directives that specify which compiler and linker to use, the flags used by the compiler and linker, target directories where built modules will be placed, commonly used include directories, and so on. Along the way, Makefile.def inserts your SOURCES file into itself so that it addresses the needs of your module. Think of it as Makefile.def wrapping itself around your SOURCES file to create a complicated and thorough Makefile for you on the fly.

This means that you can use regular Makefile syntax in your SOURCES file. However, you cannot specify any targets in this file. The reason is that Makefile.def collects all its targets toward the end. There are some additional definitions after SOURCES is included in Makefile.def and before these targets begin. You cannot insert a target in the middle of a bunch of definitions in a Makefile. Inserting a target in SOURCES would put a target in the middle of the definitions in Makefile.def.

Running Build in your directory causes it to generate include dependencies for your files. This is useful because most developers create header files, include them in their source files, and forget to update their Makefile dependencies. Among other things, Build takes care of such oversights by generating a dependency list each time it attempts to build your source by parsing your source files and looking for includes. After it does such housekeeping chores, Build calls nmake. The Makefile in your directory is used, which in turn includes Makefile.def. Makefile.def lives in \Wince\Public\Common\Oak\Misc, which reflects the fact that it is shared by all modules.

Finally, to include your module into the build process, look for a file called "DIRS" in the parent directory of your module. Add your module's directory name to the DIRS variable defined in this file. This variable tells Build to recursively go into each directory named in the DIRS variable and run Build in that directory. If you cannot find a DIRS file, create one but make sure a DIRS file exists in the grandparent directory and that the parent directory is named in its DIRS variable.

Testing

To test your driver, create the SOURCES file as just described. Run build -cfs in your driver directory. If the build executes successfully, run Buildrel.bat and then MakeImg. This will bundle your newly built driver into the ROM image to be downloaded to your target. Simply download the newly created image to your target hardware and start debugging. I don't have space to cover how downloading to the target works. Suffice to say, you use a utility called Ppsh to download via the parallel port. You debug your module over the serial port using a GUI program called Windbg. For a discussion on the options that Build can accept, check the online documentation that ships with the ETK.

Conclusion

By creating a clean and error-free build process, you can focus immediately on resolving issues in the code itself, rather than debugging the process by which the code is being compiled.

DDJ

Listing One

REM // Base componentsset CE_MODULES=coredll filesys nk toolhelp shell
set COREDLL_COMPONENTS=coremain coreloc lmem thunks fmtmsg
set FILESYS_COMPONENTS=fsysram fsreg fsheap fsmain fspass fsdbase 
REM // Base GWE components
set CE_MODULES=%CE_MODULES% gwes
set GWE1_COMPONENTS=wmbase gweshare gwesmain immthunk msgque 
                                                    loadstr GSetWinLong
set COREDLL_COMPONENTS=%COREDLL_COMPONENTS% rectapi wmgr_c 
set GWE1_COMPONENTS=%GWE1_COMPONENTS% foregnd uibase kbdui 
                                                  idle getpower nled msgbeep
REM // Base GDI components
set GWE2_COMPONENTS=mgbase mgbitmap mgblt mgblt2 mgdc mgdibsec mgdraw 
                                                     mgrgn mgwinmgr mgpalnat

Back to Article

Listing Two

; @CESYSGEN IF CE_MODULES_GWES   gwes.exe        $(_FLATRELEASEDIR)\gwes.exe                 NK  SH
; @CESYSGEN ENDIF

Back to Article

Listing Three

TARGETNAME=DDI_SAMPLE   # Name of the target.TARGETTYPE=DYNLINK  # Build this as a DLL (Can be "PROGRAM" for EXEs).
DLLENTRY=DllMain    # Entry point into DLL.
# Set up a variable for the Windows Driver Model root directory.
!IF "$(WINCE_WDM)" == "1"
WDMLIBROOT=$(_COMMONOAKROOT)
!ELSE
WDMLIBROOT=$(_TARGETPLATROOT)
!ENDIF
# Add some of your own custom flags. Make sure you define
# everything in CDEFINES back in your CDEFINES. CDEFINES will be
# set to something before you get here and you don't want to trash that.
CDEFINES=$(CDEFINES) -DDDI -D$(_TGTPLAT)
# Precompile headers to save time when compiling.
PRECOMPILED_INCLUDE=precomp.h    # Precompile this file
PRECOMPILED_PCH=precomp.pch      #    into this file
PRECOMPILED_CXX=1                # Turn precompiled headers on (saves time!)


</p>
# Include directories. Only relative directories can be specified. Absolute 
# paths won't work. Your platform directory is prepended to each directory 
# in this INCLUDES path and specified as a -I option to your compiler.
INCLUDES=              \
        ..\..\..\inc;  \
    ..\inc;
# All the source files that make up your module.
SOURCES=       \
    Setup.cpp  \
    Cursor.cpp \
        Shapes.cpp\
    Io.cpp
# This variable contains libraries you want your module to link with.
TARGETLIBS=                                             \
    $(_COMMONSDKROOT)\lib\$(_CPUINDPATH)\coredll.lib    \
    $(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\gpe.lib        \
    $(WDMLIBROOT)\lib\$(_CPUINDPATH)\wdm.lib

Back to Article


Copyright © 1998, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.