Make工程管理器
到此为止,读者已了解了如何在Linux下使用编辑器编写代码,如何使用Gcc把代码编译成可执行文档,还学习了如何使用Gdb来调试程式,那么,任何的工作看似已完成了,为什么还需要Make这个工程管理器呢?
所谓工程管理器,顾名思义,是指管理较多的文档的。读者能够试想一下,有一个上百个文档的代码构成的项目,假如其中只有一个或少数几个文档进行了修改,按照之前所学的Gcc编译工具,就不得不把这任何的文档重新编译一遍,因为编译器并不知道哪些文档是最近更新的,而只知道需要包含这些文档才能把源代码编译成可执行文档,于是,程式员就不能不再重新输入数目如此庞大的文档名以完成最后的编译工作。
但是,请读者仔细回想一下本书在3.1.2节
中所阐述的编译过程,编译过程是分为编译、汇编、链接不同阶段的,其中编译阶段仅检查语法错误连同函数和变量的声明是否正确声明了,在链接阶段则主要完成
是函数链接和全局变量的链接。因此,那些没有改变的源代码根本无需重新编译,而只要把他们重新链接进去就能够了。所以,人们就希望有一个工程管理器能够
自动识别更新了的文档代码,同时又无需重复输入冗长的命令行,这样,Make工程管理器也就应运而生了。
实际上,Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指他能够根据文档时间戳自动发现更新过的文档而减少编译的工作量,同时,他通过读入Makefile文档的内容来执行大量的编译工作。用户只需编写一次简单的编译语句就能够了。他大大提高了实际项目的工作效率,而且几乎任何Linux下的项目编程均会涉及到他,希望读者能够认真学习本节内容。
3.6.1 Makefile基本结构
Makefile是Make读入的惟一配置文档,因此本节的内容实际就是讲述Makefile的编写规则。在一个Makefile中通常包含如下内容:
· 需要由make工具创建的目标体(target),通常是目标文档或可执行文档;
· 要创建的目标体所依赖的文档(dependency_file);
· 创建每个目标体时需要运行的命令(command)。
他的格式为:
target: dependency_files
command
例如,有两个文档分别为hello.c和hello.h,创建的目标体为hello.o,执行的命令为gcc编译指令:gcc –c hello.c,那么,对应的Makefile就能够写为:
#The simplest example
hello.o: hello.c hello.h
gcc –c hello.c –o hello.o
接着就能够使用make了。使用make的格式为:make target,这样make就会自动读入Makefile(也能够是首字母小写makefile)并执行对应target的command语句,并会找到相应的依赖文档。如下所示:
[root@localhost makefile]# make hello.o
gcc –c hello.c –o hello.o
[root@localhost makefile]# ls
hello.c hello.h hello.o Makefile
能够看到,Makefile执行了“hello.o”对应的命令语句,并生成了“hello.o”目标体。
注意
在Makefile中的每一个command前必须有“Tab”符,否则在运行make命令时会出错。
3.6.2 Makefile变量
上面示例的Makefile在实际中是几乎不存在的,因为他过于简单,仅包含两个文档和一个命令,在这种情况下完全不必要编写Makefile而只需在Shell中直接输入即可,在实际中使用的Makefile往往是包含很多的文档和命令的,这也是Makefile产生的原因。下面就可给出稍微复杂一些的Makefile进行讲解:
sunq:kang.o yul.o
Gcc kang.o bar.o -o myprog
kang.o : kang.c kang.h head.h
Gcc –Wall –O -g –c kang.c -o kang.o
yul.o : bar.c head.h
Gcc - Wall –O -g –c yul.c -o yul.o
在这个Makefile中有三个目标体(target),分别为sunq、kang.o和yul.o,其中第一个目标体的依赖文档就是后两个目标体。假如用户使用命令“make sunq”,则make管理器就是找到sunq目标体开始执行。
这时,make会自动检查相关文档的时间戳。首先,在检查“kang.o”、“yul.o”和“sunq”三个文档的时间戳之前,他会向下查找那些把“kang.o”或“yul.o”做为目标文档的时间戳。比如,“kang.o”的依赖文档为:“kang.c”、“kang.h”、“head.h”。假如这些文档中任何一个的时间戳比“kang.o”新,则命令“gcc –Wall –O -g –c kang.c -o kang.o”将会执行,从而更新文档“kang.o”。在更新完“kang.o”或“yul.o”之后,make会检查最初的“kang.o”、“yul.o”和“sunq”三个文档,只要文档“kang.o”或“yul.o”中的任比文档时间戳比“sunq”新,则第二行命令就会被执行。这样,make就完成了自动检查时间戳的工作,开始执行编译工作。这也就是Make工作的基本流程。
接下来,为了进一步简化编辑和维护Makefile,make允许在Makefile中创建和使用变量。变量是在Makefile中定义的名字,用来代替一个文本字符串,该文本字符串称为该变量的值。在具体需要下,这些值能够代替目标体、依赖文档、命令连同makefile文档中其他部分。在Makefile中的变量定义有两种方式:一种是递归展开方式,另一种是简单方式。
递归展开方式定义的变量是在引用在该变量时进行替换的,即假如该变量包含了对其他变量的应用,则在引用该变量时一次性将内嵌的变量全部展开,虽然这种类型的变量能够很好地完成用户的指令,但是他也有严重的缺点,如不能在变量后追加内容(因为语句:CFLAGS = $(CFLAGS) -O在变量扩展过程中可能导致无穷循环)。
为了避免上述问题,简单扩展型变量的值在定义处展开,并且只展开一次,因此他不包含任何对其他变量的引用,从而消除变量的嵌套引用。
递归展开方式的定义格式为:VAR=var
简单扩展方式的定义格式为:VAR:=var
Make中的变量使用均使用格式为:$(VAR)
注意
变量名是不包括“:”、“#”、“=”结尾空格的任何字符串。同时,变量名中包含字母、数字连同下划线以外的情况应尽量避免,因为他们可能在将来被赋予特别的含义。
变量名是大小写敏感的,例如变量名“foo”、“FOO”、和“Foo”代表不同的变量。
推荐在makefile内部使用小写字母作为变量名,预留大写字母作为控制隐含规则参数或用户重载命令选项参数的变量名。
下面给出了上例中用变量替换修改后的Makefile,这里用OBJS代替kang.o和yul.o,用CC代替Gcc,用CFLAGS代替“-Wall -O –g”。这样在以后修改时,就能够只修改变量定义,而无需修改下面的定义实体,从而大大简化了Makefile维护的工作量。
经变量替换后的Makefile如下所示:
OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
$(CC) $(OBJS) -o sunq
kang.o : kang.c kang.h
$(CC) $(CFLAGS) -c kang.c -o kang.o
yul.o : yul.c yul.h
$(CC) $(CFLAGS) -c yul.c -o yul.o
能够看到,此处变量是以递归展开方式定义的。
Makefile中的变量分为用户自定义变量、预定义变量、自动变量及环境变量。如上例中的OBJS就是用户自定义变量,自定义变量的值由用户自行设定,而预定义变量和自动变量为通常在Makefile都会出现的变量,其中部分有默认值,也就是常见的设定值,当然用户能够对其进行修改。
预定义变量包含了常见编译器、汇编器的名称及其编译选项。下表3.14列出了Makefile中常见预定义变量及其部分默认值。
表3.14 Makefile中常见预定义变量
命 令 格 式
含 义
AR
库文档维护程式的名称,默认值为ar
AS
汇编程式的名称,默认值为as
CC
C编译器的名称,默认值为cc
CPP
C预编译器的名称,默认值为$(CC) –E
CXX
C++编译器的名称,默认值为g++
FC
FORTRAN编译器的名称,默认值为f77
RM
文档删除程式的名称,默认值为rm –f
ARFLAGS
库文档维护程式的选项,无默认值
ASFLAGS
汇编程式的选项,无默认值
CFLAGS
C编译器的选项,无默认值
CPPFLAGS
C预编译的选项,无默认值
CXXFLAGS
C++编译器的选项,无默认值
FFLAGS
FORTRAN编译器的选项,无默认值
能够看出,上例中的CC和CFLAGS是预定义变量,其中由于CC没有采用默认值,因此,需要把“CC=Gcc”明确列出来。
由于常见的Gcc编译语句中通常包含了目标文档和依赖文档,而这些文档在Makefile文档中目标体的一行已有所体现,因此,为了进一步简化Makefile的编写,就引入了自动变量。自动变量通常能够代表编译语句中出现目标文档和依赖文档等,并且具备本地含义(即下一语句中出现的相同变量代表的是下一语句的目标文档和依赖文档)。下表3.15列出了Makefile中常见自动变量。
表3.15 Makefile中常见自动变量
命令格式
含 义
$*
不包含扩展名的目标文档名称
$+
任何的依赖文档,以空格分开,并以出现的先后为序,可能包含重复的依赖文档
$
第一个依赖文档的名称
$?
任何时间戳比目标文档晚的依赖文档,并以空格分开
命令格式
含 义
$@
目标文档的完整名称
$^
任何不重复的依赖文档,以空格分开
$%
假如目标是归档成员,则该变量表示目标的归档成员名称
自动变量的书写比较难记,但是在熟练了之后会很的方便,请读者结合下例中的自动变量改写的Makefile进行记忆。
OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
$(CC) $^ -o $@
kang.o : kang.c kang.h
$(CC) $(CFLAGS) -c $
yul.o : yul.c yul.h
$(CC) $(CFLAGS) -c $
另外,在Makefile中还能够使用环境变量。使用环境变量的方法相对比较简单,make在启动时会自动读取系统当前已定义了的环境变量,并且会创建和之具备相同名称和数值的变量。但是,假如用户在Makefile中定义了相同名称的变量,那么用户自定义变量将会覆盖同名的环境变量。
3.6.3 Makefile规则
Makefile的规则是Make进行处理的依据,他包括了目标体、依赖文档及其之间的命令语句。一般的,Makefile中的一条语句就是个规则。在上面的例子中,都显示地指出了Makefile中的规则关系,如“$(CC) $(CFLAGS) -c $”,但为了简化Makefile的编写,make还定义了隐式规则和模式规则,下面就分别对其进行讲解。
1.隐式规则
隐含规则能够告诉make怎样使用传统的技术完成任务,这样,当用户使用他们时就不必周详指定编译的具体细节,而只需把目标文档列出即可。Make会自动搜索隐式规则目录来确定如何生成目标文档。如上例就能够写成:
OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
$(CC) $^ -o $@
为什么能够省略后两句呢?因为Make的隐式规则指出:任何“.o”文档都可自动由“.c”文档使用命令“$(CC) $(CPPFLAGS) $(CFLAGS) -c file.c –o file.o”生成。这样“kang.o”和“yul.o”就会分别调用“$(CC) $(CFLAGS) -c kang.c -o kang.o”和“$(CC) $(CFLAGS) -c yul.c -o yul.o”生成。
注意
在隐式规则只能查找到相同文档名的不同后缀名文档,如”kang.o”文档必须由”kang.c”文档生成。
下表3.16给出了常见的隐式规则目录:
表3.16 Makefile中常见隐式规则目录
对应语言后缀名
规 则
C编译:.c变为.o
$(CC) –c $(CPPFLAGS) $(CFLAGS)
C++编译:.cc或.C变为.o
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)
Pascal编译:.p变为.o
$(PC) -c $(PFLAGS)
Fortran编译:.r变为-o
$(FC) -c $(FFLAGS)
2.模式规则
模式规则是用来定义相同处理规则的多个文档的。他不同于隐式规则,隐式规则仅仅能够用make默认的变量来进行操作,而模式规则还能引入用户自定义变量,为多个文档建立相同的规则,从而简化Makefile的编写。
模式规则的格式类似于普通规则,这个规则中的相关文档前必须用“%”标明。使用模式规则修改后的Makefile的编写如下:
OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
$(CC) $^ -o $@
%.o : %.c
$(CC) $(CFLAGS) -c $
3.6.4 Make使用
使用make管理器很简单,只需在make命令的后面键入目标名即可建立指定的目标,假如直接运行make,则建立Makefile中的第一个目标。
此外make更有丰富的命令行选项,能够完成各种不同的功能。下表3.17列出了常用的make命令行选项。
表3.17 make的命令行选项
命令格式
含 义
-C dir
读入指定目录下的Makefile
-f file
读入当前目录下的file文档作为Makefile
命令格式
含 义
-i
忽略任何的命令执行错误
-I dir
指定被包含的Makefile所在目录
-n
只打印要执行的命令,但不执行这些命令
-p
显示make变量数据库和隐含规则
-s
在执行命令时不显示命令
-w
假如make在执行过程中改变目录,则打印当前目录名
3.7 使用autotools
在上一小节,读者已了解到了make项目管理器的强大功能。的确,Makefile能够帮助make完成他的使命,但要承认的是,编写Makefile确实不是一件轻松的事,尤其对于一个较大的项目而言更是如此。那么,有没有一种轻松的手段生成Makefile而同时又能让用户享受make的优越性呢?本节要讲的autotools系列工具正是为此而设的,他只需用户输入简单的目标文档、依赖文档、文档目录等就能够轻松地生成Makefile了,这无疑是广大用户的所希望的。另外,这些工具还能够完成系统配置信息的收集,从而能够方便地处理各种移植性的问题。也正是基于此,现在Linux上的软件研发一般都用autotools来制作Makefile,读者在后面的讲述中就会了解到。
3.7.1 autotools使用流程
正如前面所言,autotools是系列工具,读者首先要确认系统是否装了以下工具(能够用which命令进行查看)。
· aclocal
· autoscan
· autoconf
· autoheader
· automake
使用autotools主要就是利用各个工具的脚本文档以生成最后的Makefile。其总体流程是这样的:
· 使用aclocal生成一个“aclocal.m4”文档,该文档主要处理本地的宏定义;
· 改写“configure.scan”文档,并将其重命名为“configure.in”,并使用autoconf文档生成configure文档。
接下来,笔者将通过一个简单的hello.c例子带领读者熟悉autotools生成makefile的过程,由于在这过程中有涉及到较多的脚本文档,为了更清楚地了解相互之间的关系,强烈建议读者实际动手操作以体会其整个过程。
1.autoscan
他会在给定目录及其子目录树中检查源文档,若没有给出目录,就在当前目录及其子目录树中进行检查。他会搜索源文档以寻找一般的移植性问题并创建一个文档“configure.scan”,该文档就是接下来autoconf要用到的“configure.in”原型。如下所示:
[root@localhost automake]# autoscan
autom4te: configure.ac: no such file or directory
autoscan: /usr/bin/autom4te failed with exit status: 1
[root@localhost automake]# ls
autoscan.log configure.scan hello.c
如上所示,autoscan首先会尝试去读入“configure.ac”(同configure.in的配置文档)文档,此时还没有创建该配置文档,于是他会自动生成一个“configure.in”的原型文档“configure.scan”。
2.autoconf
configure.in是autoconf的脚本配置文档,他的原型文档“configure.scan”如下所示:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
#The next one is modified by sunq
#AC_INIT(FULL-PACKAGE-NAME,VERSION,BUG-REPORT-ADDRESS)
AC_INIT(hello,1.0)
# The next one is added by sunq
AM_INIT_AUTOMAKE(hello,1.0)
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
下面对这个脚本文档进行解释:
· 以“#”号开始的行为注释。
· AC_PREREQ宏声明本文档需要的autoconf版本,如本例使用的版本2.59。
· AC_INIT宏用来定义软件的名称和版本等信息,在本例中省略了BUG-REPORT-ADDRESS,一般为作者的e-mail。
· AM_INIT_AUTOMAKE是笔者另加的,他是automake所必备的宏,也同前面相同,PACKAGE是所要产生软件套件的名称,VERSION是版本编号。
· AC_CONFIG_SRCDIR宏用来侦测所指定的源码文档是否存在,来确定源码目录的有
效性。在此处为当前目录下的hello.c。
· AC_CONFIG_HEADER宏用于生成config.h文档,以便autoheader使用。
· AC_CONFIG_FILES宏用于生成相应的Makefile文档。
· 中间的注释间能够添加分别用户测试程式、测试函数库、测试头文档等宏定义。
接下来首先运行aclocal,生成一个“aclocal.m4”文档,该文档主要处理本地的宏定义。如下所示:
[root@localhost automake]# aclocal
再接着运行autoconf,生成“configure”可执行文档。如下所示:
[root@localhost automake]# autoconf
[root@localhost automake]# ls
aclocal.m4 autom4te.cache autoscan.log configure configure.in hello.c
3.autoheader
接着使用autoheader命令,他负责生成config.h.in文档。该工具通常会从“acconfig.h”文档中复制用户附加的符号定义,因此此处没有附加符号定义,所以无需创建“acconfig.h”文档。如下所示:
[root@localhost automake]# autoheader
4.automake
这一步是创建Makefile很重要的一步,automake要用的脚本配置文档是Makefile.am,用户需要自己创建相应的文档。之后,automake工具转换成Makefile.in。在该例中,笔者创建的文档为Makefile.am如下所示:
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS= hello
hello_SOURCES= hello.c
下面对该脚本文档的对应项进行解释。
· 其中的AUTOMAKE_OPTIONS为配置automake的选项。由于GNU(在第1章中已有所介绍)对自己发布的软件有严格的规范,比如必须附带许可证声明文档COPYING等,否则automake执行时会报错。automake提供了三种软件等级:foreign、gnu和gnits,让用户选择采用,默认等级为gnu。在本例使用foreign等级,他只检测必须的文档。
· bin_PROGRAMS定义要产生的执行文档名。假如要产生多个执行文档,每个文档名用空格隔开。
· hello_SOURCES定义“hello”这个执行程式所需要的原始文档。假如”hello”这个程式是由多个原始文档所产生的,则必须把他所用到的任何原始文档都列出来,并用空格隔开。例如:若目标体“hello”需要“hello.c”、“sunq.c”、“hello.h”三个依赖文档,则定义hello_SOURCES=hello.c sunq.c hello.h。要注意的是,假如要定义多个执行文档,则对每个执行程式都要定义相应的file_SOURCES。
接下来能够使用automake对其生成“configure.in”文档,在这里使用选项“—adding-missing”能够让automake自动添加有一些必需的脚本文档。如下所示:
[root@localhost automake]# automake --add-missing
configure.in: installing './install-sh'
configure.in: installing './missing'
Makefile.am: installing 'depcomp'
[root@localhost automake]# ls
aclocal.m4 autoscan.log configure.in hello.c Makefile.am missing
autom4te.cache configure depcomp install-sh Makefile.in config.h.in
能够看到,在automake之后就能够生成configure.in文档。
5.运行configure
在这一步中,通过运行自动配置配置文档configure,把Makefile.in变成了最终的Makefile。如下所示:
[root@localhost automake]# ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build enVironment is sane... yes
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for Gcc... Gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether Gcc accepts -g... yes
checking for Gcc option to accept ANSI C... none needed
checking for style of include used by make... GNU
checking dependency style of Gcc... Gcc3
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands
能够看到,在运行configure时收集了系统的信息,用户能够在configure命令中对其进行方便地配置。在./configure的自定义参数有两种,一种是开关式(--enable-XXX或--disable-XXX),另一种是开放式,即后面要填入一串字符(--with-XXX=yyyy)参数。读者能够自行尝试其使用方法。另外,读者能够查看同一目录下的”config.log”文档,以方便调试之用。
到此为止,makefile就能够自动生成了。回忆整个步骤,用户不再需要定制不同的规则,而只需要输入简单的文档及目录名即可,这样就大大方便了用户的使用。下面的图3.9总结了上述过程:
图3.9 autotools生成Makefile流程图
3.7.2 使用autotools所生成的Makefile
autotools生成的Makefile除具备普通的编译功能外,还具备以下主要功能(感兴趣的读者能够查看这个简单的hello.c程式的makefile):
1.make
键入make默认执行”make all”命令,即目标体为all,其执行情况如下所示:
[root@localhost automake]# make
if Gcc
-DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\"
-DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"hello\"
-DVERSION=\"1.0\" -I. -I. -g -O2 -MT hello.o -MD -MP -MF
".deps/hello.Tpo" -c -o hello.o hello.c; \
then mv -f ".deps/hello.Tpo" ".deps/hello.Po"; else rm -f ".deps/hello.Tpo"; exit 1; fi
Gcc -g -O2 -o hello hello.o
此时在本目录下就生成了可执行文档“hello”,运行“./hello”能出现正常结果,如下所示:
[root@localhost automake]# ./hello
Hello!Autoconf!
2.make install
此时,会把该程式安装到系统目录中去,如下所示:
[root@localhost automake]# make install
if Gcc
-DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\"
-DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"hello\"
-DVERSION=\"1.0\" -I. -I. -g -O2 -MT hello.o -MD -MP -MF
".deps/hello.Tpo" -c -o hello.o hello.c; \
then mv -f ".deps/hello.Tpo" ".deps/hello.Po"; else rm -f ".deps/hello.Tpo"; exit 1; fi
Gcc -g -O2 -o hello hello.o
make[1]: Entering directory '/root/workplace/automake'
test -z "/usr/local/bin" || mkdir -p -- "/usr/local/bin"
/usr/bin/install -c 'hello' '/usr/local/bin/hello'
make[1]: Nothing to be done for 'install-data-am'.
make[1]: LeaVing directory '/root/workplace/automake'
此时,若直接运行hello,也能出现正确结果,如下所示:
[root@localhost automake]# hello
Hello!Autoconf!
3.make clean
此时,make会清除之前所编译的可执行文档及目标文档(object file, *.o),如下所示:
[root@localhost automake]# make clean
test -z "hello" || rm -f hello
rm -f *.o
4.make dist
此时,make将程式和相关的文档打包为一个压缩文档以供发布,如下所示:
[root@localhost automake]# make dist
[root@localhost automake]# ls hello-1.0-tar.gz
hello-1.0-tar.gz
可见该命令生成了一个hello-1.0-tar.gz的压缩文档。
由上面的讲述读者不难看出,autotools确实是软件维护和发布的必备工具,也鉴于此,如今GUN的软件一般都是由automake来制作的。
想一想
对于automake制作的这类软件,应如何安装呢?
3.8.3 编写包含多文档的Makefile
1.实验目的
通过对包含多文档的Makefile的编写,熟悉各种形式的Makefile,并且进一步加深对Makefile中用户自定义变量、自动变量及预定义变量的理解。
2.实验过程
(1)用Vi在同一目录下编辑两个简单的Hello程式,如下所示:
#hello.c
#include "hello.h"
int main()
{
printf("Hello everyone!\n");
}
#hello.h
#include
(2)仍在同一目录下用Vi编辑Makefile,且不使用变量替换,用一个目标体实现(即直接将hello.c和hello.h编译成hello目标体)。然后用make验证所编写的Makefile是否正确。
(3)将上述Makefile使用变量替换实现。同样用make验证所编写的Makefile是否正确
(4)用编辑另一Makefile,取名为Makefile1,不使用变量替换,但用两个目标体实现(也就是首先将hello.c和hello.h编译为hello.o,再将hello.o编译为hello),再用make的”-f”选项验证这个Makefile1的正确性。
(5)将上述Makefile1使用变量替换实现。
3.实验步骤
(1)用Vi打开上述两个代码文档“hello.c”和“hello.h”。
(2)在shell命令行中用Gcc尝试编译,使用命令:”Gcc hello.c –o hello”,并运行hello可执行文档查看结果。
(3)删除此次编译的可执行文档:rm hello。
(4)用Vi编辑Makefile,如下所示:
hello:hello.c hello.h
Gcc hello.c -o hello
(5)退出保存,在shell中键入:make,查看结果。
(6)再次用Vi打开Makefile,用变量进行替换,如下所示:
OBJS :=hello.o
CC :=Gcc
hello:$(OBJS)
$(CC) $^ -o $@
(7)退出保存,在shell中键入:make,查看结果。
(8)用Vi编辑Makefile1,如下所示:
hello:hello.o
Gcc hello.o -o hello
hello.o:hello.c hello.h
Gcc -c hello.c -o hello.o
(9)退出保存,在shell中键入:make -f Makefile1,查看结果。
(10)再次用Vi编辑Makefile1,如下所示:
OBJS1 :=hello.o
OBJS2 :=hello.c hello.h
CC :=Gcc
hello:$(OBJS1)
$(CC) $^ -o $@
$(OBJS1):$(OBJS2)
$(CC) -c $
在这里请注意区别“$^”和“$”。
(11)退出保存,在shell中键入:make -f Makefile1,查看结果
4.实验结果
各种不同形式的makefile都能完成其正确的功能。
3.8.4 使用autotools生成包含多文档的Makefile
1.实验目的
通过使用autotools生成包含多文档的Makefile,进一步掌控autotools的正确使用方法。同时,掌控Linux下安装软件的常用方法。
2.实验过程
(1)在原目录下新建文档夹auto。
(2)利用上例的两个代码文档“hello.c”和“hello.h”,并将他们复制到该目录下。
(3)使用autoscan生成configure.scan。
(4)编辑configure.scan,修改相关内容,并将其重命名为configure.in。
(5)使用aclocal生成aclocal.m4。
(6)使用autoconf生成configure。
(7)使用autoheader生成config.in.h。
(8)编辑Makefile.am。
(9)使用automake生成Makefile.in。
(10)使用configure生成Makefile。
(11)使用make生成hello可执行文档,并在当前目录下运行hello查看结果。
(12)使用make install将hello安装到系统目录下,并运行,查看结果。
(13)使用make dist生成hello压缩包。
(14)解压hello压缩包。
(15)进入解压目录。
(16)在该目录下安装hello软件。
3.实验步骤
(1)mkdir ./auto。
(2)cp hello.* ./auto(假定原先在“hello.c”文档目录下)。
(3)命令:autoscan。
(4)使用Vi编辑configure.scan为:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(hello, 1.0)
AM_INIT_AUTOMAKE(hello,1.0)
AC_CONFIG_SRCDIR([hello.h])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT(Makefile)
(5)保存退出,并重命名为configure.in。
(6)运行:aclocal。
(7)运行:autoconf,并用ls查看是否生成了configure可执行文档。
(8)运行:autoheader。
(9)用Vi编辑Makefile.am文档为:
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=hello
hello_SOURCES=hello.c hello.h
(10)运行:automake。
(11)运行:./configure。
(12)运行:make。
(13)运行:./hello,查看结果是否正确。
(14)运行:make install。
(15)运行:hello,查看结果是否正确。
(16)运行:make dist。
(17)在当前目录下解压hello-1.0.tar.gz:tar –zxvf hello-1.0.tar.gz。
(18)进入解压目录:cd ./hello-1.0。
(19)下面开始Linux下常见的安装软件步骤:./configure。
(20)运行:make。
(21)运行:./hello(在正常安装时这一步可省略)。
(22)运行:make install。
(23)运行:hello,查看结果是否正确。
4.实验结果
能够正确使用autotools生成Makefile,并且能够安装成功短小的Hello软件。