为梦而战
全部博文(185)
分类: LINUX
2014-05-30 23:46:59
从源代码创建一个gnu程序的3步骤是./configure;make;make install。
有时并非上述那样简单,包括gemfield在内的用户需要通过自定义一些配置来满足自己的需求。比如,一些configure的基本选项就用来对安装程序进行“微调”。这些常用的基本选项有:
--prefix(确定安装的根目录)
--bindir(可执行文件的存放位置)
--libdir(确定共享库的安装/存放位置)
--program-suffix(向程序中添加一个后缀)
--enable-languages(--enable-languages=c,c++,只是用c和c++编译器)
上述功能的实现就是gnu构建工具的表现形式。构建工具和自动化工具(autotools)大抵是工具链(toolchain)的核心所在了。gemfield先说说构建工具的三个阶段吧。
第一个当然是configure,也就是配置阶段(configure stage)。这一阶段主要是通过configure脚本(从哪里来的?)来处理所有琐碎的细节问题,configure会检查你的系统(不管你用的是zsxx发行版还是其他linux发行版),确定是否有必须的已经安装的库和工具,比如gcc编译器。一些小型的项目已经包含了makefile,那么这个时候就不需要configure,但通常的情况是configure通过读取makefile.in(已经存在于源码包里)来创建一个makefile。
第2个阶段就是构建阶段(make stage),这一阶段的make不带任何参数,这一阶段将创建所有的目标文件,gnu构建工具是创建了一些伪目标的(默认的伪目标是all,all这个伪目标是用来创建所有的库和可执行文件),在这些伪目标中,除了all之外,还有clean(删除由all目标创建的目标文件和库)和install(将程序安装到运行configure时确定的目录下,这在第3阶段使用)。
如果在没有错误提示的情况下完成了上述的make stage,我们就来到了第3个阶段:安装阶段,make install,如果configure没有指定安装目录,默认路径为/usr/local/bin。
到这一步,我们已经能够把下载的或者自己编写的源代码安装在zsxx或者其他的linux操作系统里了。但一个疑问是,上文中的congfigure脚本以及makefile.in是怎么来的呢?下面gemfield不得不说的就是,autotool自动化工具的强大了(请确保你的系统中已经安装了autotools工具)。
为linux编写的软件不仅应该在运行于相同硬件平台上的发行版之间尽可能实现二进制兼容,还应该可以在大多数已提供正确的函数库和其他必备条件的系统中编译成功。正是为了实现不同编译环境之间的源代码级的可移植性,人们创建了GNU的自动化工具(autotools)。autotools的目的就是要生成一个针对源代码的合适的makefile文件。
作为示例,gemfield应用的是gemfield博客-程序语言-《制作共享函数库》一文中的正弦实现的代码:包括一个zhengxian.c文件和libsin.so共享函数库(正弦函数库的实现参见上一句中提到的文章)。这两个文件的路径为/home/gemfield/zx。
首先使用的就是autotools中的用perl语言编写的autoscan工具,Autoscan工具用来扫描源代码zsxx.c以搜寻一般的可移植性问题,比如检查编译器、库和头文件等,并创建configure.scan文件,它会在给定目录及其子目录树中检查源文件,若没有给出目录(autoscan的参数),就在当前目录及其子目录树中进行检查。
在bash中使用autoscan命令,产生一个名叫configure.scan的文件,内容如下:
*************************************************************************************
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
AC_CONFIG_SRCDIR([zhengxian.c])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([stdlib.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT
************************************************************************************
configure.scan文件包含了一些AC宏,主要是一些配置选项。这个文件需要被改名为configure.ac(改为configure.in也一样),以被后面的autoconf使用以生成会检查系统特性、环境变量、软件必须的参数的shell脚本。configure.ac文件中的宏的顺序并没有规定,但是你必须在所有宏的最前面和最后面分别加上AC_INIT宏和AC_OUTPUT宏。一句话,也即configure.in由configure.scan文件更名而来,文件内容都是以AC_INIT开头,以AC_OUTPUT结束。
confiugre.ac文件的一般布局是:
************************************************************************************
AC_INIT
测试程序
测试函数库
测试头文件
测试类型定义
测试结构
测试编译器特性
测试库函数
测试系统调用
AC_OUTPUT
**************************************************************************************
关于这个configure.ac,恐怕gemfield需要稍稍修改一下,因为从上面生成的结果来看,就连最后一个宏AC_OUTPUT也没有要输出的文件名。我们需要的是makefile文件,因此最后一句修改为AC_OUTPUT(makefile)。还有,因为等会儿还要使用automake,所以此处必须添加AM_INIT_AUTOMAKE(PACKAGE, VERSION)宏,当你使用make dist命令时,它会给你生成一个类似zhengxian-1.0.tar.gz的软件发行包,其中就有对应的软件包的名字和版本号。
另外,我们还需要引用自己的linsin.so共享库文件,因此要添加AC_CHECK_LIB (library, function, [action-if-found], [action-if-not-found], [other-libraries])宏,该宏用来检查lib库中是否存在指定的函数。当测试成功时,执行shell命令action_if_found或者action_if_found当为空时,在输出变量LIBS中添加-llib。 action_if_not_found把-lother_libs选项传给link命令。最终修改完的configure.ac文件内容如下:
**************************************************************************************
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
AC_INIT(zhengxian, 1.0, gemfield@syszux.com)
AM_INIT_AUTOMAKE(zhengxian,1.0)
AC_CONFIG_SRCDIR([zhengxian.c])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
AC_CHECK_LIB(sin,main)
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([stdlib.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT(makefile)
**************************************************************************************
接下来要使用aclocal工具生成aclocal.m4文件,aclocal是一个perl 脚本程序。aclocal根据configure.ac文件的内容,自动生成aclocal.m4文件。aclocal的定义是:“aclocal – create aclocal.m4 by scanning configure.ac”。执行aclocal后我们会得到aclocal.m4文件。m4是传统Unix的宏处理的安装启动的应用,其对应的是.m4文件,它记录了很多无法理解的宏。关于这个m4文件的更多认识可以访问。到这时,zx目录下已经有了configure.in和aclocal.m4 两个关键文件,gemfield就可以使用autoconf来产生configure文件了。
autoconf所需的原材料都具备了之后,在bash中执行autoconf命令,它将configure.ac中的宏展开,生成configure脚本。这个过程要用到aclocal.m4中定义的宏。这样configure脚本就完成了。接下来使用autoheader工具:
autoheader工具负责生成config.h.in文件。当此后gemfield在目标系统中运行configure脚本时,它将用于生成有用的头文件configure.h。
现在需要手工编写makefile.am文件,Automake工具会根据configure.in中的参量把Makefile.am转换成Makefile.in文件。在使用Automake工具前,gemfield此刻需要手工创建脚本配置文件Makefile.am。内容如下:
**************************************************
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = zhengxian
zhengxian_SOURCES = zhengxian.c
zhengxian_LDADD=libsin.so
**************************************************
注意最后一句是引用的函数库,对于gemfield本文来说,若不声明最后一句,将带来错误,比如main函数中的sin函数会被提示没有声明。
(界面大致如下:
zhengxian.o: In function `main’:
/home/gemfield/zx/zhengxian.c:9: undefined reference to `sin’)
然后使用在bash中使用automake指令,将gemfield手工打造的makefile.am转换成makefile.in文件(makefile.in是生成makefile的原材料),此刻makefile.in已经内容复杂了。gemfield此处要用到automake的选项”–add-missing”,以让Automake自动添加一些必需的脚本文件。
最后,运行此前生成的configure脚本
./configure
将makefile.in变成最终的makefile文件:
***************************************************************
gemfield@gemfield-laptop:~/zx$ ./configure
checking for a BSD-compatible install… /usr/bin/install -c
checking whether build environment is sane… yes
checking for a thread-safe mkdir -p… /bin/mkdir -p
checking for gawk… no
…………
***************************************************************
你可以看到configure是如何报告它所执行的每个测试的状态的。你可以看到很多类似于“checking for……”的输出,这正表明了configure为gemfield所作的各项测试。运行完configure后,你就看到源代码目录里有了一个新创建的configure.h文件。该文件中的每一个define声明对应配置过程中的一项成功测试。源代码zhengxian.c要使用这些定义。到这里,已经回到了本文中开始部分提到的构建gnu程序的三部曲了,接下来使用make,make install就可以了。
****************************************************************************************
gemfield@gemfield-laptop:~/zx$ make
make all-am
make[1]: 正在进入目录 `/home/gemfield/zx’
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT zhengxian.o -MD -MP -MF .deps/zhengxian.Tpo -c -o zhengxian.o zhengxian.c
mv -f .deps/zhengxian.Tpo .deps/zhengxian.Po
gcc -g -O2 -o zhengxian zhengxian.o libsin.so
make[1]:正在离开目录 `/home/gemfield/zx’
****************************************************************************************
然后使用make install指令(你可以使用sudo make install,如果遇到权限的问题的话)。make install将把二进制程序zhengxian安装到/usr/local/bin下。不过你可以通过configure --prefix定制这个安装路径。
**************************************************************
gemfield@gemfield-laptop:~/zx$ sudo make install
make[1]: 正在进入目录 `/home/gemfield/zx’
test -z “/usr/local/bin” || /bin/mkdir -p “/usr/local/bin”
/usr/bin/install -c ‘zhengxian’ ‘/usr/local/bin/zhengxian’
make[1]: 没有什么可以做的为 `install-data-am’。
make[1]:正在离开目录 `/home/gemfield/zx’
**************************************************************
然后执行程序zhengxian来检验一下:
**************************************************************************************
gemfield@gemfield-laptop:~/zx$ ./zhengxian
./zhengxian: error while loading shared libraries: libsin.so: cannot open shared object file: No such file or directory
**************************************************************************************
不过gemfield前面已经遇到过这种库搜索路径的问题了,将当前路径export为库搜索路径(configure选项里有个--libdir,但gemfield暂时还不知道怎么使用,正在研究中:)):
**************************************************************************************
gemfield@gemfield-laptop:~/zx$ export LD_LIBRARY_PATH=$PWD
gemfield@gemfield-laptop:~/zx$ ./zhengxian
please input an angle(in radians)2
sin(2.000000)=0.909347
**************************************************************************************
就这样。最后给一个图来总结一下: