wince makefile 入门

 
1 makefile入门
Windows CE的构建系统大量使用了Nmake工具和makfile。在大多数微软的软件和驱动开发包中都会包含Nmake工具。因此,这里有必要介绍一下makefile和Nmake工具。
1.1 makefile简介
对于许多Windows下的程序员来说,makefile可能还是个陌生的名词。因为Windows下的许多集成开发环境(例如:Microsoft Visual Studio和Borland C++ Builder等)可以帮助开发人员完成makefile需要完成的功能。通常只需要在集成开发环境中按个按钮,工具就可自动帮助我们编译、链接整个项目。想象如果没有了集成开发环境,那么就需要有另外一种方式来管理对项目的构建。
简单的来说,makefile负责帮助开发人员简化代码的编译、链接等构建工作。对于只包含几个文件的简单的项目,开发人员完全可以通过手动控制编译器、链接器来完成对项目的构建。但是想象一下对于一个拥有几百个、甚至几千个文件的大型项目,如果每次构建都是通过手动完成,那消耗的工作量和复杂程度是不可想象的。在这种情况下,makefile就有了它的用武之地。
makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个自动化脚本一样,其中也可以执行操作系统的命令。
makefile带来的最大的好处是“自动化构建”。写好makefile之后,在编译的时候只需要一个命令,整个工程完全自动编译、链接,极大的提高了软件开发的效率。
makefile本质上只是一个文本文件,本身并不能运行。在运行makefile的时候还是需要外部程序来对makefile进行解释执行。NMake.exe就是用来解析并执行makefile的工具。
当用户输入nmake命令后,首先nmake会读取makefile,然后解析makefile,并根据makefile的规则来确定要编译哪些代码。然后nmake会调用编译器、链接器等一些开发工具,完成对代码的编译链接。最终会生成可执行文件。
 
图:makefile的工作流程
值得一提的是makefile既不是Windows CE特有的工具也不是微软的发明创造。makefile是一种通用的自动化构建手段。在UNIX/Linux平台下有着广泛而众多的应用。许多开发工具都会提供NMake类似的工具。比如:Delphi的make,Visual C++的nmake,Linux下GNU的make等等。
1.2 makefile的编
写规则
makefile是由一个个推导和规则构成的,在NMake中这也被叫做描述块(Description Blocks)。一个最基本的推导规则的语法如下。

targets... : dependents...
    commands...

targets也就是一个目标文件,可以是Object File,也可以是可执行文件。还可以是一个标签(Label)。targets必须在一行的顶格写,前面不能有空格。
dependents就是要生成target所需要的文件或是目标依赖项。dependents与targets之间用冒号间隔。一个targets可以有多个dependents。
command也就是NMake需要执行的命令。其中commands可以是任意的Windows命令行命令。
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于dependents中的文件,其生成规则定义在command中。也就是说,dependents中如果有一个以上的文件比targets文件要新的话,command所定义的命令就会被执行。这就是makefile的规则。也就是Makefile中最核心的内容。
掌握了makefile最核心的内容,就可以尝试编写第一个makefile了。但是仅仅知道了这一点还远远不够。makefile还有很多细节的内容,下面会一点一点地介绍。在此之前,先看一个可以实际运行的makefile。以便读者对makefile有个感性的认识。
1.3 一个实际可以运行的makefile
在%_WINCEROOT%\PBWorkspaces\MyPlatform\下新建立一个目录hello,然后在hello目录下创建hello.cpp,内容如下:

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR     lpCmdLine,
                     int       nCmdShow)
{
  MessageBox(NULL, L"Hello", L"bb", 0);
}

本部分内容的目的就是使用NMake工具来把Hello.cpp构建为Hello.exe可执行文件。
为此,在hello目录下再创建一个文本文件,名为makefile(没有扩展名)。然后用文本编辑器在makefile中输入如下内容:

#This is a demo makefile

hello.exe: hello.obj
    @echo linking...
    link -MACHINE:x86 -NODEFAULTLIB -subsystem:windowsce,5.00 -entry:WinMainCRTStartup -LIBPATH:E:\WINCE500\PBWorkspaces\MyPlatform\projroot\cesysgen\sdk\lib\x86\retail hello.obj coredll.lib corelibc.lib


hello.obj: hello.cpp
    @echo compiling...
    cl -nologo -c -I. -IE:\WINCE500\public\common\sdk\inc -DUNICODE -D_UNICODE -DUNDER_CE=500 -D_WIN32_WCE=500 -DWIN32 -DSTRICT -Dx86 -D_X86_ -DINTERNATIONAL -DL0804 -DINTLMSG_CODEPAGE=1252 hello.cpp

clean:
    del hello.obj, hello.exe

第一行是注释,在makefile中,用#表示该行内容是注释。
按照上文介绍的推导规则,这段makefile定义了两个依赖规则。hello.exe依赖于hello.obj,hello.obj又依赖于hello.cpp。
要从hello.cpp生成hello.obj,需要经过编译过程,执行编译命令。上文makefile代码中定义了两个命令,一个是操作系统的内部命令echo,作用是输出一个字符串,另外一个是调用C++编译器cl.exe,并用-c指示它只进行编译工作而不进行链接。对于从hello.obj生成hello.exe的过程也是一样的。中间调用了链接器link.exe把几个库文件链接成hello.exe。
为了简单起见,用到的路径都直接采用了写死的绝对路径。
从“开始”  “程序”  “Microsoft Windows CE 5.0” 菜单打开Windows CE的控制台。然后cd到hello目录,输入nmake命令,控制台的输出结果如下:

E:\WINCE500\PBWorkspaces\MyPlatform\hello>nmake
compiling...
Windows CE Version (Release) (Built on Mar  1 2004 21:46:39)
cl -nologo -c -I. -IE:\WINCE500\public\common\sdk\inc -DUNICODE -D_UNICODE -DUNDER_CE=500 -D_WIN32_WCE=500 -DWIN32 -DSTRICT -Dx86 -D_X86_ -DINTERNATIONAL -DL0804 -DINTLMSG_CODEPAGE=1252 hello.cpp
hello.cpp
linking...
link -MACHINE:x86 -NODEFAULTLIB -subsystem:windowsce,5.00 -entry:WinMainCRTStartup -LIBPATH:E:\WINCE500\PBWorkspaces\MyPlatform\projroot\cesysgen\sdk\lib\x86\retail hello.obj coredll.lib corelibc.lib
Microsoft (R) Incremental Linker Version 7.10.4017
Copyright (C) Microsoft Corporation.  All rights reserved.

这是使用dir命令查看hello目录,可以看到多了hello.obj和hello.cpp两个文件。这说明nmake已经帮我们生成了目标文件。
对于这个makefile,还有最后要介绍的一点。makefile中的clean是一个标签,通常所有的makefile中都会有clean这样一个标签,用来清理生成的文件,以便重新编译。为了调用这个标签可以在命令行下输入如下指令

nmake clean

这样,nmake就会帮我们调用系统的del命令,删除构建时生成的hello.obj和hello.exe文件了。
1.4 使用变量
让我们再回头来看看上一节中的示例makefile。如果我们希望把生成的文件由hello.exe改变为nihao.exe,那么仅仅这一丁点改动,在makefile中需要修改的地方就多达五处。这对于makefile的维护非常不方便。如果能有一种类似于C语言中宏或者变量的机制,就可以解决这个问题了。
为了makefile的易维护,在makefile中我们可以使用变量。makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好。
比如,我们声明一个变量,叫TARGETNAME,在makefile一开始就这样定义: 

TARGETNAME = hello

于是,我们就可以很方便地在我们的makefile中以“$(TARGETNAME)”的方式来使用这个变量了,于是我们的改良版makefile就变成下面这个样子:

TARGETNAME = hello
SOURCES = hello.cpp
TARGETLIBS = $(TARGETNAME).obj coredll.lib corelibc.lib

LINK = link

CPPFLAGS = -nologo -c -I. -IE:\WINCE500\public\common\sdk\inc -DUNICODE -D_UNICODE -DUNDER_CE=500 -D_WIN32_WCE=500 -DWIN32 -DSTRICT -Dx86 -D_X86_ -DINTERNATIONAL -DL0804 -DINTLMSG_CODEPAGE=1252

LFLAGS = -MACHINE:x86 -NODEFAULTLIB -subsystem:windowsce,5.00 -entry:WinMainCRTStartup -LIBPATH:E:\WINCE500\PBWorkspaces\MyPlatform\projroot\cesysgen\sdk\lib\x86\retail

$(TARGETNAME).exe: $(TARGETNAME).obj
    @echo linking...
    $(LINK) $(LFLAGS) $(TARGETLIBS)

$(TARGETNAME).obj: $(SOURCES)
    @echo compiling...
    $(CPP) $(CPPFLAGS) $(SOURCES)

clean:
    del *.obj, *.exe

在这一版本的makefile中,我们在makefile的最开始定义了六个变量。TARGETNAME表示要生成的文件名,SOURCES表示源代码列表。TARGETLIBS表示要链接的库列表。LINK表示链接器的名称。CPPFLAGS和LFLAGS分别表示编译器和链接器的命令行参数。
有了这些变量定义之后,编译和链接的命令就可以写的非常简洁了,例如编译源代码的命令就可以写成:$(CPP) $(CPPFLAGS) $(SOURCES)。nmake工具会自动用变量替换这些标记,最终的结果与第一个版本还是一样的。
如果读者细心的话,可以发现我们在makefile中并没有定义CPP这个变量,但是在makefile中我们依然使用了CPP变量。这又是为什么呢?其实nmake工具默认会设置一些变量的值,对于C++编译器,nmake会默认定义CPP变量,并把它的值赋为cl,因此,在使用的时候,makefile代码中就不需要重复定义了。
1.5 使用预处理
经过上一节的改动,namefile已经有了很大的灵活性。但是,依然达不到尽善尽美的地步。如果我们要把EXE文件的入口点从WinMainCRTStartup()函数修改到WinMain(),那么依然需要修改makefile。
使用预处理可以很好的解决上面的问题。在makefile中,NMake工具允许使用预处理机制来完成如下功能:
 按条件处理makefile
 显示错误信息
 包含其它的makefile
 打开/关闭某些nmake工具的命令行开关
预处理指令以“!”开头,必须出现在每行的最开始。最常用的预处理指令是条件处理。Nmake支持如下的条件预处理指令:

!IF 
!IFDEF
!IFNDEF
!ELSE
!ELSEIF
!ELSEIFDEF
!ELSEIFNDEF
!ENDIF

它们的用法与C语言的预处理宏类似,相信读者可以很容易的理解它们的含义。
使用预处理机制来修改上一个版本的makefile,得到的新makefile如下所示:

TARGETNAME = hello
SOURCES = hello.cpp
EXEENTRY = WinMain
TARGETLIBS = $(TARGETNAME).obj coredll.lib corelibc.lib

LINK = link

!IFDEF EXEENTRY
!    MESSAGE EXEENTRY: $(EXEENTRY)
EXEENTRYOPTION=-entry:$(EXEENTRY)
!ELSE
EXEENTRYOPTION=-entry:WinMainCRTStartup
!ENDIF

CPPFLAGS = -nologo -c -I. -IE:\WINCE500\public\common\sdk\inc -DUNICODE -D_UNICODE -DUNDER_CE=500 -D_WIN32_WCE=500 -DWIN32 -DSTRICT -Dx86 -D_X86_ -DINTERNATIONAL -DL0804 -DINTLMSG_CODEPAGE=1252
LFLAGS = $(EXEENTRYOPTION) -MACHINE:x86 -NODEFAULTLIB -subsystem:windowsce,5.00 -LIBPATH:E:\WINCE500\PBWorkspaces\MyPlatform\projroot\cesysgen\sdk\lib\x86\retail


$(TARGETNAME).exe: $(TARGETNAME).obj
    @echo linking...
    $(LINK) $(LFLAGS) $(TARGETLIBS)

$(TARGETNAME).obj: $(SOURCES)
    @echo compiling...
    $(CPP) $(CPPFLAGS) $(SOURCES)

clean:
    del *.obj, *.exe

在这个版本中,主要的改动是新增加了一个变量EXEENTRY,并且增加了对于这个变量的预处理判断。如果用户定义了EXEENTRY变量,则把变量EXEENTRYOPTION的值设置成-entry:EXEENTRY,否则就设置成默认的CRT入口函数-entry:WinMainCRTStartup。修改相应的LFLAGS,把EXEENTRYOPTION加到LFLAGS中,修改就生效了。
这样,其实新增加的EXEENTRY是一个可选的变量,如果用户没有定义这个变量的值,构建也不会出错。使用预处理技术对于维护makefile,保持它的向下兼容非常有效。
注意,代码中出现的!MESSAGE也是一个宏,用来向标准输出stdout输出一个字符串。
1.6 包含其它文件
经过上面的修改,makefile中的有些模块已经非常通用了,对于每个项目都建立一个makefile也是比较复杂的。为了增强代码的重用性,可以考虑把makefile代码中通用的部分抽取出来,放在一个独立的文件中。以便在多个项目中公用。
预处理的另外一个作用是包含其它makefile文件。语法是:

! INCLUDE [<] 文件名 [>]

使用这个功能,可以实现把makefile拆分的目的。
这次,我们把makefile拆分成三个文件,名字分别叫:sources、makefile和makefile.def,都放在hello目录中。三个文件的内容分别如下:
sources文件的内容:

# This is a demo sources file

TARGETNAME =    hello
SOURCES =       hello.cpp
EXEENTRY =      WinMain
TARGETLIBS =    coredll.lib \
                corelibc.lib

makefile文件的内容:

!   INCLUDE makefile.def

makefile.inc文件的内容:

!   INCLUDE .\sources

TARGETLIBS =    $(TARGETLIBS) \
                $(TARGETNAME).obj

LINK = link

!IFDEF EXEENTRY
!    MESSAGE EXEENTRY: $(EXEENTRY)
EXEENTRYOPTION=-entry:$(EXEENTRY)
!ELSE
EXEENTRYOPTION=-entry:WinMainCRTStartup
!ENDIF

CPPFLAGS = -nologo -c -I. -IE:\WINCE500\public\common\sdk\inc -DUNICODE -D_UNICODE -DUNDER_CE=500 -D_WIN32_WCE=500 -DWIN32 -DSTRICT -Dx86 -D_X86_ -DINTERNATIONAL -DL0804 -DINTLMSG_CODEPAGE=1252
LFLAGS = $(EXEENTRYOPTION) -MACHINE:x86 -NODEFAULTLIB -subsystem:windowsce,5.00 -LIBPATH:E:\WINCE500\PBWorkspaces\MyPlatform\projroot\cesysgen\sdk\lib\x86\retail

$(TARGETNAME).exe: $(TARGETNAME).obj
    @echo linking...
    $(LINK) $(LFLAGS) $(TARGETLIBS)

$(TARGETNAME).obj: $(SOURCES)
    @echo compiling...
    $(CPP) $(CPPFLAGS) $(SOURCES)

clean:
    del *.obj, *.exe

在sources文件中我们只存放一些变量的定义,如果需要更改某些设置,只需要改动sources文件就好了。在makefile中,仅有简单的一行,把makefile.def文件导入进来。在makefile.def文件中包含所有关联推导和变量使用,并且还会把sources文件导入进来。
在控制台下输入nmake和nmake clean,同样可以顺利地对hello.exe进行构建和清除。
好了,sources、makefile和makefile.def。至此为止,一个具体而微的Windows CE构建系统就这么被我们给模拟出来了。Windows CE构建系统中的DIRS文件是build.exe在进行处理,NMake工具不会处理DIRS。
有了这些知识,读者在学习Windows CE的构建系统时,遇到makefile相关的内容应该不会再手足无措了。但是对于makefile本身的功能和作用而言,我们才刚刚开始
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Makefile是一种用来构建和管理程序的工具,它通过一个文本文件来指导编译器如何去编译、链接程序。理解并掌握Makefile的使用可以提高程序的编译效率和可维护性。下面是关于Makefile入门到精通的解释: 入门阶段: 在初学者阶段,需要掌握Makefile的基本语法和规则。学习如何编写一个简单的Makefile,并且能够使用Makefile来管理和编译一个简单的程序。掌握Makefile的目标、依赖关系、命令和变量的使用。 进阶阶段: 在进阶阶段,需要了解更多的Makefile的高级特性和技巧。学习如何使用条件语句、循环语句和函数来编写更灵活和复杂的Makefile。了解如何使用Makefile来管理多个源文件和目录结构。 精通阶段: 在精通阶段,需要深入理解Makefile背后的原理和机制。了解Makefile的工作原理,包括依赖关系的自动推导、文件更新的判断和并行编译等。还需要掌握一些高级的技巧,例如使用Makefile来实现代码自动生成、跨平台编译和项目的自动化构建等。 实践阶段: 在实践阶段,需要应用所学的知识来解决实际的编译和构建问题。学会分析和优化Makefile,以提高构建过程的效率和可维护性。实践中可能还需要了解如何与其他构建工具和版本控制系统进行集成,以及如何处理复杂的项目依赖关系。 总之,掌握Makefile需要从入门到精通经过一定的学习和实践过程。通过不断的学习和实践,逐渐提高对Makefile的理解和应用能力,才能真正驾驭Makefile并充分发挥其作用。 ### 回答2: Makefile是一种用于自动化编译和构建软件的脚本文件。它是基于依赖关系的构建工具,通过定义文件依赖关系和编译规则,可以自动检测源代码的变化并重新编译相关文件,从而提高软件开发的效率。 要学习Makefile,首先需要了解Makefile的基本语法和规则。Makefile由多个规则组成,每个规则包含目标文件、依赖文件和命令。目标文件是生成的文件,依赖文件是生成目标文件所需的源文件或其他目标文件,命令是生成目标文件的具体步骤。 在Makefile中,可以定义变量来存储常用的路径或编译选项,这样可以方便地在多个规则中复用。还可以使用条件判断、循环和函数等高级语法来实现更复杂的功能。 经常使用的命令有make、make clean和make install。make命令用于编译源代码并生成目标文件,如果源文件有更新,make会自动重新编译相关文件。make clean命令用于清理生成的目标文件和临时文件,make install命令用于安装生成的可执行文件或库文件到指定位置。 学习Makefile还需要掌握一些常用的编译规则和选项。例如,可以通过定义编译规则来指定编译器、编译选项和链接选项。可以使用特殊变量$@表示目标文件,$^表示所有的依赖文件,$<表示第一个依赖文件。还可以使用通配符和模式匹配来处理多个文件或目录。 除了基本的语法和规则,还可以学习一些高级的技巧和技术,例如使用配置文件、自动化测试、并行编译等。通过不断实践和积累经验,可以逐渐提高对Makefile的掌握程度,从入门到精通。 总结来说,要从入门到精通Makefile,需要掌握基本的语法和规则,学习常用的命令和选项,并通过实际项目的练习来加深理解和提高技能水平。 ### 回答3: makefile是一种用于自动化构建和管理项目的工具。它可以根据一组规则,自动推断出需要重新编译的文件,并且根据这些规则自动执行相应的指令,从而简化了项目的构建流程和维护工作。 首先,我们需要了解makefile的基本语法和组成部分。makefile由一系列规则组成,每个规则包含一个目标、依赖关系和执行的指令。目标是需要生成的文件,依赖关系是该文件生成所依赖的文件,指令则是实际执行的操作。 其次,学习makefile中的变量。变量可以用于存储常用的路径、命令等信息。使用变量可以简化项目配置和维护,提高可维护性。 然后,理解makefile中的模式规则。模式规则是一种通用的规则,可以根据目标和依赖的模式,推断出需要执行的指令。使用模式规则可以减少重复的规则定义,提高makefile的灵活性。 接下来,学习条件判断和循环控制。条件判断可以根据不同的情况选择执行不同的指令,循环控制可以重复执行某些指令。这些功能可以使makefile更加灵活和自动化。 最后,掌握makefile中的常用函数和命令。makefile提供了一系列内置函数和命令,用于处理文本、路径、文件等操作。熟练掌握这些函数和命令,可以提高makefile的处理能力和效率。 总结而言,要精通makefile需要掌握其基本语法、规则定义、变量使用、模式规则、条件判断、循环控制、内置函数和命令等知识。通过实践和不断学习,掌握这些内容后,就可以灵活运用makefile来构建和管理项目,提高开发效率和代码质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值