【原创】分享NMake模板,全自动化的Makefile

老邓 2009-09-15 10:27:14
2009-10-09更新:NMaker编写完成:http://topic.csdn.net/u/20091006/00/98203b78-394d-4f76-83c1-42ade61c586c.html
摘要:本文告诉你如何自动化管理一个Makefile工程,自动化到你在初始化设置后,不再需要手工修改Makefile就可以随意的向工程增删文件,且保持良好的文件依赖关系。

给个图先:

也许,IDE让我们忘记了NMake,然而,有的时候,她还是必需的。
近期研究Eclipse CDT,越来越被其强大的代码编辑功能、强大的智能提示所折服。于是,坚定了脱离Code::Blocks工程管理,转而使用nmake管理工程的理念!
实践:编写一个易用的Makefile模板,证明写Makefile也是一件很简单的事!

先发布在此,后续会不断完善。
欢迎批评指正!

简介:一共需要三个文件,一个工具。
其中文件Config.mk用于配置编译器,CPU类型;文件Depends.mk通过工具NMaker.exe实现自动化的文件依赖;文件Makefile中可灵活的由用户自由定制,以及决定是否使用预编译头文件;工具NMaker.exe用于自动生成文件的依赖及文件的编译链接配置文件Depends.mk,也正因为如此,称之为“全自动化”Makefile。


优点:在模板基础上略加修改Config.mk和Makefile,此后文件依赖、加入编译的工作交给工具NMaker.exe完成。从此,编写Makefile将是一件轻松、愉快的工作,享受强大的定制能力,方便的编译能力,快捷的调试能力吧!

说明:目前暂不提供NMaker.exe,原因是还需完善功能。等时间成熟,会发布在:http://blog.qpsoft.com

补充:此模板如果配合Eclipse CDT,将会发现非常的方便。从编译、调试、运行都非常轻易的完成。要从Debug转向Release,只需要修改Config.mk,将DEBUG = 1修改为DEBUG = 0即可,其他配置类似,详情见后面提供的模板。由于Config.mk由不同Makefile共享,所以修改一处,即可应用到包含该配置的所有工程。
可以添加任意target来达到特定目的:

Config.mk文件:
#----------------------------------------------
# Copyright (C) QPSOFT.COM All rights reserved.
#----------------------------------------------

# 输出目录
ROOT = D:\DengYC\Projects\NMaker

# 工程类型
DEBUG = 1
UNICODE = 1
CPU = X86

# 编译选项,只读!
CC = cl
CFLAGS = /nologo /c /W4 /Zc:forScope /Zc:wchar_t /EHsc

!IF "$(DEBUG)" == "1"
CFLAGS = $(CFLAGS) /Od /Ob0 /MTd /ZI /D"_DEBUG"
!ELSE
CFLAGS = $(CFLAGS) /O2 /Ob1 /MT /Zi /D"NDEBUG"
!ENDIF

!IF "$(UNICODE)" == "1"
CFLAGS = $(CFLAGS) /D"_UNICODE" /D"UNICODE"
!ENDIF

CFLAGS = $(CFLAGS) /Fo"$(OUT)\\" /Fd"$(OUT)\$(TARGET).pdb"

# 链接选项,只读!
LK = link
LFLAGS = /NOLOGO /MANIFEST:NO /MACHINE:$(CPU)

!IF "$(DEBUG)" == "0"
LFLAGS = $(LFLAGS) /OPT:REF /OPT:ICF
!ENDIF

LFLAGS = $(LFLAGS) /DEBUG /PDB:"$(OUT)\$(TARGET).pdb" /OUT:"$(BIN)"
LFLAGS = $(LFLAGS) kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib \
shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib

# 编译资源,只读!
RC = rc
!IF "$(DEBUG)" == "1"
RFLAGS = /nologo /l 0x804 /D"_DEBUG"
!ELSE
RFLAGS = /nologo /l 0x804 /D"NDEBUG"
!ENDIF

Depends.mk文件:
#----------------------------------------------
# Copyright (C) QPSOFT.COM All rights reserved.
#----------------------------------------------

OBJS = \
"$(OUT)\Main.obj" \
"$(OUT)\Parser.obj" \

SRC=.\Main.cpp
"$(OUT)\Main.obj" : $(SRC) "$(OUT)" "$(PCH)"

SRC=.\Parser.cpp
"$(OUT)\Parser.obj" : $(SRC) "$(OUT)" "$(PCH)"

.\Main.cpp : \
".\Parser.h"\

.\Parser.cpp : \
".\Parser.h"\

Makefile文件:
#----------------------------------------------
# Copyright (C) QPSOFT.COM All rights reserved.
#----------------------------------------------

.SILENT:
!INCLUDE "Config.mk"

TARGET = NMaker
OUT = $(ROOT)\$(TARGET)
BIN = $(OUT)\$(TARGET).exe

CFLAGS = $(CFLAGS) /D"_CONSOLE"

USEPCH = 1
!IF "$(USEPCH)" == "1"
PCH = $(OUT)\$(TARGET).pch
CFLAGS_PCH = $(CFLAGS) /Fp"$(PCH)" /Yc"StdAfx.h"
CFLAGS = $(CFLAGS) /Fp"$(PCH)" /Yu"StdAfx.h"
!ENDIF

all : "$(BIN)"

clean :
rmdir /S /Q "$(OUT)"

debug :
windbg.bat $(BIN)

run :
$(BIN)

"$(OUT)" :
if not exist "$(OUT)" mkdir "$(OUT)"

all : "$(BIN)"
copy /B /V /Y $(BIN) $(ROOT) >nul
copy /B /V /Y $(OUT)\$(TARGET).pdb $(ROOT) >nul
echo NOTICE: '$(TARGET)' Build Finished.

.c{$(OUT)}.obj::
$(CC) @<<
$(CFLAGS) $<
<<

.cpp{$(OUT)}.obj::
$(CC) @<<
$(CFLAGS) $<
<<

!INCLUDE "Depends.mk"

"$(BIN)" : "$(OUT)" $(OBJS) "$(OUT)\StdAfx.obj" "$(OUT)\Version.res"
$(LK) @<<
$(LFLAGS) $(OBJS) "$(OUT)\StdAfx.obj" "$(OUT)\Version.res"
<<

"$(OUT)\StdAfx.obj" "$(PCH)" : .\StdAfx.h "$(OUT)"
!IF "$(USEPCH)" == "1"
$(CC) @<<
$(CFLAGS_PCH) .\StdAfx.cpp
<<
!ENDIF

SRC=.\Version.rc
"$(OUT)\Version.res" : $(SRC) "$(OUT)"
$(RC) $(RFLAGS) /Fo"$(OUT)\Version.res" $(SRC)

那么,如果涉及到一个工程中有多个Makefile,需要构建不同的DLL、Lib、Plugins,那又该如何?
简单:只需要修改Makefile即可。
为节省篇幅,以下示例只包含了Makefile中的不同之处供参考。

DLL工程部分示例:
#----------------------------------------------
# Copyright (C) QPSOFT.COM All rights reserved.
#----------------------------------------------

.SILENT:
!INCLUDE "..\Config.mk"

TARGET = dllname
OUT = $(ROOT)\$(TARGET)
BIN = $(OUT)\$(TARGET).dll
LFLAGS = $(LFLAGS) /DLL


Lib工程部分示例:
#----------------------------------------------
# Copyright (C) QPSOFT.COM All rights reserved.
#----------------------------------------------

.SILENT:
!INCLUDE "..\Config.mk"

TARGET = libname
OUT = $(ROOT)\$(TARGET)
BIN = $(OUT)\$(TARGET).lib
LK = link /LIB
LFLAGS = /NOLOGO /MACHINE:$(CPU) /OUT:"$(BIN)"

Windows工程部分示例:

#----------------------------------------------
# Copyright (C) QPSOFT.COM All rights reserved.
#----------------------------------------------

.SILENT:
!INCLUDE "..\Config.mk"

TARGET = wingui
OUT = $(ROOT)\$(TARGET)
BIN = $(OUT)\$(TARGET).exe
PCH = $(OUT)\$(TARGET).pch
CFLAGS_PCH = $(CFLAGS) /Fp"$(PCH)" /Yc"StdAfx.h"
CFLAGS = $(CFLAGS) /Fp"$(PCH)" /Yu"StdAfx.h"


当构建一个大型工程时,在最上级目录中只需要定义进入各目录的Makefile,如下图所示:

#----------------------------------------------
# Copyright (C) QPSOFT.COM All rights reserved.
#----------------------------------------------

.SILENT:

all :
cd "$(MAKEDIR)\win"
$(MAKE) /nologo /$(MAKEFLAGS)
cd "$(MAKEDIR)"

cd "$(MAKEDIR)\cmd"
$(MAKE) /nologo /$(MAKEFLAGS)
cd "$(MAKEDIR)"

cd "$(MAKEDIR)\dll"
$(MAKE) /nologo /$(MAKEFLAGS)
cd "$(MAKEDIR)"

cd "$(MAKEDIR)\lib"
$(MAKE) /nologo /$(MAKEFLAGS)
cd "$(MAKEDIR)"

clean :
cd "$(MAKEDIR)\win"
$(MAKE) /nologo /$(MAKEFLAGS) clean
cd "$(MAKEDIR)"

cd "$(MAKEDIR)\cmd"
$(MAKE) /nologo /$(MAKEFLAGS) clean
cd "$(MAKEDIR)"

cd "$(MAKEDIR)\dll"
$(MAKE) /nologo /$(MAKEFLAGS) clean
cd "$(MAKEDIR)"

cd "$(MAKEDIR)\lib"
$(MAKE) /nologo /$(MAKEFLAGS) clean
cd "$(MAKEDIR)"
...全文
1976 41 打赏 收藏 转发到动态 举报
写回复
用AI写文章
41 条回复
切换为时间正序
请发表友善的回复…
发表回复
老邓 2009-10-09
  • 打赏
  • 举报
回复
[Quote=引用 40 楼 loaden 的回复:]
玩了近二十天的Eclipse CDT,实在受不了了。
速度问题!太慢了,文件少还好,文件多了,机器配置跟不上,很慢。
完成没实现的函数,竟然用了40秒,我倒!
用回CodeBlocks了。
[/Quote]
继续使用Eclipse CDT,找到了CDT提速大法,越用越爽!
http://topic.csdn.net/u/20091005/00/8a522f58-280d-4a30-ae01-d226b1fc918e.html

另,NMaker发布了,可以在Eclipse CDT里自动化管理工程了。
http://www.qpsoft.com/blog/nmaker/
老邓 2009-09-26
  • 打赏
  • 举报
回复
玩了近二十天的Eclipse CDT,实在受不了了。
速度问题!太慢了,文件少还好,文件多了,机器配置跟不上,很慢。
完成没实现的函数,竟然用了40秒,我倒!
用回CodeBlocks了。
linwy728 2009-09-26
  • 打赏
  • 举报
回复
学习了,呵呵
老邓 2009-09-21
  • 打赏
  • 举报
回复
UP!寻找共同爱好者!!
老邓 2009-09-19
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 hqin6 的回复:]
用automake不好么??
[/Quote]
这是nmake,automake只用于GNU Make
太乙 2009-09-19
  • 打赏
  • 举报
回复
用automake不好么??
老邓 2009-09-19
  • 打赏
  • 举报
回复
解决分目录编译obj了,详见1楼。
老邓 2009-09-19
  • 打赏
  • 举报
回复
想解决不同目录的源码生成的obj放在不同目录中,用nmake,只能每编译一个文件就调用一次编译器!
这会对编译速度产生影响!

mLee79,如何编写,才能使得make支持一次编译多个文件呢?
风消云散Fly 2009-09-18
  • 打赏
  • 举报
回复
学习了
老邓 2009-09-16
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 mlee79 的回复:]
重新写了下 Makefile, 现在可以自动生成依赖关系[/Quote]
co代码,并且读了你写的Makefile,对GCC来说,非常理想!
另,对GCC,应该不用单独生成.dep的,《跟我学写Makefile》中的例子是直接得到依赖关系用于编译。
当然,你生成.dep后的编译速度要快一些,但操作起来步骤上也要繁琐一些。

我写NMaker的目的,就是为了实现类似GCC的功能。

我用make 3.81,mingw4.4.1测试你的代码,发现错误:
E:\xmk>make .dep
'[' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
rm -f .deplist
process_begin: CreateProcess(NULL, rm -f .deplist, ...) failed.
make (e=2): 系统找不到指定的文件。
make: *** [.deplist] Error 2


使用nmake也是有其自身优势的。
如果不考虑跨平台项目的话,nmake是VC自带的,不像make,还需要单独下载。
从性能上来说,我认为nmake要优于make。
wshcdr 2009-09-16
  • 打赏
  • 举报
回复
MK
mLee79 2009-09-16
  • 打赏
  • 举报
回复
重新写了下 Makefile, 现在可以自动生成依赖关系, 仍在:http://x4c.googlecode.com/svn/demo/xmk/Makefile 下.
你可以 svn co http://x4c.googlecode.com/svn/demo/xmk/ 然后:

make .dep
make all
touch test.h ; make all
make all-plat
touch test.h ; make all-plat

当然如果你没有 gcc , 是没有办法 make .dep 的,这时候目标文件仅随对应的 .c 的修改重新编译。。
当然这是个不复杂的工作,自己写个简单的预处理,感觉还是容易的。。 LZ的 NMaker 应该就是干这件事。。

这样你完全不用修改 Makefile , 只要把源文件拷贝过来就直接可以 make 了。。。
当然你也可以改成支持 .cpp .l .y .res .idl 等等的版本。。。 同样,生成一个 .a 一个 .exe 也完全是个人习惯, 你可以改成只生成 .exe 的, 同样的改成生产 .so .dll 等的也不错。。。。
当然,改成把所有的临时文件放在一个指定的目录下更好,如果有功能强大点的shell,比如在 linux 下或者安装了 cygwin ,这个任务也很简单, WIN的shell功能太弱,可能搞起来就稍微麻烦点。。。。



mstlq 2009-09-15
  • 打赏
  • 举报
回复
nmake……
上一次用来做正经事,已经是3年前了……
期待楼主所谓“时机成熟”的一刻……
fox000002 2009-09-15
  • 打赏
  • 举报
回复
其实用 cmake 不错,不用管 Makefile 了
mLee79 2009-09-15
  • 打赏
  • 举报
回复
nmake 功能太弱智。。。 用 GNU make 啊。。。。
  • 打赏
  • 举报
回复
接~接~接~
whg01 2009-09-15
  • 打赏
  • 举报
回复
接分
wxgiter 2009-09-15
  • 打赏
  • 举报
回复
学习~~
失落的凡凡 2009-09-15
  • 打赏
  • 举报
回复
老邓 2009-09-15
  • 打赏
  • 举报
回复
来个wxWidgets的例子,其中WX这个环境变量可以在Eclipse里建立,也可以在系统环境变量里添加。如果只要Eclipse添加,则不能在命令行编译。

#----------------------------------------------
# Copyright (C) QPSOFT.COM All rights reserved.
#----------------------------------------------

.SILENT:
!INCLUDE "Config.mk"

TARGET = CaiPiao
OUT = $(ROOT)\$(TARGET)
BIN = $(OUT)\$(TARGET).exe

CFLAGS = $(CFLAGS) /D"__WXMSW__" /D"wxUSE_UNICODE" /I"$(MAKEDIR)" /I"$(WX)"
LFLAGS = $(LFLAGS) /LIBPATH:"$(WX)" wxqp.lib

USEPCH = 0
!IF "$(USEPCH)" == "1"
PCH = $(OUT)\$(TARGET).pch
CFLAGS_PCH = $(CFLAGS) /Fp"$(PCH)" /Yc"StdAfx.h"
CFLAGS = $(CFLAGS) /Fp"$(PCH)" /Yu"StdAfx.h"
!ENDIF

all : "$(BIN)"

clean :
rmdir /S /Q "$(OUT)"

debug :
windbg.bat $(BIN)

run :
$(BIN)

"$(OUT)" :
if not exist "$(OUT)" mkdir "$(OUT)"
if not exist "$(OUT)\gui" mkdir "$(OUT)\gui"

all : "$(BIN)"
copy /B /V /Y $(BIN) $(ROOT) >nul
copy /B /V /Y $(OUT)\$(TARGET).pdb $(ROOT) >nul
echo NOTICE: '$(TARGET)' Build Finished.

.c{$(OUT)}.obj::
$(CC) @<<
$(CFLAGS) /Fo$(OUT)\ $<
<<

.cpp{$(OUT)}.obj::
$(CC) @<<
$(CFLAGS) /Fo$(OUT)\ $<
<<

!INCLUDE "Depends.mk"

"$(BIN)" : "$(OUT)" $(OBJS) "$(OUT)\StdAfx.obj" "$(OUT)\Version.res"
$(LINK) @<<
$(LFLAGS) $(OBJS) "$(OUT)\StdAfx.obj" "$(OUT)\Version.res"
<<

"$(OUT)\StdAfx.obj" "$(PCH)" : ".\StdAfx.h" "$(OUT)"
!IF "$(USEPCH)" == "1"
$(CC) @<<
$(CFLAGS_PCH) /Fo$(OUT)\ ".\StdAfx.cpp"
<<
!ENDIF

"$(OUT)\Version.res" : ".\Version.rc" "$(OUT)"
$(RC) $(RFLAGS) /Fo"$(OUT)\Version.res" ".\Version.rc"
加载更多回复(21)
wireshark源码分析问题这几天在看wireshark(ethereal)源代码。看源代码的主要兴趣点是它的分析模块(dissect)。分析之后他的数据存在哪儿,怎么打印的(-V参数)。我想把分析后的数据,提取出来,存在自己定义的数据结构里面,或者按我自己的格式写入文本中。 看了几天,对一些数据结构,似懂非懂,一些流程也是似懂非懂。可能由于经验不足的原因,搞来搞去就在几个函数,结构体里面打转。好几次以为找到切入点,发现又回来原来的起点。 这两天看晕了。有点打击,水平太差劲了。。呵呵。先这边问问,看看有没有熟悉的朋友。指点一下。先谢谢了。 这样问问题可能太细了。感觉也不大合适。 1. 我应该如何来看代码?如何找到突破点? 2. 有wireshark有了解的朋友,说说你们关于源码剖析的体会。 3. 说什么都可以,朋友觉得对我有用,有启发就好。千万别 “我顶,UP啊”。呵呵:emn23:我觉得重要的是看 pcap库 本帖最后由 peidright 于 2010-04-02 16:36 编辑 楼上说得对!。 看源代码之前,问下你自己,看代码的目的是什么? 对于 wireshark 来说,你是想学他写界面? 还是抓包? 还是业务逻辑? 界面的话,wireshark 还行 抓包的话,应该看pcap库 业务逻辑的话。不应该看wireshark,看tcpdump.看下啊,:em03:看看这个也许对你有帮助 添加一个基础的RDP解析器 下面我们将循序渐进地设计一个基础的RDP解析器。它依次包含如下构成要素: 包类型字段(占用8比特位,可能的值为:1,初始;2,终结;3,数据); 标志集字段(占用8比特位:0x01,开始包;0x02,结束包;0x04先包); 序列号字段(占用16比特位); 1. 创建解析器 首先您需要选择解析器的类型:内置型(包含在主程序中)或插件型。 插件是容易编写的,先做一个插件型解析器吧。 例1. 解析器初始设定. #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include void proto_register_rdp(); void proto_reg_handoff_rdp(); static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree); static int proto_rdp=-1; static dissector_handle_t rdp_handle; static gint ett_rdp = -1; define TCP_PORT_RDP 3389 void proto_register_rdp(void) { proto_rdp=proto_register_protocol( "RDP Protocol", "RDP", "rdp"); } 现在来逐一分析这段代码。首先我们有一些常规的包含文件,最好依惯例在文件开始包含进来。随后是一些函数的前置声明,我们稍后定义它们。 接下来我们定义了一个整型变量"proto_rdp"用于记录我们的协议注册信息。它被初始化为"-1",当解析器注册到主程序中后,其值便会得到更新。这样做可保证我们方便地判断是否已经做了初始工作。将所有不打算对外输出的局变量和函数声明为"static"是一个良好的习惯,因为这可以保证命名空间不被污染。通常这是容易做到的,除非您的解析器非常庞大以致跨越多个文件。 之后的模块变量"TCP_PORT_RDP"则包含了协议使用的TCP端口号,我们会对通过该端口的数据流进行解析。 solaris10下proc编译问题 >紧随其后的是解析器句柄"rdp_handle",我们稍后对它进行初始化。 至此我们已经拥有了和主程序交互的基本元素,接下来最好再把那些预声明的函数定义一下,就从注册函数"proto_register_rdp"开始吧。 首先调用函数"proto_register_protocol"注册协议。我们能够给协议起3个名字以适用不同的地方。名和短名用在诸如"首选项(Preferences)"和"已激活协议(Enabled protocols)"对话框以及记录中已生成的域名列表内。缩略名则用于过滤器。 下面我们需要一个切换函数。 例2. 解析器切换. void proto_reg_handoff_rdp(void) { static gboolean initialized=FALSE; if(!initialized) { rdp_handle = create_dissector_handle(dissect_rdp, proto_rdp); dissector_add("tcp.port", TCP_PORT_RDP, rdp_handle); initialized=TRUE; } } 这段代码做了什么呢?如果解析器尚未初始化,则对它进行初始化。首先创建解析器。这时注册了了函数"dissect_rdp"用于完成实际的解析工作。之后将该解析器与TCP端口号相关联,以使主程序收到该端口的UDP数据流时通知该解析器。 至此我们终于可以写一些解析代码了。不过目前我们仅写点儿基本功能占个位置。 例3.解析 static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree) { if(check_col(pinfo->cinfo, COL_PROTOCOL)) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDP"); } if(check_col(pinfo->cinfo,COL_INFO)) { col_clear(pinfo->cinfo,COL_INFO); } } 该函数用于解析传递给它的数据包。包数据由"tvb"参数指向的特殊缓冲区保管。现在我们已深入到协议的细节,对它们您肯定是了若指掌。包信息结构参数"pinfo"包含了协议的基本数据,以供我们更新。参数"tree"则指明了详细解析发生的地方。 这里我们仅做了保证通过的少量工作。前两行检查UI中"协议(Protocol)"列是否已显示。如果该列已存在,就在这儿显示我们的协议名称。这样人们就知道它被识别出来了。另外,如果"信息(INFO)"列已显示,我们就将它的内容清除。 至此我们已经准备好一个可以编译和安装的基本解析器。不过它目前只能识别和标示协议。 为了编译解析器并创建插件,还需要在解析器代码文件"packet-rdp.c"所在目录下创建一些提供支持的文件: - Makefile.am - UNIX/Linux的makefile模板 - Makefile.common - 包含了插件文件的名称 - Makefile.nmake - 包含了针对Windows平台的Wireshark插件makefile - moduleinfo.h - 包含了插件版本信息 - moduleinfo.nmake - 包含了针对Windows平台的DLL版本信息 - packet-rdp.c - 这是您的解析器原代码文件 - plugin.rc.in - 包含了针对Windows平台的DLL资源模板 "Makefile.common"和"Makefile.am"文件中涉及到相关文件和解析器名称的地方一定要修改正确。"moduldeinfo.h"和"moduleinfo.nmake"文件中的版本信息也需要正确填充。一切准备妥善后就可以将解析器编译为DLL或共享库文件了(使用nmake工具)。在wireshark文件夹下的"plugins"文件夹中,建立"rdp"文件夹。将修改过的Makefile.common,Makefile.am,moduleinfo.nmake,moduldeinfo.h,Makefile.nmake及packet-rdp.c文件考到"rdp"文件夹下,然后进行编译,rdp插件自动生成完整,就可以正常工作了。 1. 解析协议细节 现在我们已经有了一个可以运用的简单解析器,让我们再为它添点儿什么吧。首先想到的应该就是标示数据包的有效信息了。解析器在这方面给我们提供了支持。 首先要做的事情是创建一个子树以容纳我们的解析结果。这会使协议的细节显示得井井有条。现在解析器在两种情况下被调用http://www.boomss.com:其一,用于获得数据包的概要信息;其二,用于获得数据包的详细信息。这两种情况可以通过树指针参数"tree"来进行区分。如果树指针为NULL,我们只需要提供概要信息;反之,我们就需要拆解协议完成细节的显示了。基于此,让我们来增强这个解析器吧。 例4 static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree) { proto_item *ti=NULLV; if(check_col(pinfo->cinfo,COL_PROTOCOL)) { col_set_str(pinfo->cinfo,COL_PROTOCOL,"RDP"); } if(check_col(pinfo->cinfo,COL_INFO)) { col_clear(pinfo->cinfo,COL_INFO); } if(tree) { ti = proto_tree_add_item(tree, proto_rdp, tvb, offset, -1, FALSE);} } 这里我们为解析添加一个子树。它将用于保管协议的细节,仅在必要时显示这些内容。 我们还要标识被协议占据的数据区域。在我们的这种情况下,协议占据了传入数据的部,因为我们假设协议没有封装其它内容。因此,我们用"proto_tree_add_item"函数添加新的树结点,将它添加到传入的协议树"tree"中,用协议句柄"proto_rdp"标识它,用传入的缓冲区"tvb"作为数据,并将有效数据范围的起点设为"0",长度设为"-1"(表示缓冲区内的部数据)。至于最后的参数"FALSE",我们暂且忽略。 做了这个更改之后,在包明细面板区中应该会出现一个针对该协议的标签;选择该标签后,在包字节面板区中包的剩余内容就会高亮显示。 现在进入下一步,添加一些协议解析功能。在这一步我们需要构建一组帮助解析的表结构。这需要对"proto_register_rdp"函数做些修改。首先定义一组静态数组。 例5 定义数据结构 static hf_register_info hf[]= { { &hf;_rdp_version, { "TPKT Header:Version", "rdp.version",

24,854

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧