The shared library soname
In the earlier example, we embedded the actual name (the
It is possible to create an
At run-time, the dynamic linker will use the
The purpose of the
- At run-time, executable can use a version of the shared library that is different (but compatible) from that against which it was linked.
The shared library
soname (cont.) Here's how to use a
soname: - Specify
soname when creating shared library: $ gcc -fPIC -c -Wall -g mod1.c mod2.c mod3.c $ gcc -shared -Wl,-soname,libbar.so -o libfoo.so \ mod1.o mod2.o mod3.o
instructs linker to mark the shared library libfoo.so with the soname libbar.so. - Create executable:
$ gcc -g -Wall -o prog prog.c libfoo.so
libfoo.so contains the soname libbar.so and embeds the latter name inside the executable. - Run the program:
$ LD_LIBRARY_PATH=. ./prog ./prog: error in loading shared libraries: libbar.so: cannot open shared object file: No such file or directory
libbar.so. - Create a symbolic link from the
soname to the real name of the library: $ ln -s libfoo.so libbar.so $ LD_LIBRARY_PATH=. ./prog Called mod1-x1 Called mod2-x2
At run-time this link can point to a version of the library which is different from the version against which linking was performed.
The shared library
soname (cont.) This diagram shows the steps required in building a shared library, linking a program against it, and creating the requiredsoname
symbolic link. The shared library
soname (cont.) This diagram shows the steps that occur as the program is executed:
Compatible Versus Incompatible Libraries
We probably need to change a library over time.
A new library version is said to be
compatible with an existing library version if all of the following conditions hold true: - The semantics of each function in the library remain unchanged.
- All functions continue to produce
same effect on global variables and returned arguments.
- All functions continue to return the
same result values.
- Performance improvements and bug fixes (perhaps resulting in closer conformance to specified behavior)
are compatible changes.
- All functions continue to produce
- No function in the library API is removed.
New functions can be added.
- The structures exported (i.e. allocated within and returned) by each function remain unchanged.
Possible exception: new items may be added to the end of the existing structure
If any of these conditions is violated, then the new library version is
incompatible with the previous version.
Shared library versions and naming
- If a new version of a shared library is
compatible with an existing library, we can make a new minor version of the library.
- If a new version of a shared library is
incompatible with an existing library, we must make a new major version of the library.
- Constraint: it must be possible to continue running programs requiring the older version of the library.
- Solution: a
naming convention is used for shared library real names and sonames.
Shared library versions and naming (cont.)
Real name
Name of the file containing library code.
Format:
libname.so.major-id.minor-id - Major version identifier
is a number which is sequentially incremented with each incompatible release of the library.
- Minor version identifier
distinguishes different compatible minor versions of a library within the same major version. Usually either a number, or two numbers separated by a dot, with first number identifying
minor version, and second number indicating a patch level or revision number within the minor version.
Examples:
libdemo.so.1.0.1 libdemo.so.1.0.2 libdemo.so.2.0.1 libreadline.so.4.0
Shared library versions and naming (cont.)
soname
Format:
libname.so.major-id soname
includes the same major version identifier as corresponding real name, but does not include minor versionidentifier. Purpose: run-time loading is dependent only on major version number of the library
soname
is created as a symbolic link (usually in same directory as real name). - The
soname for each major library version points to most recent minor version.
- Since it is the
soname (not the real name) that is embedded in executable by linker:
- At any time, we
can change soname symbolic link to point to a newer minor version.
- Different
major versions can co-exist and be accessed by the programs that require them.
- At any time, we
Examples of
sonames (along with the real names to which they might be symbolically linked): libdemo.so.1 -> libdemo.so.1.0.2 libdemo.so.2 -> libdemo.so.2.0.1 libreadline.so.4 -> libreadline.so.4.0
Shared library versions and naming (cont.)
Linker name
- Format:
libname.so
- Purpose: allows us to
construct version-independent link commands which automatically operate with the right (i.e. most up to date) version of the shared library.
- Created as a
symbolic link to either real name or soname of most recent major version of the library.
- More convenient to have it point to
soname. Why?
- Examples:
libdemo.so -> libdemo.so.2 libreadline.so -> libreadline.so.4
Shared library versions and naming (cont.)
Relationships between shared library names
Creating Shared Libraries Using Standard Naming Conventions
We can create a shared library using standard naming conventions as follows:
- Create the shared library with
real name libdemo.so.1.0.1 and soname libdemo.so.1. $ gcc -fPIC -g -c -Wall mod1.c mod2.c mod3.c $ gcc -shared -Wl,-soname,libdemo.so.1 -o libdemo.so.1.0.1 \ mod1.o mod2.o mod3.o
- Create symbolic links for the
soname and linker name: $ ln -s libdemo.so.1.0.1 libdemo.so.1 $ ln -s libdemo.so.1 libdemo.so $ ls -l libdemo.so* | cut -c 1-11,55- # Verify the setup lrwxrwxrwx libdemo.so -> libdemo.so.1 lrwxrwxrwx libdemo.so.1 -> libdemo.so.1.0.1 -rwxr-xr-x libdemo.so.1.0.1
- Build executable using the
linker name: $ gcc -g -Wall -o ./prog prog.c -L. -ldemo
- Run the program as usual:
$ LD_LIBRARY_PATH=. ./prog Called mod1-x1 Called mod2-x2
Installing Shared Libraries
- Production applications should not require the user to set
LD_LIBRARY_PATH.
- Privileged users can
install a shared library in one of the standard library directories:
- /usr/lib
- directory in which most standard libraries are installed
- /lib
- directory containing libraries required during system startup
- /usr/local/lib
- non-standard or experimental libraries should be installed here; Also useful if
/usr/lib is a network mount shared among multiple systems, and we want to install a library locally.
/etc/ld.so.conf.【注:linux版本如有“/etc/ld.so.conf.d目录”也可以将my.conf这样的配置文件放在/etc/ld.so.conf.d目录下, my.conf的内容格式为 /ldddir/dir】
- /usr/lib
- After installation, symbolic links for
soname and linker name must be created, as relative links in the same directory.
ldconfig(8)
ldconfig(8)
addresses two potential problems with shared libraries: - Speed: Shared libraries can reside in many different directories: it
could take the dynamic linker a long time to search them.
- Manually keeping
sonames symlinks up to date is error-prone as new versions of libraries are installed, or old versions are removed.
ldconfig
solves these problems by: - Creating a cache file:
ldconfig
Cache file is used by dynamic linker at run-timesearches for latest major library versions in:
- all of the directories specified in
/etc/ld.so.conf - /lib
- /usr/lib
andupdates a cache file, /etc/ld.so.cache, to contain a list of the latest major library versions, and their locations. when resolving library names.
- all of the directories specified in
- Automating the creation of
sonames:
- ldconfig
examines (the latest minor version of) each major version of each library to find the embedded soname, and
- creates a relative symbolic link for this
soname, in the same directory as the library.
- ldconfig
In order to work properly,
ldconfig relies on the use of the standard naming convention for shared libraries (i.e.,libname.maj.min)
ldconfig(8) (cont.)
Example - installing two different major versions of a library.
We copy both versions into
/usr/lib: # mv libdemo.so.1.0.1 libdemo.so.2.0.1 /usr/lib # cd /usr/lib
We run
ldconfig to update the dynamic linker cache: # ldconfig -v | grep libdemo libdemo.so.1 -> libdemo.so.1.0.1 (changed) libdemo.so.2 -> libdemo.so.2.0.1 (changed)
- (We use
grep to eliminate other output from ldconfig.)
Then we manually create the
linker name: # ln -s libdemo.so.2 libdemo.so
To install a new 2.x minor version:
# mv libdemo.so.2.0.2 /usr/lib # cd /usr/lib # ldconfig -v | grep libdemo libdemo.so.1 -> libdemo.so.1.0.1 libdemo.so.2 -> libdemo.so.2.0.2 (changed)
The
ldconfig command effectively also updates linker name...
ldconfig(8) (cont.)
- ldconfig
should be run whenever a new library is installed or an existing library is updated or removed.
- ldconfig -p
shows the current contents of the cache.
Upgrading Shared Libraries
Note:
A new major or minor version of a library can be installed, even while running programs are making use of an existing version. Example - upgrading a shared library with a new minor version (1.0.2):
# gcc -fPIC -g -c -Wall mod1.c mod2.c mod3.c # gcc -shared -Wl,-soname,libdemo.so.1 -o libdemo.so.1.0.2 \ mod1.o mod2.o mod3.o # mv libdemo.so.1.0.2 /usr/lib # ldconfig -v | grep libdemo libdemo.so.1 -> libdemo.so.1.0.2 (changed)
Assuming the
linker name was already correctly set up, we do not need to modify it. Then upgrading to a new major version (2.0.1):
# gcc -fPIC -g -c -Wall mod1.c mod2.c mod3.c # gcc -shared -Wl,-soname,libdemo.so.2 -o libdemo.so.2.0.1 \ mod1.o mod2.o mod3.o # mv libdemo.so.2.0.1 /usr/lib # ldconfig -v | grep libdemo libdemo.so.1 -> libdemo.so.1.0.2 libdemo.so.2 -> libdemo.so.2.0.1 (changed) # cd /usr/lib # ln -sf libdemo.so.2 libdemo.so
ldconfig
automatically creates a soname symbolic link, but we must manually update the linker name symbolic link.
Finding Shared Libraries at Run-time
The dynamic linker searches for shared libraries in the following order:
- If
LD_LIBRARY_PATH is defined, then each of the colon-separated directories listed in its value is searched in turn.
- /etc/ld.so.cache
is checked to see if it contains an entry for the library.
- /lib
and /usr/lib are searched (in that order).
英文通俗易懂,大致总结一下:
1.gcc编译编译选项-soname 为实际库文件(libsoname.so.major.minor)生成的别名,这个别名 libname.so.major,别名存放在 实际库文件的头部,执行readelf -dlibsoname.so.major.minor命令可以看到“0x0000000e (SONAME) Library soname: [libname.so.major]”
2.执行ldconfig -n /current_dir命令,ldconfig会去读取 /curr ent_dir目录下所有动态库文件中(SONAME)信息,并生成指向各动态库文件的链接文件,链接文件的名字为相应 (SONAME)字段值(libname.so.major)。
3.如果/current_dir被加入到/etc/ld.so.conf或/etc/ld.so.conf.d/中,则执行ldconfig -v命令可生成/current_dir目录下所有的SONAME链接文件并查看繁多的链接信息。
4.连接器(linker)通过SONAME字段值( libname.so.major)在用户指定的路径查找链接 libname.so.major。
5.手动指定 libname.so -->libname.so.major,控制程序(progam)链接的 实际库文件( libsoname.so.major.minor),在/current_dir目录下我们会看到形如,
libname.so--> libname.so.major
libname.so.major -->libname.so.major.minor
的链接,其中仅 libname.so.major.minor为规则文件。
6.动态库的主、次版本号利用如下的一套约定即可实现动态库的版本管理。
a.新生成库实际文件libname.so.major.minor,当库中函数接口未变化(更新不影响相关模块)主版本号major不改变,次版本号minor加1。
b. 当 库中函数接口变化(更新影响相关模块 )主版本号major加1 ,次版本号从0开始增加。
c.当出现新旧版本共存情况
libname.so.1 --> libname.so.1.2
libname.so.2--> libname.so.2.0
时需用户通过手动建立链接(libname.so链接libname.so.1还是libname.so.2),决定程序链接动态库。
7.实际项目中可通过Makefile文件管理项目的动态库版本,具体实施过程待实践。
- Specify