小z说:内核驱动的编译环境

作者:张佩】【原始URLhttp://www.yiiyee.cn/Blog/KernelBuildEnviroment/

[download id=”2″]

这一章驱动小z继续带大家遨游驱动王国。在这块地面上,小z是个地头蛇,跑动跑西惯了。贵读者有什么地方想特别了解的,都可以告诉我,很乐意陪您做半日游。

所谓登高必有卑,在把大家引入到高山圣境之前,先要在山脚下徜徉几时,为的是把一些预备的事情交代清楚。这一节讲的是驱动程序编译环境。Windows内核驱动的历史有多久,它的开发环境就要有多久,所以是很有历史的话题。话分两头讲,它起先是很不好,后来则非常好。很不好的时代是旧社会,现在则已是非常好的新时代。

旧社会

在Win8以前开发内核驱动,准备编译环境是个较繁琐的事情。程序员需要手动下载WDK并安装(注1),开发环境就在安装好的WDK中。WDK是Windows Driver Kit缩写,即Windows驱动开发包。它提供的开发环境简陋得很,它不是一个便于开发的IDE环境,而仅仅是一些散装的编译工具包。

wdkbuildEnv

安装好WDK后,WDK的编译环境链接就显示在开始菜单中了,要小心不能将它们删掉,否则会麻烦,因为手动生成链接是麻烦事,后文会讲。

编译环境是分类的。首先根据目标系统分类,也就是要编译生成运行在什么OS上的目标文件。微软大部分的产品都保持了向后兼容的习惯,这条规律也适用于此处:使用Win7子系统环境编译出来的驱动文件,一般都能运行在Vista和XP系统上,反之就不会成立(注2)。

其次根据硬件平台分类,现在Windows系统能够运行的平台有四个:X86,X64,IA64和ARM。其中ARM是Win8才开始的故事,这里还轮不到它出场,这样就只有前面三个硬件平台(注3)。

最后又要根据编译版本来分,即Checked(也可认做Debug)和Free(也可认作Release)这两种。这样来看,每个OS组别下面,就一定有6个编译环境链接。

在这本书里面,如果用旧版本WDK编译驱动,就默认使用Win7目标系统的编译环境,生成Checked版本,目标平台是X86或X64。所以就只会选两种:X86 Checked Build Environment和X64 Checked Build Environment.

编译环境打开来其实就是个控制台。它当然不同于直接从cmd.exe运行起来的控制台环境,区别在哪里呢?我们已经知道,上图的这些黑色的编译环境图标,其实都是快捷方式。不妨就看看它的快捷方式的Target内容,或许就知道端倪了。以X64 Checked Build Environment这个环境为例,打开来看到如下内容:

C:\Windows\System32\cmd.exe /k C:\WinDDK\7600.16385.1\bin\setenv.bat C:\WinDDK\7600.16385.1\ chk x64 WIN7

这一行内容仔细一看就很简单了。原来所谓的编译环境,就是一个运行cmd.exe的控制台进程,只不过它执行了用于初始化的/k参数。在Cmd.exe命令的帮助中,/k参数是这样描述的:Carries out the command specified by string but remains(执行一个命令,执行完之后不退出程序)。也就是说,启动控制台进程并执行命令,执行完后,控制台程序留给用户继续使用。

那么/k之后的所有内容,都是一条初始化的命令:

C:\WinDDK\7600.16385.1\bin\setenv.bat C:\WinDDK\7600.16385.1\ chk x64 WIN7

它却又可拆成几个部分来分析。第一个setenv.bat是初始化编译环境的批文件。后面的是它的参数:第一个参数,是WDK的路径,通过它可以找到编译器程序;第二个参数是指明要编译生成checked版本目标文件;第三个指明硬件平台是x64;第三个指明目标系统是Win7。

位于WDK中的Setenv.bat文件是负责编译环境配置的总厨,你把什么参数递给它,它就给你配出什么类型的编译环境来(菜也)。

怎么在这个控制台里面编译驱动呢?我们统一用使用以下步骤:

通过CD命令,定位到含有source文件的那个驱动目录;

输入build或bld(build –cz的简写)命令进行编译;

如果编译成功,将生成驱动文件,否则会有错误或警告信息显示出来;也可通过查看目录文件夹下面的相关log文件查看详细的错误或警告信息。

wdkbuildEnv1

走到这里,编译的事情算弄明白了。可能还会有朋友问我,我用什么东西写代码呢?不好意思,关于这个问题,此时还没有康庄大道供大家驷马高车,不过千万条小路却是现成的。您可以用notepad记事本或者任何文本编辑器来编辑代码,如果不嫌麻烦,用Visual Studio写代码也可以,只不过仅作代码编辑而已。

手动集成VS环境

放着Visual Studio这一利器而不用,降身辱命而用文本编辑器,是很不爽的事情。所以就有聪明人琢磨这件事情,最后终于琢磨出来了,就是通过手动改造VS工程的办法,将驱动项目也集成到其中去。

我遇到过两种改造办法,第一种是笨方法,而且是很麻烦的笨方法。它试图直接使用VC编译器来编译驱动,通过改造一个普通的Win32工程,修改其种种配置,包括库文件,编译宏等,来达到编译驱动程序的目的。有人贴出过详细的实现细节,我曾尝试过,但从来没有成功。

第二种方法很聪明,它需要创建一个Makefile工程,并通过直接调用WDK的编译器来编译驱动程序。这种方法很巧妙和便捷,唯一的缺点是最近的VS软件早已不包括Makefile项目模板。所以通过VS自身来创建一个Makefile工程是不可能的。最好的办法就是从别处拷贝一个现成的Makefile项目文件使用之。读者将一个空的Makefile项目文件放到项目文件夹中,打开这个项目文件后,再把需要的源文件拖进去。读者可以在本文下方下载到这个空项目文件。

打开Makefile项目的属性后,看到下图所示NMake属性设置界面。

nmakeProperty

这个NMake是很关键的东西,它对应了NMake.exe程序。这个程序是干什么用的呢?专门用来运行makefile文件的!关于NMake.exe这个小程序,读者可以自行找一找,在Visual Stuio的安装目录里一定会有。这个工具的文件属性对它的描述是:Microsoft Program Maintenance Utility(微软工程管理工具)。Makefile就是个工程管理文件,现在Linux/Unix系统上大量使用。以前在微软平台上,可能也大量使用过,只不过现在不用了,转而使用Visual Studio的项目文件了。

但这时候的Windows内核驱动程序,恰恰还是在用makefile和sources文件的。这不就巧了嘛!两方面碰到一起了,给我们一个使用VS的Makefile工程来编译驱动的机会。

NMake的属性设置里面,要手动填写Build/Rebuild/Clear这三个命令的实现。上面都已经介绍过控制台编译环境的实现了,照搬过来就可以了。以Build命令为例,先调用setenv.bat来初始化,然后调用build或blk命令编译之。那么我们就可以在build设置下面的两条命令来编译生成Win7 OS下X86平台上Checked类型驱动:

call %BASEDIR%\bin\setenv.bat %BASEDIR% chk x86 win7; bld

读者要是想编译其它类型驱动,改动一下参数即可。那么两条命令是不怎么美观的,所以上面稍微只能了一点,在系统目录里面放了一个名为my_build.bat的批文件,这个批文件内容如下:

@echo on
if “%4″==”/a” call my_clean %1 %2 %3
call %BASEDIR%\bin\setenv.bat %BASEDIR% %1 %2 %3
bld

还有一个Clear命令,其实就是把目标文件删除掉,使用del或rd命令即可,同样有一个名为my_clean.bat的批文件,其内容如下:

if exist Debug rd /s /q Debug
if exist Release rd /s /q Release
if exist obj%1_%3_%2 rd /s /q obj%1_%3_%2

新时代

好,旧社会的苦故事已经剧终了。现在开始讲翻身得解放的故事。新时代忽然就来了,VS2012给了我们新生活(此处当响起为英雄而欢呼般的掌声)!VS2012是Win8发布后出来的,有很多针对Win8的特性,但也能在Win7/Vista系统上运行。请您先下载安装VS2012软件,再安装Win8的WDK,WDK的编译环境会自动集成到VS2012中去。当您再次打开VS2012的时候,在新项目向导里面,就能够找到内核驱动项目了。

您会忍不住立刻新建一个WDF驱动项目,打开它,发现竟然有几百行自动生成的代码已经微笑着列队欢迎您了,是不是很开心?玩味个不停后,猛然按下F7,靠!竟然开始编译了,并且还能够编译成功,生成了一个.sys文件!而且不单生成一个.sys文件,并且把一个完整的驱动安装包都给您准备妥当了呢(包含签过名的.sys/.cat/.inf文件)。爽吧!

总有一天,新进的程序员见此会觉得天经地义,理所当然的事情。而此刻,我们这些个老家伙们,却已在幸福中垂泪不止了。可怜见地,后来的人们啊,请爱惜来之不易的好生活吧。

得了,我们细细地来看一下VS2012的驱动工程吧。下图是新建VS2012工程的时候模板选择界面。这里可以看到Windows Driver目录树下面目前提供的几个模板组别。我们现在只把注意力集中在WDF这个组别上面。点击WDF后,它里面包含三个模板项,分别是有自动生成代码的KMDF和没有自动代码的KMDF,以及UMDF。选择第一个模板后,填写项目名称后点击确认。没有其它的设置需要完成了,直接产生项目文件,并跳入到生成的项目界面中。假设您填写的项目名称也是MyKMDF1。

vs2012-WDFvs2012-WDF1

解决方案包括两个项目工程,一个是驱动项目,另一个是驱动安装包项目。前者包含实际的驱动代码,生成驱动文件。后者为驱动文件打包,它根据.inf文件生成.cat文件,并用指定的数字证书对驱动文件进行签名。

现在请移动尊手指,在键盘上敲击F7键,启动编译过程,观察能否成功生成MyKMDF1.sys文件及相应的驱动包?这是一个重要的里程碑,请勿掉队,如果你在这里不幸碰到了错误,需想办法解决之。

1>—— 已启动生成: 项目: MyKMDF1, 配置: Vista Debug Win32 ——
1> Stamping VistaDebug\MyKMDF1.inf [Version] section with DriverVer=05/14/2013,17.17.5.125
1> Device.c
1> Driver.c
1> Queue.c
1> 正在生成代码…
1> MyKMDF1.vcxproj -> C:\Users\mozhang\Documents\Visual Studio 2012\Projects\MyKMDF1\VistaDebug\MyKMDF1.sys
1> Done Adding Additional Store
1> Successfully signed: C:\Users\mozhang\Documents\Visual Studio 2012\Projects\MyKMDF1\VistaDebug\MyKMDF1.sys
1>
2>—— 已启动生成: 项目: MyKMDF1 Package, 配置: Vista Debug Win32 ——
2> ………………….
2> Signability test complete.
2>
2> Errors:
2> None
2>
2> Warnings:
2> None
2>
2> Catalog generation complete.
2> C:\Users\mozhang\Documents\Visual Studio 2012\Projects\MyKMDF1\VistaDebug\MyKMDF1 Package\mykmdf1.cat
2> Done Adding Additional Store
2> Successfully signed: C:\Users\mozhang\Documents\Visual Studio 2012\Projects\MyKMDF1\VistaDebug\MyKMDF1 Package\mykmdf1.cat
2>
========== 生成: 成功 2 个,失败 0 个,最新 0 个,跳过 0 个 ==========

驱动包项目

我们来学习一下这个总是自动生成的驱动包项目,它能为我们做些什么?我们通过观察,总结它做了四件事情:

  1. 为.sys文件进行数字签名
  2. 根据.inf文件生成.cat文件
  3. 给签名文件打时间戳
  4. 生成驱动包

注1:WDK安装目录不能含有空格和中文字符,如安装在c:\documents and users目录下即错,或安装在c:\我的驱动目录下亦错。错误并非发生在安装过程中,而是发生在使用WDK编译的时候。

注2:内核编译器编译的DLL文件不符合向后兼容特性

注3:Win8以后的系统不再支持IA64平台,所以Win8也只支持三种硬件平台。

7,851 total views, 1 views today

《小z说:内核驱动的编译环境》有5个想法

  1. 张老师,您好,我在安装WDK8.0时遇到一个问题,即安装路径一栏被禁用,无法修改,请问您遇到过这种情况吗?该怎么解决呢?谢谢

  2. 张老师,您好,
    我现在使用的是winxp的平台,VS6.0 + winddk 7600.16385.1。目标是为了编译一个win7 64位系统的驱动。请问编译环境时该如何选择?

    目前我选择的是win7 x64,编译了ddk之后编译项目时出现了:CPU i386 is not supported by D:\WINDDK\7600.16385.1 DDK with DDK_TARGET_OS=WinLH. 请问这个问题该如何解决?

发表评论

电子邮件地址不会被公开。