库本质上是一组可执行代码的二进制形式,可以被操作系统加载到内存中执行。它的存在意义在于:
在Linux(以及Windows)中,库主要分为两种类型:
举例:常见的库文件
在Linux中,你可以通过ls命令查看系统中的库文件。例如:
<font style="color:black;">/lib/x86_64-linux-gnu/libc.a</font>
<font style="color:black;">/lib/x86_64-linux-gnu/libc-2.31.so</font>
同样,C++的标准库也有静态和动态版本:
<font style="color:black;">/usr/lib/gcc/x86_64-linux-gnu/9/libstdc++.a</font>
<font style="color:black;">/usr/lib/gcc/x86_64-linux-gnu/9/libstdc++.so</font>
(通常是一个软链接,指向具体的版本如<font style="color:black;">libstdc++.so.6</font>
)。静态库(.a文件)在程序编译链接阶段会被完全链接到可执行文件中。生成的可执行文件包含所有需要的库代码,运行时无需再查找或加载外部库文件。这使得静态链接的程序更加独立,但也可能导致可执行文件体积较大。
生成静态库通常使用ar(GNU归档工具)命令。以下是一个典型的Makefile示例,用于生成静态库libmystdio.a****:
libmystdio.a: my_stdio.o my_string.o
@ar -rc $@ $^
@echo "build $^ to $@ ... done"
%.o: %.c
@gcc -c $<
@echo "compiling $< to $@ ... done"
.PHONY: clean
clean:
@rm -rf *.a *.o stdc*
@echo "clean ... done"
.PHONY: output
output:
@mkdir -p stdc/include
@mkdir -p stdc/lib
@cp -f *.h stdc/include
@cp -f *.a stdc/lib
@tar -czf stdc.tgz stdc
@echo "output stdc ... done"
^是所有依赖文件。
使用静态库时,需要通过gcc编译并链接。以下是几种常见场景:
场景1:头文件和库文件安装到系统路径下
假设libmystdio.a和相关头文件(如my_stdio.h)已安装到系统默认路径(如/usr/lib和/usr/include),编译命令如下:
gcc main.c -l mystdio
场景2:头文件和库文件与源文件在同一路径下
如果libmystdio.a和头文件与main.c在同一目录,编译命令为:
gcc main.c -L. -l mystdio
场景3:头文件和库文件有独立路径
如果头文件和库文件位于自定义路径,编译命令为:
gcc main.c -I头文件路径 -L库文件路径 -lmystdio
特点:生成的可执行文件包含静态库的全部代码,即使删除静态库文件,程序仍可正常运行。
使用-static选项:如果希望强制链接静态库,可以使用gcc -static main.c -lmystdio,但这会增加可执行文件的大小。
动态库(.so文件)在程序运行时才被加载到内存中。相比静态库,动态库具有以下优点:
然而,动态库的缺点是程序运行时需要依赖外部库文件,如果库文件缺失或路径错误,程序可能无法启动。
生成动态库需要使用gcc的-shared选项,并确保生成位置无关代码(Position Independent Code, PIC)。以下是Makefile示例:
libmystdio.so: my_stdio.o my_string.o
gcc -o $@ $^ -shared
%.o: %.c
gcc -fPIC -c $<
.PHONY: clean
clean:
@rm -rf *.so *.o stdc*
@echo "clean ... done"
.PHONY: output
output:
@mkdir -p stdc/include
@mkdir -p stdc/lib
@cp -f *.h stdc/include
@cp -f *.so stdc/lib
@tar -czf stdc.tgz stdc
@echo "output stdc ... done"
使用动态库的编译方式与静态库类似,但运行时需要确保动态库文件可被找到。以下是几种场景:
场景1:头文件和库文件安装到系统路径下
gcc main.c -lmystdio
场景2:头文件和库文件与源文件在同一路径下
gcc main.c -L. -lmystdio
场景3:头文件和库文件有独立路径
gcc main.c -I头文件路径 -L库文件路径 -lmystdio
查看依赖:使用ldd命令检查可执行文件或动态库的依赖。例如:
ldd a.out
输出可能如下:
linux-vdso.so.1 => (0x00007fff4d396000)
libmystdio.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007fa2aef30000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa2af2fe000)
如果libmystdio.so => not found,说明动态库未被找到,需要解决路径问题。
在运行动态链接的可执行文件时,如果动态库(如libmystdio.so)未被找到,程序会报错。例如:
./a.out: error while loading shared libraries: libmystdio.so: cannot open shared object file: No such file or directory
这是因为操作系统默认的库搜索路径中没有包含libmystdio.so。
以下是解决动态库找不到问题的几种方法:
cp libmystdio.so /usr/lib
ln -s /path/to/libmystdio.so /usr/lib/libmystdio.so
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/library
然后重新运行程序。
echo "/path/to/library" >> /etc/ld.so.conf.d/bit.conf
ldconfig
ldconfig会重新加载库搜索路径,使新添加的路径生效。
gcc/g++
默认使用动态库。 -static
,且必须存在对应的静态库exe
都可以使用visual studio
不仅可以形成可执行程序,也可以形成动静态库通过理解静态库和动态库的原理与使用方法,开发者可以更高效地利用Linux下的库资源,提升程序的开发和运行效率。如果你在实践中遇到具体问题,可以进一步探讨或查阅相关文档。