500 likes | 627 Views
Linux开发基础. 主要内容. Linux 函数库 如何使用 GCC GDB 简介 Makefile SVN/GIT 版本控制软件. Linux 下函数库( 1/3 ). 一个“程序函数库”就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。可分为两种类型:
E N D
主要内容 • Linux函数库 • 如何使用GCC • GDB简介 • Makefile • SVN/GIT版本控制软件
Linux下函数库(1/3) • 一个“程序函数库”就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。可分为两种类型: • 静态函数库(static libraries):是一个普通的目标文件的集合,一般用“.a”作为文件的后缀。静态函数库和共享函数库相比有很多的缺点,占用内存空间多。但使用ELF格式的静态库函数生成的代码可以比使用共享函数库的程序运行速度上快一些。 • 可以用ar这个程序来创建一个静态函数库文件,或者往一个已经存在地静态函数库文件添加新的目标代码。 例如, 把file1.o和file2.o加入到my_library.a这个函数库文件: arm-linux-ar rcs my_library.a file1.o file2.o 然后运行 arm-linux-ranlib,以给库加入一些索引信息
Linux下函数库(2/3) • 共享函数库(shared libraries):当一个可执行程序在启动的时候被加载的函数。每个共享函数库都有个特殊的名字,称作“soname”。soname名字命名必须以“lib”作为前缀,然后是函数库的名字,然后是“.so”,最后是版本号信息。 • 优点:多进程使用同一函数库;修改函数库不需重新连编。 • 安装一个新版本的函数库的时候,要先将这些函数库文件拷贝到一些特定的目录中,运行ldconfig就可以。ldconfig检查已经存在的库文件,然后创建soname的符号链接到真正的函数库,同时设置/etc/ld.so.cache这个缓冲文件。 • 例如,创建两个目标文件(a.o和b.o),然后创建一个包含a.o和b.o的共享函数库。 • arm-linux-gcc -fPIC -g -c -Wall a.c • arm-linux-gcc -fPIC -g -c -Wall b.c • arm-linux-gcc -shared –Wl -o liblusterstuff.so.1.0.1 a.o b.o • 注:” -fPIC ”是位置无关参数, ”-g”和“-Wall”参数不是必须的。
Linux下函数库(3/3) • 函数库和头文件的保存位置 • a. 函数库 • /lib:系统必备共享函数库 • /usr/lib:标准共享函数库和静态函数库 • /usr/i486-linux-libc5/lib:libc5 兼容性函数库 • /usr/X11R6/lib:X11R6 的函数库 • /usr/local/lib:本地函数库 • b. 头文件 • /usr/include:系统头文件 • /usr/local/include:本地头文件 • c. 共享函数库的相关配置和命令 • /etc/ld.so.conf:包含共享库的搜索位置 • ldconfig:共享库管理工具,一般在更新了共享库之后要运行该命令 • ldd:可查看可执行文件所使用的共享函数库
使用GNU cc开发应用程序 • gcc的简介 • 可执行文件的格式 • gcc的使用
源程序(*.c) 预处理 编译 组译 链接 可执行文件 预处理器 编译器 组译器 连接器 gcc的简介 • gcc 是 GNU 的 C 和 C++ 编译器。实际上,gcc 能够编译多种语言:C、C++ 和 Object C等。利用 gcc 命令可同时编译并连接 C 和 C++ 源程序。也可以对几个 C 源文件利用 gcc 编译、连接并生成可执行文件。 • gcc可以使程序员灵活地控制编译过程。编译过程一般可以分为下面四个阶段,每个阶段分别调用不同的工具进行处理
gcc的四个阶段 • 命令gcc首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(include)、预编译语句(如宏定义define等)进行分析。 • 接着调用cc1进行编译,这个阶段根据输入文件生成以.o为后缀的目标文件。 • 汇编过程是针对汇编语言的步骤,调用as进行工作,一般来讲,.S或.s为后缀的汇编语言源代码文件汇编之后都生成以.o为后缀的目标文件。 • 当所有的目标文件都生成之后,gcc就调用ld来完成最后的关键性工作,这个阶段就是连接。在连接阶段,所有的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的函数库中连到合适的地方。
可执行文件格式 • Linux系统中可执行文件有两种格式。 • 第一种格式是a.out格式,这种格式用于早期的Linux系统以及 Unix系统的原始格式。a.out来自于Unix C编译程序默认的可执行文件名。当使用共享库时,a.out格式就会发生问题。把a.out格式调整为共享库是一种非常复杂的操作。 • 因此,一种新的文件格式被引入Unix系统5的第四版本和Solaris系统中。它被称为可执行和连接的格式(ELF)。这种格式很容易实现共享库。 • ELF格式已经被Linux系统作为标准的格式采用。 • gcc编译程序产生的所有的二进制文件都是ELF格式的文件(即使可执行文件的默认名仍然是a.out)。较旧的a.out格式的程序仍然可以运行在支持ELF格式的系统上。
GNU C 的使用 • 基本语法 • gcc [options] [filenames] • 说明: • 在gcc后面可以有多个编译选项,同时进行多个编译操作。很多的gcc选项包括一个以上的字符。因此你必须为每个选项指定各自的连字符。例如,下面的两个命令是不同的: gcc -p -g test1.c gcc -pg test1.c • 当你不用任何选项编译一个程序时,GCC将会建立(假定编译成功)一个名为a.out的可执行文件。
gcc选项 • -o选项 • 你能用 -o 编译选项来为将产生的可执行文件指定一个文件名来代替 a.out。 • 例:gcc –o count count.c • -c选项:告诉GCC仅把源代码编译为目标代码而跳过汇编和连接的步骤。这个选项使用的非常频繁,因为它使得编译多个C程序时速度更快并且更易于管理。缺省时GCC建立的目标代码文件有一个.o的扩展名。 • 例:gcc –c test2.c • -E 只运行 C 预编译器。 • -S 编译选项告诉 gcc 在为 C 代码产生了汇编语言文件后停止编译。 • -shared 生成共享目标文件。通常用在建立共享库时。 • -static 禁止使用共享连接。
警告选项 • 在gcc中用开关-Wall控制警告信息,使用示例命令如下: gcc –Wall -o test3_1 test3_1.c • -w 不生成任何警告信息。
查找选项 • gcc一般使用默认路径查找头文件和库文件。如果文件所用的头文件或库文件不在缺省目录下,则编译时要指定它们的查找路径。 • -I选项:指定头文件的搜索目录 • 例: • gcc –I/export/home/st –o test1 test1.c • -L选项:指定库文件的搜索目录 • 例: • gcc –L/usr/X11/R6/lib –o test1 test1.c
多个源文件生成一个可执行文件 • 问题:有多个源文件时,如何生成一个可执行文件? • 方法1:gcc –Wall –o mytest test1.c test2.c test3.c • 方法2: gcc-Wall -c test1.c gcc-Wall –c test2.c gcc-Wall –c test3.c gcc –o mytest test1.o test2.o test3.o
优化选项 • 优化选项可以使GCC在耗费更多编译时间和牺牲易调试性的基础上产生更小更快的可执行文件。这些选项中最典型的是-O和-O2选项。 • -O0 不进行优化处理。 • -O选项:告诉GCC对源代码进行基本优化。这些优化在大多数情况下都会使程序执行的更快。 • -O2选项:告诉GCC 产生尽可能小和尽可能快的代码。-O2选项将使编译的速度比使用-O时慢。但通常产生的代码执行速度会更快。 • -O3选项:比 -O2 更进一步优化,包括 inline 函数。
版本选项 • -v选项 • 用户将会得到自己目前正在使用的gcc的版本及与版本相关的一些信息。 gcc -v 将得到如下结果: Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs gcc version 2.7.2 • -V 选项 • 如果安装了多个版本的gcc,并且想强制执行其中的某个版本,可以用命令通知系统用户要使用的版本。 gcc -V2.6.3 -v
宏定义选项 • -D MACRO 以字符串“1”定义 MACRO 宏。 • -D MACRO=DEFN 以字符串“DEFN”定义 MACRO 宏。 • -U MACRO 取消对 MACRO 宏的定义。
调试和剖析选项 • 使用调试选项后,gcc在进行编译的时候,在目标文件(.o)和创建的可执行文件中插入额外信息,这些额外信息使gdb能够判断编译过的代码和源代码之间的关系。 • -g选项:告诉GCC产生能被 GNU 调试器使用的调试信息以便调试你的程序。 • 例:gcc –g –o test3 test3.c • -pg选项:告诉GCC在你的程序里加入额外的代码,执行时,产生gprof用的剖析信息以显示你的程序的耗时情况。 • 使用gdb调试工具,命令行如下: • 例:gcc –ggdb3 –o test3 test3.c
调试工具gdb • GDB调试器简介 • gdb 的常用命令 • gdb应用实例
gdb 简介 • Linux系统中包含了GNU 调试程序gdb,它是一个用来调试C和 C++ 程序的调试器。可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况。 • gdb 所提供的一些功能如下所示: • 运行程序,设置所有的能影响程序运行的参数和环境; • 控制程序在指定的条件下停止运行; • 当程序停止时,可以检查程序的状态; • 修改程序的错误,并重新运行程序; • 动态监视程序中变量的值; • 可以单步逐行执行代码,观察程序的运行状态。 • 分析崩溃程序的产生的core文件
gdb的特点 • gdb的功能非常强大 • 到目前为止,gdb已能够支持Moduls-2、Chill、Pascal和FORTRAN程序的调试,但是调试这些语言的源程序时有一些功能还不能使用。 • 例如调试FORTRAN程序时还不支持表达式的输入、输出变量或类FORTRAN的词法。 • gdb程序调试的对象是可执行文件,而不是程序的源代码文件。 • 然而,并不是所有的可执行文件都可以用gdb调试。如果要让产生的可执行文件可以用来调试,需在执行gcc指令编译程序时,加上-g参数,指定程序在编译时包含调试信息。 • 调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。 • gdb 利用这些信息使源代码和机器码相关联。 gdb是一个用来调试C和C++程序的常用调试工具之一。
gdb的启动 • 在命令行上输入gdb并按回车键就可以运行gdb了,如果一切正常的话,将启动gdb gdb [filename] 出现 (gdb) 在这里,可以输入调试命令 • 在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源文件。可在 makefile 中如下定义 CFLAGS 变量: CFLAGS = -g 运行
获取帮助信息 • 启动gdb后,可以在命令行上指定很多的选项。输入: help 可以获得gdb的帮助信息。 • 如果想要了解某个具体命令(比如break)的帮助信息,在gdb提示符下输入下面的命令: break 屏幕上会显示关于break的帮助信息。从返回的信息可知,break是用于设置断点的命令。 • 另一个获得gdb帮助的方法是浏览gdb的手册页。在Linux Shell提示符输入: man gdb 可以看到man的手册页
gdb命令的分类 • 在 gdb 提示符处键入help,将列出命令的分类,主要的分类有: • aliases:命令别名 • breakpoints:断点定义; • data:数据查看; • files:指定并查看文件; • internals:维护命令; • running:程序执行; • stack:调用栈查看; • statu:状态查看; • tracepoints:跟踪程序执行。 • 后跟命令的分类名,可获得该类命令的详细清单
基本gdb命令(1/2) • file命令:装入想要调试的可执行文件。 • cd命令:改变工作目录。 • pwd命令:返回当前工作目录。 • run命令:执行当前被调试的程序。 • kill命令:停止正在调试的应用程序。 • list命令:列出正在调试的应用程序的源代码。 • break命令:设置断点。 • watch命令:设置监视点,监视表达式的变化。 • awatch命令:设置读写监视点。当要监视的表达式被读或写时将应用程序挂起。它的语法与watch命令相同。 • rwatch命令:设置读监视点,当监视表达式被读时将程序挂起,等侍调试。此命令的语法与watch相同。 • next命令:执行下一条源代码,但是不进入函数内部。也就是说,将一条函数调用作为一条语句执行。执行这个命令的前提是已经run,开始了代码的执行。
基本gdb命令(2/2) • step命令:执行下一条源代码,进入函数内部。如果调用了某个函数,会跳到函数所在的代码中等候一步步执行。执行这个命令的前提是已经用run开始执行代码。 • display命令:在应用程序每次停止运行时显示表达式的值。 • info break命令:显示当前断点列表,包括每个断点到达的次数 • 16)info files命令:显示调试文件的信息。 • 17)info func命令:显示所有的函数名。 • 18)info local命令:显示当前函数的所有局部变量的信息。 • 19)info prog命令:显示调试程序的执行状态。 • 20)print命令;显示表达式的值。 • 21)delete命令:删除断点。指定一个断点号码,则删除指定断点。不指定参数则删除所有的断点。 • 22)Shell命令:执行Linux Shell命令。 • 23)make命令:不退出gdb而重新编译生成可执行文件。 • 24)Quit命令:退出gdb。
gdb 使用实例(1/2) • /* 一个有错误的 C 源程序 */ #include <stdio.h> #include <stdlib.h> static char buff [256]; static char* string; int main () { printf ("Please input a string: "); gets (string); printf ("\nYour string is: %s\n", string); } • 上面这个程序非常简单,其目的是接受用户的输入,然后将用户的输入打印出来。该程序使用了 一个未经过初始化的字符串地址 string,因此,编译并运行之后,将出现 Segment Fault 错误: $ gcc -o test -g test.c $ ./test Please input a string: asfd Segmentation fault (core dumped)
gdb 使用实例(2/2) • 为了查找该程序中出现的问题,我们利用 gdb,并按如下的步骤进行: • 1.运行 gdb bugging 命令,装入 bugging 可执行文件; • 2.执行装入的 bugging 命令; • 3.使用 where 命令查看程序出错的地方; • 4.利用 list 命令查看调用 gets 函数附近的代码; • 5.唯一能够导致 gets 函数出错的因素就是变量 string。用 print 命令查看 string 的值; • 6.在 gdb 中,我们可以直接修改变量的值,只要将 string 取一个合法的指针值就可以了,为 此,我们在第 11 行处设置断点; • 7.程序重新运行到第 11 行处停止,这时,我们可以用 set variable 命令修改 string 的取值; • 8.然后继续运行,将看到正确的程序运行结果。
GNU make和makefile • GNU make概述 • Makefile 的基本结构 • Makefile中的变量 • GNU make 的主要预定义变量 • Makefile的隐含规则 • make命令行选项 • 使用automake和autoconf产生Makefile
GNU make概述 • 在大型的开发项目中,人们通常利用 make 工具来自动完成编译工作。这些工作包括: • 如果仅修改了某几个源文件,则只重新编译这几个源文件; • 如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。 • 利用这种自动编译可大大简化开发工作,避免不必要的重新编译。 • 实际上,make 工具通过一个称为 makefile 的文件来完成并自动维护编译工作。makefile 需要按照某种语法进行编写,其中说明了如何编译各个源文件并连接生成可执行文件,并定义了源文件之间的依赖关系。 当修改了其中某个源文件时,如果其他源文件依赖于该文件,则也要重新编译所有依赖该文件的源文件。 • 默认情况下,GNU make 工具在当前工作目录按如下顺序搜索 makefile: • GNUmakefile • makefile • Makefile
makefile举例 • Linux程序员使用第三种文件名Makefile。因为第一个字母是大写,通常被列在一个目录的文件列表的最前面。 • 如果要使用其他文件作为 makefile,则可利用类 似下面的 make 命令选项指定 makefile 文件: • $ make -f Makefile.debug • 例1:一个简单的makefile prog:prog1.o prog2.o gcc prog1.o prog2.o -o prog prog1.o:prog1.c lib.h gcc -c -I. -o prog1.o prog1.c prog2.o:prog2.c gcc -c prog2.c
Makefile 的基本结构(1/2) • Makefile是一个文本形式的数据库文件,其中包含一些规则来告诉make处理哪些文件以及如何处理这些文件。 • 规则主要是描述哪些文件(称为target目标文件,不要和编译时产生的目标文件相混淆)是从哪些别的文件(称为dependency依赖文件)中产生的,以及用什么命令(command)来执行这个过程。 • 依靠这些信息,make会对磁盘上的文件进行检查,如果目标文件的生成或被改动时的时间(称为该文件时间戳)至少比它的一个依赖文件还旧的话,make就执行相应的命令,以更新目标文件。 • 目标文件不一定是最后的可执行文件,可以是任何一个中间文件并可以作为其他目标文件的依赖文件。
Makefile 的基本结构(2/2) • Makefile规则的一般形式如下: • target:dependency dependency • (tab)<command> • 一个Makefile文件主要含有一系列的规则,每条规则包含以下内容。 • 一个目标(target),即make最终需要创建的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如“clean”。 • 一个或多个依赖文件(dependency)列表,通常是编译目标文件所需要的其他文件。 • 一系列命今(command),是make执行的动作,通常是把指定的相关文件编译成目标文件的编译命令,每个命令占一行,且每个命令行的起始字符必须为TAB字符。 • 除非特别指定,否则make的工作目录就是当前目录。target是需要创建的二进制文件或目标文件,dependency是在创建target时需要用到的一个或多个文件的列表,命令序列是创建target文件所需要执行的步骤,比如编译命令。
Makefile实例(1/3) • # 以#开头的为注释行 • test:prog.o code.o • gcc –o test prog.o code.o • prog.o:prog.c prog.h code.h • gcc –c prog.c –o prog.o • code.o:code.c code.h • gcc –c code.c –o code.o • clean: • rm –f *.o • 上面的Makefile文件中共定义了四个目标:test、prog.o、code.o和clean。 • 目标从每行的最左边开始写,后面跟一个冒号(:),如果有与这个目标有依赖性的其他目标或文件,把它们列在冒号后面,并以空格隔开。然后另起一行开始写实现这个目标的一组命令。 • 在Makefile中,可使用续行号(\)将一个单独的命令行延续成几行。但要注意在续行号(\)后面不能跟任何字符(包括空格和键)
Makefile实例(2/3) • 一般情况下,调用make命令可输入: • # make target • target是Makefile文件中定义的目标之一,如果省略target,make就将生成Makefile文件中定义的第一个目标。 • 对于上面Makefile的例子,单独的一个“make”命令等价于: • # make test • 因为test是Makefile文件中定义的第一个目标,make首先将其读入,然后从第一行开始执行,把第一个目标test作为它的最终目标,所有后面的目标的更新都会影响到test的更新。 • 第一条规则说明只要文件test的时间戳比文件prog.o或code.o中的任何一个旧,下一行的编译命令将会被执行。
Makefile实例(3/3) • 但是,在检查文件prog.o和code.o的时间戳之前,make会在下面的行中寻找以prog.o和code.o为目标的规则,在第三行中找到了关于prog.o的规则,该文件的依赖文件是prog.c、prog.h和code.h。同样,make会在后面的规则行中继续查找这些依赖文件的规则,如果找不到,则开始检查这些依赖文件的时间戳,如果这些文件中任何一个的时间戳比prog.o的新,make将执行“gcc –c prog.c –o prog.o”命令,更新prog.o文件。 • 以同样的方法,接下来对文件code.o做类似的检查,依赖文件是code.c和code.h。当make执行完所有这些套嵌的规则后,make将处理最顶层的test规则。如果关于prog.o和code.o的两个规则中的任何一个被执行,至少其中一个.o目标文件就会比test新,那么就要执行test规则中的命令,因此make去执行gcc命令将prog.o和code.o连接成目标文件test。 • 在上面Makefile的例子中,还定义了一个目标clean,它是Makefile中常用的一种专用目标,即删除所有的目标模块
make的工作过程 • 现在来看一下make做的工作: • 首先make按顺序读取makefile中的规则, • 然后检查该规则中的依赖文件与目标文件的时间戳哪个更新 • 如果目标文件的时问戳比依赖文件还早,就按规则中定义的命令更新目标文件。 • 如果该规则中的依赖文件又是其他规则中的目标文件,那么依照规则链不断执行这个过程,直到Makefile文件的结束,至少可以找到一个不是规则生成的最终依赖文件,获得此文件的时间戳 • 然后从下到上依照规则链执行目标文件的时间戳比此文件时间戳旧的规则,直到最顶层的规则 • 通过以上的分析过程,可以看到make的优点,因为.o目标文件依赖.c源文件,源码文件里一个简单改变都会造成那个文件被重新编译,并根据规则链依次由下到上执行编译过程,直到最终的可执行文件被重新连接。 • 例如,当改变一个头文件的时候,由于所有的依赖关系都在Makefile里,因此不再需要记住依赖此头文件的所有源码文件,make可以自动的重新编译所有那些因依赖这个头文件而改变了的源码文件,如果需要,再进行重新连接
Makefile中的变量 • Makefile里的变量就像一个环境变量。事实上,环境变量在make中也被解释成make的变量。这些变量对大小写敏感,一般使用大写宇母。几乎可以从任何地方引用定义的变量,变量的主要作用如下: • 保存文件名列表。在前面的例子里,作为依赖文件的一些目标文件名出现在可执行文件的规则中,而在这个规则的命令行里同样包含这些文件并传递给gcc做为命令参数。如果使用一个变量来保存所有的目标文件名,则可以方便地加入新的目标文件而且不易出错。 • 保存可执行命令名,如编译器。在不同的Linux系统中存在着很多相似的编译器系统,这些系统在某些地方会有细微的差别,如果项目被用在一个非gcc的系统里,则必须将所有出现编译器名的地方改成用新的编译器名。但是如果使用一个变量来代替编译器名,那么只需要改变该变量的值。其他所有地方的命令名就都改变了。 • 保存编译器的参数。在很多源代码编译时,gcc需要很长的参数选项,在很多情况下,所有的编译命令使用一组相同的选项,如果把这组选项使用一个变量代表,那么可以把这个变量放在所有引用编译器的地方。当要改变选项的时候,只需改变一次这个变量的内容即可。
变量的定义和使用 • Makefile中的变量是用一个文本串在Makefile中定义的,这个文本串就是变量的值。只要在一行的开始写下这个变量的名字,后面跟一个“=”号,以及要设定这个变量的值即可定义变量,下面是定义变量的语法: • VARNAME=string • 使用时,把变量用括号括起来,并在前面加上$符号,就可以引用变量的值: • ${VARNAME} • make解释规则时,VARNAME在等式右端展开为定义它的字符串。 • 变量一般都在Makefile的头部定义。按照惯例,所有的Makefile变量都应该是大写。如果变量的值发生变化,就只需要在一个地方修改,从而简化了Makefile的维护。
Makefile变量举例 • 现在利用变量把前面的Makefile重写一遍: OBJS=prog.o code.o CC=gcc test:${ OBJS } ${ CC } –o test ${ OBJS } prog.o:prog.c prog.h code.h ${ CC } –c prog.c –o prog.o code.o:code.c code.h ${ CC } –c code.c –o code.o clean: rm –f *.o
变量的类型 • 除用户自定义的变量外,make还允许使用 • 环境变量 • 使用环境变量的方法很简单,在make启动时,make读取系统当前已定义的环境变量,并且创建与之同名同值的变量,因此用户可以像在shell中一样在Makefile中方便的引用环境变量。 • 需要注意的是,如果用户在Makefile中定义了同名的变量,用户自定义变量将覆盖同名的环境变量 • 自动变量 • 预定义变量
GNU make 的主要预定义变量(1/2) • $* 不包含扩展名的目标文件名称。 • $+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。 • $< 第一个依赖文件的名称。 • $? 所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。 • $@ 目标的完整名称。 • $^ 所有的依赖文件,以空格分开,不包含重复的依赖文件。 • $% 如果目标是归档成员,则该变量表示目标的归档成员名称。例如,如果目标名称 为 mytarget.so(image.o),则 $@ 为 mytarget.so,而 $% 为 image.o。 • AR 归档维护程序的名称,默认值为 ar。 • ARFLAGS 归档维护程序的选项。 • AS 汇编程序的名称,默认值为 as。 • ASFLAGS 汇编程序的选项。
GNU make 的主要预定义变量(2/2) • CC C 编译器的名称,默认值为 cc。 • CFLAGS C 编译器的选项。 • CPP C 预编译器的名称,默认值为 $(CC) -E。 • CPPFLAGS C 预编译的选项。 CXX C++ 编译器的名称,默认值为 g++。 • CXXFLAGS C++ 编译器的选项。 • FC FORTRAN 编译器的名称,默认值为 f77。 • FFLAGS FORTRAN 编译器的选项。
Makefile的隐含规则 • 在上面的例子中,几个产生目标文件的命令都是从“.c”的C语言源文件和相关文件通过编译产生“.o”目标文件,这也是一般的步骤。实际上,make可以使工作更加自动化,也就是说,make知道一些默认的动作,它有一些称作隐含规则的内置的规则,这些规则告诉make当用户没有完整地给出某些命令的时候,应该怎样执行。 • 例如,把生成prog.o和code.o的命令从规则中删除,make将会查找隐含规则,然后会找到并执行一个适当的命令。由于这些命令会使用一些变量,因此可以通过改变这些变量来定制make。象在前面的例子中所定义的那样,make使用变量CC来定义编译器,并且传递变量CFLAGS(编译器参数)、CPPFLAGS(C语言预处理器参数)、TARGET_ARCH(目标机器的结构定义)给编译器,然后加上参数-c,后面跟变量$<(第一个依赖文件名),然后是参数-o加变量$@(目标文件名)。 • 综上所述,一个C编译的具体命令将会是: • $ {CC} $ {CFLAGS} $ {CPPFLAGS} $ {TARGET_ARCH} –c $< -o $@
隐含规则举例 • 在上面的例子中,利用隐含规则,可以简化为: • OBJS=prog.o code.o • CC=gcc • test:${ OBJS } • ${ CC } –o $@ $^ • prog.o:prog.c prog.h code.h • code.o:code.c code.h • clean: • rm –f *.o
make命令行选项 • 直接在 make 命令的后面键入目标名可建立指定的目标,如果直接运行 make,则建立第一个目标。还可以用 make -f mymakefile 这样的命令指定 make 使用特定的 makefile,而不是 默认的 GNUmakefile、makefile 或 Makefile。 • GNU make 命令还有一些其他选项,下面是 GNU make 命令的常用命令行选项命令行选项含义: • -C DIR 在读取 makefile 之前改变到指定的目录 DIR。 • -f FILE 以指定的 FILE 文件作为 makefile。 • -h 显示所有的 make 选项。 • -i 忽略所有的命令执行错误。 • -I DIR 当包含其他 makefile 文件时,可利用该选项指定搜索目录。 • -n 只打印要执行的命令,但不执行这些命令。 • -p 显示 make 变量数据库和隐含规则。 • -s 在执行命令时不显示命令。 • -w 在处理 makefile 之前和之后,显示工作目录。 • -W FILE 假定文件 FILE 已经被修改。
使用automake和autoconf产生Makefile • 在开始使用Automake和autoconf之前,请先确认系统已经安装以下的软件: • GNU Automake • GNU Autoconf • GNU m4 • Perl • GNU Libtool (如果你需要产生 shared library) • Automake 所产生的 Makefile 除了可以做到程序的编译和连接,也已经把如何产生程序文件的操作,以及把安装程序都考虑进去了,所以源程序所存放的目录架构最好符合GNU的标准惯例,下面用hello.c 来作为例子进行说明。
生成一个源程序 • 在工作目录下建立一个新的子目录devel,再在devel下建立一个hello的子目录,这个目录将作为存放 hello 这个程序及其相关文件的地方: • 用编辑器写个hello.c文件: • #include <stdio.h> • int main(int argc, char** argv) • { • printf("Hello, GNU!\n"); • return 0; • }
使用 Autoconf 及 Automake 来产生Makefile文件的步骤 • autoscan 产生一个configure.in的模板,执行 autoscan 后会产生一个configure.scan 的文件,可以用它做为configure.in文件的模板: • 编辑configure.scan文件,如下所示,并且把文件名改成configure.in • 执行aclocal和autoconf ,分别会产生 aclocal.m4 及 configure 两个文件: • 编辑Makefile.am文件,内容如下: • 执行automake --add-missing ,Automake 会根据 Makefile.am产生一些文件,包含最重要的Makefile.in: • 最后执行 ./configure
使用SVN/GIT来管理源代码 • Subversion (SVN) • OpenSource • 是CVS的升级软件,目前比较流行 • 每个目录下生成.svn管理文件,不是很方便 • 下面命令可删除所有目录下.svn文件 • find ./ -name .svn | xargs rm -fr • Windows SVN软件:TortoiseSVN-1.6.6.17493-win32-svn-1.6.6.msi • Linux SVN软件:yum install svn 可自动安装 • GIT • OpenSource • 与svn配合使用目前流行 • linux.org已经使用git来管理代码 • 只在根目录下生成一个.git管理文件 • Linux GIT软件:yum install git-svn 可自动安装