iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
Software Development

建構屬於自己的C/C++專案 : 我的30天CMake學習之旅系列 第 11

[Day 11] 庫的實際應用經驗--使用別人的庫

  • 分享至 

  • xImage
  •  

什麼是庫?

庫是寫好的現有的,成熟的,可以復用的二進制檔案。現實中每個專案都要依賴很多基礎的底層庫(iostream, vector, sys/resource.h ...),不可能每個人的程式都從零開始。

讀到以上說明的時候,是不是有一種 りしれ供さ小 的感覺?因此今天我帶來了庫的實際應用範例!

之前在某一間公司實習的時候,有天需要使用工業電腦控制通訊協議為CAN BUS的機器,設備商有提供一個USB轉CAN總線轉換器(I7565H1/H2),上網查了一下,手冊中的程式庫都有在網路上公開,內容也滿詳細的。

https://ithelp.ithome.com.tw/upload/images/20230925/20162026yNRLBRlWGZ.jpg

但是實際下載後發現,專案中並沒有提供SDK完整的原始碼,而是全部都包裝成動態與靜態庫供客戶選用。
不過想一想這也正常,畢竟這些都是智慧財產,總不可能把硬體data sheet和軟體SDK原始碼全部公開,萬一被抄襲了怎麼辦?
也有可能是怕使用者胡亂修改程式破壞硬體,算是某種程度的防呆機制吧,提供API給使用者,只能按照手冊上的規範操作。

以下是I7565H1/H2 SDK的檔案架構

├── 99-I7565H2.rules
├── bootinstall.service
├── ChangeLog
├── doc
│   └── linux_I7565H1H2_Software_Manual.pdf
├── examples
│   ├── i7565H1H2_a
│   ├── i7565H1H2.c
│   ├── i7565H1H2_so
│   └── Makefile
├── I7565H1H2_hotplug
├── I7565H1H2_install
├── include
│   ├── codes.h
│   ├── common.h
│   ├── debug.h
│   ├── global.h
│   ├── i7000.h
│   ├── i7565H1H2.h
│   ├── i7k.h
│   ├── Makefile
│   ├── msw.h
│   ├── sio.h
│   ├── threadfun.h
│   └── timer.h
├── lib
│   ├── libI7565H1H2_64.a
│   ├── libI7565H1H2_64.so -> ../lib/libI7565H1H2_64.so.1
│   ├── libI7565H1H2_64.so.1 -> ../lib/libI7565H1H2_64.so.1.0
│   ├── libI7565H1H2_64.so.1.0
│   ├── libI7565H1H2.a
│   ├── libI7565H1H2_arm.a
│   ├── libI7565H1H2_arm.so -> ../lib/libI7565H1H2_arm.so.1
│   ├── libI7565H1H2_arm.so.1 -> ../lib/libI7565H1H2_arm.so.1.0
│   ├── libI7565H1H2_arm.so.1.0
│   ├── libI7565H1H2.so -> ../lib/libI7565H1H2.so.1
│   ├── libI7565H1H2.so.1 -> ../lib/libI7565H1H2.so.1.0
│   ├── libI7565H1H2.so.1.0
│   ├── libi7k_64.a
│   ├── libi7k_64.so -> ../lib//libi7k_64.so.1
│   ├── libi7k_64.so.1 -> ../lib//libi7k_64.so.1.0
│   ├── libi7k_64.so.1.0
│   ├── libi7k.a
│   ├── libi7k_arm.a
│   ├── libi7k_arm.so -> libi7k_arm.so.1
│   ├── libi7k_arm.so.1 -> libi7k_arm.so.1.0
│   ├── libi7k_arm.so.1.0
│   ├── libi7k.so -> ../lib//libi7k.so.1
│   ├── libi7k.so.1 -> ../lib//libi7k.so.1.0
│   └── libi7k.so.1.0
├── Makefile
└── README

可以看到整個軟體SDK中只有examples/i7565H1H2.c是可供修改的範例原始碼(內容是API的使用範例),其他都是讓客戶使用的靜態庫、動態庫與標頭檔。

因此接下來範例內容,就是使用上一篇編譯出來的靜態與動態函式庫還有標頭檔(用來模擬別人的庫),在沒有庫原始碼的情況下,如何與主程式鍊結成最終的執行檔(使用別人的庫),而不是向昨天一樣,從原始碼編譯成庫之後再與主程式鍊結。

語法

link_directories

定義:鍊結器尋找鍊結文件的路徑。

link_directories( [directory1] [directory2] ...)

> [directory] : 庫路徑

範例

$ git clone https://github.com/m11112089/2023_iT_CMake.git
$ cd ~/2023_iT_CMake/Day11

  1. 將昨天我們編譯出來的動態庫與靜態庫放入 Day11/lib 資料夾中

$ cp ~/2023_iT_CMake/Day10/build/lib/* ~/2023_iT_CMake/Day11/lib/
// 那個星號是代表該目錄下所有的檔案

kai@esoc:~/2023_iT_CMake/Day11/lib$ cp ~/2023_iT_CMake/Day10/build/lib/* ~/2023_iT_CMake/Day11/lib/
kai@esoc:~/2023_iT_CMake/Day11/lib$ tree
.
├── libmysqrt_a.a
└── libmysqrt_so.so
  1. 修改CMakeListx.txt
  • 將庫所在的路徑加入
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 將庫所在路徑加入鍊結器的搜尋路徑中
  • 鍊結靜態庫
add_executable(main_a src/main.cpp)
# 將main.cpp編譯成一個可執行文件main_a
target_link_libraries(main_a mysqrt_a)
# 將mysqrt_a鍊結到main_a
  • 鍊結動態庫
add_executable(main_so src/main.cpp)
# 將main.cpp編譯成一個可執行文件main_so
target_link_libraries(main_so mysqrt_so)
# 將mysqrt_so鍊結到main_so
  1. 編譯與執行

$ cd build
$ cmake ..
$ make
$ ./main_a 10
$ ./main_so 10

由此可見,只要路徑正確程式可以在沒有庫原始碼的情況順利編譯並執行完畢。

注意一定要有標頭檔,原因在於C++的編譯方式為個別編譯(separate compilation),能讓程式分為數個檔案,並且每一個都能獨立編譯成binary檔,而能夠獨立的編譯的關鍵是要有標頭檔的"宣告",在最後練接(linking)的階段才會去尋找"宣告"如何實現的"定義"。


上一篇
[Day 10] 靜態庫與動態庫
下一篇
[Day 12] 動態庫與版本號
系列文
建構屬於自己的C/C++專案 : 我的30天CMake學習之旅29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言