cmake, 不能 link static library into shared one
cmake, can't link static library into shared one
我正在为某些 fpga API 编写适配器(共享库)。我有 libsomelib.a
及其 API - somelibAPI.h
。这是我的适配器的一个最小示例:
somelib_adapter.h
:
#include <string>
namespace details {
#include "somelibAPI.h"
}
class somelib_adapter {
public:
std::string foo();
};
somelib_adapter.cpp
:
#include "somelib_adapter.h"
using namespace details;
std::string somelib_adapter::foo() {
char result[64];
somelibAPI_call(result);
return std::string(result);
}
CMakeLists.txt
:
cmake_minimum_required(VERSION 3.8)
project(untitled1)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES somelib_adapter.cpp somelib_adapter.h)
FIND_LIBRARY(SOMELIB_LIBRARIES
NAMES libsomelib.a
PATHS "${SRC_CPP_DIRECTORY}")
add_library(untitled1 SHARED ${SOURCE_FILES})
set(untitled1 -Wl,--whole-archive ${SOMELIB_LIBRARIES} -Wl,--no-whole-archive)
target_link_libraries(untitled1 some_other_shared_lib_used_by_somelib)
cmake 找到 libsomelib.a
但是当我尝试 nm libuntitled1.so | c++filt
它不包含 somelibAPI_call
的符号位置。更重要的是,我为测试它而制作的可执行文件存在 undefined reference
错误。可能有什么问题?
编辑:libsomelib.a
是用 -fPIC
编译的
EDIT2:我发现我误解了一些例子。现在我得到了 target_link_libraries(untitled1 -Wl,--whole-archive ${SOMELIB_LIBRARIES} -Wl,--no-whole-archive some_other_shared_lib_used_by_somelib)
但还有另一个问题:/usr/bin/ld: ../libsomelib.a(somelibAPI.o): relocation R_X86_64_32 against .rodata.str1.1 can not be used when making a shared object; recompile with -fPIC
这通常是不可能的,除非您重新编译静态库。
这里的问题是动态库必须用 position independent code 生成,这样它们才能动态加载到现有进程的地址 space 中。也就是说,编译器必须以特定方式生成代码,以便它适合从共享库执行。
因为我们对静态库没有这个要求,编译器可以自由地在那里创建位置相关的代码(这正是你的情况),这禁止它以后被链接到共享库中。因此,要使其正常工作,您需要更改 静态库 的编译,使其知道稍后将链接到共享库。只有用正确的选项重新编译静态库才能使这个工作正常。
设置正确构建选项的确切方法当然取决于用于构建该静态库的构建系统。例如,对于使用 CMake 构建的静态库,您可以更改其构建脚本,以便它在静态库目标上设置 POSITION_INDEPENDENT_CODE
目标 属性。
我正在为某些 fpga API 编写适配器(共享库)。我有 libsomelib.a
及其 API - somelibAPI.h
。这是我的适配器的一个最小示例:
somelib_adapter.h
:
#include <string>
namespace details {
#include "somelibAPI.h"
}
class somelib_adapter {
public:
std::string foo();
};
somelib_adapter.cpp
:
#include "somelib_adapter.h"
using namespace details;
std::string somelib_adapter::foo() {
char result[64];
somelibAPI_call(result);
return std::string(result);
}
CMakeLists.txt
:
cmake_minimum_required(VERSION 3.8)
project(untitled1)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES somelib_adapter.cpp somelib_adapter.h)
FIND_LIBRARY(SOMELIB_LIBRARIES
NAMES libsomelib.a
PATHS "${SRC_CPP_DIRECTORY}")
add_library(untitled1 SHARED ${SOURCE_FILES})
set(untitled1 -Wl,--whole-archive ${SOMELIB_LIBRARIES} -Wl,--no-whole-archive)
target_link_libraries(untitled1 some_other_shared_lib_used_by_somelib)
cmake 找到 libsomelib.a
但是当我尝试 nm libuntitled1.so | c++filt
它不包含 somelibAPI_call
的符号位置。更重要的是,我为测试它而制作的可执行文件存在 undefined reference
错误。可能有什么问题?
编辑:libsomelib.a
是用 -fPIC
EDIT2:我发现我误解了一些例子。现在我得到了 target_link_libraries(untitled1 -Wl,--whole-archive ${SOMELIB_LIBRARIES} -Wl,--no-whole-archive some_other_shared_lib_used_by_somelib)
但还有另一个问题:/usr/bin/ld: ../libsomelib.a(somelibAPI.o): relocation R_X86_64_32 against .rodata.str1.1 can not be used when making a shared object; recompile with -fPIC
这通常是不可能的,除非您重新编译静态库。
这里的问题是动态库必须用 position independent code 生成,这样它们才能动态加载到现有进程的地址 space 中。也就是说,编译器必须以特定方式生成代码,以便它适合从共享库执行。
因为我们对静态库没有这个要求,编译器可以自由地在那里创建位置相关的代码(这正是你的情况),这禁止它以后被链接到共享库中。因此,要使其正常工作,您需要更改 静态库 的编译,使其知道稍后将链接到共享库。只有用正确的选项重新编译静态库才能使这个工作正常。
设置正确构建选项的确切方法当然取决于用于构建该静态库的构建系统。例如,对于使用 CMake 构建的静态库,您可以更改其构建脚本,以便它在静态库目标上设置 POSITION_INDEPENDENT_CODE
目标 属性。