在專案中為了更容易擴充、維護專案,都會將原始碼拆分成多個檔案,並使用資料夾分門別類放好,例如存放標頭檔的include資料夾、原始碼的src資料夾,還有專門存放建構過程中產生中間文件和目標文件的build資料夾。
// 今天的目錄架構
.
├── build
├── include
│ └── mysqrt.h
└── src
├── main.cpp
└── mysqrt.cpp
然後拆分出來每個獨立的 .h 和 .cpp 檔都應該要可以各自被預處理、編譯、彙編成 .o 檔而不報錯,並且在最後將各個.o檔鍊結到一個可執行文件中。
接下來會先使用g++來展示編譯多檔案的步驟,了解完原理後才會使用CMake。
$ git clone https://github.com/m11112089/2023_iT_CMake.git
$ cd ~/2023_iT_CMake/Day6/g++
1. 將原始碼編譯成 .o檔
因為我們將.h檔放入了include資料夾中,與.cpp並不在同一資料夾中,因此需要-I 這個參數新增include所在路徑,讓g++能夠搜尋到標頭檔。
語法: -I <.h檔所在路徑> -c <.cpp所在相對路徑/ .cpp名稱>
$ cd build
$ g++ -I ../include -c ../src/main.cpp
$ g++ -I ../include -c ../src/mysqrt.cpp
可以看到在 build 資料夾中生成了兩個.o檔
kai@esoc:~/2023_iT_CMake/Day6/g++/build$ tree
.
├── main.o
└── mysqrt.o
2. 鍊結兩個 .o 檔,並生成最終的執行檔main
語法:g++ -o <執行檔名稱> <1.o> <2.o> <3...>
$ g++ -o main main.o mysqrt.o
可以看到形成的執行檔 main
kai@esoc:~/2023_iT_CMake/Day6/g++/build$ tree
.
├── main
├── main.o
└── mysqrt.o
3. 執行
$ ./main
// output
kai@esoc:~/2023_iT_CMake/Day6/g++/build$ g++ -I ../include -c ../src/main.cpp
kai@esoc:~/Desktop/2023_iT_CMake/Day6/g++/build$ g++ -I ../include -c ../src/mysqrt.cpp
kai@esoc:~/Desktop/2023_iT_CMake/Day6/g++/build$ g++ -o main main.o mysqrt.o
kai@esoc:~/Desktop/2023_iT_CMake/Day6/g++/build$ ./main 10
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228
定義:設定編譯器搜尋.h的路徑
include_directories( dir1 [dir2 ...])
---
dir : CMake搜尋.h的路徑
定義:設定變數與變數內容
set(<variable> <value>)
---
variable : 變數名稱
value : 變數內容
$ cd ~/2023_iT_CMake/Day6/cmake
include_directories(${PROJECT_SOURCE_DIR}/include)
# 將include資料夾加入include路徑
set(SRC_DIR ${PROJECT_SOURCE_DIR}/src)
# 將原始碼所在路徑設定成變數 SRC_DIR
add_executable(main ${SRC_DIR}/main.cpp ${SRC_DIR}/mysqrt.cpp)
# 將main.cpp與mysqrt.cpp編譯並鍊結成執行檔main
先進入build資料夾,避免編譯過程中產生的中間文件破壞專案目錄結構,比較整齊。
$ cd build
$ cmake ..
cmake 後面那個點點的意思是讓CMake在目前所在目錄(~/2023_iT_CMake/Day6/cmake/build)的上一層目錄尋找CMakeLists.txt進行構建。
$ make
這個時候可以到 CMakeFiles/main.dir/src 中查看編譯出來的 mysqrt.cpp.o 與main.cpp.o
$ cd CMakeFiles/main.dir/src
kai@esoc:~/2023_iT_CMake/Day6/cmake/build/CMakeFiles/main.dir/src$ tree
.
├── main.cpp.o
├── main.cpp.o.d
├── mysqrt.cpp.o
└── mysqrt.cpp.o.d
在這裡也可以向上一段落一樣,直接用g++將兩個.o檔鍊結成執行檔 main。
$ g++ -o main main.cpp.o mysqrt.cpp.o
$ ./main 10
kai@esoc:~/2023_iT_CMake/Day6/cmake/build/CMakeFiles/main.dir/src$ tree
.
├── main
├── main.cpp.o
├── main.cpp.o.d
├── mysqrt.cpp.o
└── mysqrt.cpp.o.d
$ ./main
kai@esoc:~/2023_iT_CMake/Day6/cmake/build$ cmake ..
-- The CXX compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kai/2023_iT_CMake/Day6/cmake/build
kai@esoc:~/2023_iT_CMake/Day6/cmake/build$ make
[ 33%] Building CXX object CMakeFiles/main.dir/src/main.cpp.o
[ 66%] Building CXX object CMakeFiles/main.dir/src/mysqrt.cpp.o
[100%] Linking CXX executable main
[100%] Built target main
kai@esoc:~/2023_iT_CMake/Day6/cmake/build$ ./main 10
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228