<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Wirlfly's Blog]]></title> 
<link>http://wf.xplore.cn/index.php</link> 
<description><![CDATA[linux,unix,开源世界,生活感触]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Wirlfly's Blog]]></copyright>
<item>
<link>http://wf.xplore.cn/post/test_lib.php</link>
<title><![CDATA[链接静态库和动态库对符号处理的一些测试(4m/1,2/2)]]></title> 
<author>wirlfly &lt;mwishes atat gmail dotdot com&gt;</author>
<category><![CDATA[骇客帝国]]></category>
<pubDate>Mon, 01 Jun 2009 05:37:44 +0000</pubDate> 
<guid>http://wf.xplore.cn/post/test_lib.php</guid> 
<description>
<![CDATA[ 
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;前晚写了一段代码,用于测试Linux下典型的静态库和动态库对全局符号的不同处理.作为Linux C/CPP程序员,一般对静态库和动态库的使用都十分频繁,虽然也出现过静态库链接顺序导致符号无法解析的错误.但是大体理解静态库和动态库并不困难,但是真正理解静态库和动态库在链接和(或)加载过程中的原理,还是得深入阅读一些文档,写一些测试代码才能有直观的掌握.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果您对测试过程不太感兴趣(确实这个过程比较乏味),请跳跃到最后一段,直接看结论即可.<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;给出测试代码(文末给出源码包,遵循GPL发布):<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6个源代码文件(test_d.c,test.h,test_lib.c,test_lib.h,test_o.c,test_s.c).<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1个Makefile(文末给出Makefile的内容,可以当作一个模板使用).<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;生成1个动态库文件(libtest_d.so),1个静态库文件(libtest_s.a),3个可执行目标文件(test_lib_d,test_lib_s,test_lib_o).<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;还有其他3个和源码文件(*.c)相对应的可重定位目标文件(*.o).<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>[yhzh@localhost 20090530]$ ls<br/>Makefile&nbsp;&nbsp;test_d.c&nbsp;&nbsp;test.h&nbsp;&nbsp;test_lib.c&nbsp;&nbsp;test_lib.h&nbsp;&nbsp;test_o.c&nbsp;&nbsp;test_s.c<br/><br/>[yhzh@localhost 20090530]$ ls<br/>libtest_d.so&nbsp;&nbsp;Makefile&nbsp;&nbsp;test_d.o&nbsp;&nbsp;test_lib.c&nbsp;&nbsp;test_lib.h&nbsp;&nbsp;test_lib.o&nbsp;&nbsp;test_o.c&nbsp;&nbsp;test_s.c<br/>libtest_s.a&nbsp;&nbsp; test_d.c&nbsp;&nbsp;test.h&nbsp;&nbsp;&nbsp;&nbsp;test_lib_d&nbsp;&nbsp;test_lib_o&nbsp;&nbsp;test_lib_s&nbsp;&nbsp;test_o.o&nbsp;&nbsp;test_s.o</div></div><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;动态库的生成, 源码test_d.c, 定义了两个全局函数,自增一个静态变量和打印变量之值. 生成方法:<br/>gcc -o libtest_d.so test_d.o -Wl,-rpath,/home/yhzh/code/c/test/20090530 -L/usr/local/lib -L/home/yhzh/tools/lib -L. -shared<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>[yhzh@localhost 20090530]$ cat test_d.c<br/>#include "test.h"<br/>#include "test_lib.h"<br/><br/>static int a = 0;<br/><br/>int test_inc()<br/>&#123;<br/>&nbsp;&nbsp;fprintf(stdout, "[d]Begin in %s, static a is %d&#92;n", __FILE__, a);<br/>&nbsp;&nbsp;a++;<br/>&nbsp;&nbsp;fprintf(stdout, "[d]End in %s, static a is %d&#92;n", __FILE__, a);<br/><br/>&nbsp;&nbsp;return a;<br/>&#125;<br/><br/>void print_d()<br/>&#123;<br/>&nbsp;&nbsp;fprintf(stdout, "[d]In %s[%s], static a is %d&#92;n", __FILE__, __func__, a);<br/>&nbsp;&nbsp;return;<br/>&#125;<br/><br/>void addition_d()<br/>&#123;<br/>&nbsp;&nbsp;fprintf(stdout, "[d]In %s[%s], addition print&#92;n", __FILE__, __func__);<br/>&nbsp;&nbsp;return;<br/>&#125;</div></div><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;静态库的生成, 源码test_s.c, 和动态库的测试方法一致,定义了两个全局函数,自增一个静态变量和打印变量之值. 生成方法:<br/>ar ru libtest_s.a test_s.o && ranlib libtest_s.a<br/><br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">[yhzh@localhost 20090530]$ cat test_s.c<br/>#include "test.h"<br/>#include "test_lib.h"<br/><br/>static int a = 0;<br/><br/>/* add __attribute__((weak)) here? */<br/>int test_inc()<br/>&#123;<br/>&nbsp;&nbsp;fprintf(stdout, "[s]Begin in %s, static a is %d&#92;n", __FILE__, a);<br/>&nbsp;&nbsp;a++;<br/>&nbsp;&nbsp;fprintf(stdout, "[s]End in %s, static a is %d&#92;n", __FILE__, a);<br/><br/>&nbsp;&nbsp;return a;<br/>&#125;<br/><br/>void print_s()<br/>&#123;<br/>&nbsp;&nbsp;fprintf(stdout, "[s]In %s[%s], static a is %d&#92;n", __FILE__, __func__, a);<br/>&nbsp;&nbsp;return;<br/>&#125;<br/><br/>void addition_s()<br/>&#123;<br/>&nbsp;&nbsp;fprintf(stdout, "[s]In %s[%s], addition print&#92;n", __FILE__, __func__);<br/>&nbsp;&nbsp;return;<br/>&#125;</div></div><br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;源码test_lib.c, 调用同名的自增函数, 调用打印动态库函数, 调用或者不调用打印静态库函数. 生成两个可执行目标文件的方法:<br/>gcc -o test_lib_d test_lib.o -Wl,-rpath,/home/yhzh/code/c/test/20090530 -L/usr/local/lib -L/home/yhzh/tools/lib -L. -ltest_d -ltest_s<br/>gcc -o test_lib_s test_lib.o -Wl,-rpath,/home/yhzh/code/c/test/20090530 -L/usr/local/lib -L/home/yhzh/tools/lib -L. -ltest_s -ltest_d<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以不同顺序加载静态库和动态库生成可执行目标文件.<br/><br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">[yhzh@localhost 20090530]$ cat test_lib.c<br/>#include "test.h"<br/>#include "test_lib.h"<br/><br/>int main(int argc, char **argv)<br/>&#123;<br/>&nbsp;&nbsp;int a = 0;<br/><br/>&nbsp;&nbsp;a = test_inc();<br/>&nbsp;&nbsp;print_d();<br/>&nbsp;&nbsp;print_s();<br/>&nbsp;&nbsp;fprintf(stdout, "[1]after test_inc, a is %d&#92;n", a);<br/><br/>&nbsp;&nbsp;a = test_inc();<br/>&nbsp;&nbsp;print_d();<br/>&nbsp;&nbsp;print_s();<br/>&nbsp;&nbsp;fprintf(stdout, "[2]after test_inc, a is %d&#92;n", a);<br/><br/>&nbsp;&nbsp;return 0;<br/>&#125;</div></div><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A部分: 运行生成的test_lib_d 和 test_lib_s, 可以得到如下结果:<br/>&nbsp;&nbsp;<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">[yhzh@localhost 20090530]$ ./test_lib_d<br/>[s]Begin in test_s.c, static a is 0<br/>[s]End in test_s.c, static a is 1<br/>[d]In test_d.c[print_d], static a is 0<br/>[s]In test_s.c[print_s], static a is 1<br/>[1]after test_inc, a is 1<br/>[s]Begin in test_s.c, static a is 1<br/>[s]End in test_s.c, static a is 2<br/>[d]In test_d.c[print_d], static a is 0<br/>[s]In test_s.c[print_s], static a is 2<br/>[2]after test_inc, a is 2<br/><br/>[yhzh@localhost 20090530]$ ./test_lib_s<br/>[s]Begin in test_s.c, static a is 0<br/>[s]End in test_s.c, static a is 1<br/>[d]In test_d.c[print_d], static a is 0<br/>[s]In test_s.c[print_s], static a is 1<br/>[1]after test_inc, a is 1<br/>[s]Begin in test_s.c, static a is 1<br/>[s]End in test_s.c, static a is 2<br/>[d]In test_d.c[print_d], static a is 0<br/>[s]In test_s.c[print_s], static a is 2<br/>[2]after test_inc, a is 2</div></div><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这个结果似乎很出乎意料, 为什么首先加载动态库时, 调用test_inc()也是进入了静态库中定义的函数中呢?<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;B部分: 当注释掉test_lib.c中的两行print_s():<br/>&nbsp;&nbsp;<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">11&nbsp;&nbsp;&nbsp;&nbsp;//print_s();<br/>...<br/>16&nbsp;&nbsp;&nbsp;&nbsp;//print_s();</div></div><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;然后再编译运行,可以得到如下结果:<br/>&nbsp;&nbsp;<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">[yhzh@localhost 20090530]$ ./test_lib_d<br/>[d]Begin in test_d.c, static a is 0<br/>[d]End in test_d.c, static a is 1<br/>[d]In test_d.c[print_d], static a is 1<br/>[1]after test_inc, a is 1<br/>[d]Begin in test_d.c, static a is 1<br/>[d]End in test_d.c, static a is 2<br/>[d]In test_d.c[print_d], static a is 2<br/>[2]after test_inc, a is 2<br/><br/>[yhzh@localhost 20090530]$ ./test_lib_s<br/>[s]Begin in test_s.c, static a is 0<br/>[s]End in test_s.c, static a is 1<br/>[d]In test_d.c[print_d], static a is 0<br/>[1]after test_inc, a is 1<br/>[s]Begin in test_s.c, static a is 1<br/>[s]End in test_s.c, static a is 2<br/>[d]In test_d.c[print_d], static a is 0<br/>[2]after test_inc, a is 2</div></div><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这个结果才是意料之中(可以看运行结果,也可以看链接之后的可执行目标文件的大小).要理解这样的结果,必须理解链接器在链接静态库和动态库的过程中处理符号表的原理.如果能理解在运行可执行目标文件时,加载器的工作原理会更完美. 对于定义在多处的同样的全局符号名(例如分别定义在静态库中,动态库中和可重定位目标文件),在链接器链接过程中:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于动态库中的全局符号是这样处理的:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. 将动态库中一些符号信息和重定位信息拷贝进新目标文件的符号表(代码和数据都不处理).选择需要拷贝的符号是在新目标文件的符号表中未知的.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 将从动态库中引入的符号表中的head index域设置为UNDEF,value设置为0(可以通过readelf -s/nm/objdump -t查看),这样做的目的是,方便装载器运行时可以解析动态库文件中的代码和数据引用.<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于静态库中的全局符号是这样处理的:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. 先扫描新目标文件的符号表中未定义域(U域),寻找定义在静态库中的符号信息.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 如果存在某个符号信息或者重定位信息相对应,可以让未定义引用的符号从U域转移出来的话,则拷贝整个静态库的全局符号信息和重定位信息过来,并做head index和value调整.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3. 如果不存在任何一个符号信息或者重定位信息相对应,则放弃拷贝静态库的任何内容.<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;因此,在链接器同时处理既有可重定位目标文件,静态库文件和动态库文件时:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. 在静态库文件之间,链接顺序可以会导致未知符号错误(连接完毕之后,U域不为空),解决办法是调整静态库顺序,或交叉链接相互依赖的静态库.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 在静态库和动态库文件之间,这个关系比较复杂.如果链接动态库在前,而静态库在后, 那么只要静态库中没有U域中相应的任何一个全局符号,也就是链接器主动放弃操作静态库, 那么定义在动态库中的全局符号能得到保存;一旦存在任何一个全局的符号, 动态库中的全局同名符号, 会被静态库中的符号覆盖, 不管是否在静态库中强制设置了weak BIND属性,这个属性只对可重定位目标文件有效(这里不列出,源码包了也做了这个测试). 如果静态库在前,动态库在后,直接按流程链接即可.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;总之,在Linux平台(2.6.25/29),在加载多处定义的全局符号是,静态库优先级似乎高于动态库.如果对此感兴趣,可以参考< CS:APP >的第七章和< LINKER and LOADER >全书.<br/>&nbsp;&nbsp;<br/>附Makefile:<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">## <br/>## Copyright (C) 2008 Spark Zheng<br/>##<br/>## TAKE AS a common prototype of Makefile <br/>##<br/><br/>PREFIX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?= /home/yhzh/tools<br/>PROJECT_HOME&nbsp;&nbsp;?= /home/yhzh/code/c/test/20090530<br/><br/>export PREFIX<br/>export PROJECT_HOME<br/><br/>CC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= gcc<br/>CXX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= g++<br/><br/>CFLAGS&nbsp;&nbsp;&nbsp;&nbsp;= -g -W -Wall -fPIC<br/>CXXFLAGS&nbsp;&nbsp;= -g -W -Wall -fPIC<br/><br/>CFLAGS_WARN&nbsp;&nbsp;= -Wshadow -Wcast-qual -Winline -Wunreachable-code&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Wredundant-decls -Wmissing-prototypes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Wstrict-prototypes -Wnested-externs<br/>CXXFLAGS_WARN&nbsp;&nbsp;= <br/><br/>CFLAGS_PREVD&nbsp;&nbsp;= -D_DEBUG<br/>CXXFLAGS_PREVD&nbsp;&nbsp;= -D_DEBUG<br/><br/>CFLAGS_OPT&nbsp;&nbsp;&nbsp;&nbsp;= -O2 -fomit-frame-pointer<br/>CXXFLAGS_OPT&nbsp;&nbsp;= -O2<br/><br/>INCFLAGS&nbsp;&nbsp;:= -I. -I./include -I.. -I../include -I$(PREFIX)/include<br/><br/>LDFLAGS&nbsp;&nbsp; := -Wl,-rpath,$(PROJECT_HOME) &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -L/usr/local/lib -L$(PREFIX)/lib -L.<br/>LIB_LDFLAGS&nbsp;&nbsp;:= $(LDFLAGS) -shared<br/><br/>LIBS&nbsp;&nbsp;&nbsp;&nbsp; = -lpthread -levent<br/><br/>RANLIB&nbsp;&nbsp;&nbsp;&nbsp;= ranlib<br/>AR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= ar<br/>ARFLAGS&nbsp;&nbsp;&nbsp;&nbsp;= ru<br/><br/>INSTALL&nbsp;&nbsp; ?= install -c<br/>UNINSTALL&nbsp;&nbsp;?= rm -f<br/><br/>DIRS&nbsp;&nbsp;&nbsp;&nbsp;= <br/>DIRS&nbsp;&nbsp;&nbsp;&nbsp; += <br/><br/><br/>TARGETS&nbsp;&nbsp; = $(EXEC_TARGETS) $(LIB_TARGETS) <br/>EXEC_TARGETS&nbsp;&nbsp;= test_lib_d test_lib_s test_lib_o<br/>LIB_TARGETS&nbsp;&nbsp;&nbsp;&nbsp;= libtest_d.so libtest_s.a<br/>LIB_HEADS&nbsp;&nbsp;&nbsp;&nbsp;= <br/><br/>OBJECTS&nbsp;&nbsp;&nbsp;&nbsp;= $(EXEC_OBJECTS) $(LIB_OBJECTS)<br/>EXEC_OBJECTS&nbsp;&nbsp;= test_lib.o<br/>LIB_OBJECTS&nbsp;&nbsp;&nbsp;&nbsp;= test_d.o test_s.o test_o.o<br/><br/><br/>all: $(TARGETS)<br/><br/>test_lib_d: $(EXEC_OBJECTS) $(LIB_TARGETS)<br/>&nbsp;&nbsp;set -e; for i in $(DIRS); do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make all enter $$i."; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;make -C $$i; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make all leave $$i."; &#92;<br/>&nbsp;&nbsp;done;<br/>&nbsp;&nbsp;$(CC) -o $@ $(EXEC_OBJECTS) $(LDFLAGS) -ltest_d -ltest_s<br/><br/>test_lib_s: $(EXEC_OBJECTS) $(LIB_TARGETS)<br/>&nbsp;&nbsp;set -e; for i in $(DIRS); do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make all enter $$i."; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;make -C $$i; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make all leave $$i."; &#92;<br/>&nbsp;&nbsp;done;<br/>&nbsp;&nbsp;$(CC) -o $@ $(EXEC_OBJECTS) $(LDFLAGS) -ltest_s -ltest_d<br/>&nbsp;&nbsp;<br/>test_lib_o: $(EXEC_OBJECTS) $(LIB_TARGETS) test_o.o<br/>&nbsp;&nbsp;set -e; for i in $(DIRS); do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make all enter $$i."; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;make -C $$i; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make all leave $$i."; &#92;<br/>&nbsp;&nbsp;done;<br/>&nbsp;&nbsp;$(CC) -o $@ $(EXEC_OBJECTS) $(LDFLAGS) -ltest_s -ltest_d test_o.o<br/><br/>libtest_d.so: test_d.o<br/>&nbsp;&nbsp;$(CC) -o $@ $< $(LIB_LDFLAGS)<br/><br/>libtest_s.a: test_s.o<br/>&nbsp;&nbsp;$(AR) $(ARFLAGS) $@ $<<br/>&nbsp;&nbsp;$(RANLIB) $@<br/><br/><br/>.SUFFIXES:<br/>.SUFFIXES:&nbsp;&nbsp;.c .cc .C .cpp .o<br/><br/>.c.o :<br/>&nbsp;&nbsp;$(CC) -o $@ -c $< $(CFLAGS) $(CFLAGS_WARN) $(CFLAGS_PREVD) $(INCFLAGS)<br/><br/>count:<br/>&nbsp;&nbsp;-wc *.c *.cc *.C *.cpp *.h *.hpp<br/>&nbsp;&nbsp;set -e; for i in $(DIRS); do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make count enter $$i."; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;make -C $$i count; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make count leave $$i."; &#92;<br/>&nbsp;&nbsp;done;<br/><br/>clean:<br/>&nbsp;&nbsp;-rm -f $(OBJECTS) $(TARGETS) *.swp *~ core.*<br/>&nbsp;&nbsp;set -e; for i in $(DIRS); do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make clean enter $$i."; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;make -C $$i clean; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make clean leave $$i."; &#92;<br/>&nbsp;&nbsp;done;<br/><br/>install:<br/>ifneq ("$(EXEC_TARGETS)","")<br/>&nbsp;&nbsp;$(INSTALL) $(EXEC_TARGETS) $(PREFIX)/bin/<br/>endif<br/>ifneq ("$(LIB_TARGETS)","")<br/>&nbsp;&nbsp;$(INSTALL) $(LIB_TARGETS) $(PREFIX)/lib/<br/>endif<br/>ifneq ("$(LIB_HEADS)","")<br/>&nbsp;&nbsp;$(INSTALL) $(LIB_HEADS) $(PREFIX)/include/<br/>endif<br/>&nbsp;&nbsp;set -e; for i in $(DIRS); do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make install enter $$i."; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;make -C $$i install; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make intall leave $$i."; &#92;<br/>&nbsp;&nbsp;done;<br/><br/>uninstall:<br/>ifneq ("$(EXEC_TARGETS)","")<br/>&nbsp;&nbsp;set -e;&nbsp;&nbsp;for i in $(EXEC_TARGETS); do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;$(UNINSTALL) $(PREFIX)/bin/$$i; &#92;<br/>&nbsp;&nbsp;done;<br/>endif<br/>ifneq ("$(LIB_TARGETS)","")<br/>&nbsp;&nbsp;set -e;&nbsp;&nbsp;for i in $(LIB_TARGETS) do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;$(UNINSTALL) $(PREFIX)/lib/$$i; &#92;<br/>&nbsp;&nbsp;done;<br/>endif<br/>ifneq ("$(LIB_HEADS)","")<br/>&nbsp;&nbsp;set -e;&nbsp;&nbsp;for i in $(LIB_HEADS) do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;$(UNINSTALL) $(PREFIX)/include/$$i; &#92;<br/>&nbsp;&nbsp;done;<br/>endif<br/>&nbsp;&nbsp;set -e; for i in $(DIRS); do &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make uninstall enter $$i."; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;make -C $$i uninstall; &#92;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo "make uninstall leave $$i."; &#92;<br/>&nbsp;&nbsp;done;<br/><br/>.PHONY: all<br/>.PHONY: count<br/>.PHONY: clean<br/>.PHONY: install<br/>.PHONY: uninstall<br/></div></div><br/><a href="attachment.php?fid=2">点击这里下载文件</a><br/>Tags - <a href="http://wf.xplore.cn/go.php/tags/linker/" rel="tag">linker</a>
]]>
</description>
</item><item>
<link>http://wf.xplore.cn/post/test_lib.php#blogcomment5</link>
<title><![CDATA[[评论] 链接静态库和动态库对符号处理的一些测试(4m/1,2/2)]]></title> 
<author>vps观察者 &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Wed, 29 Jul 2009 19:39:18 +0000</pubDate> 
<guid>http://wf.xplore.cn/post/test_lib.php#blogcomment5</guid> 
<description>
<![CDATA[ 
	在linux下编译我一直很头疼
]]>
</description>
</item><item>
<link>http://wf.xplore.cn/post/test_lib.php#blogcomment26</link>
<title><![CDATA[[评论] 链接静态库和动态库对符号处理的一些测试(4m/1,2/2)]]></title> 
<author>涂涂 &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Mon, 28 Jun 2010 23:54:12 +0000</pubDate> 
<guid>http://wf.xplore.cn/post/test_lib.php#blogcomment26</guid> 
<description>
<![CDATA[ 
	<br/><br/>我也是刚刚开始学习linux最起码的权限划分都不会 - -！
]]>
</description>
</item><item>
<link>http://wf.xplore.cn/post/test_lib.php#blogcomment34</link>
<title><![CDATA[[评论] 链接静态库和动态库对符号处理的一些测试(4m/1,2/2)]]></title> 
<author>cowboys jersey &lt;donejerseys@yahoo.cn&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Fri, 06 Aug 2010 02:18:32 +0000</pubDate> 
<guid>http://wf.xplore.cn/post/test_lib.php#blogcomment34</guid> 
<description>
<![CDATA[ 
	很好的东东<a href="http://www.nflcowboysjerseys.com" target="_blank">Dallas Cowboys shop</a>
]]>
</description>
</item><item>
<link>http://wf.xplore.cn/post/test_lib.php#blogcomment35</link>
<title><![CDATA[[评论] 链接静态库和动态库对符号处理的一些测试(4m/1,2/2)]]></title> 
<author>watch &lt;grayvoice@163.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Wed, 18 Aug 2010 01:34:01 +0000</pubDate> 
<guid>http://wf.xplore.cn/post/test_lib.php#blogcomment35</guid> 
<description>
<![CDATA[ 
	虽然看的不是很懂，还是要说一句谢谢的<br/><a href="http://www.watch680.com" target="_blank">手表品牌排名</a>
]]>
</description>
</item>
</channel>
</rss>