⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 038.htm

📁 尝试使用有意义的结构与组织
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<HTML><HEAD><meta http-equiv="Content-Type" content="text/html; charset=GB2312"><TITLE>-->Linux HowTo 中译版-->The Linux GCC HOWTO中译版V0.1: 连结(Linking)</TITLE>
<META NAME="keywords" CONTENT=" Linux HowTo 中译版 The Linux GCC HOWTO中译版V0.1: 连结(Linking)">
<META NAME="description" CONTENT=" - Linux HowTo 中译版 - The Linux GCC HOWTO中译版V0.1: 连结(Linking)">

<style>
<!--
#page {position:absolute; z-index:0; left:0px; top:0px}
.tt3 {font: 9pt/12pt "宋体"}
.tt2 {font: 12pt/15pt "宋体"}
a {text-decoration:none}
a:hover {color: blue;text-decoration:underline}
-->
</style>
</HEAD>
<body text="#000000" aLink=#9900ff link=#006699 vLink=#006699 bgcolor="#FFFFFF" leftmargin="3" topmargin="3" marginheight="3" marginwidth="3">
<TABLE WIDTH="100%" CELLPADDING=10 CELLSPACING=0 BORDER=0>
<TR>
<TD CLASS="tt3" VALIGN="top" width="8%"  bgcolor="#e0e0e0"><strong><A HREF="039.htm">后一页</A><BR>
<A HREF="037.htm">前一页</A><BR>

<A HREF="index.html">回目录</A><BR>
<A HREF="../../../../index.htm">回首页</A><BR>
</strong>
</TD>
<TD class="tt2" bgcolor="#F5F8F8" width="84%"><center><B><FONT style="FONT-SIZE: 16.5pt" COLOR="#FF6666" FACE="楷体_GB2312">The Linux GCC HOWTO中译版V0.1: 连结(Linking)</FONT></B></center>
<hr color="#EE9B73" size="1" width="94%">
姓名:Daniel Barlow<br>
Email:dan@detached.demon.co.uk<br>
地址 :<br>
转摘 :http://member.netease.com/</p>
<BR>
<BR>
<hr SIZE="0">
<BR>
<p><br>
<br>
6. 连结(Linking) <br>
由於静态(static)与共享(shared)程式库两者间不相容的格式(incompatible
binary formats)的差异性(distinction)与动词*link*过量使用(overloading)於指称*编译完成後的事情*与*当编译过的程式使用时(invoke)所发生的事情*这两件事上头,使得这一章节变得复杂了许多.(
and, actually, the overloading of the word `load' in a comparable but opposite sense)不过,再复杂也就是这样了,所以阁下不必过於担心.
<br>
<br>
为了稍微减轻读者的困惑,我们称执行期间(runtime)所发生的事为*动态载入(dynamic
loading)*,这一主题会在下一章节中谈到.你也会在别的地方看到我把动态载入描述成*动态连结(dynamic
linking)*,不过不会是在这一章节中.换句话说,这一章节所谈的,全部是指发生在编译结束後的连结(linking).
<br>
<br>
6.1. 共享程式库 vs静态程式库 <br>
建立程式的最後一个步骤便是连结;也就是将所有分散的小程式(pieces)组合起来,看看是否遗漏了些什麽.很明显的,有一些事情是很多程式都会想做的---例如,开启档案(open
files),接著所有与开档有关的小程式(pieces)就会以程式库的档案型态提供给你的程式.在普通的Linux系统上,这些小程式可以在/lib与/usr/lib/目录底下找到.
<br>
<br>
<br>
当你用的是一静态的程式库时,连结器会找出程式所需的模组(bits),然後实际(physically)将它们拷贝到执行档内.然而,对共享程式库而言,就不是这样了.共享程式库会在执行档内留下一个符号(note),指明*当程式执行时,首先必须载入这个程式库*.很明显的,共享程式库是试图使执行档变得更小;也等同於使用更少的记忆体与磁碟空间.Linux内定的行为是连结共享程式库,只要Linux能找到这些共享程式库的话,就没什麽问题;不然,Linux就会连结静态的了.如果你想要共享程式库的话,检查这些程式库(*.sa
for a.out, *.so for ELF)是否住在它们该在的地方,而且是可读取的. <br>
<br>
在Linux上,静态程式库会有类似libname.a这样的名称;而共享程式库则称做libname.so.x.y.z,此处的x.y.z是指版本序号的样式.共享程式库通常都会有连结符号指向静态程式库(很重要的)与(on
a.out configurations)相关联的.sa档案.标准的程式库会包含共享与静态程式库两种格式.
<br>
<br>
你可以用ldd (List Dynamic Dependencies)来查出某支程式需要哪些共享程式库.
<br>
<br>
$ ldd /usr/bin/lynx <br>
libncurses.so.1 =&gt; /usr/lib/libncurses.so.1.9.6 <br>
libc.so.5 =&gt; /lib/libc.so.5.2.18 <br>
<br>
<br>
这是说在我的系统上,WWW浏览器(browser)*lynx*会依赖libc.so.5 (the C library)与libncurses.so.1(终端机萤幕的控制)的存在(presence).若某支程式缺乏独立性(dependencies),
ldd就会说`statically linked'或是`statically linked (ELF)'. <br>
<br>
6.2. Interrogating libraries (`which library is sin() in?') <br>
nm 程式库名称 应该会列出此程式库名称所参考到的所有符号(symbols).这个指令可以应用在静态与共享程式库上.假设你想知道tcgetattr()是在哪儿定义的:你可以如此做
<br>
<br>
<br>
$ nm libncurses.so.1 |grep tcget <br>
U tcgetattr <br>
<br>
<br>
*U*说明了*未定义(undefined)*---也就是说ncurses程式库有用到tegetattr(),但是并没有定义它.你也可以这样做,
<br>
<br>
<br>
$ nm libc.so.5 | grep tcget <br>
00010fe8 T __tcgetattr <br>
00010fe8 W tcgetattr <br>
00068718 T tcgetpgrp <br>
<br>
<br>
*W*说明了*弱势(weak)*,意指符号虽已定义,但可由不同程式库中的另一定义所取代(overridden).而最直接的(straightforward)*正常(normal)*定义(像是tcgetpgrp)是由*T*所标示.
<br>
<br>
<br>
标题所谈的问题,最简明的答案便是libm.(so|a)了.所有定义在&lt;math.h&gt;的函数都保留在maths程式库内;因此,当你用到其中任何一个函数时,都需要以-lm的参数连结此程式库.
<br>
<br>
6.3. X档案??? <br>
ld: Output file requires shared library `libfoo.so.1` <br>
<br>
ld与其相类似的命令在搜寻档案的策略(strategy)上,会依据版本的差异而有所不同,但是唯一一个你可以合理假设的内定目录便是/usr/lib了.如果你希望身处它处的程式库也列入搜寻的行列中,那麽你就必须以-L选项告知gcc或是ld.
<br>
<br>
要是你发现一点效果也没有,就赶紧察看看那档案是不是还乖乖的躺在原地.就a.out而言,以-lfoo参数来连结,会驱使ld去寻找libfoo.sa
(shared stubs);如果没有成功,就会换成寻找libfoo.a (static).就ELF而言, ld会先找libfoo.so,然後是libfoo.a.libfoo.so通常是一个符号连结,连结至libfoo.so.x.
<br>
<br>
6.4. 建立你自己的程式库(Building your own libraries) <br>
6.4.1. 版本控制(Version control) <br>
与其它任何的程式一样,程式库也有修正不完的bugs的问题存在.它们也可能产生出一些新的特点,更改目前存在的模组的功效,或是将旧的移除掉.这对正在使用它们的程式而言,可能会是一个大问题.如果有一支程式是根据那些旧的特点来执行的话,那怎麽办?
<br>
<br>
所以,我们引进(introduce)了程式库版本编号(versioning)的观念.我们将程式库*次要(minor)*与*主要(major)*的变更分门别类(categorize),同时我们规定*次要*的变更是不允许用到这程式库的旧程式发生中断的现象(break).你可以从程式库的档名分辨出它的版本(实际上,严格来讲,对ELF而言仅仅是一场天大的谎言;继续读将下去,便可明白为什麽了):
libfoo.so.1.2的主要版本是1,次要版本是2.次要版本的编号可能真有其事,也可能什麽都没有---libc在这一点上用了*修正程度(patch-level)*的观念,而给出了名称像libc.so.5.2.18这样的程式库.次要版本的编号内若是放一些字母,底线,或是任何可以列印的ASCII字元,也是很合理的说.
<br>
<br>
ELF与a.out格式最主要的差别之一就是在建立共享程式库上.我们先看ELF,因为它比较简单一些.
<br>
<br>
6.4.2. ELF? 它到底是什麽东东ㄋㄟ? <br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -