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號