Linux中gcc的編譯、靜態庫和動態庫的製作
本文已參與「新人創作禮」活動,一起開啟掘金創作之路。
gcc是文字編譯器,就是編譯程式碼的工具,下面介紹gcc編譯C語言(.c檔案)的流程。
1 gcc的編譯過程
1.1 gcc的編譯過程
gcc的編譯分為以下四個階段:
- gcc前處理器:把
.c檔案
編譯成預處理
的.i檔案
- gcc編譯器:把
預處理
的.i檔案
編譯成.s
的彙編檔案 - gcc彙編器:把
.s
的彙編檔案
編譯成.o
的二進位制檔案
- gcc連結器:把
.o
的二進位制檔案
連結成一個可執行檔案
四個階段的編譯命令:
* 預處理:gcc -E hello.c -o hello.i
* 編譯:gcc -S hello.i -o hello.s
* 彙編:gcc -c hello.s -o hello.o
* 連結:gcc hello.o -o hello
上面的四個過程也可以用一個命令
執行,直接生成可執行
的檔案:
```python
gcc hello.c -o hello
或
gcc hello.c # 沒有指定輸出問價名,預設是生成一個a.out可執行檔案。 ``` 注意:
1、記憶引數可以用ESc
,-o
引數是指定輸出檔案的名字
2、在windows下,如果gcc hello.c
,預設生成的可執行檔案為a.exe
;如果gcc hello.c -o myapp
,會直接生成可執行檔案myapp.exe
,自動新增字尾。
3、在第二階段把預處理
的.i檔案
編譯成.s
的彙編檔案
最浪費時間
。
4、即使是直接生成可執行檔案,但是也是經過了預處理
、編譯
、彙編
、連結
這些過程,只是沒有生成中間的這些檔案。
四個階段的具體功能:
* 預處理:1)把.c
檔案中的標頭檔案展開
新增到.i
預處理檔案的開頭;2)然後把.c
檔案程式碼新增到.i
的標頭檔案內容之後;3)把巨集定義
的量值替換為具體的值,去掉原始碼中的註釋
。
-
編譯:把c檔案
翻譯
成彙編檔案
,就是兩種程式語法的轉化。 -
彙編:把
彙編檔案
程式設計二進位制
檔案,此時的檔案已經看不出具體的內容。 -
連結:將函式庫中相應的程式碼組合到目標檔案中。
1.2 gcc的常用引數
下面具體例項:
一、執行檔案和標頭檔案同級目錄
1、建立一個sum.c
檔案,內容如下:
```python
include
// 雙引號匯入的標頭檔案是自己寫的
include "head.h"
define DEBUG
// main是入口函式 int main(void) { int a = NUM1; int aa; int b = NUM2; int sum = a + b; // 這是一個加法運算
ifdef DEBUG
printf("The sum value is : %d + %d = %d\n", a, b, sum);
endif
return 0;
} ```
2、在sum.c的同級建立head.h
標頭檔案,內容如下:
```python
ifndef __HEAD_H_
define __HEAD_H_
define NUM1 10
define NUM2 20
endif
```
兩個檔案的層級結構,同級目錄:
python
├── head.h
├── sum.c
3、預處理:gcc -E sum.c -o sum.i
執行完之後用vi sum.i
檢視預處理之後
的sum.i
內容,如下:
從檔案中可以看到,檔案內容很長,之前的匯入的標頭檔案
,被替換為具體的標頭檔案程式碼內容
,程式碼中的巨集定義量
被替換為具體的值,程式碼中的註釋
被去掉
。(相當於做菜食材的準備階段)
4、編譯:gcc -S sum.i -o sum.s
編譯就是把預處理的.i檔案
編譯成.s的組合語言
,編譯之後的sum.s
內容,如下:
從檔案中可以看出,這個檔案顯示的已經不是C語言
編寫的程式碼,已經被轉換為組合語言的程式碼
,如果你對微控制器
瞭解,你可能也對組合語言的語法
有所瞭解。(編譯:就是把C語言翻譯成組合語言
)
5、彙編:gcc -c sum.s -o sum.o
彙編就是把彙編檔案
變成二進位制檔案
,彙編之後的sum.o
內容,如下:
從檔案中可以看出,彙編成二進位制檔案
之後,裡面的內容已經看不出來了。
6、連結:gcc sum.o -o sum
使用gcc連結器
把二進位制檔案
連結成一個可執行檔案
,將函式庫中相應的程式碼組合到目標檔案中。通過./sum
即可執行該可執行檔案,執行結果如下:
如果你開啟可執行檔案sum
,顯示的內容和sum.o
差不多。
二、執行檔案和標頭檔案同級目錄
目錄層級結構:
python
├── include
│ └── head.h
├── sum.c
如果直接編譯(gcc sum.c -o sum),會提示找不到標頭檔案,如下:
找不到標頭檔案有兩種解決方法:
* 直接在程式編寫的時候指定標頭檔案的位置
* 在編譯的時候用-I引數
,指定標頭檔案所在的資料夾
位置
gcc sum.c -I ./include -o sum
三、gcc的其他引數使用
1、引數-D:指定一個巨集定義
上面的程式中有printf()
列印程式除錯的log資訊
,但是程式釋出的時候,我們是不需要這些log資訊的,當然我們可以通過加除錯的#define DEBUG
巨集的宣告,但是,程式中需要除錯輸出的log資訊比較多的時候,這種方法顯然不合適。
現在我們把DEBUG
的巨集定義註釋掉
```python
include
// 雙引號匯入的標頭檔案是自己寫的
include "head.h"
//#define DEBUG
// main是入口函式 int main(void) { int a = NUM1; int aa; int b = NUM2; int sum = a + b; // 這是一個加法運算
// 程式有 DEBUG巨集定義,程式才會執行prinf()
ifdef DEBUG
printf("The sum value is : %d + %d = %d\n", a, b, sum);
endif
return 0;
} ```
然後再執行: ```python
gcc sum.c -o sum ./sum
`` 結果: 並不會輸出print列印的資訊了,如果再次打印出資訊呢,此時可以通過引數
-D,在執行命令的時候給程式
指定一個巨集`,如下:
```python
gcc sum.c -o sum -D DEBUG ./sum
`` 此時就可以打印出
printf()`資訊了。
總結:
-D
引數的作用:不在程式中定義巨集,在程式編譯的時候定義。不指定,在程式預處理的時候,printf()就會被刪掉了。
2、-O引數:程式預處理的時候對程式碼優化
在程式預處理的時候對程式碼進行優化,把冗餘的程式碼去掉,有三個優化等級: * -O1:優化等級低 * -O2:優化等級中 * -O3:優化等級高
舉個例子: ```python int a = 10 int b = a int c = b int d = c
優化完之後就是
int d = 10 // 就是對d的一個賦值操作 ```
3、-Wall引數:輸出程式中的警告資訊
例如我們在程式中定義一個變數int aa;
,但是沒有使用,此時就會輸出警告資訊。
4、-g引數:在程式中新增一些除錯資訊
gcc sum.c -o sum -g
- 加
-g
引數之後,輸出的可執行檔案會比不加的大(因為包含除錯資訊) - 程式釋出是不需要加
-g
引數 - 除錯需要加
-g
引數,否則沒有除錯資訊不可以除錯。(gdb除錯的時候必須加此引數
)
總結:
引數:
-E
、-S
,不是很重要,-c
比較重要,後面我們在製作靜態庫和動態庫的時候需要用到生成的.o二進位制值檔案
。
2 gcc 靜態庫的製作
比如你和別人做專案合作,你不可能直接把原始碼
給別人,那樣別人就可以自己開發,因為原始碼就是你的核心技術。你不應該賣給他原始碼
,而是應該是程式
,這樣你就可以根據他有什麼需求進行改或新增什麼功能模組等,就可以改一次就可以收費一次,這樣就可以有一個長期合作。
那應該給到客戶的是什麼呢? * 生成的庫 * 標頭檔案
這樣把生成的庫
和標頭檔案
給客戶也能夠使用,只是他不知道里面具體怎麼實現的。這樣二者才能維持一個長期的合作
。
標頭檔案對應的
.c檔案
都被打包到了靜態庫
和動態庫
裡面了。
2.1 靜態庫的製作流程
一、靜態庫的製作
1、命名規則 * 1)lib + 庫的名字 + .a * 2)例如:libmytest.a
2、製作步驟:
* 1)生成對應的.o二進位制檔案
.c --> .o
eg:gcc sum.c -c sum.o
* 2)將生成的.o檔案打包
,使用ar rcs + 靜態庫的名字(libMytest.a) + 生成的所有的.o
* 3)釋出和使用靜態庫:
* 釋出靜態庫
* 標頭檔案
說明:
* 把.c
檔案,也就是原始碼
轉化成.o
的二進位制檔案
之後,客戶就不知道到你的核心技術
具體是怎麼實現的了。
* ar
是對.o的二進位制檔案進行打包
,rcs是打包引數
,把所有
的.o二進位制檔案
打包成一個.a檔案
,即:靜態庫
。因此:靜態庫是一個打包了二進位制檔案的集合
。
* 介面API
是在標頭檔案
中體現出來的。
例項:
目錄結構: ```python Calc ├── include │ └── head.h ├── lib ├── main.c └── src ├── add.c ├── div.c ├── mul.c └── sub.c
``
**說明:**
* include資料夾:存放標頭檔案,提供給使用者呼叫的
介面API* lib資料夾:存放庫檔案,即:生成的靜態庫、動態庫
* src資料夾:存放原始檔
* main.c程式:是使用者呼叫
head.h標頭檔案`裡面的介面,然後在呼叫靜態庫裡面我們實現的演算法(只不過已經不是原始碼,而是被編譯成二進位制檔案)
下面開始吧:
原始碼 src/add.c
實現的是加法運算:
```python
include "head.h"
int add(int a, int b) { int result = a + b; return result; } ```
標頭檔案 include/head.h
實現是對原始碼呼叫的介面API
:
```python
ifndef __HEAD_H_
define __HEAD_H_
int add(int a, int b); int sub(int a, int b); int mul(int a, int b); int div(int a, int b);
endif
```
main.c是對標頭檔案呼叫,然後呼叫靜態檔案,對演算法的使用,但是並不知道演算法的具體實現原始碼
```python
include
include "head.h"
int main(void) { int sum = add(2, 24); printf("sum = %d\n", sum); return 0; } ```
使用者在
main.c
中引入標頭檔案#include "head.h"
,即在./include/head.h
,就可以使用./include/head.h
中定義的介面int add(int a, int b);
,當main.c
程式執行到add(int a, int b);
介面時,就會到./src
資料夾下找靜態檔案(打包的二進位制檔案——即:加法演算法的具體實現)
下面是具體的製作流程:
```python shliang@shliang-vm:~/shliang/gcc_learn/Calc$ tree . ├── include │ └── head.h ├── lib ├── main.c └── src ├── add.c ├── div.c ├── mul.c └── sub.c
3 directories, 6 files shliang@shliang-vm:~/shliang/gcc_learn/Calc$ cd src shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ ls add.c div.c mul.c sub.c
1、原始碼生成二進位制檔案(.o檔案) shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ gcc *.c -c -I ../include shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ ls add.c add.o div.c div.o mul.c mul.o sub.c sub.o
2、對生成的二進位制檔案(.o檔案),打包成靜態檔案(.a檔案),並移動到lib目錄下 shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ ar rcs libMyCalc.a *.o shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ ls add.c add.o div.c div.o libMyCalc.a mul.c mul.o sub.c sub.o shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ mv libMyCalc.a ../lib shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ cd .. shliang@shliang-vm:~/shliang/gcc_learn/Calc$ ls
3、呼叫include目錄下的標頭檔案(即:封裝的API介面)
shliang@shliang-vm:~/shliang/gcc_learn/Calc$ gcc main.c lib/libMyCalc.a -I ./include -o sum
shliang@shliang-vm:~/shliang/gcc_learn/Calc$ ls
include lib main.c src sum
shliang@shliang-vm:~/shliang/gcc_learn/Calc$ ./sum
sum = 26
shliang@shliang-vm:~/shliang/gcc_learn/Calc$
``
主要:
* 製作好的靜態檔案要放到
lib目錄下* 呼叫標頭檔案中的介面API,然後用
gcc編譯的自己呼叫的
main.c檔案,需要加上
靜態檔案(.a檔案)`。
* 程式釋出的時候只需要給使用者的檔案:
* 1)include目錄下的標頭檔案(head.h):封裝的是具體演算法實現的介面API
* 2)lib目錄下的靜態檔案(.a檔案):是原始碼編譯的之後的二進位制檔案(.o檔案),然後被打包成靜態檔案(.a檔案)
用於另外一種呼叫靜態庫的方法為:
gcc main.c -Iinclude -L lib -l MyCalc -o myapp
引數說明:
* -I
引數:指定頭文所在的資料夾名,資料夾名可以和引數貼著寫在一起
* -L
引數:指定靜態庫的資料夾名
* -l
引數:指定靜態庫的名字,但名字要掐頭去尾
,eg:原靜態庫名字為libMyCalc.a
,在指定-l
引數值的時候為:-l MyCalc
* -o
引數:輸出編譯之後可執行檔案的名字
注意:
之所以用
-l
指定靜態庫的名字,是因為lib
目錄下可能有多個靜態庫檔案,但是我們只需要使用其中的某一個,此時可以用這種方法指定相應的靜態庫檔案。
二、靜態庫相關檔案檢視
1、nm命令
檢視靜態庫
可以使用
nm命令
檢視靜態庫檔案中具體打包了哪些二進位制檔案
即.o檔案
2、nm命令
檢視生成的可執行檔案
T
:代表的含義是把add
程式碼會被放到程式碼區
2.2 靜態庫的優缺點
1、通過靜態庫生成可執行檔案
- 靜態庫中封裝了多個
.o檔案
- main.c 中呼叫靜態庫中相應可執行檔案(二進位制檔案)中的函式
- 圖中只調用了add.o和sub.o中的函式,因此main.c在生成可執行檔案的時候只會把靜態檔案中的
add.o
和sub.o
兩個檔案打包到可執行檔案中,靜態檔案中的其他沒有用到的.o
檔案不會被打包進可執行檔案中。 - 在生成可執行檔案的時候也是以
.o可執行檔案
為單位
打包的,並不會把整個靜態檔案.a
都打包到可執行檔案中。
靜態庫的優點: * 1)釋出程式的時候,不需要提供對應的庫了,因為庫已經被打包到了可執行檔案中去了。 * 2)庫的載入速度比較快,因為庫已經被打包到可執行檔案中去了。
靜態庫的缺點:
* 1) 庫被打包到應用程式(最後生成的可執行檔案)中,如果庫很多的話就會導致應用程式
的體積很大。
* 2)庫發生了改變,需要重新編譯程式
,如果原始碼比較多,可能編譯一遍一天就過去了。
3 gcc 動態庫 / 共享庫 的製作
動態庫
也叫共享庫
,在windows中對用.dll檔案
3.1 動態庫 / 共享庫的製作流程
一、動態庫相關說明
1、命名規則: * 1)lib + 名字 + .so * 2)例如:libMyCalc.so
2、製作步驟: * 1)生成與位置無關的程式碼 (生成與位置無關的.o) * 2)將.o打包成共享庫(動態庫) * 3)釋出和使用共享庫:
注意:
* 靜態庫生成的.o檔案
是和位置有關的
* 用gcc
生成和位置無關的.o檔案
,需要使用引數-fPIC(常用) 或 -fpic
二、動態庫製作相關例項
在瞭解什麼叫生成和位置無關的.o檔案
,我們來先了解一下虛擬地址空間
。
linux上開啟一個
執行的程式
(程序
),作業系統就會為其分配一個(針對32位作業系統)0-4G的地址空間
(虛擬地址空間
),虛擬地址空間
不是在記憶體中
,而是來自硬碟
的儲存空間。
從下到上:
0-3G:是使用者區
* .text 程式碼段:存放的是程式碼
* .data :存放的是已初始化的變數
* .bss:存放的是未初始化的變數
* 堆空間:
* 共享庫:動態庫的空間,每次程式執行的時候把動態庫載入到這個空間
* 棧空間:我們定義的區域性變數
都是在棧空間
分配的記憶體
* 命令列引數
* 環境變數
在往上 3-4G
是核心區
-
靜態庫生成與
位置有關
的二進位制檔案(.o檔案)
虛擬地址空間是從
0開始
的,生成的二進位制檔案(.o檔案)
會被放到程式碼段
,即.text程式碼區
。生成的.o程式碼每次都被放到同一個位置
,是因為使用的是絕對地址
。 -
動態庫生成與
位置無關
的二進位制檔案(.o檔案)
動態庫 / 共享庫 在程式打包的時候並不會把
.o檔案
打包到可執行檔案
中,只是做了一個記錄
,當程式執行之後
才去把動態庫載入到程式中,也就是載入到上圖中的共享庫
空間,但是每次載入到共享庫
空間的位置可能不同
。 還是和上面靜態庫製作同樣的目錄結構:
動態庫製作例項
python
Calc
├── include
│ └── head.h
├── lib
├── main.c
└── src
├── add.c
├── div.c
├── mul.c
└── sub.c
```python shliang@shliang-vm:~/shliang/gcc_learn/Calc$ cd src/ shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ ls add.c div.c mul.c sub.c
1、把原始碼生成和位置無關的二進位制檔案 shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ gcc -fPIC -c *c -I ../include shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ ls add.c add.o div.c div.o mul.c mul.o sub.c sub.o
2、使用gcc把生成的二進位制檔案(.o檔案),打包成動態庫(.so檔案) shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ gcc -shared -o libMyCalc.so *o -Iinclude shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ ls add.c add.o div.c div.o libMyCalc.so mul.c mul.o sub.c sub.o
3、把生成的動態庫檔案移動到lib目錄下 shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ mv libMyCalc.so ../lib shliang@shliang-vm:~/shliang/gcc_learn/Calc/src$ cd .. shliang@shliang-vm:~/shliang/gcc_learn/Calc$ ls include lib main.c src shliang@shliang-vm:~/shliang/gcc_learn/Calc$ ```
引數說明:
* -PIC
:生成和位置無關的.o檔案
* -shared:共享,就是把.o
檔案,打包成動態庫 / 共享庫
上面就已經完成動態庫的製作,然後把下面的兩個檔案釋出
給使用者
即可呼叫
* include/head.h: 標頭檔案,定義介面API
* lib/libMyCalc.so:動態庫,封裝了編譯之後的原始碼二進位制檔案
使用者使用動態庫
使用者使用動態庫和靜態庫一樣有兩種方法:
- 使用者使用動態庫方法一:
gcc main.c lib/libMyCalc.so -o app -Iinclude
- 使用者使用動態庫方法二:
gcc main.c -Iinclude -L lib -l MyCalc -o myapp
3.2 動態庫查詢不到解決方法
我們可以看到,第二種方法,至執行可執行程式的時候,提示找不到動態庫
,這並不一定是動態庫檔案不存在,可能是由於連結不到
是不是真的連結
不到,我們可以通過一個命令ldd
:檢視可執行檔案
在執行
的時候,依賴
的所有共享庫/動態庫(.so檔案)
ldd命令
使用:
ldd 可執行檔名
python
shliang@shliang-vm:~/shliang/gcc_learn/Calc$ ldd myapp
linux-vdso.so.1 => (0x00007fff59d26000) # 後面的數字是庫的地址
# 提示我們自己的動態庫 / 共享庫 libMyCalc.so沒有找到
libMyCalc.so => not found
# libc.so.6 是linux下的標準C庫 (寫C程式都會呼叫標準C庫裡的一些函式)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1e27462000)
# 動態連結器,動態連結器的本質就是一個動態庫
/lib64/ld-linux-x86-64.so.2 (0x00007f1e2782c000)
shliang@shliang-vm:~/shliang/gcc_learn/Calc$
如上圖:可執行程式./a.out
在執行的時候,呼叫需要呼叫動態庫libmytest.so
,但是實際上這個呼叫是通過動態連結器
的來呼叫的。動態庫就是通過動態連結器--/lib64/ld-linux-x86-64.so.2
載入到我們的可執行程式(應用程式)中的。
那麼動態連結器是-- /lib64/ld-linux-x86-64.so.2
是通過什麼規則查詢可執行檔案在執行時,需要的動態檔案的呢?
其實就是通過
環境變數
在linux下檢視環境變數:
echo $PATH
當然PATH下並不是存放動態庫的路徑,這裡只是做一個演示,如何檢視環境變數。
一、動態庫查詢不到解決方法一(不推薦——不允許使用
)
把自己製作的動態庫放到根目錄
下的系統動態庫
中,即/lib目錄下
sudo cp ./lib/libMyCalc.so /lib
從上面的結果可以看到,把自己製作的動態庫拷貝到系統動態庫中之後,
動態連結器
根據環境變數就可以找到這個動態庫,然後正確載入到可執行程式中。
注意:
這種方法一般不會使用的,因為如果你的動態庫的名字和系統中某個動態庫的名字一樣,就可能會導致系統奔潰的!!!這裡只是做一個演示,證明動態連結器是根據環境變數去查詢要載入的動態庫。
二、動態庫查詢不到解決方法二(臨時測試設定
)
通過把動態庫新增到
動態庫環境變數中
,即:LD_LIBRARY_PATH
使用export
新增環境變數,把當前動態庫所在的位置(資料夾位置)新增到LD_LIBRARY_PATH
變數中,可執行程式在執行的時候會在預設的動態庫之前從LD_LIBARAY_PATH
變數中查詢有沒有所需動態庫。
```python
export
export LD_LIBARAY_PATH=./lib ```
注意:
但是,這種方法只是
臨時的
,當我們關閉終端,下次再執行程式又會提示找不到動態庫。因此,這鐘方法一般是再開發動態庫
的過程中,用於臨時的測試
。
三、動態庫查詢不到解決方法三(永久設定——不常用
)
在當前使用者
的家目錄
(home
)下的.bashrc
檔案中配置LD_LIBRARY_PAHT
環境變數。
```python cd ~ vi .bashrc
然後再最後一行新增一個環境變數,如果沒有就建立(Shift+G跳到最後一行)
然後把動態庫的絕對路徑賦值給該變數
export LD_LIBARAY_PATH=/home/shliang/shliang/gcc_learn/Calc/lib
儲存退出,用source啟用配置,如果不啟用需要重啟終端,因為終端每次重啟都會從.bashrc中載入一次配置
source .bashrc
```
上面新增完環境變數之後就可以找到動態庫了。
四、動態庫查詢不到解決方法四(永久設定
)
這種方法,相對與前三種複雜一些,一定要掌握,可能以後用作中用到的就是這種。做法如下:
1、需要找到動態聯結器
的配置檔案
:/etc/ld.so.conf
2、把我們自己製作的動態庫目錄的絕對路徑寫到配置檔案中
3、更新配置檔案:sudo ldconfig -v
- ld:dynamic library 動態庫的縮寫
- -v :是更細配置檔案的時候輸出更新資訊。
修改配置檔案的路徑位置:/etc/ld.so.conf
把
/home/shliang/shliang/gcc_learn/Calc/lib
新增到/etc/ld.so.conf
配置檔案中
之後就可以找到動態庫了,如下:
3.3 動態庫的優缺點
1、動態庫的優點 * 執行程式的體積小:程式在執行的時候採取載入動態庫,並沒有和可執行程式打包在一起 * 動態庫更新了,不需要重新編譯程式(不是絕對的,前提是函式的介面不變,內容便裡沒事)
2、動態庫的缺點 * 程式釋出的時候,需要把動態庫提供給使用者 * 動態庫沒有被打包到應用程式中,載入速度相對較慢
- windows上比較好用的截圖軟體 Gif錄製軟體 看圖軟體,建議收藏!
- python使用pyinstaller把程式進行打包
- 深度學習視覺化工具visdom使用
- linux後臺執行命令screen的使用
- NVIDIA Jetson Xavier NX上匯入tensorflow報錯:AttributeError: module ‘wrapt‘ has no att
- 在NVIDIA Jetson Xavier NX上把yolov4-deepsort的模型pb模型轉換為tensorrt模型
- 在NVIDIA Jetson Xavier NX上安裝llvm和numba,以及在Jetxon NX上跑通CenterTrack的目標跟蹤模型
- TensorRT7.0版本在Linux環境安裝,以及安裝python API介面,測試TensorRT中的測試用例
- Jetson nano刷好機之後需要做的準備工作
- 本地直播平臺的搭建—四種方式
- python opencv用電腦呼叫手機攝像頭或其他網路攝像頭
- Linux中gcc的編譯、靜態庫和動態庫的製作
- Linux開機自動啟動python指令碼程式,或 Jetson nano或Jetson Xavier NX開機自動啟動python指令碼程式
- lidar鐳射雷達介紹,以及使用鐳射雷達資料通過深度學習做目標檢測
- Camelot:從pdf中提取表格資料
- python中的h5py開源庫的使用
- python3建立定時任務