在上一篇博文中已经可以开发简单的C程序,并成功引用已有静态库。
对于中小规模的程序很好,程序达到一定规模就有问题了,磁盘空间和运行时占用空间都会成问题,因为静态链接是在编译阶段把所有以来都打包到程序中,运行时也会一次性被加载到内存中。
Linux中动态链接库(.so)有两种使用方式,动态链接和动态加载:
动态链接
动态链接需要动态库在链接时候对程序可见,动态库制作方法如下:
gcc -Wall -shared -fPIC -o libjoin.so join.c
或者
gcc -Wall -fPIC -c join.c
gcc -Wall -shared -fPIC join.o -o libjoin.so
其中用到的几个选项:
-
-Wall: include warnings. See man page for warnings specified.
-
-fPIC: Compiler directive to output position independent code, a characteristic required by shared libraries. Also see fpic.
- -shared: Produce a shared object which can then be linked with other objects to form an executable.
在gcc的man手册中-shared让编译器生成共享库,否则没有main方法的代码无法独立编译;-fPIC是-shared子选项,告诉编译器生成位置无关的代码。
经过以上步骤动态库已经编译好,但是如果要在程序中引用,还需要想办法告诉系统.so库的位置。
编译器通过/etc/ld.so.conf查找动态库。ldconfig用于配置运行时动态库查找路径,实际是更新/etc/ld.so.cache。
通过ld --verbose实际查看,默认加载路径如下:
到这里其实有三种方法可以让编译器能够寻到我的.so库:
1、修改ld.so.conf配置,把.so所在目录加入进去
2、建立软连接或者将.so直接拷贝过去
3、ldconfig `pwd`,直接让编译器到当前目录来加载
这里直接把.so拷贝到/usr/lib下,测试通过;
作为测试程序这样是做法没问题的,但是如果是正式发布的程序,需要考虑到部署、卸载过程,软连接方式更为稳妥。
运行时动态加载
上面的案例演示了动态链接库的一种使用方式即由Linux系统自动链接和加载动态库。
Linux提供了另外一组API,使用户程序在运行期间动态加载特定动态库而无需重新编译,为Apache、Nginx等模块化可插拔软件提供了可能性。
The dlopen
function also automatically resolves dependencies in shared libraries. In this way, if you open an object that is dependent upon other shared libraries, it automatically loads them. The function returns a handle that is used in subsequent calls to the API. The prototype for dlopen
is:
#include <dlfcn.h>
/**
* Makes an object file accessible to a program
* @param file libarary file name(full path)
* @param mode RTLD_LAZY/RTLD_NOW/RTLD_GLOBAL
*/
void *dlopen( const char *file, int mode );
With a handle to the ELF object, you can identify addresses to symbols within this object using the dlsym
call. This function takes a symbol name, such as the name of a function contained within the object. The return value is a resolved address to the symbol within the object:
/**
* Obtains the address of a symbol within a dlopened object file
* @param handle library handle obtained by dlopen
* @param name method name
*/
void *dlsym( void *handle, const char *name );
If an error occurs during a call with this API, you can use the dlerror
function to return a human-readable string representing the error. This function has no arguments and returns a string if a prior error occurred or returns NULL if no error occurred:
/**
* Returns a string error of the last error that occurred
*/
char *dlerror();
Finally, when no additional calls to the shared object are necessary, the application can call dlclose
to inform the operating system that the handle and object references are no longer necessary. This is properly reference-counted, so that multiple users of a shared object do not conflict with one another (it remains in memory as long as there is a user for it). Any symbols resolved through dlsym
for the closed object will no longer be available.
/**
* Closes(unload) an object file
* @param handle of library object
*/
char *dlclose( void *handle );
示例代码
hello_l.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
void hello(char* name, char* familyName){
void* lib_handle;
char* (*fn)(char* f, char* l);
char* error;
lib_handle = dlopen("/home/daiyma/work/dynamic/libjoin.so", RTLD_LAZY);
if (!lib_handle){
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
fn = dlsym(lib_handle, "join");
if ((error = dlerror()) != NULL){
fprintf(stderr, "%s\n", error);
exit(1);
}
char* who = (*fn)(name, familyName);
printf("Hi, i am :%s\n", who);
free(who);
dlclose(lib_handle);
}
这里仍然沿用之前的示例,只是动态库使用方式有变化(hello.c变为hello_l.c)。
编译代码:
gcc -o main -rdynamic -ldl -L. -ljoin main.c hello_l.c
运行结果:
有一点需要注意,通过ldd main查看,已经看不到所依赖的动态库了:
因为编译的时候增加了一下两个选项:
-rdynamic tell the linker to add all symbols to the dynamic symbol table (to permit backtraces with the use of dlopen).
-ldl indicates that the dllib should be linked to this program
参考连接:
[1]https://www.ibm.com/developerworks/library/l-dynamic-libraries/index.html
[2]http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html
[3]https://typecodes.com/cseries/gcclderrlibrarypath.html
- 大小: 35.3 KB
- 大小: 4.9 KB
- 大小: 9.2 KB
分享到:
相关推荐
这些内容只是Linux服务和C语言入门的冰山一角,实际学习过程中还需要结合实践,动手编写代码,解决实际问题,从而不断深化理解和提升技能。通过不断学习和实践,你将能够更好地掌握这两个领域的知识,并在IT行业中...
总的来说,Linux操作系统下的C语言编程入门不仅涉及C语言的基本语法和编程技巧,还包括了与Linux系统交互的相关知识。通过学习和实践,开发者可以编写出高效、可靠的系统级程序,进一步理解和利用Linux的强大功能。
"Linux环境C语言编程入门"这本书籍旨在引导初学者掌握在Linux系统中编写、编译和调试C程序的基本技巧。 首先,C语言是一种强大的编程语言,它简洁、高效,且提供了对底层硬件的直接访问,因此在系统级编程中广泛...
C语言是一种历史悠久且功能强大的编程语言,它广泛应用于系统软件、应用软件以及嵌入式开发领域。C语言因其高效率和灵活性而深受开发者喜爱,尤其在...通过不断学习和实践,初学者可以逐渐成长为熟练的C语言开发者。
本教程《Linux下C语言编程入门教程》将帮助初学者掌握在Linux环境下进行C语言编程的基本技能。 首先,你需要了解Linux的基本操作,包括命令行界面(CLI)的使用。在Linux中,一切皆为文件,包括硬件设备。掌握常用...
在“Linux 操作系统C语言编程入门”这个主题中,我们将会探讨如何在Linux环境下进行C语言编程。C语言是一种强大的、低级别的编程语言,它为程序员提供了对计算机硬件的直接控制,使得开发者能够创建高效且灵活的软件...
### Linux操作系统下C语言编程入门:经典总结 在IT领域,尤其是软件开发中,Linux操作系统与C语言结合,成为了一种极为重要的技能组合。本文旨在深入解析Linux环境下C语言编程的关键知识点,涵盖从基础概念到高级...
总之,Linux下的C语言编程是一个广阔而深邃的领域,从基础的编译、链接,到高级的网络编程、线程操作,每一个环节都需要深入理解和实践。掌握这些知识点,不仅能够让你成为一个合格的C语言程序员,还能为后续深入...
- 静态与动态链接:理解静态库和动态库的区别,以及如何创建和使用它们。 - 系统编程:编写系统级别的程序,如设备驱动、守护进程、系统服务等。 - 网络编程:利用socket API进行网络通信,包括TCP/IP、UDP等协议...
在IT领域,Linux操作系统与C语言的结合是程序员的基础技能之一。这个压缩包文件"Linux操作系统C语言编程入门pd"显然是一份关于这个主题的学习资料,可能是电子书或教程。以下将详细介绍Linux操作系统和C语言编程相关...
"Linux操作系统下C语言编程入门"这个主题涵盖了两个重要的知识点:Linux操作系统的基本使用和C语言的编程实践。 首先,Linux操作系统是一个自由、开放源代码的操作系统,被广泛应用于服务器、嵌入式设备以及个人...
【头歌Linux系统编程之C编程入门】是一个关于在Linux环境下进行C语言编程学习的教程。这个教程覆盖了从基础的C语言编程到更高级的Linux系统编程技术,旨在帮助初学者逐步掌握在Linux系统中编写C程序的能力。 1. **...
在深入探讨Linux操作系统下C语言编程的入门知识之前,我们首先要理解Linux和C语言的基本概念。Linux是一种开源、自由的操作系统,它基于Unix系统,并且在全球范围内被广泛应用于服务器、嵌入式设备以及个人计算机。...
本资源“Linux编程入门之C语言环境”旨在帮助初学者建立起在Linux环境下进行C语言编程的基础。以下是一些核心知识点: 1. **安装开发工具**:首先,你需要在Linux系统上安装必要的开发工具,如GCC(GNU Compiler ...
### Linux下C语言编程入门教程知识点详述 #### 一、Linux的发展与特点 ##### 1. Linux的历史背景与发展 - **起源与创始人**:Linux操作系统最初由芬兰赫尔辛基大学的学生Linus Torvalds在1991年创建。起初是作为...