前置知识

  1. Windows上叫动态链接库,通常以*.dll形式命名;Linux上叫共享库,通常以lib*.so形式命名。(此处统一叫动态库

  2. Windowsdll路径的一般搜索顺序为:当前目录->系统目录(如:C:\Windows\System32C:\Windows\SysWOW64)->Windows目录(如C:\Windows)->PATH环境变量指定的目录。

  3. Linuxso路径的一般搜索顺序为:编译时使用-rpath指定的路径->LD_LIBRARY_PATH环境变量指定的路径->系统默认库路径(如/lib/usr/lib等)->/etc/ld.so.conf/etc/ld.so.conf.d/目录中配置的路径。

  4. Lazarus/Delphi调用动态库有两种形式:静态调用动态调用

  5. 静态调用:主程序启动时加载,若动态库不存在或不匹配,则主程序抛异常并中止;主程序退出时卸载。

  6. 动态调用:主程序在需要时可随时加载,不需要时可随时卸载;动态库发生异常时,一般不会导致主程序中止。

使用动态库

动态库

动态库本身不需要特殊设置,正常编译、构建即可。(以名为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',保存并重新编译,即可正常运行。

注意事项

  1. 静态调用方案,代码中动态库名为*.solib*.so均可;动态调用方案,则必须为lib*.so

  2. 动态库主程序不在同一目录下,动态调用方案,只需将代码中动态库名改为动态库相对路径/lib*.so即可;静态调用方案,则需在-L中追加所有用到的动态库路径,在-rpath中追加动态库与主程序的相对路径。

总结

为保证灵活性,避免过多的编译配置,建议使用动态调用方式,只需在Project Options->Compiler Options->Compilation and Linking中,勾选Pass options to linker with "-k", delimiter is space,并在下方填入-rpath='$ORIGIN',代码中指定好与主程序的相对路径即可。