c++ 写一个c静态链接库 供c或c++项目调用
静态链接库:输出的库文件及头文件提供给调用方之后,会随着编译将代码拷贝到调用者处;优点是无依赖;缺点是,静态库有更新后,所有可执行文件需要重新链接。
动态链接库:优点:编译时不需要拷贝代码,运行时动态链接,这样比较节省资源。缺点:运行时动态加载,可能影响程序执行性能。
本节通过CLion编辑器,创建c静态链接库;后通过分别给c和c++控制台项目,以达到了解静态链接库的创建和使用的基本流程。
创建c静态链接库项目
# 头文件 library.h
#ifndef CSTATICLIB_LIBRARY_H
#define CSTATICLIB_LIBRARY_H
typedef void (*callback)(void);
void add_handler(callback event);
void raise_event();
#endif // CSTATICLIB_LIBRARY_H
# library.c文件
#include "library.h"
#include <stdio.h>
callback close;
void add_handler(callback event) {
close = event;
}
void raise_event() {
if (close != NULL) {
close();
}
}
CMakeLists.txt文件配置
cmake_minimum_required(VERSION 4.0)
project(cstaticlib C)
set(CMAKE_C_STANDARD 11)
add_library(cstaticlib STATIC library.c)
编译项目得到静态库文件
创建c可执行控制台项目
创建可执行c控制台项目,用来测试如何使用静态链接库。
引入库文件和静态库文件
创建include目录和lib目录,将静态库文件libcstaticlib.a文件拷贝到lib目录,将library.h文件拷贝到include目录下。

配置CMakeLists.txt 配置文件查找路径 链接库文件
直接在main.c文件中引入library.h头文件是会报错的,因为静态库需要将静态库文件在链接阶段和本可执行项目合并,所以需要在CMake配置文件中指定要链接哪些库;
cmake_minimum_required(VERSION 4.0)
project(testcdemo C)
set(CMAKE_C_STANDARD 11)
#设置链接库查找路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
#设置头文件查找路径
include_directories(${PROJECT_SOURCE_DIR}/include)
add_executable(testcdemo main.c)
#指定要链接哪个库
#target_link_libraries(${PROJECT_NAME} libcstaticlib.a)
#库文件一般都是libxxx.a或者libxxx.lib这种格式,所以可以将文件后缀和lib前缀省略。这样写跨平台性好。
target_link_libraries(${PROJECT_NAME} cstaticlib)
编译并运行项目
在main函数中写入下面代码,编译并调试代码运行情况:
#include <stdio.h>
#include <library.h>
void onclose();
int main(void) {
callback event = onclose;
add_handler(event);
raise_event();
return 0;
}
void onclose() {
printf("Closing...\n");
}
输出
Closing...
以上便是,c可执行项目中调用静态链接库项目。
创建c++可执行控制台项目
引入库文件和头文件、配置CMakeLists.txt、编写代码步骤同上面操作;但编译报错:
FAILED: teststaticlib
: && /usr/bin/c++ -g -arch arm64 -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/teststaticlib.dir/main.cpp.o -o teststaticlib -L/Users/a77/Code/teststaticlib/lib -Wl,-rpath,/Users/a77/Code/teststaticlib/lib -lcstaticlib && :
Undefined symbols for architecture arm64:
"add_handler(void (*)())", referenced from:
_main in main.cpp.o
(found _add_handler in /Users/a77/Code/teststaticlib/lib/libcstaticlib.a(library.c.o), declaration possibly missing extern "C")
"raise_event()", referenced from:
_main in main.cpp.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
add_handler函数被发现变成了_add_handler,这个属于c++为照顾c语言不支持函数重载所设计的名称管理机制,为的是函数名不重复;
windows平台可以使用VisualStudio提供的dumpbin.exe /EXPORTS xxx.dll 查看函数导出符号;macos可以使用 nm xxx.dylib 或者 otool -tV xxx.dylib 来查看
a77@iMac Code % nm /Users/a77/Code/dynamiclib/cmake-build-debug/libdynamiclib.dylib
0000000000003f50 T _add_handler
0000000000004000 S _close
0000000000003f70 T _raise_event
a77@iMac Code % otool -tV /Users/a77/Code/dynamiclib/cmake-build-debug/libdynamiclib.dylib
/Users/a77/Code/dynamiclib/cmake-build-debug/libdynamiclib.dylib:
(__TEXT,__text) section
_add_handler:
0000000000003f50 sub sp, sp, #0x10
0000000000003f54 str x0, [sp, #0x8]
0000000000003f58 ldr x8, [sp, #0x8]
0000000000003f5c adrp x9, 1 ; 0x4000
0000000000003f60 add x9, x9, #0x0
0000000000003f64 str x8, [x9]
0000000000003f68 add sp, sp, #0x10
0000000000003f6c ret
_raise_event:
0000000000003f70 stp x29, x30, [sp, #-0x10]!
0000000000003f74 mov x29, sp
0000000000003f78 adrp x8, 1 ; 0x4000
0000000000003f7c add x8, x8, #0x0
0000000000003f80 ldr x8, [x8]
0000000000003f84 subs x8, x8, #0x0
0000000000003f88 cset w8, eq
0000000000003f8c tbnz w8, #0x0, 0x3fa8
0000000000003f90 b 0x3f94
0000000000003f94 adrp x8, 1 ; 0x4000
0000000000003f98 add x8, x8, #0x0
0000000000003f9c ldr x8, [x8]
0000000000003fa0 blr x8
0000000000003fa4 b 0x3fa8
0000000000003fa8 ldp x29, x30, [sp], #0x10
0000000000003fac ret
a77@iMac Code %
从上面的输出信息可以看到 函数名确实如报错信息中所述,前面加了下划线;好在,编译器提示我们要使用 extern "C"这样的代码块解决问题:
代码如下:
#include <csignal>
#include <iostream>
extern "C" {
#include <library.h>
}
void action();
int main() {
callback func = action;
add_handler(func);
raise_event();
return 0;
}
void action() {
std::cout << "receive event" << std::endl;
}
好了,以上便是从创建静态库项目和分别使用c和c++控制台项目引用静态库的全过程记录。

浙公网安备 33010602011771号