有必要 LD_LIBRARY_PATH(linux) 还是 DYLD_LIBRARY_PATH mac
Is it necessary LD_LIBRARY_PATH(linux) or DYLD_LIBRARY_PATH mac
我正在使用 openCV 库进行计算机视觉研究,在编译时遇到了一些问题,这些问题让我试图了解操作系统如何将库与源代码链接起来。在互联网上寻找了一段时间以获得 g++/gcc 的良好概述和阅读手册后,ld...我有一些结论,我希望有更多经验的人来解释我。
首先是我使用的编译行。这是:
-输入:g++
pkg-config --cflags --libs opencvimage-conversion.cpp -o image-conversion
输出:可执行代码
输入:pkg-config --cflags --libs opencv
输出:-I/opt/local/include/opencv -I/opt/local/include -L/opt/local/lib -lopencv_shape -lopencv_stitching -lopencv_objdetect -lopencv_superres -lopencv_videostab -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_video -lopencv_photo -lopencv_ml -lopencv_imgproc -lopencv_flann -lopencv_core
我的代码需要的库是 -lopenhighgui
,但我更喜欢用这种方式编译,因为这个库依赖于其他库。问题是,当我去 /opt/local/lib
查看图书馆时,我有三个文件:
-libopencv_highgui.3.1.0.dylib
-libopencv_highgui.3.1.dylib
-libopencv_highgui.dylib
我不知道 -lopenhighgui
指的是哪个图书馆。我在 g++ 的手册中发现 -l
标志指定库名称避免 lib
前缀和 *.a
*.so
(linux)/*.dylib
(mac) 后缀。执行 otool -L
可执行文件后,我得到输出:
/opt/local/lib/libopencv_highgui.3.1.dylib (compatibility version 3.1.0, current version 3.1.0)
那么为什么它使用这个而不是其他的,它的使用方式是什么?三个库有什么区别?
另一个问题是关于链接和执行过程。我已经了解使用静态库时的链接过程。我的问题是在编译动态库时。在下一个示例中:
-输入:g++ -I/opt/local/include/opencv -I/opt/local/include -L/opt/local/lib -lopencv_highgui image-conversion.cpp -o image-conversion
我发现一个程序从编译到执行的过程可以分为三个部分。
编译器首先寻找标准目录下的头文件或通过-I
标志的目录进行代码解析。
其次,它链接由 -lflag
指定的库,在路径 -L 或标准路径下。这是通过链接器 (ld)
完成的
第三,在执行时,动态链接器程序 (dyld) 负责 "adding" 将代码写入 RAM 内存以便执行。
问题是下一个:我在网上发现一些人说如果他们不设置$LD_LIBRARY_PATH
(在linux)或$DYLD_LIBRARY_PATH
(在mac OSx) 与库的非标准目录(在我的例子中是 export LD_LIBRARY_PATH="/opt/local/lib"
),动态链接器找不到库并且程序执行失败。我发现我的程序没有崩溃,如果我执行 otool(用于查看链接的内容)。我得到这个(这是所有链接的库的摘要):
/opt/local/lib/libopencv_shape.3.1.dylib (compatibility version 3.1.0, current version 3.1.0)
/opt/local/lib/libopencv_imgproc.3.1.dylib (compatibility version 3.1.0, current version 3.1.0)
...
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
这是怎么回事?我发现 LD_LIBRARY_PATH 可用于测试新库,但为什么这些人说他们只需要为执行程序设置此变量?这最后一部分是如何工作的?我没有设置它,它工作得很好。
感谢任何人。
实际上有两个问题(顺便说一句,这不是一个很好的 SO 实践),所以我将独立回答它们。
此外,我将重点关注 Linux - 这是我熟悉的领域。从问题的文本来看,我认为 Mac 世界中的事情非常相似。
库命名约定
在 Linux 环境中使用 .so 库时,经常会看到动态库通常以三元组的形式出现。例如,库 foo 可能存在于 3 个文件中:libfoo.so、libfoo.so.6、libfoo.so.6.5.4。如果你仔细看,你会发现它们都是同一个文件——通常其中两个只是符号 links 到第三个。为了进一步讨论,libfoo.so 将被称为 unversioned 库,ibfoo.so.6 将被称为 major-versioned 和 libfoo.so.6.5.4 *full-versioned。你为什么需要那些?为了更好的版本控制。
当您 link 您的应用程序时,您总是使用 linker 规则用于未版本化的 livbary - 考虑到 linker 添加 lib
和 .so
按照规则,它看起来像
g++ ... -lfoo ...
当您的应用程序被 linked 时,linker 打开 libfoo.so 并检查它的几项内容。它检查的内容之一是 so-called SONAME
header。此 header 是在 linked .so 库时创建的,它的文件名可以与 linker 当前正在查看的文件名不同。例如,它可能有一个 major-versioned 文件,link 用户会看到它:SONAME = libfoo.so.6。
当 linker 看到 SONAME 时,它会将生成的应用程序文件标记为需要 libfoo.so.6
- 即使您实际上要求 libfoo.so
.
通过这样做 linker 保留了库的特定版本。您的应用程序最初是使用版本 6 编译和 linked 的,因此只要应用程序是 运行,就需要版本 6。
如果稍后系统升级(或应用程序 运行s 在不同的系统上),其中 foo
是不同的版本(比如 7),.so 文件将不同: libfoo.so, libfoo.so.7, libfoo.so.7.6.5。由于您的应用程序需要 libfoo.so.6
,它将无法启动 - 这是一件好事,因为谁知道版本 7 是否仍然兼容?如果没有此保护,应用程序将启动并使用不同的库版本,其影响可能是毁灭性的。
LD_LIBRARY_PATH 搜索
你的第二个问题是 LD_LIBRARY_PATH。确实如此,run-time linker 在查找动态库时参考这个变量。然而,这并不是它咨询的唯一内容。除此之外,除了默认搜索路径外,还有一个per-application动态库路径,它在应用程序linked时记录在应用程序中,通常由[=85=的rpath参数控制]呃,比如:
g++ ... -Wl,rpath,/path/to/so/library
当这样记录路径时,run-time link 用户将在加载应用程序时将这些路径添加到搜索路径列表中。
可以在没有 LD_LIBRARY_PATH 的情况下为您的应用程序找到库的事实意味着以下两种情况之一:在 linked 应用程序时记录了 rpath,或者实际上包含了 /opt/local/lib
在您平台的默认搜索路径中。
我正在使用 openCV 库进行计算机视觉研究,在编译时遇到了一些问题,这些问题让我试图了解操作系统如何将库与源代码链接起来。在互联网上寻找了一段时间以获得 g++/gcc 的良好概述和阅读手册后,ld...我有一些结论,我希望有更多经验的人来解释我。
首先是我使用的编译行。这是:
-输入:g++
pkg-config --cflags --libs opencvimage-conversion.cpp -o image-conversion
输出:可执行代码
输入:
pkg-config --cflags --libs opencv
输出:
-I/opt/local/include/opencv -I/opt/local/include -L/opt/local/lib -lopencv_shape -lopencv_stitching -lopencv_objdetect -lopencv_superres -lopencv_videostab -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_video -lopencv_photo -lopencv_ml -lopencv_imgproc -lopencv_flann -lopencv_core
我的代码需要的库是 -lopenhighgui
,但我更喜欢用这种方式编译,因为这个库依赖于其他库。问题是,当我去 /opt/local/lib
查看图书馆时,我有三个文件:
-libopencv_highgui.3.1.0.dylib
-libopencv_highgui.3.1.dylib
-libopencv_highgui.dylib
我不知道 -lopenhighgui
指的是哪个图书馆。我在 g++ 的手册中发现 -l
标志指定库名称避免 lib
前缀和 *.a
*.so
(linux)/*.dylib
(mac) 后缀。执行 otool -L
可执行文件后,我得到输出:
/opt/local/lib/libopencv_highgui.3.1.dylib (compatibility version 3.1.0, current version 3.1.0)
那么为什么它使用这个而不是其他的,它的使用方式是什么?三个库有什么区别?
另一个问题是关于链接和执行过程。我已经了解使用静态库时的链接过程。我的问题是在编译动态库时。在下一个示例中:
-输入:g++ -I/opt/local/include/opencv -I/opt/local/include -L/opt/local/lib -lopencv_highgui image-conversion.cpp -o image-conversion
我发现一个程序从编译到执行的过程可以分为三个部分。
编译器首先寻找标准目录下的头文件或通过
-I
标志的目录进行代码解析。其次,它链接由
-lflag
指定的库,在路径 -L 或标准路径下。这是通过链接器 (ld) 完成的
第三,在执行时,动态链接器程序 (dyld) 负责 "adding" 将代码写入 RAM 内存以便执行。
问题是下一个:我在网上发现一些人说如果他们不设置$LD_LIBRARY_PATH
(在linux)或$DYLD_LIBRARY_PATH
(在mac OSx) 与库的非标准目录(在我的例子中是 export LD_LIBRARY_PATH="/opt/local/lib"
),动态链接器找不到库并且程序执行失败。我发现我的程序没有崩溃,如果我执行 otool(用于查看链接的内容)。我得到这个(这是所有链接的库的摘要):
/opt/local/lib/libopencv_shape.3.1.dylib (compatibility version 3.1.0, current version 3.1.0)
/opt/local/lib/libopencv_imgproc.3.1.dylib (compatibility version 3.1.0, current version 3.1.0)
...
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
这是怎么回事?我发现 LD_LIBRARY_PATH 可用于测试新库,但为什么这些人说他们只需要为执行程序设置此变量?这最后一部分是如何工作的?我没有设置它,它工作得很好。
感谢任何人。
实际上有两个问题(顺便说一句,这不是一个很好的 SO 实践),所以我将独立回答它们。
此外,我将重点关注 Linux - 这是我熟悉的领域。从问题的文本来看,我认为 Mac 世界中的事情非常相似。
库命名约定
在 Linux 环境中使用 .so 库时,经常会看到动态库通常以三元组的形式出现。例如,库 foo 可能存在于 3 个文件中:libfoo.so、libfoo.so.6、libfoo.so.6.5.4。如果你仔细看,你会发现它们都是同一个文件——通常其中两个只是符号 links 到第三个。为了进一步讨论,libfoo.so 将被称为 unversioned 库,ibfoo.so.6 将被称为 major-versioned 和 libfoo.so.6.5.4 *full-versioned。你为什么需要那些?为了更好的版本控制。
当您 link 您的应用程序时,您总是使用 linker 规则用于未版本化的 livbary - 考虑到 linker 添加 lib
和 .so
按照规则,它看起来像
g++ ... -lfoo ...
当您的应用程序被 linked 时,linker 打开 libfoo.so 并检查它的几项内容。它检查的内容之一是 so-called SONAME
header。此 header 是在 linked .so 库时创建的,它的文件名可以与 linker 当前正在查看的文件名不同。例如,它可能有一个 major-versioned 文件,link 用户会看到它:SONAME = libfoo.so.6。
当 linker 看到 SONAME 时,它会将生成的应用程序文件标记为需要 libfoo.so.6
- 即使您实际上要求 libfoo.so
.
通过这样做 linker 保留了库的特定版本。您的应用程序最初是使用版本 6 编译和 linked 的,因此只要应用程序是 运行,就需要版本 6。
如果稍后系统升级(或应用程序 运行s 在不同的系统上),其中 foo
是不同的版本(比如 7),.so 文件将不同: libfoo.so, libfoo.so.7, libfoo.so.7.6.5。由于您的应用程序需要 libfoo.so.6
,它将无法启动 - 这是一件好事,因为谁知道版本 7 是否仍然兼容?如果没有此保护,应用程序将启动并使用不同的库版本,其影响可能是毁灭性的。
LD_LIBRARY_PATH 搜索
你的第二个问题是 LD_LIBRARY_PATH。确实如此,run-time linker 在查找动态库时参考这个变量。然而,这并不是它咨询的唯一内容。除此之外,除了默认搜索路径外,还有一个per-application动态库路径,它在应用程序linked时记录在应用程序中,通常由[=85=的rpath参数控制]呃,比如:
g++ ... -Wl,rpath,/path/to/so/library
当这样记录路径时,run-time link 用户将在加载应用程序时将这些路径添加到搜索路径列表中。
可以在没有 LD_LIBRARY_PATH 的情况下为您的应用程序找到库的事实意味着以下两种情况之一:在 linked 应用程序时记录了 rpath,或者实际上包含了 /opt/local/lib
在您平台的默认搜索路径中。