1. 目录结构如下:
example
|——src 目录(存放源代码文件)
|——hello.c
|——lib 目录(存放用来生成库的文件)
|——test.c 用来生成静态库libhello.a
|——include 目录(存放程序中使用的头文件)
|——hello.h
2. 编写的各个目录下的源文件
hello.h 文件
extern void print(char *);
test.c 文件
#include<stdio.h>
void print(char *msg)
{
print(“%s\n”, msg);
}
hello.c 文件
#include “hello.h”
int main()
{
print(“Hello static library!”);//这里用到的是静态库中的函数
return 0;
}
3. 编写lib/Makefile.am 文件
noinst_LIBRARIES=libhello.a
libhello_a_SOURCES=test.c
AUTOMAKE_OPTIONS=foreign
第一行noinst 表示生成的是静态库,不需要make install ,直接制定它的位置和名字就
可以使用。
第二行表示用来生成静态库的源文件。如果要把静态库生成到其他地方,可以在=后面
加上路径(建议用绝对路径,并将所要用到的静态库生成在同一个文件夹下,如lib)。
第三行AUTOMAKE_OPTIONS 是Automake 的选项。Automake 主要是帮助开发 GNU 软
件的人员来维护软件,所以在执行Automake 时,会检查目录下是否存在标准 GNU 软件中
应具备的文件,例如 'NEWS'、'AUTHOR'、 'ChangeLog' 等文件。设置为foreign 时,Automake
会改用一般软件的标准来检查。如果不加这句的话,需要在autoconf之前,先执行touch NEWS
README AUTHORS ChangeLog 来生成'NEWS'、'AUTHOR'、 'ChangeLog' 等文件
4. 编写src/Makefile.am 文件
AUTOMAKE_OPTIONS=foreign
INCLUDES= -I../include
bin_PROGRAMS=hello
hello_SOURCES=hello.c
hello_LDADD=../lib/libhello.a
第二行指定头文件的位置,-I 是idirafter 的缩写。../include 指定头文件的位置,..是上
一级目录,也就是这里的example 目录。
第三行指定生成可执行文件名hello,在这里可执行文件生成在src 下,建议将可执行文
件生成到一个特定的文件夹下,让它和源代码分开,如/root/test 目录下。写法为:
bin_PROGRAMS=/root/test/hello,后面的第四、五行也相对应地变为:
_root_test_hello_SOURCES=hello.c
_root_test_hello_LDADD=../lib/libhello.a
第四行指定生成可执行文件hello 的源代码文件,如果hello.c 在其他目录下,需要加上
完整的路径。
第五行指定需要使用静态库的位置。
5. 生成静态库文件lib/libhello.a。
执行autoscan 生成configure.scan 文件,将它重命名为configure.in 并修改其内容。
#configure.in
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(libhello.a,1.1,[])
AM_INIT_AUTOMAKE
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
AC_PROG_RANLIB//需要加入的内容,因为使用了静态库
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT([Makefile])
AC_INIT(FILE)
该宏用来检查源代码所在路径,autoscan 会自动产生,一般无须修改它。
AM_INIT_AUTOMAKE(PACKAGE,VERSION)
这个是使用 Automake 所必备的宏,PACKAGE 是所要产生软件的名称,VERSION 是版
本编号。也可以把包和版本号等信息放在AC_INIT(FILE) 宏里。
AC_PROG_CC
检查系统可用的C 编译器,若源代码是用C 写的就需要这个宏。
AC_OUTPUT(FILE)
设置 configure 所要产生的文件,若是Makefile ,configure 便会把它检查出来的结果
填充到Makefile.in 文件后产生合适的 Makefile。 后面的FILE 是一个Makefile 的输出列表,
你可以选着将要输出的Makefile 的位置和个数。建议只在src 中输出Makefile。
在lib 目录下依次执行 aclocal 、autoconf、automake --add-missing、./configure、make,
此时在该目录下就可以看到生成的静态库文件libhello.a
6. 在src 目录下,执行autoscan 生成configure.scan 文件,将它重命名为configure.in 并修
改其内容。
#configure.in
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(hello,1.1,[])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([hello.c])
# 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])
7. 在src 目录下依次执行 aclocal 、autoconf、automake --add-missing、./configure、make,
生成可执行文件hello
8. 执行make install 进行安装,最后输入hello 来运行程序,查看效果:
Hello static library!
执行成功!
使用gcc 创建和使用静态库
1. 编写mylib.h 文件
#ifndef _mylib_h_
#define _mylib_h_
void welcome();
void outstring(const char * str);
#endif
2. 编写mylib.c 文件,用来生成静态库。
#include <stdio.h>
void welcome()
{
printf(“welcome to libmylib\n”);
}
void outstring(const char * str)
{
if(str!=NULL)
printf(“%s”,str);
}
3. 编译源文件,产生目标代码
gcc –o mylib.o –c mylib.c
4. 将上面产生的目标文件加入到静态库中,并把静态库拷贝到系统默认的路径
ar rcs libmylib.a mylib.o
cp libmylib.a /usr/lib/
5. 编写测试程序来使用刚才创建的静态库 libmylib.a
#include “mylib.h”
#include <stdio.h>
Int main()
{
printf(“create and use library:\n”);
welcome();
outstring(“It’s a successful\n”);
}
6. 编译使用库函数的程序
gcc –o test test.c -lmylib
运行./test 查看结果。
使用Automake 创建和使用动态库
动态库与静态库的差别在于:动态库是在程序执行的时候加载到内存,供调用函数使用。
1. 目录结构如下:
example
|——src 目录(存放源代码文件)
|——hello.c
|——lib 目录(存放用来生成库的文件)
|——test.c 用来生成动态库libhello.la
|——include 目录(存放程序中使用的头文件)
|——hello.h
2. 编写各个目录下的源文件如下:
hello.h 文件
extern void print(char *);
test.c 文件
#include<stdio.h>
void print(char *msg)
{
print(“%s\n”, msg);
}
hello.c 文件
#include “hello.h”
int main()
{
print(“Hello static library!”);//这里用到的是动态库中的函数
return 0;
}
3. 在lib 目录下编译需要生成动态库的文件,生成动态库,并安装到系统的标准库中,供
程序调用。具体步骤如下:
(1) 编写Makefile.am 文件
AUTOMAKE_OPTIONS=foreign
lib_LTLIBRARIES=libhello.la
libhello_la_SOURCES=test.c
这里lib_LTLIBRARIES 的意思是生成的动态库,然后指定动态库依赖的源文件
test.c ,若有多个源文件用空格隔开。
(2) 在lib 目录下,用命令autoscan 产生configure.scan 文件,并改名为configure.in。 这
里需加上宏AC_PROG_LIBTOOL,表示利用libtool 来自动生成动态库
#configure.in
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(hello,1.0, [miaoquan@nou.com.cn])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([test.c])
#AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_PROG_LIBTOOL
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
(3) 执行命令aclocal、libtoolize -f -c 、autoconf、automake --add-missing、./configure、
make、make install 将动态库安装到系统的标准库中,以供调用(一般为/usr/local/lib)。
注:libtoolize 提供了一种标准的方式来将libtool 支持加入一个软件包,而GNU libtool 是
一个通用库支持脚本,将使用动态库的复杂性隐藏在统一、可移植的接口中。
4. 生成src 目录下的hello 可执行文件
(1) 编写src/Makefile.am 文件
AUTOMAKE_OPTIONS=foreign
INCLUDES= -I../include
bin_PROGRAMS=hello
hello_SOURCES=hello.c
hello_LDADD=-lhello
-ldir 指定编译时搜索库的路径。与静态库不同的是,创建动态库时不用指定库路
径,编译器自动在标准库中查找libhello.so 文件。
(2) 执行autoscan 生成configure.scan 文件,将它重命名为configure.in 并修改其内容。
# configure.in
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(hello,1.0, [miaoquan@nou.com.cn])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([hello.c])
#AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
(3) 在src 目录下编译并生成目标文件,执行命令aclocal、libtoolize -f -c 、autoconf、
automake --add-missing、./configure、make,此时你一定会觉得,成功近在咫尺了。再
执行目标文件./hello,结果却在你的意料之外:
./hello: error while loading shared libraries: libhello.so.0 : cannot open shared object file:
No such file or directory
在执行目标文件的时候,Shell 找不到共享库的位置,需要我们手工载入库路径。
5. shell 搜索动态库路径位置的两种方法
(1) 使用命令导入动态库的路径,命令如下:
export LD_LIBRARY_PATH=dir (如/usr/local/lib)
(2) 修改/etc/ld.so.conf 文件,加入搜索路径,修改后用ldconfig 命令载入修改。
将自己可能存放库文件的路径都加入到/etc/ld.so.conf 中是明智的选择 ^_^。添加
方法也极其简单,将库文件的绝对路径直接写进去就OK 了,一行一个。例如:
/usr/local/lib
/usr/lib
/lib
需要注意的是:这种搜索路径的设置方式对于程序连接时的库(包括共享库和静态
库)的定位已经足够了,但是对于使用了共享库的程序的执行还是不够的。这是 因为
为了加快程序执行时对共享库的定位速度,避免使用搜索路径查找共享库的低效率,所
以是直接读取库列表文件 /etc/ld.so.cache 从中进行搜索的。/etc/ld.so.cache 是一个非
文本的数据文件,不能直接编辑,它是根据 /etc/ld.so.conf 中设置的搜索路径由
/sbin/ldconfig 命令将这些搜索路径下的共享库文件集中在一起而生成的(ldconfig 命令
要以 root 权限执行)。因此,为了保证程序执行时对库的定位,在 /etc/ld.so.conf 中
进行了库搜索路径的设置之后,还必须要运行 /sbin/ldconfig 命令更新 /etc/ld.so.cache
文件之后才可以。ldconfig ,简单的说,它的作用就是将/etc/ld.so.conf 列出的路径下的库
文件 缓存到/etc/ld.so.cache 以供使用。因此当安装完一些库文件,(例如刚安装好glib),
或者修改ld.so.conf 增加新的库路径后,需要运行一下/sbin/ldconfig 使所有的库文件都
被缓存到ld.so.cache 中,如果没做,即使库文件明明就在/usr/lib 下的,也是不会被使
用的,结果编译过程中报错,缺少xxx 库,去查看发现明明就在那放着,搞的想大骂
computer 蠢猪一个^_^。极力推荐使用这种方法!
利用gcc 创建和使用动态库
1. 用下面的命令将mylib.c 程序创建成一个动态库:
gcc –fPIC –o mylib.o –c mylib.c
gcc –shared –o libtt.so mylib.o
-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),
则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的
任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不
是固定的。
-shared 作用于链接阶段,实际传递给链接器ld,让其添加作为共享库所需要的额外描
述信息,去除共享库所不需的信息。
也可以直接使用下面一条命令:
gcc –fPIC –shared –o libtt.so mylib.c
2. 将动态库拷贝到linux 的标准库中,usr/local/lib 或者/usr/lib 或者/lib:
cp libttt.so /usr/local/lib
3. 编译src 目录下的源程序时,指定动态库文件的目录,调用动态库中的函数
gcc –o test test.c /usr/lib/libttt.so
4. 设置shell 动态库搜索路径,运行生成的可执行文件。
---------------------------------------------------------------------------
AUTOMAKE_OPTIONS=foreign
INCLUDES=-I$(top_srcdir)/libpr/include -I$(top_srcdir)/vt/include
noinst_PROGRAMS =libvt.so
libvt_so_SOURCES=vty/vtcmd.c vty/vtdrv.c vty/vty.c vty/evtd.c telnet/telcmd.c telnet/teldrv.c telnet/telnegot.c telnet/telsvr.c telnet/telsess.c vty/defcmd.c vty/vtobj.c
libvt_so_LDFLAGS = -fPIC -shared
libvt_so_LDADD=$(top_srcdir)/libpr/libpr.a
bin_PROGRAMS = test_telnetd
test_telnetd_SOURCES = test/test_telnetd.c
test_telnetd_LDADD=$(top_srcdir)/libpr/libpr.a libvt.so
上面这段代码是从我的一个工程的Makefile.am中摘抄过来的,使用不少技巧。
1、动态库实际上也是ELF格式,所以我们使用PROGRAMS宏,automake将他按执行文件规格设置环境,如果使用noinstall_LIBRARIES那么就变成*.a静态库了。
2、因为是动态库,所以我们有必要加入-fPIC -shared
3、test_telnetd需要调用libvt.so,所以他们之间存在依赖关系。我们将libvt.so直接添加在LDADD 中,automake会自动他们建立依赖关系,在Makefile中可以到test_telnetd_DEPENDENCIES,里面包含 libvt.so。
这里有几个要紧需要注意:
1、$(bin_PROGRAMS)编译顺序在$(noinstall_PROGRAMS)之前,因为test_telnetd需要libvt.so,所以会找不到libvt.so。
2、在LDADD中如果使用-lvt不会建立依赖关系,如果使用$(top_srcdir)/vt/libvt.so也不行。
3、实际上如果不行的话,我们可以直接使用test_telnetd_DEPENDENCIES来指定libvt.so
4、如果需要make install 安装libvt.so到lib,那么使用XXX_PROGRAMS=...的方法,然后指定XXXbin=...就行了。类似于bin_PROGRAMS。
这里使用到的技巧都很有用,值得记录下来。