前置知识
-
Windows
上叫动态链接库
,通常以*.dll
形式命名;Linux
上叫共享库
,通常以lib*.so
形式命名。(此处统一叫动态库
) -
Windows
上dll
路径的一般搜索顺序为:当前目录->系统目录(如:C:\Windows\System32
、C:\Windows\SysWOW64
)->Windows
目录(如C:\Windows
)->PATH
环境变量指定的目录。 -
Linux
上so
路径的一般搜索顺序为:编译时使用-rpath
指定的路径->LD_LIBRARY_PATH
环境变量指定的路径->系统默认库路径(如/lib
、/usr/lib
等)->/etc/ld.so.conf
和/etc/ld.so.conf.d/
目录中配置的路径。 -
Lazarus
/Delphi
调用动态库有两种形式:静态调用
和动态调用
。 -
静态调用
:主程序启动时加载,若动态库
不存在或不匹配,则主程序抛异常并中止;主程序退出时卸载。 -
动态调用
:主程序在需要时可随时加载,不需要时可随时卸载;动态库
发生异常时,一般不会导致主程序中止。
使用动态库
动态库
动态库
本身不需要特殊设置,正常编译、构建即可。(以名为dll
的动态库为例,实际文件名为libdll.so
)
主程序
编译时
静态调用方式
主程序
直接编译会报错:Warning: linker:/usr/bin/ld: cannot find -ldll: No such file or directory
,意思是链接器找不到名为dll
的动态库文件。
解决方案
打开Project Options
->Compiler Options
->Compilation and Linking
,勾选Pass options to linker with "-k", delimiter is space
,并在下方填入-L’动态库所在路径’
,保存即可正常编译。
动态调用方式
主程序
直接编译即可。
运行时
静态调用方式
此时编译后的程序并不能正常运行,会报错error while loading shared libraries: libdll.so: cannot open shared object file: No such file or directory
,意思是加载动态库时找不到名为libdll.so
的动态库文件。
这是前面提到的路径搜索顺序导致的,可将动态库放入相应的搜索路径下,也可使用-rpath
指定路径。对于自定的动态库,建议使用-rpath
指定路径,最好指定的路径为当前路径(与Windows
保持一致)。
解决方案
打开Project Options
->Compiler Options
->Compilation and Linking
,勾选Pass options to linker with "-k", delimiter is space
,并在下方填入-rpath='$ORIGIN'
(与之前的-L’动态库所在路径’
之间要添加一个空格
),保存并重新编译,即可正常运行。
注:$ORIGIN
代表程序所在的路径。
动态调用方式
主程序
可以正常运行,但并不能正常使用动态库
的功能。打断点可发现LoadLibrary
返回的句柄为0
,主要原因与静态调用相同,即未找到动态库文件。
解决方案
打开Project Options
->Compiler Options
->Compilation and Linking
,勾选Pass options to linker with "-k", delimiter is space
,并在下方填入-rpath='$ORIGIN'
,保存并重新编译,即可正常运行。
注意事项
-
静态调用
方案,代码中动态库
名为*.so
或lib*.so
均可;动态调用
方案,则必须为lib*.so
。 -
若
动态库
与主程序
不在同一目录下,动态调用
方案,只需将代码中动态库
名改为动态库相对路径/lib*.so
即可;静态调用
方案,则需在-L
中追加所有用到的动态库路径,在-rpath
中追加动态库与主程序的相对路径。
总结
为保证灵活性,避免过多的编译配置,建议使用动态调用
方式,只需在Project Options
->Compiler Options
->Compilation and Linking
中,勾选Pass options to linker with "-k", delimiter is space
,并在下方填入-rpath='$ORIGIN'
,代码中指定好与主程序的相对路径即可。