静态编译makefile
① Makefile.am 规则和实例详解
编写linux C 程序的时候,自己来写Makefile着实的让人很头疼,如果是简单的项目自己写写也就罢了,但是如果遇到大项目自己写Makefile,那是要弄死人的,所以最近在研究Autotools工具自动生成Makefile,在用到autotools工具生成Makefile的时候,还是有一部分需要自己来完成的,那就是Makefile.am文件。
项目中写在源文件里的Makefile.am是一种比我们了解的Makefile更高层次的编译规则,它可以和编写的configure.in(了解更多configure.in的规则请阅读《 configure.ac (configure.in)详解 》)文件一起通过调用automake命令,来生成Makefile.in文件,然后再调用./configure,将Makefile.in文件自动的生成Makefile文件。所以Makefile.am文件是要自动生成Makefile必不可少的元素,下面鹏博客就来和大家着重的学习下Makefile.am的写法和规则。
先来说下Makefile.am中常见的文件编译类型,详细的编译类型和全局变量鹏博客会在下面在图表中列出:
PROGRAMS 表示可执行文件
SOURCES 表示源文件
HEADERS 头文件。
LIBRARIES 表示库文件
LTLIBRARIES 这也是表示库文件,前面的LT表示libtool。
DATA 数据文件,不能执行。
SCRIPTS 脚本文件,这个可以被用于执行。如:example_SCRIPTS,如果用这样的话,需要我们自己定义安装目录下的example目录,很容易的,往下看。
一、基本写法
下面就直接引入一个例子进行详细讲解,如下:
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = client
client_SOURCES = key.c connect.c client.c main.c session.c hash.c
client_CPPFLAGS = -DCONFIG_DIR=\“$(sysconfdir)\” -DLIBRARY_DIR=\”$(pkglibdir)\”
client_LDFLAGS = -export-dynamic -lmemcached
noinst_HEADERS = client.h
INCLUDES = -I/usr/local/libmemcached/include/
client_LDADD = $(top_builddir)/sx/libsession.la \
$(top_builddir)/util/libutil.la
上面就是一个Makefile.am示例文件,这个文件是用于生成client可执行应用程序,引用了两个静态库和MC等动态库的连接。
先来看个图表一(列出了可执行文件、静态库、头文件和数据文件,四种书写Makefile.am文件个一般格式。):
对于可执行文件和静态库类型,如果只想编译,不想安装到系统中,可以用noinst_PROGRAMS代替bin_PROGRAMS,noinst_LIBRARIES代替lib_LIBRARIES。以此类推。
根据这个图表一来分析下具体内容:
AUTOMAKE_OPTIONS :这个是用来设定automake的选项。automake主要是帮助开发GNU软件的人员维护软件套件,一般在执行automake时会检查目录下是否存在标准GNU套件中应具备的文件档案,例如NEWS、AUTHOR、ChangeLog等,设成foreign时,automake会改用一般软件套件标准来检查,而gnu是缺省设置,该级别下将尽可能地检查包是否服从GNU标准,gnits是严格标准,不推荐。
bin_PROGRAMS :表示要生成的可执行应用程序文件,这里的bin表示可执行文件在安装时需要被安装到系统中,如果只是想编译。不想被安装到系统中,可以用noinst_PROGRAMS来代替。
那么整个第一行 bin_PROGRAMS=client 详细表示什么意思那,解释如下:
PROGRAMS知道这是一个可执行文件。
client表示编译的目标文件。
bin表示目录文件被安装到系统的目录。
如程序和图片所示,包括头文件,静态库的定义等等都是这种形式,如lib_LIBRARIES=util,表示将util库安装到lib目录下。
继续解释文件内容:
client_SOURCES :表示生成可执行应用程序所用的所有源文件源文件,多个就空格隔开,我们注意到client_是由前面的bin_PROGRAMS指定的,如果前面是生成example, 那么这里也就变成example_SOURCES,其它的规则类似标识也是一样。
client_CPPFLAGS :这个和我们写Makefile的时候意思是一样的,都表示C语言的预处理器参数,这里指定了DCONFIG_DIR,以后在程序中,就可以直接使用CONFIG_DIR,不要把这个和另一个CFLAGS混淆,后者表示编译器参数。
client_LDFLAGS :表示在连接时所需要的库文件选项标识。这个也就是对应一些如-l,-shared等选项。
noinst_HEADERS :表示该头文件只是参加可执行文件的编译,而不用安装到安装目录下。如果需要安装到系统中,可以用include_HEADERS来代替。
INCLUDES :表示连接时所需要的头文件。
client_LDADD :表示连接时所需要的库文件,这里表示需要两个库文件的支持,下面会看到这个库文件又是怎么用Makefile.am文件后成的。
如图表二:
全局变量 ,可能有人注意到文件中的$(top_builddir)等全局变量,其实这个是Makefile.am系统定义的一个基本路径变量,表示生成目标文件的最上层目录,如果这个Makefile.am文件变成其它的Makefile.am文件,那么这个就表示其它的目录,而不是这个当前目录。我们还可以使用$(top_srcdir),这个表示工程的最顶层目录,其实也是第一个Makefile.am的入口目录,因为Makefile.am文件可以被递归性的调用。
如图表三:(在Makefile.am中尽量使用相对路径,系统预定义了两个基本路径)
$(sysconfdir) :在系统安装工具的时候,我们经常能遇到配置安装路径的命令,如:./configure –prefix=/install/apache 其实在调用这个之后,就定义了一个变量$(prefix), 表示安装的路径,如果没有指定安装的路径,会被安装到默认的路径,一般都是/usr/local。在定义$(prefix),还有一些预定义好的目录,其实这一些定义都可以在顶层的Makefile文件中可以看到,如下面一些值:
bindir = $(prefix)/bin。
libdir = $(prefix)/lib。
datadir=$(prefix)/share。
sysconfdir=$(prefix)/etc。
includedir=$(prefix)/include。
这些量还可以用于定义其它目录,例如我想 将client.h安装到include/client目录下 ,这样写Makefile.am文件:
clientincludedir=$(includedir)/client
clientinclude_HEADERS=$(top_srcdir)/client/client.h
这就达到了我的目的,相当于定义了一个安装类型,这种安装类型是将文件安装到include/client目录下。
我们自己也可以 定义新的安装目录下的路径 ,如我在应用中简单定义的:
devicedir = ${prefix}/device
device_DATA = package
这样的话,package文件会作为数据文件安装到device目录之下,这样一个可执行文件就定义好了。注意,这也相当于定义了一种安装类型:devicedir,所以你想怎么安装就怎么安装,后面的XXXXXdir,dir是固定不变的。
二、配置静态库
下面我们来说下编译静态库和编译动态库,我们说下静态库,下面这个例子比较简单。直接指定 XXXX_LTLIBRARIES或者XXXX_LIBRARIES就可以了。同样如果不需要安装到系统,将XXXX换成noinst就可以。
一般推荐使用libtool库编译目标,因为automake包含libtool,这对于跨平台可移植的库来说,是一个很好的事情。
看例子如下:
noinst_LTLIBRARIES = libutil.la
oinst_HEADERS = inaddr.h util.h compat.h pool.h xhash.h url.h device.h
ibutil_la_SOURCES = access.c config.c datetime.c hex.c inaddr.c log.c device.c pool.c rate.c sha1.c stanza.c str.c xhash.c
ibutil_la_LIBADD = @LDFLAGS@
第一行的noinst_LTLIBRARIES,这里要注意的是LTLIBRARIES,另外还有LIBRARIES,两个都表示库文件。前者表示libtool库,用法上基本是一样的。如果需要安装到系统中的话,用lib_LTLIBRARIES。
.la 为libtool自动生成的一些共享库,vi编辑查看,主要记录了一些配置信息。可以用如下命令查看*.la文件的格式 $file *.la
.a 为静态库,是好多个.o合在一起,用于静态连接
如果想编译 .a 文件,那么上面的配置就改成如下结果:
noinst_LTLIBRARIES = libutil.a
oinst_HEADERS = inaddr.h util.h compat.h pool.h xhash.h url.h device.h
ibutil_a_SOURCES = access.c config.c datetime.c hex.c inaddr.c log.c device.c pool.c rate.c sha1.c stanza.c str.c xhash.c
ibutil_a_LIBADD = @LDFLAGS@
注意:静态库编译连接时需要其它的库的话,采用XXXX_LIBADD选项,而不是前面的XXXX_LDADD。编译静态库是比较简单的,因为直接可以指定其类型。
三、配置动态库
如果想要编译XXX.so动态库文件,需要用到_PROGRAMS类型,有一个关于安装路径的问题,如果希望将动态库安装到lib目录下,按照前面所说的,只需要写成lib_PROGRAMS就可以了,lib表示安装的路径,但是automake不允许这样直接定义,所以可以采用下面的办法,同样是将动态库安装到lib目录下:
projectlibdir=$(libdir)//新建一个目录,就是该目录就是lib目录
projectlib_PROGRAMS=project.so
project_so_SOURCES=xxx.C
project_so_LDFLAGS=-shared -fpic//GCC编译动态库的选项
这个动态库的编译写法是鹏博客网上总结的,希望有要的人自己来验证下。
四、SUBDIRS功能用法
SUBDIRS 这是一个很重要的词,我们前面生成了一个目标文件,但是一个大型的工程项目是由许多个可执行文件和库文件组成,也就是包含多个目录,每个目录下都有用于生成该目录下的目标文件的Makefile.am文件,但顶层目录是如何调用,才能使下面各个目录分别生成自己的目标文件呢?就是SUBDIRS关键词的用法了。
看一下我的工程项目,这是顶层的Makefile.am文件
EXTRA_DIST = Doxyfile.in README.win32 README.protocol contrib UPGRADE
devicedir = ${prefix}/device
device_DATA = package
SUBDIRS = etc man
ifUSE_LIBSUBST
SUBDIRS += subst
endif
SUBDIRS += tools io sessions util client dispatch server hash storage sms
SUBDIRS表示在处理目录之前,要递归处理哪些子目录,要注意处理的顺序。比如配置中的client对sessions和utils这两上目标文件有依赖关系,就在client之前需要处理这两个目标文件。
EXTRA_DIST :将哪些文件一起打包。
五、打包处理
Automake会自动的打包 ,自动打包的内容如下:
所有程序的源文件。
所有子目录里的的Makefile.am文件。
Makefile.am中包含的文件。
./configure所要读取的文件。
EXTRA_DIST所指定的文件。
dist和nodist指定的文件,也可将其中一个源文件指定为不打包:
例如: nodist_client_SOURCES = client.c
六、最后
这里是鹏博客总结的一些比较实用的Makefile.am的写法和规则,看完了这篇文章已经可以很详细的理解这个文件的内容,写起来也应该不会陌生,但automake还有许多其他的规则需要掌握,鹏博客将会继续全面的总结关于autotools 的一些规则和写法,希望对大家有用处。也欢迎大家指出问题,帮我完善这个博客,希望大家支持!
automake的Makefile.am Makefile.am写法
② makefile 生成动态库和静态库的区别
生成动态库的时候要注意,编译生成目标文件的时候加上-fPIC参数,生成位置无关的可重定位代码,然后链接的时候加上-shared生成动态共享库。比如一个hello.c,生成静态库:
gcc-ohello.o-chello.c
arrcslibhello.ahello.o
生成动态库的命令:
gcc-fPIChello.o-chello.c
gcc-shared-olibhelllo.sohello.o
还有一个区别是:静态库参与链接过程,而动态库不链接到可执行文件中,可执行程序在运行的时候,对应的动态库也要加载到内存中,否则可执行程序运行不了。
更多详细细节,可以网络搜索视频教程:Makefile工程实践
③ makefile的选项CFLAGS,CPPFLAGS,LDFLAGS和LIBS的区别
Linux内核的配置系统由三个部分组成,分别是:Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则; 配置文件(config.in):给用户提供配置选择的功能; 配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于 Xwindows 图形界面的用户配置界面,各自对应于 Make config、Make menuconfig 和 make xconfig)。这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。所以,在本文中,我们只对 Makefile 和配置文件进行讨论。另外,凡是涉及到与具体 CPU 体系结构相关的内容,我们都以 ARM 为例,这样不仅可以将讨论的问题明确化,而且对内容本身不产生影响。2. Makefile2.1 Makefile 概述Makefile 的作用是根据配置的情况,构造出需要编译的源文件列表,然后分别编译,并把目标代码链接到一起,最终形成 Linux 内核二进制文件。由于 Linux 内核源代码是按照树形结构组织的,所以 Makefile 也被分布在目录树中。Linux 内核中的 Makefile 以及与 Makefile 直接相关的文件有:Makefile:顶层 Makefile,是整个内核配置、编译的总体控制文件。 .config:内核配置文件,包含由用户选择的配置选项,用来存放内核配置后的结果(如 make config)。 arch/*/Makefile:位于各种 CPU 体系目录下的 Makefile,如 arch/arm/Makefile,是针对特定平台的 Makefile。 各个子目录下的 Makefile:比如 drivers/Makefile,负责所在子目录下源代码的管理。 Rules.make:规则文件,被所有的 Makefile 使用。 用户通过 make config 配置后,产生了 .config。顶层 Makefile 读入 .config 中的配置选择。顶层 Makefile 有两个主要的任务:产生 vmlinux 文件和内核模块(mole)。为了达到此目的,顶层 Makefile 递归的进入到内核的各个子目录中,分别调用位于这些子目录中的 Makefile。至于到底进入哪些子目录,取决于内核的配置。在顶层 Makefile 中,有一句:include arch/$(ARCH)/Makefile,包含了特定 CPU 体系结构下的 Makefile,这个 Makefile 中包含了平台相关的信息。位于各个子目录下的 Makefile 同样也根据 .config 给出的配置信息,构造出当前配置下需要的源文件列表,并在文件的最后有 include $(TOPDIR)/Rules.make。Rules.make 文件起着非常重要的作用,它定义了所有 Makefile 共用的编译规则。比如,如果需要将本目录下所有的 c 程序编译成汇编代码,需要在 Makefile 中有以下的编译规则:%.s: %.c$(CC) $(CFLAGS) -S $< -o $@有很多子目录下都有同样的要求,就需要在各自的 Makefile 中包含此编译规则,这会比较麻烦。而 Linux 内核中则把此类的编译规则统一放置到 Rules.make 中,并在各自的 Makefile 中包含进了 Rules.make(include Rules.make),这样就避免了在多个 Makefile 中重复同样的规则。对于上面的例子,在 Rules.make 中对应的规则为:%.s: %.c$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(*F)) $(CFLAGS_$@) -S $< -o [email protected] Makefile 中的变量顶层 Makefile 定义并向环境中输出了许多变量,为各个子目录下的 Makefile 传递一些信息。有些变量,比如 SUBDIRS,不仅在顶层 Makefile 中定义并且赋初值,而且在 arch/*/Makefile 还作了扩充。常用的变量有以下几类:1) 版本信息版本信息有:VERSION,PATCHLEVEL, SUBLEVEL, EXTRAVERSION,KERNELRELEASE。版本信息定义了当前内核的版本,比如 VERSION=2,PATCHLEVEL=4,SUBLEVEL=18,EXATAVERSION=-rmk7,它们共同构成内核的发行版本KERNELRELEASE:2.4.18-rmk72) CPU 体系结构:ARCH在顶层 Makefile 的开头,用 ARCH 定义目标 CPU 的体系结构,比如 ARCH:=arm 等。许多子目录的 Makefile 中,要根据 ARCH 的定义选择编译源文件的列表。3) 路径信息:TOPDIR, SUBDIRSTOPDIR 定义了 Linux 内核源代码所在的根目录。例如,各个子目录下的 Makefile 通过 $(TOPDIR)/Rules.make 就可以找到 Rules.make 的位置。SUBDIRS 定义了一个目录列表,在编译内核或模块时,顶层 Makefile 就是根据 SUBDIRS 来决定进入哪些子目录。SUBDIRS 的值取决于内核的配置,在顶层 Makefile 中 SUBDIRS 赋值为 kernel drivers mm fs net ipc lib;根据内核的配置情况,在 arch/*/Makefile 中扩充了 SUBDIRS 的值,参见4)中的例子。4) 内核组成信息:HEAD, CORE_FILES, NETWORKS, DRIVERS, LIBSLinux 内核文件 vmlinux 是由以下规则产生的:vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o --start-group $(CORE_FILES) $(DRIVERS) $(NETWORKS) $(LIBS) --end-group -o vmlinux可以看出,vmlinux 是由 HEAD、main.o、version.o、CORE_FILES、DRIVERS、NETWORKS 和 LIBS 组成的。这些变量(如 HEAD)都是用来定义连接生成 vmlinux 的目标文件和库文件列表。其中,HEAD在arch/*/Makefile 中定义,用来确定被最先链接进 vmlinux 的文件列表。比如,对于 ARM 系列的 CPU,HEAD 定义为: HEAD := arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o表明 head-$(PROCESSOR).o 和 init_task.o 需要最先被链接到 vmlinux 中。PROCESSOR 为 armv 或 armo,取决于目标 CPU。 CORE_FILES,NETWORK,DRIVERS 和 LIBS 在顶层 Makefile 中定义,并且由 arch/*/Makefile 根据需要进行扩充。 CORE_FILES 对应着内核的核心文件,有 kernel/kernel.o,mm/mm.o,fs/fs.o,ipc/ipc.o,可以看出,这些是组成内核最为重要的文件。同时,arch/arm/Makefile 对 CORE_FILES 进行了扩充:# arch/arm/Makefile# If we have a machine-specific directory, then include it in the build.MACHDIR := arch/arm/mach-$(MACHINE)ifeq ($(MACHDIR),$(wildcard $(MACHDIR)))SUBDIRS += $(MACHDIR)CORE_FILES := $(MACHDIR)/$(MACHINE).o $(CORE_FILES)endifHEAD := arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.oSUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpeCORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)LIBS := arch/arm/lib/lib.a $(LIBS)5) 编译信息:CPP, CC, AS, LD, AR,CFLAGS,LINKFLAGS在 Rules.make 中定义的是编译的通用规则,具体到特定的场合,需要明确给出编译环境,编译环境就是在以上的变量中定义的。针对交叉编译的要求,定义了 CROSS_COMPILE。比如:CROSS_COMPILE = arm-linux-CC = $(CROSS_COMPILE)gccLD = $(CROSS_COMPILE)ld......CROSS_COMPILE 定义了交叉编译器前缀 arm-linux-,表明所有的交叉编译工具都是以 arm-linux- 开头的,所以在各个交叉编译器工具之前,都加入了 $(CROSS_COMPILE),以组成一个完整的交叉编译工具文件名,比如 arm-linux-gcc。CFLAGS 定义了传递给 C 编译器的参数。LINKFLAGS 是链接生成 vmlinux 时,由链接器使用的参数。LINKFLAGS 在 arm/*/Makefile 中定义,比如:# arch/arm/MakefileLINKFLAGS :=-p -X -T arch/arm/vmlinux.lds6) 配置变量CONFIG_*.config 文件中有许多的配置变量等式,用来说明用户配置的结果。例如 CONFIG_MODULES=y 表明用户选择了 Linux 内核的模块功能。.config 被顶层 Makefile 包含后,就形成许多的配置变量,每个配置变量具有确定的值:y 表示本编译选项对应的内核代码被静态编译进 Linux 内核;m 表示本编译选项对应的内核代码被编译成模块;n 表示不选择此编译选项;如果根本就没有选择,那么配置变量的值为空。2.3 Rules.make 变量前面讲过,Rules.make 是编译规则文件,所有的 Makefile 中都会包括 Rules.make。Rules.make 文件定义了许多变量,最为重要是那些编译、链接列表变量。O_OBJS,L_OBJS,OX_OBJS,LX_OBJS:本目录下需要编译进 Linux 内核 vmlinux 的目标文件列表,其中 OX_OBJS 和 LX_OBJS 中的 "X" 表明目标文件使用了 EXPORT_SYMBOL 输出符号。M_OBJS,MX_OBJS:本目录下需要被编译成可装载模块的目标文件列表。同样,MX_OBJS 中的 "X" 表明目标文件使用了 EXPORT_SYMBOL 输出符号。O_TARGET,L_TARGET:每个子目录下都有一个 O_TARGET 或 L_TARGET,Rules.make 首先从源代码编译生成 O_OBJS 和 OX_OBJS 中所有的目标文件,然后使用 $(LD) -r 把它们链接成一个 O_TARGET 或 L_TARGET。O_TARGET 以 .o 结尾,而 L_TARGET 以 .a 结尾。
④ 如何编译静态链接的程序,通过./configure 把参数-static传入Makefile。
./configure LDFLAGS=-static
⑤ Linux2.6 如何编写Makefile,使驱动程序能够编译链接静态库
就我的感觉,静态库是编译好的.o文件,你只要将静态库(mylib.a)放置于 /lib 以及/usr/lib 文件夹下,然后在gcc编译器的变量中 加上 -lmylib,就可以了。
⑥ 多级目录makefile,静态库
在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 proce a configure script.
AC_PREREQ(2.59)
AC_INIT(hello,1.0, [[email protected]])
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 proce a configure script.
AC_PREREQ(2.59)
AC_INIT(hello,1.0, [[email protected]])
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 动态库搜索路径,运行生成的可执行文件。
⑦ 如何将第三方静态库加入Makefile.am中
将库和对应的头文件放到指定目录,然后编译的时候,指定这个库路径,链接使用这个库即可。
⑧ makefile如何链接静态库
makefile 里面写法,同你的编译器 如何链接静态库的方法有关。例如:指定库名
VC++ 用 编译选项 /MT 链接 LIBCMT.LIB 就是 链接静态库。
-----
unix/linux makefile 里面,例如
LIBS = libmine.a -lpthread 这里写你要链接的静态库库名
CXXFILES = pthreads.cpp 程序名字们
CXXFLAGS = -O3 -o prog -rdynamic -D_GNU_SOURCE -L./libmine 编译选项
LIBS = libmine.a -lpthread 库名
all:
$(CXX) $(CXXFILES) $(LIBS) $(CXXFLAGS)
clean:
rm -f prog *.o