实战KDevelop进行Linux软件开发 2009-02 V0.1

实战KDevelop进行Linux软件开发

陈 浩 2009-02 (Ver. 0.1) MSN: [email protected]

Linux开发并不高深,我们需要一个新的角度进行近距离接触!

欢迎指正!

Horky ([email protected]) 1. 实战KDevelop进行Linux软件开发 2009-02 V0.1 目录 开始之前...... 3 第1章 认识KDevelop...... 4 1.1简单起步 ...... 4 1.1.1 一个实例 – Hello, Kdevelop! ...... 4 1.1.2 KDevelop的项目组织 ...... 6 1.1.3 KDevelop的布局 ...... 8 1.1.4 集成调试环境...... 10 1.2配置KDevelop ...... 11 第2章 应用程序开发 ...... 14 2.1 GTK+应用程序开发 ...... 14 2.1.1 Glade 2.x的应用程序开发...... 14 2.1.2 Glade 3.x 的应用程序开发 (Libglade + Glade 3.x) ...... 20 第3章 动态库与静态库 ...... 23 3.1 例程 静态库的创建与使用 ...... 23 3.2 动态库 ...... 28 3.3 库的调试 ...... 32 附录1. GDB使用介绍...... 35

Horky ([email protected]) 2. 实战KDevelop进行Linux软件开发 2009-02 V0.1 开始之前

很多高手在Linux下很喜欢使用Makefile进行开发,但事实上并不是所有人都适合使用Makefile,尤其是初入 Linux世界的人。 许多年来,Linux很难得以普及,就是因为使用及开发的难度被无端地夸大了,许多高手都以 能运用复杂的指令为荣,而不愿意轻意妥协于那些更易于掌握的工具。而我认为不要在意用什么开发,只要关 注你要开发什么!所以至于工具,自然由你决定。KDevelop也是一个选择,至少它可以使开发者摆脱Makefile体 系的困扰! 软件开发要以产品论英雄,任何工具都是熟能生巧罢了,结果也都是殊途同归,没什么复杂的。

先介绍一下KDevelop吧。KDevelop和Anjuta是Linux下两个最为重要的免费集成开发环境,其中KDevelop最 为稳定。虽然KDevelop从名称上看较接近于KDE开发,但事实上它可以支持诸多Linux应用程序开发,如GTK+ 应用程序开发。它也可以支持多种语言,而不仅限于C/C++。 它的安装也是相当简单,所有主流的Linux发行 版都会在安装盘中附带KDevelop,所以利用本身的包管理系统就可以安装KDevelop。当然对于使用LiveCD安装的 Ubuntu,自然是需要从网上下载安装了。安装简单,我们略去不谈,看看界面先:

这是一个GTK+应用程序的项目界面,并不复杂。见过面后,我们就开始一步步来深入掌握这个开发利 器吧!

Horky ([email protected]) 3. 实战KDevelop进行Linux软件开发 2009-02 V0.1 第1章 认识KDevelop 本章将带你使用KDevelop建立一个简单的工程,让你有一个基本的认识。会涉及诸如创建项目,编译 与调试等重点。本文所有的示例及图片均在Ubuntu 8.04/Debian 4.0及openSUSE 11下使用 KDevelop完成。

1.1简单起步

我将以简单为主要原则来展开KDevelop的使用,所以建个项目最为实际。没办法,还是挑大家最熟 的Hello,World程序了,这样大家就只要关心KDevelop的使用了。

1.1.1 一个实例 – Hello, Kdevelop!

下面为项目创建过程,如果你已经熟悉这个过程,这一节就可以跳过了。 1. 通过Programming中KDevelop菜单进入KDevelop,这里选择KDevelop:C/C++,至于其它项 目,稍后再谈.

2. 选择菜单Project->New Project来创建一个新的项目.

3. 在新的窗口中,勾选"Show all project templates”(否则你只能看到C++),然后设定以下项目: All Projects: Simple Hellow world program Application name: HelloKDevelop Location:选择项目所在的目录

Horky ([email protected]) 4. 实战KDevelop进行Linux软件开发 2009-02 V0.1

点"Next”进入下一步。 4. 在新的界面里设定项目作者和邮箱地址如下: 然 后 点 " N e x t ” , 进 入 到 下 一 面 ,以后的各项也都请按Next进行下去,直至点Finish完成项目的创建。

5. 现在你就可以编译这个程序了,试一下按F8,或者菜单"Build”-> “Build Project”, 然后 在下面的菜单中点选"Run Them”。然后就等待一下吧。

6. 经过一系列的动作后,你就可以在KDevelop下面的信息栏中看到如下的信息:

Horky ([email protected]) 5. 实战KDevelop进行Linux软件开发 2009-02 V0.1 编绎成功了,可是还没有完成。现在把hellokdevelop.c中的"Hello,world!”改成KDevelop吧 ,这个很简单了。存盘后,再次执行一下第5步的编译!

7. 现在可以看看我们的成果了,按一下F9或者是菜单"Debug”->”Start”,程序就会被执行了 ,然在KDevelop下的Application栏里就会出现程序的输出结果,如下:

这就是我们第一个Kdevelop工程了。

1.1.2 KDevelop的项目组织

我们来看看刚刚建的项目生成了哪些目录和文件: HelloKDevelop [autom4te.cache] Autoconf所创建的目录,不属于KDevelop所创建的目录。 [debug] Debug模式所生成的目录,包括中间代码及可执行代码。 [optimized] Optimized模式所生成的目录,同样包括中间代码及可执行代码。 [src] 源代码目录。 [templates] 包含了基本的模板定义信息。 其中的debug和optimized等同于Visual Studio中的Debug和Release模式。 在KDevelop中一个项目可以分为不同的子项目(sub-project),不同的子项目(sub-project)会包含 不同的目标程序(Target),这是项目组织的不同。而每个项目都会有两种基本编译配置:debug和 optimized,你还可以按需要添加你自己的配置。依次看一下它们的位置:

配置(Configuration):

Horky ([email protected]) 6. 实战KDevelop进行Linux软件开发 2009-02 V0.1

在Project->Build Configuration可以选择不同的配置。若要编辑不同配置时可以通过Project->Project Options进行配置:

如果需要添加新的配置,只要给Configuration起一个不同的名字,右侧的Add就会可用,允许你添 加新的配置。后面我们还会具体用到配置的编辑功能。

子项目(Sub-project)及目标程序(Target):

Horky ([email protected]) 7. 实战KDevelop进行Linux软件开发 2009-02 V0.1

上图中项目需要点右侧的"Automake Manager”来打开或关闭的。其中上半部分为子项目(sub- project),下半部分则为目标程序(Target)。后面我们也会有例子来讲述sub-project及Target的运用。

1.1.3 KDevelop的布局

我们再来详细认识一下KDevelop的布局,主要如下图:

其 中 的 工 具 栏 包 括 了 一 些 常 用 的 功 能 , 还 是 要 留意一下: A:Main Toolbar (主工具栏)

Horky ([email protected]) 8. 实战KDevelop进行Linux软件开发 2009-02 V0.1

依次分别为: Open Project: 打开一个现有的项目 Goto Last Edit Position:跳转到上次编辑位置 Back: 退回到上次停留的位置,不一定是编辑操作位置 Forward:跳转到后一次的停留的位置。以上三个在编辑时用于代码间跳转。 New (File):创新一个新文件 Save: 存盘 Save as: 另存为 Print:打印 Undo:恢复 Redo:重做上一次动作 Cut:剪切 Copy:复制 Paste:贴上 Find:查找 Full Screen mode:全屏模式 Enlarge Font:放大字体 Shrink Font:缩小字体 What's This:这是什么?用于帮助你了解具体每个项目的功能。

B:Build Toolbar (编译工具栏) 依次分别为: Build project: 编译项目 Build Active Target: 编译活动目标。当有多个Target时,可以右击某个Target使其变为Active Target. Execute the program:执行目标程序 Stop:停止或中断

C:Browser Toolbar(浏览工具栏)

依次分别为: Generate a new class: 生成一个类,可以选择是否创建头文件和源文件。 Sync ClassView: 同步当前的ClassView信息. Function Navigation: 显示当前单元的函数列表.

D:Debugger Toolbar (调试工具栏) 依次分别为: Start in debugger (F9): 在调试器中执行程序,也是开始Deubg。 Restart the program: 在调试过程中重新执行程序。 Over: 跳过执行,不进入函数内部。 Step Over: 进入执行,会进入函数内部。 Step out of the current function: 跳出当前函数。 Debugger Viewer: 切换到调试视图界面。

Horky ([email protected]) 9. 实战KDevelop进行Linux软件开发 2009-02 V0.1 E: Session Toolbar (Session工具栏)

依次分别为: New session Open session Save session Delete session 都是基本的编辑功能,就不再说明。但是对于Session,还是要多说两句。当项目包含的文件太多 时,如何确保有效找开某组相关联的源代码,这就是Session的作用,它可以帮你更有效的组织项 目代码。然后也可以在Project->Project Options的File List中设定当项目打开时自动加载的session。

如下:

F: Astyle Toolbar (Astyle工具栏) 是一组代码格式化的工具栏。这是一套自定义的工具栏,并非所有平台都有此项,但在Edit菜单 也可以发现它们。

依次为: Format files: 对多个或单个进行格式化。 Reformat Source: 对当前代码进行重新格式化。

1.1.4 集成调试环境

使用Debug配置编译程序时,可以使用F9或菜单Debug->Start进入调试模式! 则此时出现如下的界面 布局。正上方为GDB工具栏,左侧为Watch View窗口,代码区绿色箭头为当前执行的行,下方的GDB Console允许你输入GDB指令并查看输出的结果。

Horky ([email protected]) 10. 实战KDevelop进行Linux软件开发 2009-02 V0.1

设定或取消断点,只要在指定行右击,从菜单选择Toggle Breakpoint就可以了。 *如果你进入Debug状态未能出现如此画面,那就有可能所选择的配置并非Debug,亦或配置选项 中指定了优化选项。另一种则可能是没有安装Konsole,点一下下方的Konsole,如果是灰灰的一 片,那就是需要安装Konsole了。 到此,我们已经了解了KDevelop的主要组成部分。如果现在你要急于进行开发,那就直接跳到第 2章吧。下面一节,我会介绍一些KDevelop的基础配置,有时间回头看一下就可以了。

1.2配置KDevelop

如果想让KDevelop用起来更为顺手,还需要一些细节上的设置。我们一一展开。 1.2.1配置编辑环境 编辑环境重点是字体和布局。KDevelop菜单Settings->Configure Editor便是用于编辑 环境的设置:

Horky ([email protected]) 11. 实战KDevelop进行Linux软件开发 2009-02 V0.1

从上至下,我只会介绍几个主要选项: Appearance: Dynamic word wrap => 是否允许自动换行 Show icon border => 是否显示断点标志所在的边框 Show line numbers => 是否显示行号 Fonts & Colors: 设定编辑器字体及色彩方案 Editing Tab Width : 显定Tab键显示的宽度,建议改为4 Indentation: Indentation mode: 直接在这里设定缩进风格,比如选择C Style. Open/Save Encoding: 对于我们经常需要中文开发,这里最好改成Unicode (utf8) Highlighting : 高亮显示的规则,其本涵盖了常用的语言了 Shortcuts : 快捷键设置 Plugins: 里面提供了有用的插件。包括自动补全功能。

如果你想要一个舒服的编辑环境,这些还是要了解一下的。 如果觉得字体太少,你可再补充一 下Linux下字体管理的知识,帮你添加更多可用的字体. 总之写程序,舒服最重要。

1.2.2 配置系统环境 Kdevelop除编辑器外还有一些其它的设定,可以通过菜单Settings-> Configure Kdevelop,叫出 KDevelop的配置对话框,值得一提的是,里面的Formatting选项,允许你选择不同的编码风格,如 下图所示:

Horky ([email protected]) 12. 实战KDevelop进行Linux软件开发 2009-02 V0.1

1.2.3 配置代码管理环境 一般我们常用CVS或SVN来管理代码, Kdevelop支持四种的代码管理方式。代码管理的方式是要基 于项目设定的,需要执行菜单Project → Project Options, 然后选择Version Control就可以设定所适 用管理方式了:

以Subversion为例,当设定完成后,在编辑区右击就可以发现多出一个Subversion子菜单:

当然,如果你的项目不是从SVN Repository上check out出来的,你这样直接执行指令是不行的,因 为你现在的代码还没有进行SVN管理,你可以先通过客户端或svn指令将代码上传到Repository中 就可以了。 KDevelop的准备到此完成,现在我们可以正式开始着手进行新项目开发了。

Horky ([email protected]) 13. 实战KDevelop进行Linux软件开发 2009-02 V0.1 第2章 应用程序开发 Linux 下的应用程序开发框架,常用的有QT及GTK+。有关GTK+和QT,自然永远是那句:各有千 秋。但有一点Free这是一个重要的精神,难以想像我在Linux下写的GUI程序,可能是依据一个商 业包开发的。GTK正适合这种开发,因为它是完全Free的。KDevelop本身冠以K,就显而易见它是 针对KDE开发而设计的,对QT应用程序开发自然顺手,KDE桌面本身就是基于QT而来的。但使 用KDevelop进行GTK+程序开发则需要一些设定,也刚好符合我们这个主题。

如果你想了解更多有关QT/GTK+的信息,可以从下面网站了解一下:

QT的问题 http://www.kdecn.org/whatiskde/qt.php 为什么使用GTK+

http://www.ibm.com/developerworks/cn/opensource/os-gtk1/

下面,我们就选择GTK+程序来继续学习KDevelop。

2.1 GTK+应用程序开发

GTK+的UI目前有三种开发方式,一种为Glade 2.x的代码生成UI的方式,另一种则为Glade XML 方式,还有一种就是由开发者自行撰写UI代码。目前常用的还是前一种方式。以我个人的观点来 看,我会更愿意选择后者。原因是这样的UI和你的代码才能真正分离,这一点很重要,当你试着 写两个GTK+程序,你就会深有感触的。不过对于程序员而言,却需要有观念上的转变。

2.1.1 Glade 2.x的应用程序开发

先从创建一个GTK+ 2.x程序开始,下面我们按步骤来完成一个工程。GTK+使用Glade来进行界面 设计,并生成相应的代码,如果你没有个程序,那就需要手动安装起来。装完之后就可以看到这 样一个Glade 2.x的程序:

1.使用Glade,先把界面设计好:

Horky ([email protected]) 14. 实战KDevelop进行Linux软件开发 2009-02 V0.1

2. 然后执行Glade的菜单Project → Build来创建代码:

Glade弹出对话框,你只要选择好输出目录就可以了。

在指定目录里面有以下几个文件,它们的意义分别是: callback.c & callback.h 主要是事件处理函数 interface.c & interface.h 主要是生成UI界面的代码 support.c & support.h 包含了一些基础函数,如PIXMAP相关的函数 有关更多Glade及GTK+的知识,可以到GTK官网下载开发文档。

3. 现在开启KDevelop,创建一个GTK+项目,如下:

Horky ([email protected]) 15. 实战KDevelop进行Linux软件开发 2009-02 V0.1

4.在Automake Manager里的Target中选择 ”Add Existing Files”,将已生成的代码加入工程中:

5.如果现在就编译,就会有如下一堆的错误信息出来:

Horky ([email protected]) 16. 实战KDevelop进行Linux软件开发 2009-02 V0.1

6. 这时我们需要在项目选项做些设定,还记得菜单项: Project → Project Configuration:

7.按如下方式设置C/C++ preprocessor flags (CPPFLAGS): CPPFLAGS: -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 - I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include - I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pixman-1 -I/usr/include/libglade-2.0 - I/usr/include/libxml2

Horky ([email protected]) 17. 实战KDevelop进行Linux软件开发 2009-02 V0.1

然后再编译一次,KDevelop会问你是不是要重新运行configure,点击”Rerun”确认。

configure是什么? configure是Linux下交叉编译的主角,由autoconf生成,当然还要配合autoscan,aclocal,automake一 起使用。绝大多数以源代码发布的项目,都会提供一个configure脚本,用于不同平台的兼容性及 编译环境处理,并生成相应的Makefile。

8. 现在所有有关头文件的错误就消失了,不过有些平台下还会有如下的错误: 这是目录设置的问题,如果没有发现就跳过下面的处理。

9.右击Target,在Target options中将“Working Directory”中除去“./”,如下:

Horky ([email protected]) 18. 实战KDevelop进行Linux软件开发 2009-02 V0.1

10. 再编译一次。这时如果还有错误,那就是库链接的错误,需要在Project Options中将LDFLAG 修改成如下内容: -lglade-2.0 -lgtk-x11-2.0 -lxml2 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 - lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0

现在就大功告成了。似乎是繁琐了些,但只要多做两次,就会熟悉了,并且是一劳永逸。

在整个过程中,你或许会问如何知道应怎样设定CPPFLAGS及LDFALG呢? 这些其实都可 以通过pkg-config来完成。指令如下: LDFLAGS: pkg-config --libs gtkmm-2.4 CPPFLAGS: pkg-config --cflags gtkmm-2.4 下面是一个执行的示例:

Horky ([email protected]) 19. 实战KDevelop进行Linux软件开发 2009-02 V0.1 2.1.2 Glade 3.x 的应用程序开发 (Libglade + Glade 3.x)

使用Glade 2.x进行开发,最大的问题就是UI的设置问题。 你如果通过Glade修改了界面,则你的 interface及supports单元都会被重新覆盖,你之前如果不幸在其中做了修改,则必须重来。当然如 果你不使用Glade来修改界面,你就必须对Glade生成的UI相关代码进行手动修改,工作效率也会 降低。 Glade 3.x就可以帮你解决这些问题,当然也还有许多改进空间,至少这是很好的开始。

Glade 3.x将glade文件内容改为DocBook XML格式,这类似于Mac OS的实现方法,以此将UI和你的 代码区隔开来。你可以通过libglade提供相应的机制来动态加载这个UI文件。相对于Mac OS,它还少 了一些将代码与控制连接的设定,这些都需要开发者自己手动加入到代码中。好在,这点投入相 对我们所节省的维护成本,还是很小的。

不是所有的Linux平台都可以使用Glade 3的,它需要有GTK+ 2.8及LibXML 2.4.1以上版本的支持。 比如Debian etch现在不能直接Glade 3. 不过其它几个主流的发行版都没问题。

下面,我们再来使用一个实作来了解GTK+ 3.x的开发过程。 1.首先使用Glade 3来建立一个UI工程: 确保你已经安装了Glade 3.x,然后执行,并设计好一个UI,存储成一个glade文件。

一些属性需要检查一下,比如Window的Visible及Type Hint,有时默认值是错误的。注意一定要将 主窗体命名为Main_Window,Button命名为btn_close。这些需要在源代码中使用到。只要 保持一致即可。

2. 采用上面介绍过的方法新建一个GTK+程序,不需要其它文件操作。整个工程中只需要保留一 个单元文件即可。

3. 项目的设置参考GTK+ 2.x的设定,只是要注意你现在需要一个glade库来为你动态加载界面提供 支持。所以CPPFlags和LDFlags需要按以下指令获得: LDFlags: pkg-config --libs libglade-2.0 CPPFlags: pkg-config --cflags libglade-2.0

4. 然后修改源代码,类似如下:

Horky ([email protected]) 20. 实战KDevelop进行Linux软件开发 2009-02 V0.1 #include

void close_button_clicked (GtkWidget *widget, gpointer user_data) { printf ("Quit now!.\n"); gtk_main_quit (); }

int main (int argc, char *argv[]) { GladeXML *main_window; GtkWidget *widget;

gtk_init (&argc, &argv);

/* Load glade file */ main_window = glade_xml_new ("/xxx/xxxx.glade", NULL, NULL);

/* connect the signals in the interface */ widget = glade_xml_get_widget (main_window, "btn_close"); g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (close_button_clicked), NULL);

widget = glade_xml_get_widget (main_window, "Main_Window"); g_signal_connect (G_OBJECT (widget), "delete_event", G_CALLBACK (gtk_main_quit), NULL);

gtk_main ();

return 0; } 将代码中指定glade文件的代码改成真实的文件就可以了。

5. 现在就可以编译运行了。

你现在可以尝试一下使用Glade修改glade文件,然后再观察一下程序运行结果。UI和功能实现就这 样分离了。

我们再观察一下你的glade文件,使用一个文本编辑器打开它,你可以查看到它的内容了: True True GDK_WINDOW_TYPE_HINT_DIALOG True ⋯⋯

Horky ([email protected]) 21. 实战KDevelop进行Linux软件开发 2009-02 V0.1 相信你可以很轻松地了解到这个文件的意义。

更多有关Glade 3.x和libglade的信息请参考以下网站: Glade: http://glade.gnome.org (中文: http://www.gnome- cn.org/Filescenter/documents/developer_doc/API/libglade) Libglade : http://library.gnome.org/devel/libglade/

Horky ([email protected]) 22. 实战KDevelop进行Linux软件开发 2009-02 V0.1 第3章 动态库与静态库 动态库与静态库也是我们已经使用的开发形式,本章就将详述两者在KDevelop中的开发过程.

Linux下的动态库称为Shared Library, 一般存放于/usr/lib 或/usr/local/lib 目录中,扩展名一般 为so 。静态库的概念和Windows下一样,都会在编译过程嵌入到目标程序中,扩展名一般为a。库在开发 过程中是十分常见的,也有很多的技术主题, 这里不会详述库的开发技术,而是侧重在Kdevelop的 运用。

3.1 例程 静态库的创建与使用

在本节,我们将以一个例程来阐述KDevelop的库开发及使用过程。

1. 新建一个项目,这里可以先命名为TestLibrary.

后面的设置按默认设定就可以了。

2.项目创建完成后,会类似如下画面:

Horky ([email protected]) 23. 实战KDevelop进行Linux软件开发 2009-02 V0.1

3. 然后右击Automake Manager上的sub-project, 在菜单中选择”Add Target”,如下:

4. 在如下的对话框中设定Target为Library,Filename输出为demo. Prefix保持默认的lib即可。

Horky ([email protected]) 24. 实战KDevelop进行Linux软件开发 2009-02 V0.1

5. 然后在新建的Target上右击,并选择”Create New File⋯”,如下图所示:

KDevelop会让你设定新件的命名及类型,这个文件就是我们以后静态库和动态库的程序代码了。 同时记得确保勾选”Add to project”,如下:

6.然后,KDevelop会让你选择添加到哪个Target中,选择我们新建的libdemo.a即可。 Horky ([email protected]) 25. 实战KDevelop进行Linux软件开发 2009-02 V0.1

7. 完成后就可以发现libdemo.a的Target中有一个单元文件,如下:

8. 双击打开它,并填入一些代码: int g_IntValue = 0;

int IncInteger( int nValue ) { g_IntValue ++; return nValue + 1; }

Horky ([email protected]) 26. 实战KDevelop进行Linux软件开发 2009-02 V0.1

int GetGlobalValue(void) { return g_IntValue; } 只是简单地加个1,再返回。还有一个全局计数的变量。就这么简单。

同时将testlibrary.c中main函数的代码改为: /*Following functions be defined in library*/ int IncInteger( int nValue ); int GetGlobalValue(void);

int main(int argc, char *argv[]) { printf("Hello, world!\n"); printf("Call IncInteger in library with 2, and result is %d!\n",IncInteger(2)); printf("The global integer value in library is %d!\n",GetGlobalValue()); return EXIT_SUCCESS; } 代码已经完成了。还需要再设定一下testlibrary的静态连接的问题。

9. 右击Target:testlibrary,并选择”Target Options”,设定其中的Libraries页签,勾选libdemo.a即可。

现在就可以使用编译功能来编译这两个Target了。(*可以按F8->Build Project来同时编译这两个 Target。)

编译完成后,按Shift+F9或Build/Execute Program来执行看看:

Horky ([email protected]) 27. 实战KDevelop进行Linux软件开发 2009-02 V0.1

如果你没有安装konsole,就不会正常执行。你可以选择安装konsole或利用Debug/Start (F9)来执 行。

以上就是静态库的开发及运用过程。

3.2 动态库

现在我们再来看看动态库的创建。KDevelop并没有直接创建动态库的项目及Target,需要使用 KDevelop的其它设置来实现。

1. 我们再来加一个新的Target,默认其为一个可执行程序,命名为libdync,在下面的Linker Flags中,将 Other设为:

-shared –Wl,-soname,libdync.so –o libdync.so.

如下所示:

(*在一些发行版中,如openSUSE, 需要将File name设置成为libdync.so才能正常工作。下面在库调试 一节中所使用的程序即为在openSUSE下开发界面。)

Horky ([email protected]) 28. 实战KDevelop进行Linux软件开发 2009-02 V0.1 2. 然后将之前的demo.c添加到这个Target中,如下:

这个新建的Target就可以编译,编译后会生成libdync.so文件。

3. 刚刚的testlibrary是用来测试静态库的,现在我们还需要做些设定,来使其调用我们新的动态库。 同样是在它的Target Options中,去掉之前勾选的libdemo.a,并在下方,点Add按钮添加新的动态库 引用.这就表示这个程序在编译时需要引用这个动态库。如下图所示:

Horky ([email protected]) 29. 实战KDevelop进行Linux软件开发 2009-02 V0.1

因为GCC默认会在库前加lib,所以你在输入时可以略去前面的lib,直接在-l后面输入dync即可。

保存好,就可以编译了。

4. 编译完成后,在项目的编译目录中,可以发现如下的程序文件:

6. 这时当你执行testlibrary时,会有如下错误出现,主要是因为无法定位到依赖库libdync.so,如下:

Horky ([email protected]) 30. 实战KDevelop进行Linux软件开发 2009-02 V0.1

原因是testlibrary会默认到/usr/lib中查找libdync.so,但是我们并没有将动态库放到指定的目录中。当 然我们可以将此动态库拷入到/usr/lib目录中,一切就会正常了。不过我们这里再谈一个方式,我 们可以让testlibrary到指定的目录中去查找动态库。

ldd是Linux下动态库依赖性检测工具。可以使用man ldd获取更多信息。

7. 回到KDeveop,并在testlibrary的Target Options中,将Flags页签中的Other修改为如下内容:

你可以设置为其它目录,只要里面会存在指定的动态库就可以了。

8. 设置完成后,我们再编译一次即可。

将之前的动态库拷入到/usr/local/lib目录中,再执行看看:

Horky ([email protected]) 31. 实战KDevelop进行Linux软件开发 2009-02 V0.1

一切都可以正常工作了。

至此,你就可以运用KDevelop开发你所需要的静态库或动态库了。在Linux中围绕着库最 常出现的问题就是依赖性的问题。常常会出现某个程序因为依赖的包不存在或版本不正确而 无法运行。所以系统中也提供了一些工具用来检测试库间的依赖性问题。比如上面我们使用 到的ldd, 另外也有GNU的readelf等工具,也可以进行一些检测。

3.3 库的调试

静态库与动态库的调试在KDevelop中也比较简单,我以动态库来说明它们的调试方法。再以上 例中的libdync.so同testlibrary结合即可。首先需要确保在Project Options->Configure Options中的 C/C++的编译选项中没有使用优化选项(-O0),且设定了Debug信息输出模式(-g)。有关调试信息的 更多知识请参考附录1。设置结果如下图:

使用Debug模式执行testlibrary (按F9或使用菜单Debug->Start), 此时KDevelop会停留在默认的断点 上,尚未进入你所设置的断点,此时切换到demolib.c在相应位置设置断点,如下图:

Horky ([email protected]) 32. 实战KDevelop进行Linux软件开发 2009-02 V0.1

注意下方的GDB项目,你可以使用其中的GDB cmd下一些GDB指令,比如此处可以下info b来查 看当前断点设定情况。如果发现了一些你不需要的断点,也可以使用GDB指令删除掉。有关更多 GDB指令的信息可以参考附录1或GDB手册。

此时你就可以使用F10之类的运行指令来一步步执行了,如下图:

Horky ([email protected]) 33. 实战KDevelop进行Linux软件开发 2009-02 V0.1

其实只要了解了GDB,无论使用KDevelop或是其它的调试工具,亦或是直接使用GDB都是非常容易 的,而了解GDB前还一定要了解GCC生成调试信息的方式。有了这样的基础就能做到以不变应万 变。

Horky ([email protected]) 34. 实战KDevelop进行Linux软件开发 2009-02 V0.1

附录1. GDB使用介绍

在Linux下最强大的Debug工具就是GDB了,许多IDE都集成了GDB进行调试。使用源代码级调试能够更 直接的进行调试,效率明显高于输出Log信息。但目前无论是Mac下的XCode,还是Linux下的其它集成工具 ,对于调试库函数都是相当困难的,如果直接使用GDB这些问题就迎刃而解。我们首先来探讨一下GDB 的基础知识。

GDB调试流程

GDB调试依赖于编译器输出的调试信息,所以进行调试前必须确定GCC输出了调试信息。 1.生成符号文件 使用GCC编译时需要生成相应的调试信息,编译时可以使用-g选项: <<详细内容参GCC Manual>> Section 3.9 -g 表示将Symbol Table以系统原生格式直接生成到可执行文件中 -g选项最好不要同-O一起使用,因为代码经过优化后有时会同源代码差异很大,可能找不到指定的变量等等 。 -ggdb 表示将专门为GDB调试使用生成调试信息,它会包括很多GDB的扩展信息 其它的Symbol Table的格式还有COFF,DWARF,Stabs等. (Mac OS默认为DWARF. DWARF也是基于COFF实现 [Common Object File Format])

输出的调试信息的多少由三个等级: -g[level] 默认为2 0 表示不生成任何调试信息 1 表示生成最少的调试信息,不提供局部变量及源代码行列等信息。 2 标准模式 3 较2而言,包含了宏定义等额外信息

其它同调试相关的编译选项还有: -p 生成额外的代码用于输出profile信息,用于另一个工具程序使用:prof --coverage 用于统于代码的覆盖率. --ftest-coverage 类似上面的--coverage -d* 用于Dump一些有用的信息,详细内容参GDB Manual.

2.启动GDB进行调试 下面的过程,我都以下面的工程进行解释: 目标程序: text2bin 源代码:text2bin.c 功能: 将文本文件转成二进制文件 使用方法: ./text2bin txt_file_name [offset] txt_file_name为源文本文件名 offset指定忽略左侧多少字节

A.调试应用程序 (1)启动 直接在命令行下输入gdb ./text2bin 或者运行gdb后输入file ./text2bin都可以加载指定的应用程序. GDB会显示加载Symbols的过程,注意如果没有出现加载text2bin的调试信息的过程,就是表明无法获取调 试信息! Horky ([email protected]) 35. 实战KDevelop进行Linux软件开发 2009-02 V0.1 Reading symbols for shared libraries ... done Reading symbols from /Horky/Project/WINBASE/WINBASE/TextToRaw/text2bin... warning: UUID mismatch detected between: /Horky/Project/WINBASE/WINBASE/TextToRaw/text2bin

(2)设置断点 *除了断点外还有Watchpoints(观测点)及Catchpoints (异常捕捉点) 输入b或break 加上断点位置或断点函数名,如 b main #在main函数入口设置断点 b text2bin.c:50 在源代码第50行设置断点

如果需要查看断点信息可以使用指令: info breakpoints

清除所有断点使用指令: clear 清除特定的断点使用指令: clear text2bin.c:50 或 clear main

在调试过程可以使用disable及enable开关某个特定的断点.如enable 2 及 disable 2开关第2个断点。 在使用info b查看断点时,注意其中Enb栏位的变化。

对于观测点(Watchpoints),是指在某个条件下触发的断点,如text2bin中77行: Buffer2[nCount++] = ConvertTextToInt(sData);

我们要查看当nCount为10时的运行状况,我们可以通过下面的步骤完成: a. 执行b 77,返回这个断点号是3 b. 执行condition 3 nCount=10 过程如下: (gdb) b 77 Breakpoint 3 at 0x1c73: file text2bin.c, line 77. (gdb) condition 3 nCount=10 (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x00001e1e in ConvertTextToInt at text2bin.c:124 breakpoint already hit 1 time 2 breakpoint keep y 0x00001e25 in ConvertTextToInt at text2bin.c:125 3 breakpoint keep y 0x00001c73 in main at text2bin.c:77 stop only if nCount = 10

这样就可以控制当nCount为10时在77行处中断.

如果在调试时,需在下面若干行代码后追加一个断点,在指定位置可以使用偏移量来指定断点, 如b +5 及b -5,即表示在当前行的后五行及前五行位置设置断点

(3)控制调试过程 在开始时需要告诉GDB目标程序是哪一个,可以用gdb ./text2bin,也可以在启动gdb后使用指令: file ./text2bin来指定。 运行则使用r/run指令,可以同时带上参数,如 r ./expert.txt 7 Horky ([email protected]) 36. 实战KDevelop进行Linux软件开发 2009-02 V0.1

在调试过程中需要有一系列操作控制调试的过程: c / continue /fg *fg是foreground的缩写 从断点状态恢复程序的执行.

s / step [count] 单步执行 (step in)

n / next [count] 单步执行,跳过函数 (step out)

u / until [location] 执行到某个位置。 当遇到循环时可以使用此指令方便地跳转到指定的位置。

finish 执行到当前函数结束位置为止,同时显示函数返回值

backtrace 查看当前位置的被调用路径

(4)监测变量及内存 简单地显示变量的值可以使用print指令直接输出. p / print [expression] 如输出main函数中的文件名变量 p argv[1] 输出ConvertTextToInt函数中n的值 p n或p ConvertTextToInt::n

查看内存内容时则使用x指令: x /nfu addr 以指定格式显示内存内容 x addr 显示指定地址处理内存内容 x 显示当前数据段内容

如以字串形显示某内存内容的指令为: x /sb 0xbffff80e 以数据形式显示某内存中5个字节的内容的指令为: x /5db 0xbffff80e

设定local variable watch,用来在每条执行后显示某些变量的值,可以使用display指令来指定,如: display S display /sb 0xbffff707

去除时使用undisplay # (#为display列表中的序号)

display后面所带的参数同x指令: n 表示repeat count f 表示格式,分为: x 十六制数据 d 带符号之整型数据 u 无符号整型数据 o 八进制整型数据 t 二进制数据 a 以地址格式显示,包括十六进制及偏移量 Horky ([email protected]) 37. 实战KDevelop进行Linux软件开发 2009-02 V0.1 c 以字符形式输出 f 小数位输出 s 以字串形式输出

u表示大小单位: b Bytes h Halfwords w Words g Giant words (eight bytes)

(5)查看源代码 使用l / list指令就可查看源代码了, 如: l 150 查看当前代码的第150行 l text2bin.c:150 查看text2bin.c的150行. l main 查看main函数内容 查看时如果需要翻页,直接回车.

默认GDB一次显示10行,我们也可以通过set linesize [count]进行调整。

B.如何调试动态库或静态库 当调试库函数时,需要透过主程序调用的形式来挂载,所以不能直接使用GDB对目标库进行调试,而是需要 attach指定的父进程,然后再进行测试. 这里有两种情况: (1)主程序启动时自动加载库,此时使用GDB挂载时也会自动加载相应的调试信息. (2)主程序动态加载库,对于这种情况则需要另外使用symbol filename来加载特定的调试信息。

*提醒:当进行多线程调试时,一定要确保能找出真正的主线程。 *断开主线程时,使用detach指令来完成

C.如何调试多线程的程序 我们在写程序时常常会有多线程的运用, 比如有些程序中读取数据及数据处理,就是通过两个线程来完成的 。对 多线程进行调试最大的难点在于线程的同步问题. GDB提供了一套指令针对多线程: info threads 查看当前有多少线程 thread # 切换到指定线程 set print thread-events on/off 设定是否打印线程状态 当设置中断时,也可以专为某个线程设置,如 b/break [location] thread # 即表示为#线程在location处设置断点,这样就可以进行线程别的调试。

3. 技巧 (1)在GDB中如果需要调用外部程序可以使用shell [command]来完成 (2)当源代码目录被移动了,或者在另一台PC上调试,GDB不能通过Debug信息找到源代码时,可以使用 directory/dir来指搜索的目录

Horky ([email protected]) 38. 实战KDevelop进行Linux软件开发 2009-02 V0.1 4.GDB的前台程序(GDB frontend) 使用命令行是显得不方便了,所以我们可以选择一些GDB前端程序: DDD [GNU] (http://www.gnu.org/software/ddd 目前功能最为强大的GDB前端程序) [GNOME] (http://home.gna.org/nemiver/) Kdbg [KDE] (www.kdbg.org) Insight [Wirte in Tcl/Tk] (http://sourceware.org/insight) Emacs (不用介绍了!) 一般的IDE也带有GDB frontend程序,如XCode,KDevelop,Anjuta,Eclipse.

*GDB Frontend都是通过伪终端(pseudo-terminal)的方式来实现,有兴趣可以了解一下.

扩展GDB的功能 已经有人在通GDB进行代码覆盖率测试,事实上我们也可以通过类似GDB的方式读取Debug信息中的符号表 来进行语法检查。有关Debug信息的存放,可以使用objdump -x或readelf -a来查看其中的不同,这有助更好的 理解程序的结构.

需求是多样的,GDB本身提供了两种方式来扩展GDB,一种为组合GDB的指令,类似宏的方式,另一种方式则 是功能强大的python脚本。 (1)在GDB环境下使用define指令来定义一个指令,如 define localv info scope $arg0 end 这样我们在使用时,想查看main函数中的所有的变量,就可以通过下面的指令完成: (gdb) localv main Scope for main: Symbol argc is at the address (reg 5 + 8), length 4. Symbol argv is at the address (reg 5 + 12), length 4. Symbol fpSrc is at the address (reg 5 + -44), length 4......

如果这样的指令非常好用,每次调试时都定义一次不太现实。所以GDB允许将这些操作定义在一个文本文 件中,然后在GDB中使用source [command_file]来执行,如source /TestData/localv.cmd 。 在执行过程中GDB不会显示每个指令的执行结果,如果需要显示就在source加-v来打开。

除了组织指令集外,还有另一种有用的自定义指令: Hooks. GDB允许用户指定在特定的GDB指令执行前后执 行一段自定义指令。比如,如果希望在设置断点前后都显示当前断点状况,就可以定义两个如下指令: (gdb) define hook-break Type commands for definition of "hook-break". End with a line saying just "end". >info b >end (gdb) define hookpost-break Type commands for definition of "hookpost-break". End with a line saying just "end". >info b >end

然后执行break / b指令时就可以看到类似下面的输出: (gdb) b GetFileSize Num Type Disp Enb Address What Horky ([email protected]) 39. 实战KDevelop进行Linux软件开发 2009-02 V0.1 1 breakpoint keep y 0x00001a68 in main at text2bin.c:25 2 breakpoint keep y 0x00001e1e in ConvertTextToInt at text2bin.c:124 Breakpoint 3 at 0x1d86: file text2bin.c, line 108. Num Type Disp Enb Address What 1 breakpoint keep y 0x00001a68 in main at text2bin.c:25 2 breakpoint keep y 0x00001e1e in ConvertTextToInt at text2bin.c:124 3 breakpoint keep y 0x00001d86 in GetFileSize at text2bin.c:108

hook及hookpost即表示在某个指令的前后。后面的指令一定要使用GDB指令的全写,如上面就不能写成 define hook-b或define hookpost-b。

*如果需要更为详细的资料,请参考GDB Manual,20. Extending GDB

(2)在GDB环境可以直接调用python,如在GDB环境下执行python print 23 使用Python编写脚本同上面定义指令集是类似的,可以执行指令python, GDB就会要求输入python脚本,并以 end为结束标志。 GDB为编写Python提供了一个新的模块gdb, 在脚本中可以进行引用,其中包括了几个主要的指令: execute command command是GDB CLI(Command Line Interface)指令字串. get_parameter parameter 获取一项GDB的参数,诸如上面提到的linesize. write string 输出一个字串到GDB输出窗口 flush Flush当前GDB输出流

*只有当编译GDB时指定了—with-python时,GDB才会支持python指令.

参考文档: (1) 使用GDB进行代码覆盖率测试 http://www.ibm.com/developerworks/cn/linux/l-cn-gdb/ (2) 使用 GDB 调试 Linux 软件 http://www.ibm.com/developerworks/cn/linux/sdk/gdb/ (3) 掌握 Linux 调试技术 http://www.ibm.com/developerworks/cn/linux/sdk/l-debug/ (4) 用GDB调试程序 http://docs.chinalinuxpub.com/doc/pro/gdb.html (5) GDB调试精粹及使用实例 http://fanqiang.chinaunix.net/program/other/2006-07-14/4834.shtml (6) GDB的官方文档 http://www.gnu.org/software/gdb/documentation/ (7) GDB指令参考 (可以打出来方便查询) http://users.ece.utexas.edu/~adnan/gdb-refcard.pdf

Horky ([email protected]) 40.