1. 现在要生成libmydll.so的库文件,头文件如下
#ifndef _MYDLL_H
#define _MYDLL_H
#include "stdio.h"#ifdef WIN32
#ifdef MYDLL_EXPORTS
#define MYDLLAPI extern "C" __declspec(dllexport)
#else
#define MYDLLAPI extern "C" __declspec(dllimport)
#endif
#else
#define MYDLLAPI extern "C"
#endif #define MAXBUFLEN 0x1000000
MYDLLAPI int Add(int x, int y);
MYDLLAPI int TestWrite(char *p, int buflen = MAXBUFLEN);#endif
命令: g++ mydll.cpp -fPIC -shared -o libmydll.so
-shared表示生成共享库, -fPIC表示生成的库可以重入
2. 如果依赖头文件, 则使用 -I +路径包括
g++ -o ../yu.a yu.cpp -I../../ //在上一级的目录上生成yu.a
3.这里如果动态库与cpp不在同一个目录下,就是用-L + 动态库的路径。
g++ main.cpp -I../../mydll -L../../mydll -lmydll -o main.a
或者 g++ main.cpp -I../../mydll ../../mydll/libmydll.so -o main.a也可以,但是名称必须是 libmydll.so这样有前缀的,否则错误
当依赖多个动态库的时候,依次加上动态库就可以了
g++ main.cpp -I../../mydll -I../../JTFS -L../../mydll -lmydll -L../../JTFS -ljtfs -o main.a或者写成
g++ main.cpp -I../../mydll -I../../JTFS -L../../mydll -L../../JTFS -ljtfs -lmydll -o main.a
注意,这里还要将库加到环境变量中,否则运行的时候提示找不到库
4.添加动态库搜索路径
(1)export LD_LIBRARY_PATH=$LD_LIBRAR_PATH:/路径 注意等于号左右2边不要加空格,不然提示找不到路径
export功能是创建一个新的环境变量
查看当前的所有环境变量 env
(2) 打开/etc/ld.so.conf文件, 直接添加你的路径,保存好ldconfig即可.例如:
include ld.so.conf.d/*.conf
/home/ywy/liuzaoxiang/80/videoDownloadSDK/version
5.查看动态库的内容
静态库用ar -t YourFile
动态库用 nm -D YourFile
6.动态库静态加载时,在程序运行时被加载进内存,程序退出时才退出内存,多个线程调用时全局变量变量和静态变量公用一块区域, 需要加锁。
动态加载时LoadLibrary加载动态库到内存,FreeLibrary清理内存。
7.在linxu下添加新的动态库后,如果无法使用。则运行ldconfig
8. windows下库函数重复定义: /FORCE:MULTIPLE
9. windows静态库可以直接导出类, 动态库导出类需要添加关键字__declspec(dllexport).
linux动态库和静态库可直接导出类
#ifdef WIN32
#ifdef MYDLL_EXPORTS
#define MYDLLCLASS __declspec(dllexport)
#else
#define MYDLLCLASS __declspec(dllimport)
#endif
#else
#define MYDLLCLASS
#endif class MYDLLCLASS CTest
{
public:
CTest();
~CTest();
public:
int Add(int , int);
int m_iSum;
virtual void Help();
};
10.动态库后面的数字含义
如libiconv.so.2等,数字一般表示版本号,在使用的时候可以为libiconv.so.2创建一个硬链接libiconv.so,宿主模块直接通过LD_LIBRARY_PATH或其他方法链接到libiconv.so就可以调用libiconv.so.2的库了.如果升级,如有libiconv.so.3,只需要修改链接就可以了。
关于链接
如果一个文件有链接如libmydll.so则:
ll -i *.txt
1070305 -rw-r--r-- 3 root root 0 Jan 15 11:09 my.txt //硬链接 有3个链接
1070305 -rw-r--r-- 3 root root 0 Jan 15 11:09 she.txt
1070304 lrwxrwxrwx 1 root root 6 Jan 15 11:10 you.txt -> my.txt //软链接
通过find / -inum 1070305可以找到所有的链接文件
可以为动态库创建一个硬链接到/usr/lib或者/lib,这样宿主就能直接使用。软链接不可直接使用
11. 动态库中的全局变量问题 (这个是转载的)
在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的,因为所有的进程用的都收同一块地址空间;而在Win32环境中,情况却发生了变化,每个进程都有了它自己的地址空间,DLL函数中的代码所创建的任何对象(包括变量)都归调用它的进程所有。当进程在载入DLL时,操作系统自动把DLL地址映射到该进程的私有空间,也就是进程的虚拟地址空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间。(在物理内存中,多进程载入DLL时,DLL的代码段实际上是只加载了一次,只是将物理地址映射到了各个调用它的进程的虚拟地址空间中,而全局数据会在每个进程都分别加载)。也就是说每个进程所拥有的相同的DLL的全局数据,它们的名称相同,但其值却并不一定是相同的,而且是互不干涉的。
在DLL的实现文件中添加下列代码:
#pragma data_seg(
"
DLLSharedSection
"
)
//
声明共享数据段,并命名该数据段
int
SharedData
=
50
;
//
必须在定义的同时进行初始化!!!!
#pragma data_seg()
在#pragma data_seg("DLLSharedSection")和#pragma data_seg()之间的所有变量将被访问该Dll的所有进程看到和共享。仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性,有三种方法可以实现该目的(其效果是相同的),一种方法是在.DEF文件中加入如下语句:
SETCTIONS
DLLSharedSection READ WRITE SHARED
另一种方法是在项目设置的链接选项(Project Setting --〉Link)中加入如下语句:
/ SECTION:DLLSharedSection,rws
还有一种就是使用指令:
#pragma comment(linker, " /section:.DLLSharedSection,rws "
)
那么这个数据节中的数据可以在所有DLL的实例之间共享了。所有对这些数据的操作都针对同一个实例的,而不是在每个进程的地址空间中都有一份。
当进程隐式或显式调用一个动态库里的函数时,系统都要把这个动态库映射到这个进程的虚拟地址空间里。这使得DLL成为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈。
下面来谈一下在具体使用共享数据段时需要注意的一些问题:
· 所有在共享数据段中的变量,只有在数据段中经过了初始化之后,才会是进程间共享的。如果没有初始化,那么进程间访问该变量则是未定义的。
· 所有的共享变量都要放置在共享数据段中。如何定义很大的数组,那么也会导致很大的DLL。
· 不要在共享数据段中存放进程相关的信息。Win32中大多数的数据结构和值(比如HANDLE)只在特定的进程上下文中才是有效地。
· 每个进程都有它自己的地址空间。因此不要在共享数据段中共享指针,指针指向的地址在不同的地址空间中是不一样的。
· DLL在每个进程中是被映射在不同的虚拟地址空间中的,因此函数指针也是不安全的。
当然还有其它的方法来进行进程间的数据共享,比如文件内存映射等,这就涉及到通用的进程间通信了,这里就不多讲了。
12.进程调用dll里开辟的内存,属于调用进程内存。
13.g++安装 http://jingyan.baidu.com/article/a3f121e4faf03bfc9052bbeb.html
注意: 一定要选择支持的版本
14.查看.so编译的GCC版本
strings -a libxxx.so |grep -i gcc
GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4