`
vaqeteart
  • 浏览: 304156 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Linux系统中程序库文件简介

 
阅读更多
Linux系统中程序库文件简介
简介
库文件一般就是编译好的二进制文件,用于在链接阶段同目标代码一起生成可执行文件,或者运行可执行文件的时候调用库文件的某段代码。它与可执行文件相同之处是:两者都是编译好的二进制文件;与可执行文件不同的是,库文件无法直接执行(直观上来看它的源代码中没有main函数,一般只是一些函数模块的定义和实现)。我们开发的程序,无论是程序运行的时候,还是编译、链接的时候,一般都需要借助一些库,而很少直接只通过程序源代码生成完全独立的可执行文件。有许多著名的常用的用于开发或者程序运行的库,例如Qt库,gtk库,甚至是标准C库等等,通过使用它们可以充分体会到模块化编程和代码重用等的好处。本文对Linux库的编译,生成,使用进行了介绍,并且通过一个简单例子(开发自己的库)进行说明。

主要内容
原理
举例
其它

[原理]
为便于理解,我们可以将库分为三种类型:静态库,共享库,动态加载库,。下面分别介绍。
一、 静态库:
静态库实际就是一些目标文件(一般以.o结尾)的集合,静态库一般以.a结尾,只用于链接生成可执行文件阶段。具体来说,以c程序为例,一般我们编译程序源代码的时候,过程大致是这样的:以.c为后缀的源文件经过编译生成.o的目标文件,以.o为后缀的目标文件经过链接生成最终可执行的文件。我们可以在链接的时候直接链接.o的目标文件,也可以将这些.o目标文件打包集中起来,统一链接,而这个打包生成的集中了所有.o文件的文件,就是静态库。静态库只在程序链接的时候使用,链接器会将程序中使用到函数的代码从库文件中拷贝到应用程序中。一旦链接完成生成可执行文件之后,在执行程序的时候就不需要静态库了。由于每个使用静态库的应用程序都需要拷贝所用函数的代码,所以静态链接的文件会比较大,多个程序运行时占用空间比较大(每个程序在内存中都有一份重复的静态库代码),当然由于运行的时候不用动态加载了,速度会比共享库快一些。
我们可以在后面的例子中看到静态库的生成和应用的具体过程。

二、共享库:
1、共享库的概念:
共享库以.so结尾. (so == share object) 在程序链接的时候并不像静态库那样拷贝库中使用的函数代码到生成的可执行文件中,而只是作些标记。然后在程序开始启动运行的时候,动态地加载所需模块。所以,应用程序在运行的时候仍然需要共享库的支持。共享库链接出来的文件比静态库要小得多,运行多个程序时占用内存空间比静态库少(因为内存中只有一份共享库代码的拷贝),由于有一个动态加载的过程所以速度稍慢。
2、共享库的命名
一般一个共享库的有三个名字:soname, real-name, linker-name。
soname是用于区分版本的名字,它可能就是指向real-name(如果有这个文件的话)的链接,名称的形式一般是lib*.so.X.Y(这里的X,Y就是代表版本号)。
real-name是包含真正代码的实现文件。
linker-name是传递给连接器的名字,用于链接的搜索,一般它可能就是指向soname的连接,名称的形式一般是lib*.so。
这样做的目的主要是允许系统中多个版本的库文件共存,习惯上在命名库文件的时候通常与soname相同
下面看一个实例:
[quietheart@lv-k test]$ ls -l /usr/lib/libncurses*
lrwxrwxrwx 1 root root     20 2008-05-25 13:54 libncurses.so -> /lib/libncurses.so.5
lrwxrwxrwx 1 root root     13 2008-05-26 15:18 libncurses.so.5 -> libtermcap.so
上面的libncurses.so.5就是soname, 其中ncurses是库名,5分别是主版本号(major),当然也可以有次版本号(minor)和发行号(release)。(类似于libncurses.so.5.0.0)。这里的".so"表示共享库。通常soname只是real name的一个链接。而libtermcap.so 是ncurse库的real-name, 也就是包含真实代码实现的文件。libncurses.so 则是linker name,用于应用程序链接的时候的一个搜索名使用这个名字传递给链接器进行链接。 它通常是soname的一个链接,形式为libname.so。
实际上,每一个库都有一个soname,当连接器发现它正在查找的程序库中有这样一个名称,连接器便会将soname嵌入连结中的二进制文件内,而不是它正在运行的实际文件名,在程序执行期间,程序会查找拥有 soname名字的文件,而不是库的文件名,换句话说,soname是库的区分标志。
3、共享库的装载
(1) 在所有基于GNU glibc的系统(当然包括Linux)中,在启动一个ELF二进制执行程序时,
一个特殊的程序"程序装载器"会被自动装载并运行。在linux中,这个程序装载器就是
/lib/ld-linux.so.X(X是版本号)。它会查找并装载应用程序所依赖的所有共享库。
被搜索的目录保存在/etc/ls.so.conf文件中,但如果某个所使用的库的路径不在搜索之列,那么就只好自己加上了。当然,如果程序每次启动都要去搜索一遍,势必效率不堪忍受。Linux系统已经考虑这一点,对共享库采用了缓存管理。ldconfig就是实现这一功能的工具,其缺省读取/etc/ld.so.conf文件,对所有共享库按照一定规范建立符号连接,然后将信息写入/etc/ld.so.cache。每次搜索的时候实际通过ld.so.cache这个萑片文件进行搜索,/etc/ld.so.cache的存在大大加快了程序的启动速度。当然,每次修改ld.so.conf文件之后,应当运行一下“ldconfig”命令以便把信息也更新到缓存文件中。
(2) 也可以通过设置环境变量LD_LIBRARY_PATH来设置ld的装载路径。这样装载器就会首先搜索该变量的目录,然后才是默认目录。但是记住,LD_LIBRARY_PATH是用于开发和测试的,你可以将一些用于测试的替代共享库的目录放到该变量中,类似于/etc /ld.so.preload的作用。但是该变量不应该用于正常用户的正常程序。
(3) 如果不使用LD_LIBRARY_PATH环境变量,可以通过如下方式给装载器传入路径:
[quietheart@lv-k test]$ /lib/ld-linux.so.2 --library-path PATH EXECUTABLE
总之,想要你的共享库被装载,那么一般通过一下三个方式:
a)拷贝你的库到默认的库搜索路径/usr/lib中。
b)或设置环境变量LD_LIBRARY_PATH,在其中添加你的库所在的路径。
c) 或修改配置文件/etc/ld.so.conf加入你的库所在的路径,并刷新缓存ldconfig。

三、 动态加载库
1. 概念
动态加载库(dynamically loaded (DL) libraries)是指在程序运行过程中可以加载的函数库。而不是像共享库一样在程序启动的时候加载。DL对于实现插件和模块非常有用,因为他们可以让程序在允许时等待插件的加载。在Linux中,动态库的文件格式跟共享库没有区别,主要区别在于共享库是程序启动时加载,而动态加载库是运行的过程中加载。
有专门的一组API用于完成打开动态库,查找符号,处理出错,关闭动态库等功能。
下面对这些接口函数逐一介绍:
(1) dlopen  
函数原型:void *dlopen(const char *libname,int flag);
功能描述:dlopen必须在dlerror,dlsym和dlclose之前调用,表示要将库装载到内存,准备使用。
如果要装载的库依赖于其它库,必须首先装载依赖库。如果dlopen操作失败,返回NULL值;如果库已经被装载过,则dlopen会返回同样的句柄。
参数中的libname一般是库的全路径,这样dlopen会直接装载该文件;如果只是指定了库名称,在dlopen会按照下面的机制去搜寻:
a.根据环境变量LD_LIBRARY_PATH查找
b.根据/etc/ld.so.cache查找
c.查找依次在/lib和/usr/lib目录查找。
flag参数表示处理未定义函数的方式,可以使用RTLD_LAZY或RTLD_NOW。RTLD_LAZY表示暂时不去处理未定义函数,先把库装载到内存,等用到没定义的函数再说;RTLD_NOW表示马上检查是否存在未定义的函数,若存在,则dlopen以失败告终。
(2) dlerror
函数原型:char *dlerror(void);
功能描述:dlerror可以获得最近一次dlopen,dlsym或dlclose操作的错误信息,返回NULL表示无错误。dlerror在返回错误信息的同时,也会清除错误信息。
(3) dlsym
函数原型:void *dlsym(void *handle,const char *symbol);
功能描述:在dlopen之后,库被装载到内存。dlsym可以获得指定函数(symbol)在内存中的位置(指针)。
如果找不到指定函数,则dlsym会返回NULL值。但判断函数是否存在最好的方法是使用dlerror函数,
(4) dlclose
函数原型:int dlclose(void *);
功能描述:将已经装载的库句柄减一,如果句柄减至零,则该库会被卸载。如果存在析构函数,则在dlclose之后,析构函数会被调用。  

[举例]
首先给出我们所需要的程序的源代码:

//main.cpp文件,生成可执行文件的源代码。
#include<iostream>
#include "myfile.h"
using std::cout;
using std::endl;
int main(int argc, char *argv[])
{
cout<<"begin test"<<endl;
printInfo();
return 0;
}

//myfile.h,库的头文件
#ifndef __MYFILE_H
#define __MYFILE_H
void printInfo();
#endif

//myfile.cpp,库的实现代码
#include "myfile.h"
#include <iostream>
using std::cout;
using std::endl;
void printInfo()
{
cout<<"hello"<<endl;
}

从以上代码结构中我们可以知道,我们的代码只有三个文件:main.cpp,myfile.h,和myfile.cpp。
一、不使用库
有一点Linux编程知识的读者都会知道,有了这三个文件,我们就可以通过"g++ main.cpp myfile.cpp"命令,生成我们的可执行文件并运行。具体过程如下:
[root@lv-k mytest]# ls
main.cpp  myfile.cpp  myfile.h
[root@lv-k mytest]# g++ main.cpp myfile.cpp
[root@lv-k mytest]# ls
a.out  main.cpp  myfile.cpp  myfile.h
[root@lv-k mytest]# ./a.out
begin test
hello
在上面生成可执行文件的过程中,我们并没有使用任何库的概念,也就是说我们将所有文件都做为可执行文件的一个部分,最终生成了一个无论是编译、链接,还是运行的时候,都不依赖于任何库的,独立执行的可执行文件(实质上严格来讲这个可执行文件还是依赖库的,至少它依赖iostream库,这里不考虑这些),用下载过许多软件的朋友们的“术语”来说,我们现在生成的软件,就是一个“绿色”软件^_^。如果程序的源代码结构很复杂的化,那么这样编译的缺点是非常明显的,那就是这个程序采用非模块化的方式编译,至少不满足可重用性的特点。后面我们将介绍使用库来实现模块化编译这个程序。

二、使用库
我们将要用如下的方式组织我们的程序:
1)对应我们应用程序,也就是可执行文件的代码只有一个,那就是main.cpp文件。
2)我们的可执行文件的生成或者运行,依赖外部的一些库,例如iostream,以及myfile.h所对应的库,这里我们重点关注myfile.h这个我们自己定义的库。
3)将myfile.h和myfile.cpp做为独立的库进行编译,库的实现实际是通过myfile.cpp生成的;而myfile.h的作用就是让使用这个库的程序知道这个库包含了什么功能的函数,也就是说,库的头文件只是一个让其它程序使用该库的接口文件。
这样就实现了模块化的目的,将整个程序划分为可执行文件部分,以及可执行文件所使用的库这两个相对独立的部分。后面将讲述如何真正在编译执行的角度实现这种划分的思想。

1、静态库方式
采用如下方式进行:
1.1生成静态库:
1)只编译myfile.cpp生成myfile.o
[quietheart@lv-k test]$g++ -c myfile.cpp
2)根据myfile.o生成库libmy.a
[quietheart@lv-k test]$ar r libmy.a myfile.o
3)删除myfile.o和myfile.cpp
[quietheart@lv-k test]$rm myfile.cpp myfile.o
这样,我们第2步使用ar命令,将.o文件打包添加到libmy.a中,打包生成的lib*.a文件,就是静态库(相对的动态库是lib*.so文件)。关于ar命令,除了r选项还有c,s等选项: r表明将模块加入到静态库中,c表示创建静态库,s表示生产索引。具体参见ar命令的用户手册。另外这里,为简明起见,我们删除了myfile.o和myfile.cpp文件。

1.2使用静态库链接:
1)使用libmy.a进行编译连接:
[quietheart@lv-k test]$g++ main.cpp -L./ -lmy
2)运行程序:
[quietheart@lv-k test]$./a.out
这里,可以修改libmy.a的名字为libmy2.a,这样就相应地用“g++ main.cpp -L./ -lmy2”进行链接。
进一步的说明:
这里的-L选项,使用-L.表示将当前目录加入到库搜索路径。否则使用默认的库搜索路径搜索库文件,也就是/usr/lib目录。
另外有个类似的容易混淆的参数-I, 它表示搜索头文件的路径。使用它这样gcc在查找头文件的时候会首先到-I指定的目录查找头文件,然后才是系统默认目录,也就是/usr/include。
这里的-l选项, -lname表示库搜索目录下的libname.a 或者libname.so文件 ,这也是为什么库文件都以lib开头的原因之一,如果你的库文件不是libmy,而是my. 那就不能用-l参数编译了。 可以这样:
[quietheart@lv-k test]$g++ main.cpp -L. my.a -o test
注意: $g++ -L. -lmy main.o -o test 会出错!。
原因是: -l是链接器选项,必须要放到被编译文件的后面。 所以上面的命令中-lmy一定要放到 main.o的后面。

2、共享库方式
采用如下方式进行:
1.1生成共享库:
1)只编译myfile.cpp生成myfile.o
[quietheart@lv-k test]$g++ -c myfile.cpp
2)根据myfile.o生成动态库libmy.so
[quietheart@lv-k test]$g++ -shared -fPCI -o libmy.so myfile.o
3)删除myfile.o和myfile.cpp
这里,我们第2步生成的libmy.so就是动态连接库(共享库)。实践发现使用gcc也行,还可用"g++ -shared -o libmy.so myfile.o"。
进一步的说明:  -fpic或者-fPIC表明创建position independent code,这通常是创建共享库必须的。另外,-Wl 表明给链接器传送参数,所以这里-soname, library_name 为给链接器的参数。-shared 表明是使用共享库。
下面是使用a.c和b.c创建共享库的示例:
gcc -fPIC -g -c -Wall a.c
gcc -fPIC -g -c -Wall b.c
gcc -shared -Wl,-soname, libmyab.so.1 -o libmyab.so.1.0.1 a.o b.o -lc
说明: lc == libc
还有几个需要注意的地方:
a.不推荐使用strip处理共享库,最好不要使用-fomit-frame-pointer编译选项,
b.-fPIC和-fpic都可以产生目标独立代码,具体应用取决于平台,-fPIC是always work,
尽管其产生的目标文件可能会大些; -fpic产生的代码小,执行速度快,但可能有平台依赖限制。
c.一般情况下,-Wall,-soname,your_soname编译选项是需要的。当然,-share选项更不能丢。

1.2使用共享库libmy.so进行链接:
1)编译链接:
[quietheart@lv-k test]$g++ main.cpp -L./ -lmy
这里,不要和libmy.a冲突了,如果同时存在libmy.a和libmy.so会优先选择libmy.so。编译选项类似前面请参照链接静态库,时候的选项。

1.3运行时加载共享库libmy.so:
1)将动态库移动到/usr/lib等标准路径:
[quietheart@lv-k test]$sudo cp libmy.so /usr/lib
注意这里和静态库不同,还需要把库移动到特定的位置。
实际三种方法:
a)拷贝到/usr/lib
b)或设置环境变量LD_LIBRARY_PATH加上你的路径
c) 或修改配置文件/etc/ld.so.conf加入你的路径,并刷新缓存ldconfig
2)运行程序:
./a.out

3、动态加载库方式
动态加载库的方式,就是说启动程序的时候不用将事先编译好的库加载,而是在用到的时候动态加载库,这种方式常常用在插件加载的方式上。需要修改我们的main.cpp文件如下:
#include<iostream>
#include<dlfcn.h>
using std::cout;
using std::cerr;
using std::endl;
int main(int argc, char *argv[])
{
//初始变量
void *handle;
void (*pPrint)(void);
char *error;

cout<<"Begin to call:"<<endl;
//动态加载库,RTLD_LAZY表示如果遇到标号不存在的情况,不做处理,而是运行时候再说。
handle = dlopen("./libmy.so", RTLD_LAZY);
if(handle == NULL)
{  
cerr<<dlerror()<<endl;
exit(1);
}  

//找到将要调用的函数标号,采用的标号不是库文件源代码中的printInfo,
//而是通过"nm libmy.so" 或者"readelf -s libmy.so"查询得知,标号名称为:_Z9printInfov
pPrint = (void(*)())dlsym(handle,"_Z9printInfov");
error = dlerror();
if( error != NULL )
{  
cerr<<error<<endl;
exit(1);
}  

//调用函数
pPrint();

//关闭
dlclose(handle);
return 0;
}
由上可知,使用动态加载的方式,不用在可执行文件中包含库的头文件就能够使用库中的函数。并且,库文件的搜索路径除了像前面那样通过系统确定,我们还可以在代码中“硬性”指定在哪里加载库。
具体编译运行过程如下。

3.1,生成动态库文件:
1)只编译myfile.cpp生成myfile.o
[quietheart@lv-k test]$g++ -c myfile.cpp
2)根据myfile.o生成动态库libmy.so
[quietheart@lv-k test]$g++ -shared -fPCI -o libmy.so myfile.o
3)删除myfile.o和myfile.cpp
这里,我们第2步生成的libmy.so就是动态加载的库(生成方式和共享库一样)。

3.2,编译链接可执行程序:
1)生成可执行文件:
[quietheart@lv-k test]$g++ main.cpp -ldl
2)运行:
[quietheart@lv-k test]$./a.out
这里,我们链接的时候需要通过指定"-ldl",这样才能使用动态加载技术提供的那些函数。
另外,注意:在源代码main.cpp中我们可以看到,这里使用dlsym的时候,采用的标号不是库文件源代码myfile.cpp中的printInfo,
而实际是通过"nm libmy.so" 或者"readelf -s libmy.so"查询得知的,标号名称为:"_Z9printInfov"的函数。通过这样的方式,加载,可以不用包含库的头文件而使用库的函数。


[其它]
1, nm命令可以查可能一个库中的符号
nm列出的符号有很多,常见的有三种,一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示;一种是库中定义的函数,用T表示,这是最常见的;另外一种是所谓的“弱态”符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示。
*查看库中所有的符号
$nm libhello.so

*假设开发者希望知道上文提到的 hello库中是否定义了 printf():
$nm libhello.so |grep printf
U printf
U表示符号printf被引用,但是并没有在函数内定义,由此可以推断,要正常使用hello库,必须有其它库支持,再使用ldd命令查看hello依赖于哪些库:
$ldd hello
libc.so.6=>/lib/libc.so.6(0x400la000)
/lib/ld-linux.so.2=>/lib/ld-linux.so.2 (0x40000000)
从上面的结果可以继续查看printf最终在哪里被定义.

2,ldd命令可以查询一个程序依赖哪些共享库:
*查看一个程序依赖那些共享库:
[root@lv-k mytest]# ldd a.out
linux-gate.so.1 =>  (0x00322000)
libdl.so.2 => /lib/libdl.so.2 (0x002f3000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x025ab000)
libm.so.6 => /lib/libm.so.6 (0x002c8000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x0013d000)
libc.so.6 => /lib/libc.so.6 (0x0016d000)
/lib/ld-linux.so.2 (0x0014e000)

3,使用readelf可以查看一个文件是否是可执行文件,是否是库文件。
一般而言,Linux中的可执行文件和库文件的都是elf的二进制文件,所以就以elf文件为例,而这个命令也是针对elf格式文件的。
readelf更多的命令选项应当查看man手册,这里给出几个简单的例子。
*查看一个文件是否为库文件:
[root@lv-k mytest]# readelf -h libmy.so
ELF Header:
Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class:                             ELF32
Data:                              2's complement, little endian
Version:                           1 (current)
OS/ABI:                            UNIX - System V
ABI Version:                       0
Type:                              DYN (Shared object file)
Machine:                           Intel 80386
Version:                           0x1
Entry point address:               0x550
Start of program headers:          52 (bytes into file)
Start of section headers:          2768 (bytes into file)
Flags:                             0x0
Size of this header:               52 (bytes)
Size of program headers:           32 (bytes)
Number of program headers:         5
Size of section headers:           40 (bytes)
Number of section headers:         27
Section header string table index: 24
这里,Type字段就指明了DYN类型,就是共享目标文件,实际lib*.so就属于这个类型。

*查看一个可执行文件:
[root@lv-k mytest]# readelf -h a.out
ELF Header:
Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class:                             ELF32
Data:                              2's complement, little endian
Version:                           1 (current)
OS/ABI:                            UNIX - System V
ABI Version:                       0
Type:                              EXEC (Executable file)
Machine:                           Intel 80386
Version:                           0x1
Entry point address:               0x80486e0
Start of program headers:          52 (bytes into file)
Start of section headers:          3728 (bytes into file)
Flags:                             0x0
Size of this header:               52 (bytes)
Size of program headers:           32 (bytes)
Number of program headers:         8
Size of section headers:           40 (bytes)
Number of section headers:         29
Section header string table index: 26
这里,Type字段就指明了EXEC类型,就是可执行文件。

*查看一个静态库文件:
[root@lv-k mytest]# readelf -h libmy.a

File: libmy.a(myfile.o)
ELF Header:
Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class:                             ELF32
Data:                              2's complement, little endian
Version:                           1 (current)
OS/ABI:                            UNIX - System V
ABI Version:                       0
Type:                              REL (Relocatable file)
Machine:                           Intel 80386
Version:                           0x1
Entry point address:               0x0
Start of program headers:          0 (bytes into file)
Start of section headers:          516 (bytes into file)
Flags:                             0x0
Size of this header:               52 (bytes)
Size of program headers:           0 (bytes)
Number of program headers:         0
Size of section headers:           40 (bytes)
Number of section headers:         15
Section header string table index: 12
这里,Type字段就指明了REL类型,就是可重定位文件,实际静态库文件就是这个类型。

*查看一个目标文件:
[root@lv-k mytest]# readelf -h myfile.o
ELF Header:
Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class:                             ELF32
Data:                              2's complement, little endian
Version:                           1 (current)
OS/ABI:                            UNIX - System V
ABI Version:                       0
Type:                              REL (Relocatable file)
Machine:                           Intel 80386
Version:                           0x1
Entry point address:               0x0
Start of program headers:          0 (bytes into file)
Start of section headers:          516 (bytes into file)
Flags:                             0x0
Size of this header:               52 (bytes)
Size of program headers:           0 (bytes)
Number of program headers:         0
Size of section headers:           40 (bytes)
Number of section headers:         15
Section header string table index: 12
这里,Type字段就指明了REL类型,就是可重定位文件,可见,目标文件类型和静态库一样,实际我们可以将目标文件当做静态库来用。

*查看一个普通文件:
[root@lv-k mytest]# readelf -h myfile.cpp
readelf: Error: Unable to read in 0x7473 bytes of section headers
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
可见,如果不是elf格式的文件,就会输出错误信息。
更多信息需要对elf格式有一定的了解。


比较好的参考资料:
http://blog.chinaunix.net/u/19573/showart_1822303.html

作者:QuietHeart
Email:quiet_heart000@126.com
日期:2011年7月5日
分享到:
评论

相关推荐

    Linux下一个简单的文件系统实现

    在Linux操作系统中,文件系统是核心的重要组成部分,它负责组织和管理存储设备上的数据,使得用户和应用程序可以方便地存取文件。本项目名为“Linux下一个简单的文件系统实现”,其核心是一个名为XORFS(意为“或许...

    Linux操作系统编程教学pdf

    "2.6 Linux文件定位.pdf"将讲解如何在Linux系统中查找文件,包括使用find、locate、which等命令,这对于日常的系统维护和问题排查至关重要。 "2.8 Linux文件共享2.pdf"将涉及文件的共享机制,如网络文件系统(NFS)...

    Linux C语言的配置文件操作库

    在Linux系统中,C语言作为底层编程的主要工具,其对配置文件的操作往往涉及到繁琐的文件I/O操作。然而,为了简化这一过程,开发者通常会利用特定的库来处理配置文件,比如读取、写入、解析键值对等。本文将深入探讨...

    linux文件系统电子书籍

    2. **基本库**:例如glibc库,这是大多数Linux系统中用于提供标准C库功能的基础库。 3. **基本的系统配置文件**:如`rc`、`inittab`等脚本文件,用于控制系统的启动和初始化过程。 4. **必要的设备文件支持**:例如`...

    嵌入式Linux根文件系统

    根文件系统是Linux系统中所有其他文件和目录的起点,包含了启动系统所需的必要程序和服务。在嵌入式环境中,由于硬件资源有限,根文件系统需要被精心优化以适应这些限制。 ubIFS(Unsorted Block Image File System...

    linux下mediainfo和依赖库文件

    在Linux系统中,动态链接库可以在程序运行时被加载,而不是在编译时嵌入到可执行文件中,这样可以节省磁盘空间并便于库的更新。 2. `libzen.so.0`:这是另一个必要的库文件,可能包含了`Mediainfo`依赖的特定功能或...

    linux下独立程序执行php文件

    在Linux环境下,独立程序执行PHP文件是一个常见的需求,特别是在自动化脚本、服务器管理和持续集成等场景中。这里提到的"snail007-phprunner-0ce9948"可能是一个专为此目的编写的特定工具,允许你在不依赖系统PHP...

    Alias2.4 for linux 程序库

    ALIAS_TAR可能是这个压缩包的主文件,它是一个tar归档文件,是Linux系统中常用的文件打包格式。这种格式可以将多个文件和目录打包成一个单一的文件,便于存储、传输和管理。用户通常需要使用tar命令来解压这个文件,...

    嵌入式Linux系统的移植及其根文件系统的实现.pdf

    根据嵌入式系统的特点,为了使嵌入式Linux系统既具备必要的功能又保持小型化,其组成通常包括启动加载程序、内核、初始化进程、硬件驱动程序、文件系统、必要的应用程序和TCP/IP协议栈等。 - **3.1 启动加载程序的...

    Linux操作系统中的文件目录结构详解

    - **用途**:此目录包含所有命令、程序库、文档和其他文件。这些文件在正常操作中通常是不会被更改的。它还包含Linux发行版中的主要应用程序,如Netscape。 - **子目录**: - `/usr/bin`:存储用户常用的命令。 - ...

    linux文件系统(英文版)

    7. **/lib**:存放系统运行时所需的库文件,支持/bin和/sbin目录下的程序。 8. **/media**:用于临时挂载外部设备,如USB驱动器或CD/DVD。 9. **/mnt**:传统上用于挂载临时文件系统,但在现代Linux中,/media更常...

    Linux下打包发布QT程序,并运行在其他没有安装QT环境或多个QT环境的linux系统上

    这意味着在编译Qt应用程序时,所有的Qt库文件会被合并到可执行文件中。这可以通过修改Qt的配置选项(如使用`qmake -static`)来实现,但需要注意静态编译可能会导致文件较大且编译时间较长。 3. **创建自包含运行...

    libldap.so.2、liblber.so.2等linux系统缺少的库文件完整版

    在Linux系统中,库文件是操作系统提供给应用程序调用的一系列预编译的函数和数据结构,它们使得软件开发者能够创建高效且可移植的代码。标题提到的"libldap.so.2"和"liblber.so.2"是Lightweight Directory Access ...

    linux 动态库静态库

    在Linux系统中,动态库(Dynamic Library)和静态库(Static Library)是程序开发中不可或缺的部分,它们提供了代码复用和模块化的功能。本篇文章将深入探讨这两种库的创建、使用以及它们之间的区别。 首先,我们来...

    linux下QT程序读写配置文件小程序

    在Linux系统中,通常会使用ini格式的配置文件。 要使用`QSettings`,首先需要包含相应的头文件: ```cpp #include #include ``` 然后,我们可以创建一个`QSettings`对象,指定配置文件的位置和格式: ```cpp ...

    Linux文件系统详解.pdf

    但当文件扩充时,会造成文件中文件块的不连续,从而导致过多的磁盘寻道时间。扩展分配:文件创建时,一次性分配一连串连续的块,当文件扩展时,也一次分配很多块。 Linux 文件系统的管理和维护是 Linux 操作系统的...

    Linux.文件系统精通指南

    用户和组管理是Linux系统管理的基础。用户通过`adduser`或`useradd`创建,`passwd`修改密码,`groupadd`创建新组,`usermod`调整用户属性。`sudo`允许非root用户以管理员权限执行命令,通过`visudo`编辑`/etc/...

    linux文件系统制作

    5. **制作根文件系统**:将BusyBox和必要的配置文件、库文件一起打包成根文件系统镜像,适配嵌入式设备的特殊需求。 总之,Linux文件系统的制作是一个复杂而精细的过程,涉及到对系统结构、硬件兼容性、软件包管理...

    linux根文件系统文件rootfs

    5. **lib**:系统运行所需的库文件,包括动态链接库(.so文件)和一些辅助程序库。 6. **usr**:包含用户应用程序和系统软件,如`/usr/bin`(用户命令)、`/usr/share`(共享数据)和`/usr/lib`(库文件)。 7. **...

    基于嵌入式Linux平台的最小文件系统的制作

    在嵌入式领域,开发人员经常需要构建一个定制化的Linux系统,以便更好地满足特定硬件平台的功能需求和性能要求。一个重要的组成部分就是文件系统,特别是对于资源受限的设备来说,创建一个最小的文件系统尤为重要。...

Global site tag (gtag.js) - Google Analytics