The Windows 2000 build environment is a wild animal that must be tamed.
If you try to feed an NT V4.0 (orV3.51) SOURCES file to the Win2K build environment, it will throw up and refuse to build your driver. If you eventually manage to make your SOURCES file palatable, you may have to search for the location where the build environment hid your target files. Once you get your changes to work, you are likely to discover that your new SOURCES file is no longer appetizing to the old 4.0 or 3.51 build procedure.
This article will explain how to solve these problems. Additionally, the article will present a number of ways to make the build environment a friendlier, mellower, sort of beast. When you’re through, you’ll have the tools necessary to tame the wild Windows 2000 build environment for yourself.
Writing a Universal SOURCES File
Those of you who have been developing Windows NT 4.0 or 3.51 drivers will probably feel disoriented the first time you try to build your driver for Win2K. The directory structure of the Win2K DDK has changed from the NT 4.0 DDK. Consequently, your old SOURCES files, which depend on the structure of the NT 4.0 DDK, will not successfully build your drivers for Win2K. This particularly affects those of us in file system land where not enough of the infrastructure above the storage stack has changed to warrant maintaining separate source code bases for Win2K and NT 4.0.
There are several obstacles you must overcome to write a SOURCES file that works for both NT 4.0 and Win2K. For example, your TARGETPATH must be specified differently for Win2K and NT 4.0. The old DDK insists on appending a path such as i386\free to your TARGETPATH. The new DDK insists on appending a path such as i386. Accordingly, portions of the Win2K DDK directory tree are inverted from the NT 4.0 DDK directory tree. The new library tree is an example of this inversion.
Libraries no longer reside in familiar locations such as \DDK\lib\i386\free. Now they inhabit alien directories such as \DDK\libfre\i386. As a result, libraries must be specified differently in your SOURCES file. For example, the old DDK samples specified library paths similar to $(BASEDIR)\lib\*\$(DDKBUILDENV)\class.lib. The new DDK samples specify library paths like $(DDK_LIB_PATH)\classpnp.lib.
What can you do about these changes if you need to maintain a common source code base for Win2K and NT 4.0? A time-honored technique for dealing with seemingly arbitrary changes is to insulate yourself from them. By adding an additional layer of abstraction, you can write a SOURCES file that allows you to build NT 4.0 as well as Win2K drivers. That layer of abstraction, MYSOURCES.DEF, appears in Figure 1. Using MYSOURCES.DEF results in a simplified SOURCES file that appears in Figure 2. When using this SOURCES file to build your driver, Win2K target files are output to a directory such as C:\mybin\50\checked\i386. Windows NT 4.0 target files are generated in a directory such as C:\mybin\40\i386\checked. Lastly, if you still support it, Windows NT 3.51 target files are deposited in a directory like C:\mybin\351\i386\checked.
# determine DDK version: 351, 40, or 50
!if "$(MIDL_OPTIMIZATION_NT5)" != ""
!elseif "$(NEW_CRTS)" != ""
!if $(DDKVER) == 50
# create output directory if it does not exist
!if [mkdir $(MYLIBS)] > 1
!error Failed to create directory "$(MYLIBS)."
Figure 1 — MYSOURCES.DEF
Now that your SOURCES problems are solved, we will discuss how to further domesticate the build environment. There are several behaviors you may desire to eliminate. For example, when you open a Win2K build window, the system thrashes wildly for a number of seconds. When you specify a start directory for your build window shortcut, the build window opens with its current working directory set to the root of the DDK. Moreover, every time a build window is opened, the build environment searches for an updated compiler. If it finds one, it updates itself to use the latest compiler without asking for your approval. Fortunately, there are effective solutions to all of these problems.
TARGETLIBS= $(MYLIBS)\my.lib $(DDKLIBS)\libcntpr.lib
SOURCES= $(SOURCES) driver.cpp
Figure 2 — SOURCES
The first thing you notice when opening up a Win2K build windows is a distinct pause while the system grinds away at the disk. This is more noticeable for people with slower processors and disks. One way to eliminate this annoyance, of course, is to acquire an expensive new computer for building your drivers. However, if you are not trying to finagle a better system out of your boss, there is a cheaper alternative.
The root of this evil thrashing is a new addition to the DDK named VcCheck. Every time you open a Win2K build window, VcCheck is invoked with the parameter "/d." When invoked with the "/d" option, VcCheck walks the src subdirectory of your DDK installation generating all the dirs files in the src tree. Unless you are constantly adding new sample source code to the src subdirectory of the DDK, there is no reason these files need to be written every time you open a build window.
To disable this thrashing, find the last occurrence of VcCheck in your SETENV.BAT file in the bin directory of the DDK, and insert rem at the beginning of the line. Refer to Figure 3 for a snapshot of what this portion of the file should look like. If you add new samples to your DDK's src directory after making this change, you can run VcCheck manually from the build environment to regenerate the dirs files.
rem Disable writing of "dirs" files
rem %1\bin\vccheck /p %1 /d
if "%OS%" == "Windows_NT" goto WinNT
Figure 3 — SETENV.BAT Modified to Eliminate Thrashing
Specifying a Compiler/SDK
Another new feature of the Win2K DDK you cannot miss is the DDK searching for the latest version of the compiler on your workstation every time you open a build window. This feature does not wait for the Win2K developers to adopt the compiler before updating your build environment to use the latest compiler (well, at least as far as we know!). Moreover, this feature does not wait for Windbg to support the latest compiler's symbol format. For these reasons, you may want to disable this feature.
Yet again, the root of the evil is our friend VcCheck, with slightly different parameters than before. When VcCheck is invoked with the "/e" option, VcCheck inspects a few values in the registry to determine what directory contains the latest version of the compiler. Once VcCheck has this information, it writes the file DDKVARS.BAT. SETENV.BAT in turn invokes DDKVARS.BAT to insert the compiler's directories into your build environment.
Again, disabling this feature entails modifying SETENV.BAT. With the addition of a few lines to SETENV.BAT, you can specify a compiler and SDK as well as bypass DDKVARS.BAT and VcCheck. Refer to Figure 4.
if "%1"=="/?" goto usage
if "%1"=="-?" goto usage
if "%1"=="\?" goto usage
if "%1"=="" goto usage
rem Explicitly specify compiler then jump past VcCheck and DDKVARS.BAT.
rem Note, you may have installed your compiler in a directory other than "vs."
call e:\vs\vc98\bin\VCVARS32.BAT x86
call e:\mssdk\setenv e:\mssdk
rem Check for new or updated install of MSVC
%1\bin\vccheck /p %1 /e
if NOT EXIST %1\bin\ddkvars.bat goto devdir
if "%MSVCDIR%"=="" set MSVCDIR=%MSDEVDIR%
Figure 4 — SETENV.BAT Modified to Specify Compiler/SDK
Specifying a Start Directory
If you are working on multiple driver projects, you may find it convenient to have multiple build icons that open build environments in specific projects' directories. The obvious solution to this problem is to copy the build environment shortcut and change the shortcut's start directory on the Shortcut tab of the shortcut's property page. If you have tried this, then you know this does not work. The build environment persists in opening with the current working directory set to the root of the DDK. While this may be convenient for the DDK team, it is likely to be rather inconvenient for almost everyone else.
Fortunately, there is an easy solution to this problem. The secret is to find the line in SETENV.BAT that sets the current directory to the root of the DDK and insert rem at the beginning of the line. This portion of your SETENV.BAT should look like Figure 5. After making this change, each of your build windows will open with their current working directory set to the start directory specified in the property page of the build window's shortcut.
rem cd /d %BASEDIR%
Figure 5 — SETENV.BAT Modified to Open Build Window in Specified Directory
Miscellaneous Win2K DDK Problems
Although this will not affect most driver writers, an incompatibility exists between the Windows NT 3.51 DDK and the Win2K DDK. Specifically, the format of the _objects.mac file generated by either of the two build environments is not suitable for the other build environment. This problem manifests itself as NMAKE claiming it does not know how to make any of your object files. One possible solution is to delete _objects.mac when switching build environments. The build process will magically regenerate _objects.mac in a format suitable for the current build environment.
You may have observed that specifying $(BASEDIR)\inc\ddk as part of your INCLUDES in your SOURCES file is optional when including ntddk.h. Unfortunately, this is not optional when building DDK libraries. Failing to specify this as part of your INCLUDES causes the library build process to die with an error message indicating ntddk.h was not found.
Although the Win2K build environment seems like an untamable beast, it is highly trainable. The build environment is robust and responds well to modifications. Developers often avoid modifying their build environments for fear of breaking them or wasting valuable time. Yet, if you apply some of the customizations presented in this article, you will find the rewards of customizing the DDK's build environment outweigh the risks.