我正在C中构建一个由我没有源访问权限的程序动态加载的共享库.目标平台是64位Linux平台,我们正在使用gcc构建.我能够在~100行中构建问题的复制品,但仍有一点需要阅读.希望它是说明性的.
核心问题是我在共享库中定义了两个非静态函数(bar和baz).两者都需要是非静态的,因为我们希望调用者能够使用它们.另外,baz电话bar.正在使用我的库的程序也有一个名为的函数bar,这通常不是问题,但调用程序是用-rdynamic它编译的,因为它有一个foo需要在我的共享库中调用的函数.结果是我的共享库最终链接到bar运行时调用程序的版本,产生不直观的结果.
在理想的世界中,我可以在编译共享库时包含一些命令行开关,以防止这种情况发生.
我当前的解决方案是将我的非静态函数重命名为funname_local并将它们声明为静态.然后我定义一个新函数:
funname() { return funname_local(); },并将funname我共享库中的任何引用更改为funname_local.这有效,但感觉很麻烦,我更喜欢告诉链接器更喜欢本地编译单元中定义的符号.
internal.c
#include <stdio.h>
#include "internal.h"
void
bar(void)
{
printf("I should only be callable from the main program\n");
}
Run Code Online (Sandbox Code Playgroud)
internal.h
#if !defined(__INTERNAL__)
#define __INTERNAL__
void
bar(void);
#endif /* defined(__INTERNAL__) */
Run Code Online (Sandbox Code Playgroud)
main.c中
#include <dlfcn.h>
#include <stdio.h>
#include "internal.h"
void
foo(void)
{
printf("It's important that I am callable from both main …Run Code Online (Sandbox Code Playgroud) 我在使用 cmake/gcc/Linux 时遇到问题。
无论我尝试什么,我都无法摆脱链接器行上的 CMAKE_CXX_FLAGS。CMake 在链接模式下调用 g++ 时不断传递它们。
我的 CMAKE_CXX_FLAGS 中有 -fopenmp 并且它不能出现在链接线上,所以 g++ 不会链接到 gomp(我使用的是 Intel 的 iomp5)。
编辑:我在 CMakeLists.txt 的开头尝试了以下内容,但没有帮助:
set(CMAKE_CXX_LINK_EXECUTABLE
"<CMAKE_CXX_COMPILER> <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
Run Code Online (Sandbox Code Playgroud)
谢谢
如何通过CMAKE将链接标志"DEF"和"NODEFAULTLIB"添加到vs2012项目?
我的其他库不允许我设置-ObjC或all_load标志.所以我需要使用-force_load链接我的库.
我的项目下有"GoogleOpenSource.framework"和"GooglePlus.framework",所以如何正确地将这些映射到工作中.
我设置了这样的路径:
-force_load $(PROJECT_DIR)/Project_name/GooglePlus.framework/Versions/A/Headers/GooglePlus.h
-force_load $(PROJECT_DIR)/Project_name/GoogleOpenSource.framework/Versions/A/Headers/GoogleOpenSource.h
Run Code Online (Sandbox Code Playgroud)
在其他链接器标志下,但它不起作用.
谁能告诉我这里做错了什么?
我有:
Bar带有方法的类int Bar::do(int d) constFoo带有方法的类int Foo::act(int a) const.代码Bar是这样的:
//Bar.h
class __attribute__ ((visibility ("default"))) Bar
{
private:
__attribute__ ((visibility ("hidden"))) int privateMethod(int x) const;
public:
Bar() {}
int do(int d) const;
}
//Bar.cpp
#include "Bar.h"
#include "Foo.h"
int Bar::do(int d) const {
Foo foo;
int result = foo.act(d) + this->privateMethod(d);
return result;
}
Run Code Online (Sandbox Code Playgroud)
libShared.so使用flag -fvisibility = hidden编译.
问题如下:我执行Linux命令nm -g -D -C --defined-only libShared.so …
我注意到,包括我在内的许多人都不知道链接程序搜索路径背后的原理和预期用途:“库路径”,“ rpath”和“ rpath-link”。有人可以向我们解释吗?
在阅读完所有内容后,我倾向于认为“ library-path”和“ rpath”就足够了。“ rpath-link”的原理和预期用途对我来说还是一个谜。让我解释一下原因。
设置'library-path'会将指定的路径传递给链接器,以在link(/ build)时在指定的路径中查找库。
设置“ rpath”会将指定的路径存储在生成的可执行文件中,链接器随后会在运行应用程序时(即在运行时)查看指定的路径。
因此,如果您的库位于非标准位置,则需要指定“ library-path”来构建可执行文件,并指定“ rpath”来运行它。
现在,GNU链接器文档说:“ -rpath和-rpath-link之间的区别在于,-rpath选项指定的目录包含在可执行文件中并在运行时使用,而-rpath-link选项仅在链接时有效。 ”
这引起了两个问题:
1)如果“ rpath-link”中的“ r”代表“运行时”,则名称“ rpath-link”似乎具有误导性,因为它是在链接时使用的。
2)我已经在“ library-path”中为链接时间指定了我的库目录。我认为“ rpath-link”没有用。奇怪的现实:来自http://www.kaizou.org/2015/01/linux-libraries/我知道'library-path'不用于辅助依赖性(从一个共享库到另一个共享库的依赖)。要解决这些次级依赖性,您需要设置“ rpath”或“ rpath-link”。那么我的问题是:什么是你不能使用“库路径”的理由也说明二次依赖性,而是有义务使用“rpath的链接”?
我有一个名为app的可执行文件,它想使用liba.so中的功能,因此我将app链接到liba.so。liba.so取决于libb.so。liba.so和libb.so都位于目录mylibs中。当我想生成可执行文件时,遇到了以下消息:
/usr/bin/ld: warning: libb.so.80, needed by /.../liba.so, not found (try using -rpath or -rpath-link)
Run Code Online (Sandbox Code Playgroud)
随后是几个未定义的参考错误。
为了正确构建它,我必须将“ library-path”和“ rpath-link”(或“ rpath”)都设置到目录mylibs中。这使我感到困惑,为什么不同时使用“ library-path”来搜索二级依赖libb.so,而必须设置一个附加的“ rpath-link”来搜索该二级依赖。
相关问题: -rpath-link的原理
gcc 6.3 的手册页说:
--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to
symbol will be resolved to "__wrap_symbol". Any undefined
reference to "__real_symbol" will be resolved to symbol.
...
If you link other code with this file using --wrap malloc, then all
calls to "malloc" will call the function "__wrap_malloc" instead.
The call to "__real_malloc" in "__wrap_malloc" will call the real
"malloc" function.
Run Code Online (Sandbox Code Playgroud)
所以我创建了一个简单的例子:
#include <stdio.h>
int foo() {
printf("foo\n");
return 0;
}
int __wrap_foo() {
printf("wrap foo\n"); …Run Code Online (Sandbox Code Playgroud) 我正在尝试在使用cmake编译的项目中使用armcc,但使用自定义专有链接器(不是armlink)。
我已将toolchain.cmake文件中的变量更改如下:
unset (CMAKE_LINKER CACHE)
set (CMAKE_LINKER "my_linker" CACHE STRING "" FORCE)
unset (CMAKE_ARMCC_LINKER CACHE)
set (CMAKE_ARMCC_LINKER "my_linker" CACHE STRING "" FORCE)
unset (CMAKE_EXE_LINKER_FLAGS CACHE )
set (CMAKE_EXE_LINKER_FLAGS "-flag1 -flag2" CACHE STRING "" FORCE)
unset (CMAKE_C_LINK_EXECUTABLE)
set (CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_EXE_LINKER_FLAGS> <OBJECTS> <LINK_LIBRARIES> -o <TARGET>")
unset (CMAKE_CXX_LINK_EXECUTABLE)
set (CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_EXE_LINKER_FLAGS> <OBJECTS> <LINK_LIBRARIES> -o <TARGET>")
Run Code Online (Sandbox Code Playgroud)
但是当cmake尝试检查我的编译器套件时,它在链接步骤中失败:
-- Check for working C compiler: armcc.exe -- broken
CMake Error at C:/Program Files (x86)/CMake/share/cmake-3.6/Modules/CMakeTestCCompiler.cmake:61 …Run Code Online (Sandbox Code Playgroud) man ld有以下话要说-z lazy:
...告诉动态链接器将函数调用解析推迟到调用函数时...延迟绑定是默认设置。
另一方面,gcc --verbose main.c传递-z now -z relro给 ld 以获得一个空的 main.cmain()
$ gcc --verbose main.c
Using built-in specs.
COLLECT_GCC=gcc
[...]
Thread model: posix
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
[...]
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/7/collect2 [...] -pie -z now -z relro [...]
Run Code Online (Sandbox Code Playgroud)
我在默认安装 gcc 的 Ubuntu 18.04 和 19.04 中看到了这一点。
所以-z lazy可能是 ld 的默认值,但是 gcc 在哪里/为什么将其更改为-z now -z relro?
如何告诉链接器g++允许多个符号定义(选择第一个出现)?
-z multidefs 允许多个符号定义。默认情况下,可重定位对象(.o 文件)之间出现的多个符号定义将导致致命错误条件。此选项抑制错误条件并允许采用第一个符号定义。此选项仅在指定了 -b svr4 选项时有效。
-zmuldefs不能识别该选项g++,也不能识别-z OPTION。什么是正确的参数?是否可以?
比方说,我已上载在一个封装库柯南,它使用OpenGL,并与这些链接GL中CMakeLists.txt。库的用户是否需要再次明确链接到 GL?柯南是否提供了一种方法来跟踪它并将其包含在 中${CONAN_LIBS}?
我在文档中找到的最接近的东西是 method package_info,您似乎可以在其中指定链接器额外选项,但我似乎没有在我的库的conanfile.py. 我尝试了所有:
self.cpp_info.sharedlinkflags = ["-lGL", "GL", "libGL", "libGL.so", "-llibGL.so"]
Run Code Online (Sandbox Code Playgroud)
但是如果在用户代码中我没有放置链接标志,它会引发对 GL 方法的“未定义引用”。
编辑:我在 linux mint 17 中工作。
我正在使用最新版本的opencv(opencv 2.4.9),我必须拥有Core Plot(绘图框架)所需的-ObjC标志.
当我在其他标志中设置-ObjC时,我得到了很多类型的错误(实际上是28个):Undefined symbols for architecture i386如下:
Undefined symbols for architecture i386:
"_CMSampleBufferGetImageBuffer", referenced from:
-[CaptureDelegate captureOutput:didOutputSampleBuffer:fromConnection:] in opencv2(cap_avfoundation.o)
CvCaptureFile::retrieveFramePixelBuffer() in opencv2(cap_avfoundation.o)
-[CvVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:] in opencv2(cap_ios_video_camera.o)
"_CMSampleBufferGetPresentationTimeStamp", referenced from:
-[CvVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:] in opencv2(cap_ios_video_camera.o)
"_CMSampleBufferInvalidate", referenced from:
CvCaptureFile::retrieveFramePixelBuffer() in opencv2(cap_avfoundation.o)
"_CMTimeMake", referenced from:
CvCaptureCAM::startCaptureDevice(int) in opencv2(cap_avfoundation.o)
CvVideoWriter_AVFoundation::writeFrame(_IplImage const*) in opencv2(cap_avfoundation.o)
-[CvVideoCamera createVideoDataOutput] in opencv2(cap_ios_video_camera.o)
"_CMVideoFormatDescriptionGetPresentationDimensions", referenced from:
CvCaptureCAM::getProperty(int) in opencv2(cap_avfoundation.o)
"_CVBufferRelease", referenced from:
-[CaptureDelegate captureOutput:didOutputSampleBuffer:fromConnection:] in opencv2(cap_avfoundation.o)
-[CaptureDelegate …Run Code Online (Sandbox Code Playgroud) linker-flags ×12
c++ ×6
gcc ×5
cmake ×3
linker ×3
linux ×3
c ×2
g++ ×2
ld ×2
objective-c ×2
xcode ×2
conan ×1
flags ×1
gcc-warning ×1
ios ×1
opencv ×1
visibility ×1