- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我创建了一个cpp项目,该项目使用了一个名为libblpapi3_64.so
的lib文件
该文件来自我从Internet下载的库。
我的项目运行没有任何错误。所以我将其更新为bitbucket。
然后我的同事下载并在自己的计算机上运行它。但是他得到了一个错误:usr/bin/ld: cannot find -lblpapi3_64
。
实际上,我已将其复制到项目存储库中。我的意思是我在项目下创建了一个名为lib的文件,并且我使用的所有lib文件都在其中。
还有其他lib文件,例如liblog4cpp.a
,但它们都很好。仅libblpapi3_64.so
收到错误。
是否因为它是.so文件而不是.a
文件?还是还有其他原因?
顺便说一句,libblpapi3_64.so
的文件名是green
,其他文件(.a)是white
。我认为这不是链接文件,而是原始文件。
最佳答案
简介:ld
不知道您的项目库位于何处。您必须将其放置在ld的已知目录中,或通过链接器的-L
参数指定库的完整路径。
为了能够构建程序,您需要将库放在/bin/ld
搜索路径中,并且您的同事也必须位于。为什么?查看详细答案。
详细信息:
首先,我们应该了解哪些工具可以做什么:
object files
(它在运行时不太在乎符号)。 object
和archive files
组合在一起,重新定位它们的数据并将符号引用绑定(bind)到一个文件中:可执行文件或库。 main.c
,
func.h
和
func.c
。
#include "func.h"
int main() {
func();
return 0;
}
void func();
#include "func.h"
void func() { }
main.c
)编译为目标文件(
main.o
)时,由于它具有未解析的符号,因此无法运行。让我们从
producing an executable
工作流程的开头开始(没有详细信息):
main.c.preprocessed
:
void func();
int main() {
func();
return 0;
}
func.c.preprocessed
:
void func();
void func() { }
main.c.preprocessed
中看到的那样,您的
func.c
文件和
void func()
的实现都没有连接,编译器根本不知道它,它会分别编译所有源文件。因此,要编译该项目,您必须使用
cc -c main.c -o main.o
和
cc -c func.c -o func.o
之类的东西来编译两个源文件,这将产生2个目标文件
main.o
和
func.o
。
func.o
可以解决所有符号问题,因为它只有一个函数在
func.c
内部编写了主体,但是
main.o
尚未解决
func
符号,因为它不知道在哪里实现。
func.o
里面是什么:
$ nm func.o
0000000000000000 T func
func
函数。
main.o
:
$ nm main.o
U func
0000000000000000 T main
main.o
具有已实现并已解析的静态函数
main
,我们可以在目标文件中看到它。但是我们还看到
func
符号,标记为未解析的
U
,因此我们无法看到其地址偏移量。
void func();
)。如果链接器因某种原因无法执行此操作,则会引发类似
unresolved external symbol
:
void func()
的错误。如果不将
func.o
对象文件提供给链接器,则可能会发生这种情况。因此,让我们将所有需要的目标文件提供给链接器:
ld main.o func.o -o test
main.o
,然后通过
func.o
,尝试解析符号,如果一切正常-将其输出到
test
文件。如果我们查看产生的输出,我们将看到所有符号都已解析:
$ nm test
0000000000601000 R __bss_start
0000000000601000 R _edata
0000000000601000 R _end
00000000004000b0 T func
00000000004000b7 T main
func.c
源文件中创建一个共享库:
gcc -c func.c -o func.o
gcc -shared -fPIC -Wl,-soname,libfunc.so.1 -o libfunc.so.1.5.0 func.o
/usr/lib/
中:
sudo mv libfunc.so.1.5.0 /usr/lib/ # to make program be able to run
sudo ln -s libfunc.so.1.5.0 /usr/lib/libfunc.so.1 #creating symlink for the program to run
sudo ln -s libfunc.so.1 /usr/lib/libfunc.so # to make compilation possible
func()
符号,创建可执行文件并将其(动态)链接到我们的共享库(
libfunc
),使我们的项目依赖于该共享库:
cc main.c -lfunc
$ nm a.out | grep fun
U func
func
符号将在每个程序启动之前由动态加载程序解析。好的,现在让我们回到理论上。
ar
工具和由
ranlib
工具创建的单个符号表将它们放置在单个存档中。
symbols
。这些符号将由链接器替换为地址。因此,可以通过两件事来解析符号:
the linker
和
dynamic loader
:
ld
,完成2个工作:_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_
更改为0x07f4123f0
。undefined reference to
错误并中断构建过程,因为您尝试使用这些符号,但链接器无法在其中找到此类符号这是它正在处理的目标文件。否则,此链接器会将一些信息添加到ELF
可执行文件中,该信息是:.interp
部分-请求interpreter
-执行之前调用动态加载程序,因此此部分仅包含动态加载程序的路径。例如,如果您查看依赖于共享库(libfunc
)的可执行文件,则会看到interp部分$ readelf -l a.out
:INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
.dynamic
部分-interpreter
在执行之前将查找的共享库的列表。您可以通过ldd
或readelf
看到它们:$ ldd a.out
linux-vdso.so.1 => (0x00007ffd577dc000)
libfunc.so.1 => /usr/lib/libfunc.so.1 (0x00007fc629eca000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fefe148a000)
/lib64/ld-linux-x86-64.so.2 (0x000055747925e000)
$ readelf -d a.out
Dynamic section at offset 0xe18 contains 25 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libfunc.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
ldd
还会找到文件系统中的所有库,而readelf仅显示程序需要的库。因此,所有这些库都将由动态加载程序搜索(下一段)。ld.so
或ld-linux
。它查找并加载程序所需的所有共享库(如果之前未加载),通过在程序开始之前将它们替换为实际地址来解析符号,准备运行程序,然后运行它。在构建之后和运行程序之前,它可以工作在。简而言之,动态链接意味着在每个程序启动之前在可执行文件中解析符号。 ELF
节运行.interp
可执行文件时(需要加载一些共享库),操作系统(Linux)首先运行解释器,但不运行程序。否则,您将具有未定义的行为-程序中有符号,但符号没有由地址定义,这通常意味着程序将无法正常运行。/lib/ld-linux.so.2
,对于64位架构的elf,二进制文件是/lib64/ld-linux-x86-64.so.2
)。/usr/bin/ld: cannot find -lblpapi3_64
?因为它尝试查找其已知路径中的所有库。为什么要在运行时加载该库,为什么要搜索该库?因为它需要检查该库是否可以解析所有需要的符号,并将其名称放入动态加载程序的.dynamic
部分。实际上,.interp
节几乎存在于每个c/c++精灵中,因为libc
和libstdc++
库都是共享的,并且编译器默认情况下将任何项目动态链接到它们。您也可以静态链接它们,但这将扩大可执行文件的总大小。因此,如果找不到共享库,您的符号将仍然无法解析,并且您将 UNABLE 来运行您的应用程序,因此无法生成可执行文件。您可能会获得通常通过以下方式搜索库的目录列表:ld --verbose
的输出。 ldconfig
的输出。 DT_RPATH
动态部分。 DT_RUNPATH
部分。 LD_LIBRARY_PATH
环境变量。 /etc/ld.so.cache
-自己的缓存文件,其中包含以前在增强库路径中找到的候选库的已编译列表。 -z nodeflib
链接器选项链接,则将跳过此步骤。 .so
,而是.so.version
格式。当您构建应用程序时,链接器将查找.so
文件(通常是.so.version
的符号链接(symbolic link)),但是在您运行应用程序时,动态加载程序将查找.so.version
文件。例如,假设我们有一个库test
,根据semver的版本为1.1.1
。在文件系统中,它将看起来像:/usr/lib/libtest.so -> /usr/lib/libtest.so.1.1.1
/usr/lib/libtest.so.1 -> /usr/lib/libtest.so.1.1.1
/usr/lib/libtest.so.1.1 -> /usr/lib/libtest.so.1.1.1
/usr/lib/libtest.so.1.1.1
libtest.so.1
,libtest.so.1.1
和libtest.so.1.1.1
)和一个libtest.so
文件,但是要运行您的应用程序,您首先必须仅列出3个版本控制的库文件。这也解释了为什么Debian或rpm软件包分别具有devel
-packages:普通的软件包(仅包含已编译的应用程序运行它们所需的文件),具有3个版本化的库文件,以及一个devel软件包,仅包含用于创建的symlink文件可以编译项目。-L<somePathToTheSharedLibrary>
作为参数来添加共享库位置目录。 ld-linux
)搜索,因此它必须位于路径(请参见上文)或系统链接器路径中。在大多数linux程序发行版中,例如Steam发行的游戏,都有一个shell脚本来设置LD_LIBRARY_PATH
变量,该变量指向游戏所需的所有共享库。 关于c++ - cpp : usr/bin/ld: cannot find -l<nameOfTheLibrary>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30600978/
我正在尝试创建尽可能小的 ELF。我创建了一个这样的测试文件(NASM 语法): SECTION .text dd 0xdeadbeef 使用此链接描述文件: SECTIONS { .text
GNU LD 链接器命令语言是否有条件语句? 背景:我正在为 arm cortex m0+ 开发固件,该固件由引导加载程序和应用程序组成。两者都在单独的项目中进行编译和刷新,但我使用了一个框架,其中包
我很确定 ld 有一个手册页链接器脚本语法,但我找不到它。 最佳答案 如果您更喜欢比 info 更方便的东西, 这是一个可浏览的 HTML 版本:ld.info: Scripts .但它可能不是完全最
谁能解决这个练习,这样我就能明白我错在哪里,因为有太多的 LOL 变量。 生成一个 C 代码,将其放在以下表达式之前 printf ("% ld% ld% ld \ n", lol, & lol, *
在他关于理解 Linux Kernel Initcall Mechanism 的文章中, Trevor 创建了一个用户空间程序来模拟调用 linux 驱动程序的 init_module() 的机制。
/usr/bin/ld: cannot find -ldlib /usr/bin/ld: cannot find -lcblas /usr/bin/ld: cannot find -llapack 在
我想以 json-ld 格式创建一组人,但我需要保留一些键而不是使用数组,所以我首先尝试了这个: { "@context" : { "@base" : "http://www.exampl
所以我试图围绕 JSON-LD 进行思考,我看到的所有示例主要包括嵌入“链接数据”。但我想提供对链接数据的引用(主要是因为嵌入所有数据可能会产生 10MB 的有效负载)。所以我想知道我这样做是否正确。
我在这里复制了 json-ld standard 中的示例的一部分: { "@context": { "foaf": "http://xmlns.com/foaf/0.1/", "
考虑这样一个程序: #include void foo() __attribute__((__weak__)); int main() { printf("%p\n", (void *)fo
我正在尝试使用一个名为 GLV 的小部件库对于我正在开发的应用程序。我正在运行 Linux Mint 17。我安装了所有库并成功构建了 GLV 库,但是当我尝试运行已构建的示例之一时,出现了此共享库错
在将未编辑的 JSON 数据转换为 JSON-LD 时,使用前缀和数据值为对象构造 IRI 时遇到问题。我运行的示例代码是: { "@context" : { "prefix" : "
假设我有一个 JSON 对象,它在嵌套对象中包含一些属性。 { "title": "My Blog Post", "meta": { "publishedAt": "2
我是 JSON-LD 和 LOD 的新手,所以请原谅我使用的术语。我正致力于在 JSON-LD 中创建数据模型,以描述基于欧洲数据模型 (http://pro.europeana.eu/edm-doc
我有一个玩具 x86 汇编程序,我正在用 as 编写和编译它和 ld : .text .global _start _start: movq $1, %rax movq
我正在尝试创建 Google 的结构化数据,但不知道我在做什么。我将其设置为一个组织,然后将 SD 标记工具用于我的所有产品。我将每个 JSON-LD 产品直接从标记工具而不是嵌套放入它自己的脚本标签
我正在尝试创建 Google 的结构化数据,但不知道我在做什么。我将其设置为一个组织,然后将 SD 标记工具用于我的所有产品。我将每个 JSON-LD 产品直接从标记工具而不是嵌套放入它自己的脚本标签
我正在尝试使用 vcpkg 和 ndk r20 为 android arm 构建 tesseract我必须编辑 CMakeLists.txt 并添加 glob.c 和 glob.h,因为它们不在 nd
长话短说: 有没有办法让我(没有 root 访问权限)使链接器(由 gcc 调用)不知道 /etc/ld.so.conf 中包含的目录的内容 在通过 ldconfig 缓存之后? 详细说明: 我正在尝
我想将/opt/vertica/lib64 添加到系统库路径中,所以我执行以下步骤: (1) 将/opt/vertica/lib64加入/etc/ld.so.conf,运行ldconfig, (2)
我是一名优秀的程序员,十分优秀!