在 Unix 上写过程序的人尤其是用 C 来开发程序的人一般都遇到过 Makefile,用 make 来开发和编译程序的确很方便,可是要写出一个 Makefile 就不那么简单了。GNU Autoconf 及Automake 这两个软件就是帮助程序开发者轻松产生 Makefile 文件的。现在的 GNU 软件如 Apache, MySQL Minigui 等都是利用 Autoconf,Automake实现自动编译的。用户只要使用 “./configure”, “make”, “make install” 就可以把程序安裝到系统中。
具体地:
1、configure,这一步一般用来生成 Makefile,为下一步的编译做准备,你可以通过在 configure 后加上参数来对安装进行控制,比如代码: ./configure –prefix=/usr 意思是将该软件安装在 /usr 下面,执行文件就会安装在 /usr/bin (而不是默认的 /usr/local/bin),资源文件就会安装在 /usr/share(而不是默认的/usr/local/share)。同时一些软件的配置文件你可以通过指定 –sys-config= 参数进行设定。有一些软件还可以加上 –with、–enable、–without、–disable 等等参数对编译加以控制,你可以通过允许 ./configure –help 察看详细的说明帮助。
2、make,这一步就是编译,大多数的源代码包都经过这一步进行编译(当然有些perl或python编写的软件需要调用perl或python来进行编译)。如果 在 make 过程中出现 error ,你就要记下错误代码(注意不仅仅是最后一行),然后你可以向开发者提交 bugreport(一般在 INSTALL 里有提交地址),或者你的系统少了一些依赖库等,这些需要自己仔细研究错误代码。
3、make insatll,这条命令来进行安装(当然有些软件需要先运行 make check 或 make test 来进行一些测试),这一步一般需要你有 root 权限(因为要向系统写入文件)
4、最后,可以运行make clean删除临时文件;make distclean:除了清除可执行文件和目标文件外,把configure所产生的Makefile也清除掉。
下面介绍详细使用步骤。
目录结构:
|- sample
|- src : 存放源代码文件 main.c
|- lib : 存放生成库文件 hello.c
|- include: 存放库中头文件 hello.h
main.c:
#include "hello.h"
int main()
{
char* s = "Mr.Sandman";
hello(s);
return 0;
}
hello.c
#include <stdio.h>
void hello(char* str)
{
printf("Hello %s\n",str);
}
hello.h
void hello(char* str);
生成静态库:
1. 编写lib/Makefile.am 文件
# touch Makefile.am
# vim Makefile.am
第一行AUTOMAKE_OPTIONS 是Automake 的选项。设置为foreign 时,Automake 会用一般软件的标准来检查。如果不加这句,在执行Automake 时,会检查目录下是否存在标准GNU软件中应具备的文件,例如’NEWS’、‘AUTHOR’、 ‘ChangeLog’ 等文件,需要在autoconf之前,先执行touch NEWS README AUTHORS ChangeLog 来生成对应文件。
第二行表示用来生成静态库的源文件。前缀为libmyhello_a_,对应静态库名为libmyhello.a。
第三行noinst 表示生成的静态库,不需要make install ,直接指定它的位置和名字就可以使用。
2 执行autoscan 生成configure.scan 文件,将它重命名为configure.ac 并修改其内容
注:修改原因为autoconf只能识别configure.ac的后缀名
# autoscan
# ls
autoscan.log configure.scan hello.c Makefile.am
# mv configure.scan configure.ac
# vim configure.ac
主要修改如下:
- 修改AC_INIT([软件名], [版本编号], [])
- 增加AM_INIT_AUTOMAKE,防止报错
- 增加 AC_PROG_RANLIB,因为使用了静态库
另外:
- AC_PROG_CC 检查系统可用的C 编译器,若源代码是用C 写的就需要这个宏。
- AC_OUTPUT([Makefile]) 用于设置 configure 所产生的文件,若是Makefile ,configure 便会把它检查出来的结果填充到Makefile.ac 文件后产生合适的 Makefile。 后面的FILE 是一个Makefile 的输出列表
3.依次执行下列指令,在lib目录下生成了静态库libmyhello.a
# aclocal
# autoconf
# autoheader
# automake --add-missing
# ./configure
# make
# ls
aclocal.m4 config.h.in configure.ac hello.o Makefile.am
autom4te.cache config.log depcomp install-sh Makefile.in
compile config.status hello.c libmyhello.a missing
config.h configure hello.c~ Makefile stamp-h1
生成可执行文件:
1. 编写src/Makefile.am 文件
- 第二行指定头文件的位置,-I 是idirafter 的缩写。…/include 指定头文件的位置,…是上 一级目录,也就是这里的example 目录。
- 第三行指定生成可执行文件名main,在这里可执行文件生成在src 下,建议将可执行文件生成到一个特定的文件夹下,让它和源代码分开。
- 第四行指定生成可执行文件main的源代码文件,如果main.c 在其他目录下,需要加上 完整的路径。
- 第五行指定需要使用静态库的位置。
2. 执行autoscan 生成configure.scan 文件,将它重命名为configure.ac 并修改其内容
# autoscan
# ls
autoscan.log configure.scan main.c Makefile.am
# mv configure.scan configure.ac
# vim configure.ac
主要修改如下:
- 修改AC_INIT([软件名], [版本编号], [])
- 增加AM_INIT_AUTOMAKE,防止报错
3.依次执行下列指令,在src目录下生成了可执行文件main
c# aclocal
# autoconf
# autoheader
# automake --add-missing
# ./configure
# make
# ./main
Hello Mr.Sandman
# make install
# make clean
# make dist
# ls
aclocal.m4 config.h configure main-1.0.tar.gz Makefile.in
autom4te.cache config.h.in configure.ac main.c missing
autoscan.log config.log depcomp Makefile stamp-h1
compile config.status install-sh Makefile.am
# rm -rf main
make install 后软件安装成功,任意目录下执行main都可运行。
make clean:清除编译产生的可执行文件及目标文件(object file,*.o)。
make distclean:除了清除可执行文件和目标文件外,把configure所产生的Makefile也清除掉
make dist:将程序和相关的档案包装成一个压缩文件以供发布。执行完在目录下会产生一个以PACKAGE-VERSION.tar.gz为名称的文件。 PACKAGE和VERSION这两个变数是根据configure.in文件中AM_INIT_AUTOMAKE(PACKAGE,VERSION)的定义。在此范例中会产生main-1.0.tar.gz的档案。
rm -rf :卸载tar软件
tar包与rpm包
上文已经得到了一个 tar包,但是,如果仅仅是上述的tar包发送给别人是无法安装使用的,因为涉及其他依赖文件,因此必须是整个目录打包:
# tar -czvf sample.tar.gz sample
具体安装方式为:
# tar -zxvf sample.tar.gz //解压
# cd sample/src/
# ./configure
# make
# make install
# make clean
显然每次安装都得编译,怎么办呢?那就根据我们的需求制作RPM包吧,相当于windows下的exe,可以直接安装。
用rpmbuild制作rpm包:
- 创建/root/rpmbuild/目录
- 在/root/rpmbuild/目录下创建以下5个子目录:
BUILD 源代码解压后的存放目录
RPMS 制作完成后的RPM包存放目录,里面有与平台相关的子目录
SOURCES 收集的源材料,补丁的存放位置
SPECS SPEC文件存放目录
SRMPS 存放SRMPS生成的目录 - 将sample.tar.gz放在 /root/rpmbuild/SOURCES/目录下
- 在 /root/rpmbuild/SPECS/目录下编写 main.spec文件,具体内容在后面介绍
- 在 /root/rpmbuild/目录下执行:
rpmbuild -ba SPECS/main.spec - 在/root/rpmbuild/RPMS/x86_64/下将生成二进制rpm包
在/root/rpmbuild/SRPMS/下将生成含源码的rpm包 - 显示rpm包详细信息,执行:
rpm -qpi sample-1.0.0-1.src.rpm
安装:rpm -ivh sample-1.0.0-1.src.rpm --force
查看:rpm -qa|grep main
卸载:rpm -e
针对本用例编写的main.spec文件如下:
Group:Applications
License:GPL
URL:http://blog.csdn.net/qq_15437629/article/details/77587588
Source:sample.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
%description
my test rpm
%prep
tar -xzvf $RPM_SOURCE_DIR/sample.tar.gz
%build
cd $RPM_BUILD_DIR/sample/src
./configure
make
%install
cd $RPM_BUILD_DIR/sample/src
make install
%clean
rm -rf $RPM_BUILD_DIR
%files
%defattr(-,root,root,-)
%doc
%changelog
下面来说说其中最最重要的spec的格式:
vi tengine.spec
### 0.define section #自定义宏段,这个不是必须的
### %define nginx_user nginx #这是我们自定义了一个宏,名字为nginx_user值为nginx,%{nginx_user}引用
### 1.The introduction section #介绍区域段
Name: tengine #名字为tar包的名字
Version: 1.4.2 #版本号,一定要与tar包的一致哦
Release: 1%{?dist} #释出号,也就是第几次制作rpm
Summary: tengine from TaoBao #软件包简介,最好不要超过50字符
Group: System Environment/Daemons #组名,可以通过less /usr/share/doc/rpm-4.8.0/GROUPS 选择合适组
License: GPLv2 #许可,GPL还是BSD等
URL: http://laoguang.blog.51cto.com #可以写一个网址
Packager: Laoguang <ibuler@qq.com>
Vendor: TaoBao.com
Source0: %{name}-%{version}.tar.gz
#定义用到的source,也就是你收集的,可以用宏来表示,也可以直接写名字,上面定义的内容都可以像上面那样引用
#patch0: a.patch #如果需要补丁,依次写
BuildRoot: %_topdir/BUILDROOT
#这个是软件make install 的测试安装目录,也就是测试中的根,我们不用默认的,我们自定义,
#我们可以来观察生成了哪此文件,方便写file区域
BuildRequires: gcc,make #制作过程中用到的软件包
Requires: pcre,pcre-devel,openssl,chkconfig #软件运行需要的软件包,也可以指定最低版本如 bash >= 1.1.1
%description #软件包描述,尽情的写吧
It is a Nginx from Taobao. #描述内容
### 2.The Prep section 准备阶段,主要目的解压source并cd进去
%prep #这个宏开始
%setup -q #这个宏的作用静默模式解压并cd
#%patch0 -p1 #如果需要在这打补丁,依次写
### 3.The Build Section 编译制作阶段,主要目的就是编译
%build
./configure \ #./configure 也可以用%configure来替换
--prefix=/usr \ #下面的我想大家都很熟悉
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_flv_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--http-client-body-temp-path=/var/tmp/nginx/client/ \
--http-proxy-temp-path=/var/tmp/nginx/proxy/ \
--http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
--http-scgi-temp-path=/var/tmp/nginx/scgi \
--with-pcre
make %{?_smp_mflags} #make后面的意思是:如果就多处理器的话make时并行编译
### 4.Install section 安装阶段
%install
rm -rf %{buildroot} #先删除原来的安装的,如果你不是第一次安装的话
make install DESTDIR=%{buildroot}
#DESTDIR指定安装的目录,而不是真实的安装目录,%{buildroot}你应该知道是指的什么了
### 4.1 scripts section #没必要可以不写
%pre #rpm安装前制行的脚本
if [ $1 == 1 ];then #$1==1 代表的是第一次安装,2代表是升级,0代表是卸载
/usr/sbin/useradd -r nginx 2> /dev/null ##其实这个脚本写的不完整
fi
%post #安装后执行的脚本
%preun #卸载前执行的脚本
if [ $1 == 0 ];then
/usr/sbin/userdel -r nginx 2> /dev/null
fi
%postun #卸载后执行的脚本
### 5.clean section 清理段,删除buildroot
%clean
rm -rf %{buildroot}
### 6.file section 要包含的文件
%files
%defattr (-,root,root,0755) #设定默认权限,如果下面没有指定权限,则继承默认
/etc/ #下面的内容要根据你在%{rootbuild}下生成的来写
/usr/
/var/
### 7.chagelog section 改变日志段
%changelog
* Fri Dec 29 2012 laoguang <ibuler@qq.com> - 1.0.14-1
- Initial version
备注:
rpm -Uvh升级时执行顺序
1、执行新包spec文件中 %pre 段.
2、安装新包的相关依赖包.
3、执行新包spec文件中的 %post 段.
4、执行旧包spec文件中的 %preun 段.
5、删除新包中不需要的旧文件。
6、执行旧包spec文件中的 %postun 段.
当进行不同操作的时候,会传递不同的参数给段,完整的参数传递及释义如下:
%pre和%post段
当传递的第一个参数为1时,表示新安装一个rpm包。
当传递的第一个参数为2时,表示升级一个已经存在的包。
%preun和%postun段
当传递的第一个参数为0时,表示删除一个包。
当传递的第一个参数为1时,表示更新一个包。