我有这样的 C++ 共享库:
extern "C"{
#include <foo.h>
int test(int a){
return 1;
}
}
我可以查找和调用函数
int test(int a);
,但包含的库 (foo.h
) 中导出的 C 函数无法调用。
如何使所有
foo.h
C 函数可见并调用它们?
我正在使用 CMake 来构建项目。
我可以查找并调用函数 int test(int a);,但包含的库 (foo.h) 中导出的 C 函数不可见且无法调用。
您看不到您在头文件中定义的所有函数,因为它们未被使用。这是一个小例子:
// header_only.h
#ifndef HEADER_ONLY_H
#define HEADER_ONLY_H
extern "C" {
// these functions are used
inline int sum(int a, int b) { return a + b; }
inline int sub(int a, int b) { return a - b; }
// there functions are not
inline int mult(int a, int b) { return a * b; }
}
#endif // !HEADER_ONLY_H
我们来尝试调用其中的函数:
// test.cpp
#include "header_only.h"
extern "C" {
int test() {
int a = 5;
int b = 4;
int add_result = sum(a, b);
int sub_result = sub(a, b);
return a * b;
}
}
请注意,我们只调用了
sum
和sub
,而mult
被定义但未被使用。
现在让我们编译目标文件并将其链接到库文件中:
# compile the source file into object file
❯ g++ -c test.cpp -o test.o
# create a library file
❯ ar rcs libtest.a test.o
# print all symbol names
❯ nm -U libtest.a
test.o:
0000000000000074 T _sub
0000000000000054 T _sum
0000000000000000 T _test
0000000000000000 t ltmp0
0000000000000098 s ltmp1
如您所见,
mult
没有编译到lib中。如果我们编写一个像这样的 main
函数:
// test_lib.cpp
extern "C" {
extern int test();
int main() {
test();
return 0;
}
}
使用命令编译:
❯ g++ test_lib.cpp libtest.a -o main
❯ ./main
❯ echo $?
0
一切都会顺利进行。但如果您尝试直接在
mult
中使用 test_lib.cpp
而不包含 header_only.h
:
// test_lib.cpp
extern "C" {
int main() {
// test();
mult(3, 4);
return 0;
}
}
让我们编译一下:
❯ g++ test_lib.cpp libtest.a -o main
test_lib.cpp:5:3: error: use of undeclared identifier 'mult'
mult(3, 4);
如果你想使用你在头文件中定义的所有函数,最好的选择是将它们分成头文件和源文件,就像提到的这个答案一样。并用其他源文件编译您拆分出来的源代码(比方说
foo.cpp
)。
// header_only.h
#ifndef HEADER_ONLY_H
#define HEADER_ONLY_H
extern "C" {
// these functions are used
int sum(int a, int b);
int sub(int a, int b);
// there functions are not
int mult(int a, int b);
}
#endif // !HEADER_ONLY_H
//header_only.cpp
#include "header_only.h"
extern "C" {
int sum(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mult(int a, int b) { return a * b; }
}
其他源文件未修改。我们再编译一下:
❯ g++ -c header_only.cpp test.cpp
❯ ar rcs libtest.a test.o header_only.o
❯ nm -a libtest.a
test.o:
U _sub
U _sum
0000000000000000 T _test
0000000000000000 t ltmp0
0000000000000058 s ltmp1
header_only.o:
0000000000000040 T _mult
0000000000000020 T _sub
0000000000000000 T _sum
0000000000000000 t ltmp0
0000000000000060 s ltmp1
您可以看到所有符号都已导出。您可以在
mult
函数中使用 main
:
❯ cat test_lib.cpp
#include "header_only.h"
extern "C" {
int main() {
// test();
mult(3, 4);
return 0;
}
}
❯ g++ libtest.a test_lib.cpp
❯ ./a.out
❯ echo $?
0
您可以在 CMake 中执行相同的操作。按照上面的操作,将你在
foo.h
中拆分出来的源代码的文件名添加到add_library
中。
cmake_minimum_required(VERSION 3.17)
project(test_link)
add_library(link header_only.cpp test.cpp)
add_executable(main test_lib.cpp)
target_link_libraries(main link)
让我们构建项目:
❯ cmake -B build
cmake-- The C compiler identification is AppleClang 14.0.3.14030022
-- The CXX compiler identification is AppleClang 14.0.3.14030022
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/liuyuan/Desktop/test/build
❯ cmake --build build
[ 20%] Building CXX object CMakeFiles/link.dir/header_only.cpp.o
[ 40%] Building CXX object CMakeFiles/link.dir/test.cpp.o
[ 60%] Linking CXX static library liblink.a
[ 60%] Built target link
[ 80%] Building CXX object CMakeFiles/main.dir/test_lib.cpp.o
[100%] Linking CXX executable main
[100%] Built target main
❯ ./build/main
❯ echo $?
0