文章轉錄--Linux環境撰寫Shared Library

撰寫範例程式

1
bool isPalindrome(char* word);

{: file=”pal.h” }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "pal.h"
#include <string.h>

bool isPalindrome(char* word)
{
bool ret = true;

char *p = word;
int len = strlen(word);
char *q = &word[len-1];

for (int i = 0 ; i < len ; ++i, ++p, --q)
{
if (*p != *q)
{
ret = false;
}
}

return ret;
}

{: file=”pal.cpp” }

編譯shared library

在終端機輸入以下GCC指令,注意這裡我們有-c選項,這告訴GCC不要進行linking stage,如果沒加GCC就會報錯,因為一個應用程式一定會有main()函式,但是Library不需要main()函式。這行指令將會產生一個pal.o

1
g++ -fPIC -c -Wall pal.cpp

接下來我們要用pal.o檔和以下指令產生真正的library。ld是linker program,通常會被g++呼叫。-shared告訴ld製作一個shared object,以pal.o為輸入輸出名為libpal.so。在Linux通常shared libraries的副檔名都是.so。

1
ld -shared pal.o -o libpal.so

使用shared library

首先建立一個main.cpp來呼叫我們的library的isPalindrome函式。在程式中我們include函式庫的標頭檔pal.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "pal.h"
#include <iostream>

using namespace std;

int main()
{
while (1)
{
char buffer[64] = {0};
cin >> buffer;

if (isPalindrome(buffer))
{
cout << "Word is a palindrome" << endl;
}
else
{
cout << "Word is not a palindrome" << endl;
}
}

return 0;
}

{: file=”main.cpp” }

接下來我們可能直接用g++ -Wall main.cpp -lpal這行指令連接我們的shared library,c但是如果這麼做我們會得到下面錯誤訊息。這是因為ld在預設的搜尋路徑下找不到libpal.so

1
2
/usr/bin/ld: cannot find -lpal: No such file or directory
collect2: error: ld returned 1 exit status

其中一種解法是用g++告入ld函式庫的位置

1
g++ -Wall -L<libpal.so的路徑> -Wl,-rpath=<libpal.so的路徑> main.cpp -lpal

例如

1
g++ -Wall -L/home/faye -Wl,-rpath=/home/faye/ main.cpp -lpal

其中:

  • -Wall是用來檢查所有編譯警告的
  • L式shared library的路徑,讓ld知道要去那裡尋找
  • -Wl是一連串用逗號分隔的linker指令,在這裡有
    • -rpath表示library 的路徑會被嵌入到主程式的執行檔,因此loader在執行主程式的時候可以找到library

-L-rpath的區別是:

  • -L是給linker用的
  • -rpath是被嵌入到執行檔給loader看的

最後g++會幫我們產生a.out執行檔,執行方式和結果如下

1
2
3
4
5
$ ./a.out 
ada
Word is a palindrome
team
Word is not a palindrome

安裝自己開發的Shared Libraries

用剛剛的方式連接Shared Libraries的方法有個缺點,也就是你的編譯指令直接給其他人的話可能會出錯,因為Shared Libraries在每個人的電腦上的位置可能都不一樣。因此rpath-L選項的路徑也會不一樣。而我們的解決方法之一就是LD_LIBRARY_PATH

LD_LIBRARY_PATH

如果我們直接在終端機輸入指令echo $LD_LIBRARY_PATHLD_LIBRARY_PATH的值,他應該會是空的,除非你以前曾經設定過他。要是用LD_LIBRARY_PATH我們只需要以下指令

1
export LD_LIBRARY_PATH=<Shared Library所在資料夾>:$LD_LIBRARY_PATH

例如

1
export LD_LIBRARY_PATH=/home/faye:$LD_LIBRARY_PATH

這時在輸入一次echo $LD_LIBRARY_PATH應該就會輸出/home/faye:。而這時候我們編譯main.cpp的時候就算沒有-rpath選項編譯出來的執行檔也不會找不到libpal.so

1
g++ -Wall -L/home/faye/sotest main.cpp -lpal

你可以先嘗試看看在還沒設定LD_LIBRARY_PATH之前或是利用unset LD_LIBRARY_PATH指令清空LD_LIBRARY_PATH變數,所編譯出來的執行檔會出現什麼問題。
你應該會發現編譯的過程沒有任何錯誤訊息,但是一旦你執行編譯出來的執行檔a.out就會跳出錯誤訊息./a.out: error while loading shared libraries: libpal.so: cannot open shared object file: No such file or directory,這表示執行檔loader找不到libpal.so
{: .prompt-tip }

不過LD_LIBRARY_PATH其實只適合在開發階段拿來測試library用,因為它不需要root權限,但是函式庫發布給大家使用的時候,要求每個人都去設定LD_LIBRARY_PATH並不是個好方法。

ldconfig : 安裝Shared Libraries正統方法

首先我們先清除上一個教學的LD_LIBRARY_PATH設定,可以用unset LD_LIBRARY_PATH指令來清除。
接下來我們必須把我們的函式庫複製到/usr/lib資料夾。複製函式庫到/usr/lib必須擁有root權限,因此我們用sudo來幫助我們。

1
sudo mv <函式庫所在資料夾>/libpal.so /usr/lib

例如

1
sudo mv /home/faye/libpal.so /usr/lib

接下來更新系統中儲存可用libraries的cache。

1
sudo ldconfig

你可以用下面指令來確定cache已經被更新了而且系統可以找到你的函式庫

1
ldconfig -p | grep libpal

系統應該會回應你

1
libpal.so (libc6,x86-64) => /lib/libpal.so

接下來你就可以用下面指令編譯我們的執行檔了,而且這次我們不需要-rpath,也不需要-L選項!!因為現在我們的函式庫已經位於系統預設的函式庫搜尋路徑下了。

1
g++ -Wall main.cpp -lpal

參考:
https://www.fayewilliams.com/2015/07/07/creating-a-shared-library/
https://www.fayewilliams.com/2015/07/14/installing-and-accessing-shared-libraries/

相關文章:
Linux安裝prebuild函式庫以OpenCV為例

Ubuntu NTP 校時

timedatectl 時間管理工具

  • 顯示目前的設定狀態
    1
    2
    # 顯示目前狀態
    timedatectl
1
2
3
4
5
6
7
               Local time: 三 2023-04-26 11:00:22 CST
Universal time: 三 2023-04-26 03:00:22 UTC
RTC time: 三 2023-04-26 03:00:22
Time zone: Asia/Taipei (CST, +0800)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
  • 啟動網路校時
    輸入下面指令後,就會打開網路校時功能

    1
    2
    # 啟用 NTP 校時
    timedatectl set-ntp yes

    Ubuntu使用的是systemd-timesyncd,因此等一下要設定systemd-timesyncd

  • 檢查systemd-timesyncd服務狀態

    1
    2
    # 檢查 systemd-timesyncd 服務狀態
    systemctl status systemd-timesyncd
1
2
3
4
5
6
7
8
9
10
● systemd-timesyncd.service - Network Time Synchronization
Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2023-04-26 10:58:34 CST; 1min 19s ago
Docs: man:systemd-timesyncd.service(8)
Main PID: 221565 (systemd-timesyn)
Status: "Synchronized to time server 91.189.89.198:123 (ntp.ubuntu.com)."
Tasks: 2 (limit: 38317)
Memory: 1.2M
CGroup: /system.slice/systemd-timesyncd.service
└─221565 /lib/systemd/systemd-timesyncd
  • 設定校時伺服器
    要設定校時伺服器可以用root權限編輯以下檔案/etc/systemd/timesyncd.conf
1
2
3
4
5
6
[Time]
# NTP 伺服器(以空白分隔多個伺服器)
NTP=tw.pool.ntp.org jp.pool.ntp.org

# 備用 NTP 伺服器(以空白分隔多個伺服器)
FallbackNTP=sg.pool.ntp.org ntp.ubuntu.com
  • 重新啟動systemd-timesyncd服務
    重啟服務讓更改生效

    1
    2
    # 重新啟動 systemd-timesyncd 服務
    systemctl restart systemd-timesyncd
  • 檢查一下是不是有跟NTP校時了
    用指令systemctl status systemd-timesyncd看一下目前服務狀態,如果有更新成功會顯示出來

錯誤排除

  • 出現Server has too large root distance. Disconnecting.訊息
    表示機器跟ntp server之間回應的時間太久,因此可以去修改/etc/systemd/timesyncd.conf並加入RootDistanceMaxSec=,通常30秒已經很夠用了
    1
    2
    3
    4
    5
    6
    7
    # See timesyncd.conf(5) for details.
    [Time]
    NTP=10.10.1.30
    #FallbackNTP=
    RootDistanceMaxSec=30
    #PollIntervalMinSec=32
    #PollIntervalMaxSec=2048

timedatectl的NTP service為active的時候查看目前使用的是哪一個NTP服務

  • systemd-timesyncd
    1
    systemctl status systemd-timesyncd.service

ntpd 或 chronyd

1
ps -e | grep ntp
1
ps -e | grep chrony

chronyc說明書

https://chrony-project.org/doc/4.6.1/chronyc.html

詳細說明如下
https://unix.stackexchange.com/a/655489

參考:
https://www.cnblogs.com/pipci/p/12833228.html
https://officeguide.cc/ubuntu-linux-timedatectl-time-synchronization-tutorial/
https://www.digitalocean.com/community/tutorials/how-to-set-up-time-synchronization-on-ubuntu-20-04
https://www.tenable.com/audits/items/CIS_Ubuntu_18.04_LTS_Server_v2.1.0_L1.audit:26286d27c59292cfdb9c7b04593edbed
https://serverfault.com/questions/1024770/ubuntu-20-04-time-sync-problems-and-possibly-incorrect-status-information

X11 Server顯示遠端GUI

X Window 的Client和Server角色

一般來說如果遠端連線到一台電腦,通常遠端那台電腦是Server,但是對於X Window來說,顯示畫面的才是Server,因此如果你要遠端觀看遠端的電腦畫面,你手上的電腦是X Server,遠端的電腦是X Client

X Server的Port

當你啟動X Server的時候,他會開始監聽6000port,更詳細的來說X Server會給定display number,而每個display number所監聽的port為6000+display number

X11 forwdarding

如果你的電腦在防火牆後,這時候6000port不一定有打開,而X11 forwdarding不只幫打開一條通道讓遠端電腦可以連到你的6000port,同時還幫你處理好X serve連線的事情。

step1. Ubuntu 安裝x11套件

1
sudo apt install x11-apps

step2. 設定遠端電腦開啟x11

修改遠端電腦的/etc/ssh/sshd_config檔案,確認檔案內X11Forwarding yes
enable x11{: w=”350” h=”200” }

step3. 檢查x11設定

用以下指令確認設定正確

1
sudo cat /etc/ssh/sshd_config |grep -i X11Forwarding

在Windows下安裝VcXsrv Windows X Server

在windows下必須安裝x server,可以到以下連結下載
https://sourceforge.net/projects/vcxsrv/

問題排除

  1. Warning: untrusted X11 forwarding setup failed: xauth key data not generated

https://serverfault.com/a/355986

測試

Docker container 透過ssh x11 forwarding傳送影像到遠端電腦

以DeepStream container 為例

1
docker run --gpus all -it --rm --net=host --privileged -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY --volume="$HOME/.Xauthority:/root/.Xauthority:rw" -w /opt/nvidia/deepstream/deepstream-6.1 nvcr.io/nvidia/deepstream:6.1.1-devel 

參考:
X window解說
https://www.cs.odu.edu/~zeil/cs252/latest/Public/xtrouble/index.html

What You Need to Know About X11 Forwarding
https://goteleport.com/blog/x11-forwarding/

How to enable X11 forwarding from Red Hat Enterprise Linux (RHEL), Amazon Linux, SUSE Linux, Ubuntu server to support GUI-based installations from Amazon EC2
https://aws.amazon.com/tw/blogs/compute/how-to-enable-x11-forwarding-from-red-hat-enterprise-linux-rhel-amazon-linux-suse-linux-ubuntu-server-to-support-gui-based-installations-from-amazon-ec2/

Built-in SSH X11 forwarding in PowerShell or Windows Command Prompt
https://x410.dev/cookbook/built-in-ssh-x11-forwarding-in-powershell-or-windows-command-prompt/

https://dreamanddead.github.io/post/ssh-x11-forward/

https://juejin.cn/post/7009593663894323231

https://stackoverflow.com/questions/65468655/vs-code-remote-x11-cant-get-display-while-connecting-to-remote-server

https://zhuanlan.zhihu.com/p/461378596

X11 Forwarding on Windows with Cygwin
https://www.csusb.edu/sites/default/files/cse_x11_forwarding_on_windows_with_cygwin.pdf

Cygwin/X
https://x.cygwin.com/

ssh option
https://www.microfocus.com/documentation/rsit-server-client-unix/8-4-0/unix-guide/ssh_options_ap.html

What exactly is X/Xorg/X11?
https://www.reddit.com/r/linuxquestions/comments/3uh9n9/what_exactly_is_xxorgx11/

SSH X11 Forwarding Of Gnome-Boxes Under Wayland & Mixed Wayland & X11 Environments
https://www.dbts-analytics.com/notesxfwdgb.html

  • X11 forwarding docker container裡面的影像
    docker run 指令要多加 –volume=”$HOME/.Xauthority:/root/.Xauthority:rw”

X11 forwarding of a GUI app running in docker
https://stackoverflow.com/a/51209546

Run X application in a Docker container reliably on a server connected via SSH without “–net host”
https://stackoverflow.com/questions/48235040/run-x-application-in-a-docker-container-reliably-on-a-server-connected-via-ssh-w

git 筆記

  • git alias

    1
    git config --global alias.slog "log --graph --all --topo-order --pretty='format:%h %ai %s%d (%an)'"
  • 移動git tag 位置

    1
    2
    git tag --force <tag名稱>
    git push origin <tag名稱> --force #強迫推送到遠端

Linux crontab 自動化例行性工作

查看例行性工作

1
2
# 查看自己的 crontab
crontab -l

建立例行性工作

1
2
# 編輯 crontab 內容
crontab -e

如果要用高權限執行例行性工作可以加上sudo

1
sudo crontab -e

工作設定的格式

每個例行工作會有時間搭配要下達的指令,*代表所對應的時間只要一改變就執行,例如下面範例每分鐘都會執行一次python3 test.py指令(因為全部是*號)

1
2
*        *           *        *        *            python3 test.py
MIN(分鐘) HOUR(小時) DOM(日) MON(月) DOW(星期幾) 指令(CMD)

指令

1
2
sudo crontab -e
01 14 * * * /home/joe/myscript >> /home/log/myscript.log 2>&1

參考:
https://ithelp.ithome.com.tw/articles/10293218
https://blog.gtwang.org/linux/linux-crontab-cron-job-tutorial-and-examples/
https://askubuntu.com/a/121560

CMake教學系列一使用CMake編譯專案

安裝最新版的CMake,越新越好,因為新版的CMake提供更多的工具幫你尋找函式庫或套件,尤其如果你需要用到CUDA,新版的CMake可以省去你許多的麻煩
{: .prompt-tip }

安裝CMake

Ubuntu可以跟著這篇官方教學安裝最新的CMake

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sudo apt-get update
sudo apt-get install ca-certificates gpg wget

test -f /usr/share/doc/kitware-archive-keyring/copyright ||
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null

# Ubuntu 20.04
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null
sudo apt-get update

test -f /usr/share/doc/kitware-archive-keyring/copyright ||
sudo rm /usr/share/keyrings/kitware-archive-keyring.gpg

sudo apt-get install kitware-archive-keyring

sudo apt-get install cmake

嘗試用CMake編譯程式

讓我們嘗試用CMake編譯一個開源專案

1
2
git clone https://github.com/CLIUtils/CLI11.git # 下載專案
cd CLI11 #進入資料夾

然後我們就可以開始編譯,過程中你會發現CMake幫你建立了一個build資料夾,第一行指令-S表示source directoryB會幫你建立一個build資料夾如果他不存在的話,CMake產生的東西會全部放在build資料夾裡面,你隨時可以刪除他而且他也不需要被版本控制。第二行的-j讓你可以指定要用多少核心來加速編譯。第三行-t代表執行測試程式,如果你沒有測試程式也可以不需要這行指令。

1
2
3
cmake -S . -B build
cmake --build build -j 8
cmake --build build -t test

你很容易在網路上看到CMake傳統的編譯方式,不過在CMake 3.15之後你可以用前面提到的新的方法,他可以幫你處理掉一些小麻煩。

1
2
3
4
5
mkdir build
cd build
cmake ..
make
make test

{: .prompt-tip }

查看編譯選項

CLI11資料夾中,你可以用cmake -S . -L列出所有你可以設定的選項,有些是CMake內建的選項,有些是這著專案中設定讓你可以選的選項。cmake -S . -LH不但會列出所有選項,還把說明文字也印出來。在許多開源專案用CMake編譯的時候經常會需要知道他提供哪些選項,這個指令會非常有幫助。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ cmake -S . -B build -LH
-- CMake 3.22.1
-- Could NOT find Doxygen (missing: DOXYGEN_EXECUTABLE)
-- Doxygen not found, building docs has been disabled
-- Configuring done
-- Generating done
-- Build files have been written to: /home/steven/CLI11/build
-- Cache values
// Build the testing tree.
BUILD_TESTING:BOOL=OFF

// Path to a file.
Boost_INCLUDE_DIR:PATH=Boost_INCLUDE_DIR-NOTFOUND

// Turn on boost test (currently may fail with Boost 1.70)
CLI11_BOOST:BOOL=ON

// Build CLI11 examples
CLI11_BUILD_EXAMPLES:BOOL=ON

// Build CLI11 json example
CLI11_BUILD_EXAMPLES_JSON:BOOL=OFF

// Build the tests with NVCC to check for warnings there - requires CMake 3.9+
CLI11_CUDA_TESTS:BOOL=OFF

// Install the CLI11 folder to include during install process
CLI11_INSTALL:BOOL=OFF
...以下省略

如果你想要設定選項值,你可以在CMake指令中用-D加上選項名稱來設定,例如

1
cmake -DCLI11_INSTALL=ON -S . -B build

這時候被設定的值會被保存在build資料夾裡面的CMakeCache.txt。你可以打開這份文件並且找到這個選項被設定的值。你可以看到CLI11_INSTALL:BOOL=ON

1
2
3
4
5
6
7
8
9
10
11
...以上省略
//Build the tests with NVCC to check for warnings there - requires
// CMake 3.9+
CLI11_CUDA_TESTS:BOOL=OFF

//Install the CLI11 folder to include during install process
CLI11_INSTALL:BOOL=ON

//Value Computed by CMake
CLI11_IS_TOP_LEVEL:STATIC=ON
...以下省略

{: file=’CMakeCache.txt’}

如果在設定一次就可以發現他的值被改成OFF

1
cmake -DCLI11_INSTALL=OFF -S . -B build
1
2
3
4
5
6
7
8
9
10
11
...以上省略
//Build the tests with NVCC to check for warnings there - requires
// CMake 3.9+
CLI11_CUDA_TESTS:BOOL=OFF

//Install the CLI11 folder to include during install process
CLI11_INSTALL:BOOL=OFF

//Value Computed by CMake
CLI11_IS_TOP_LEVEL:STATIC=ON
...以下省略

{: file=’CMakeCache.txt’}
另外還有一些常見的CMake標準選項你可以設定

CMake除錯技巧

這節特別重要,如果要自己撰寫CMakeLists.txt話十分有用。--trace-source選項讓你指定你有興趣的檔案,並且依照他執行的順序依序印出他所執行的行數

1
cmake build --trace-source="CMakeLists.txt"

動手寫第一個CMakeLists.txt

我們將製作一個簡單的C語言程式,並且寫一個CMakeLists.txt

1
2
3
mkdir cmakeQuickStart
cd cmakeQuickStart
code .

cmakeQuickStart資料夾內建立一個CMakeLists.txt和一個simple.cpp

  1. cmake_minimum_required指定使用這份CMakeLists.txt最小所需的CMake版本。
  2. project指定專案名稱,而專案使用的語言預設為C++和C。如果要指定專案語言可以輸入LANGUAGES參數。
  3. 最後你要輸出執行檔或是library。add_executable指令輸出執行檔,add_library指令輸出library,輸出的執行檔或是library檔名在跟第一個參數一樣。在這裡特別注意,add_executable``add_library第一個參數為兩個東西命名,首先他命名了輸出檔案的檔案名稱,其次是他命名了一個CMake的targettarget在後面會很常用到。
1
2
3
4
5
6
7
/* simple.c or simple.cpp */
#include <stdio.h>

int main() {
printf("Hello, World!\n");
return 0;
}

{: file=’simple.cpp’}

1
2
3
4
5
cmake_minimum_required(VERSION 3.15)

project(MyProject)

add_executable(myexample simple.cpp)

{: file=’CMakeLists.txt’}

你也可以把CMakeLists.txt改成下面這樣,他指定了CMake的版本範圍,並且為專案增加說明和版本號

1
2
3
4
5
6
7
8
9
10
11
12
cmake_minimum_required(VERSION 3.15...3.21)

project(MyProject
VERSION
1.0
DESCRIPTION
"Very nice project"
LANGUAGES
CXX
)

add_executable(myexample simple.cpp)

{: file=’CMakeLists.txt’}

接下來你就可以編譯你的程式了,編譯後你會看到build資料夾出現一個myexample檔,跟你在add_executable指定的名稱一樣

1
2
cmake -S . -B build
cmake --build build

More Modern CMake
https://hsf-training.github.io/hsf-training-cmake-webpage/

An Introduction to Modern CMake
https://cliutils.gitlab.io/modern-cmake/

ssh連線設定

非對稱式加密

  • 非對稱式加密有兩把key,一把只能加密,一把只能解密
  • 非對稱式加密public key是公開給外界,作為解密專用key,只能解密用對應的private key加密的內容
  • 非對稱式加密private key必須妥善保存,作為加密專用key,只被對應的public key解密

public key像帳號,private key像密碼

把自己的的public key提供給目標連線電腦,就像在那台帳號註冊帳號一樣

ssh會把public key存在~/.ssh/authorized_keys這個檔案裡面

  1. 利用ssh-copy-id複製public key到ssh server主機
  • linux
    1
    ssh-copy-id 192.168.122.7  # 指令為ssh-copy-id 遠端主機的ip
  • windows
    在powershell中沒有ssh-copy-id這個指令,不過我們可以用下面指令達成相同目標
    1
    type $env:USERPROFILE\.ssh\id_rsa.pub | ssh {IP-ADDRESS-OR-FQDN} "cat >> .ssh/authorized_keys"

參考:
https://kb.iu.edu/d/aews
https://www.chrisjhart.com/Windows-10-ssh-copy-id/

更改主機名稱後RabbitMQ無法啟動

作業系統: Windows10

更改主機名稱後,會發現rabbitmq無法啟動,這時候要重新安裝Service。
注意:需要備份的資料先備份起來

  1. 利用rabbitmq提供的bat(RabbitMQ Service - remove.bat),並且以系統管理員執行
  2. 利用rabbitmq提供的bat(RabbitMQ Service - (re)install.bat),並且以系統管理員執行重新安裝service
  3. 利用rabbitmq提供的bat(RabbitMQ Service - start.bat),並且以系統管理員執行重新安裝service啟動服務
  4. 成功後會看到log資料夾出現新的log,rabbit@(新的主機名稱).log,代表成功了。

參考: https://dennymichael.net/2014/06/16/rabbitmq-change-the-hostname/

Windows下讓cmake找到OpenCV和Eigen

OpenCV

從(cmake 3.12)[https://cmake.org/cmake/help/v3.12/policy/CMP0074.html]之後,可以利用環境變數來告訴cmake套件的位置,在Windows下很方便,因為windows不像linux會把函式庫集中放在一起。設定方法就是利用設定環境變數

1
<PackageName>_ROOT

其中<PackageName>就是你的套件名稱,例如在這裡我們要設的環境變數就是OpenCV_ROOT,注意<PackageName>必須要和你寫在CMakeLists.txt裡面find_package(<PackageName>)大小寫都要一致

設定完後會看到cmake輸出找到的路徑

1
2
3
Environment variable OpenCV_ROOT is set to:

D:\lib\build_opencv

另外由於相容性的關係,cmake預設不會使用環境變數的OpenCV_ROOT,我們必須在CMakeLists.txt中設定打開這個功能

1
cmake_policy(SET CMP0074 NEW)

成功設定後可以看到cmake會有以下輸出

1
2
3
-- Found OpenCV: D:/lib/build_opencv (found version "4.6.0")
-- OpenCV library status:
-- version: 4.6.0

詳細寫法可以參考這個範例
https://gist.github.com/jenhaoyang/924698b31f7e3baede14286c67d6059a

Eigen3.4.0

使用find_package(Eigen3 REQUIRED)後需要get_target_property(EIGEN3_INCLUDE_DIR Eigen3::Eigen INTERFACE_INCLUDE_DIRECTORIES)
,根據這個issue的寫法https://gitlab.com/libeigen/eigen/-/issues/2486


參考:
https://seanzhengw.github.io/blog/cmake/2018/04/23/cmake-find-package.html
https://cmake.org/cmake/help/v3.12/policy/CMP0074.html
https://stackoverflow.com/questions/21314893/what-is-the-default-search-path-for-find-package-in-windows-using-cmake