imx6ull/linux應用編程學習(13) CMAKE

什么是cmake?

????????cmake 工具通過解析 CMakeLists.txt 自動幫我們生成 Makefile,可以實現跨平臺的編譯。cmake 就是用來產生 Makefile 的工具,解析 CMakeLists.txt 自動生成 Makefile:

cmake 的使用方法
?

cmake 就是一個工具命令,在 Ubuntu 系統下通過 apt-get 命令可以在線安裝,如下所示
?

sudo apt-get install cmake

利用cmake --version命令檢查:

使用實例1.單個源文件:

一個經典的 C 程序“Hello World”,如何用 cmake 來進行構建呢?

首先利用touch命令創建倆文件(mkdir是創建文件目錄),后利用vi工具將代碼寫入。

touch main.c
touch CMakeLists.txt
//main.c
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}

????????現在我們需要新建一個CMakeLists.txt文件, CMakeLists.txt文件會被cmake工具解析,就好比是Makefile文件會被 make 工具解析一樣; CMakeLists.txt 創建完成之后,在文件中寫入如下內容:

project(HELLO)
add_executable(hello ./main.c)

寫入完成之后,保存退出,當前工程目錄結構如下所示:
?

├── CMakeLists.txt
└── main.c

在我們的工程目錄下有兩個文件,源文件 main.c 和 CMakeLists.txt,接著我們在工程目錄下直接執行cmake 命令,如下所示:
?

cmake ./

可見

成功生成了文件。有了 Makefile 之后,接著我們使用 make 工具編譯我們的工程

make

利用file hello 可見:

其中有arm,需要在arm開發板上運行,利用scp指令將文件傳至開發板

開發板執行./hello,可見:

是不是有疑問,為什么是在開發板上運行而不是Ubuntu上?

這是因為電腦安裝了交叉編譯鏈,所以生成了arm環境下的編譯文件。需要在ubuntu上運行也很簡單;

我們先來看看CMakeLists.txt文件里的語句的意思:

project(HELLO)

????????這條指令定義了一個名為 HELLO 的項目。它會告訴 CMake 這是一個新項目,并且所有接下來的指令都將在這個項目的上下文中執行。多個參數使用空格分隔而不是逗號“,”

add_executable(hello ./main.c)

????????這條指令用于定義一個可執行目標文件。它告訴 CMake 要創建一個名為 hello 的可執行文件,并且這個可執行文件是由 main.c 源文件編譯而來的。第一個參數表示生成的可執行文件對應的文件名,第二個參數表示對應的源文件; 所以 add_executable(hello ./main.c)表示需要生成一個名為 hello 的可執行文件,所需源文件為當前目錄下的 main.c

因為我們之前設置的環境默認為交叉編譯鏈的 ,所以只要在里面聲明就行

將之前編譯生成的文件刪除。

后修改?CMakeLists.txt文件,改為

set(CMAKE_C_COMPILER "gcc")
set(CMAKE_CXX_COMPILER "g++")project(HELLO)
add_executable(hello ./main.c)

第一句指定c語言的利用gcc,c++的利用g++編譯器。

后make,執行file hello可見:

環境為x86-64.成功

在ubuntu執行

./hello

但是各位是否有沒有發現,當我們改編譯器重新編譯的時候,需要把生成文件刪除特別麻煩,所以我們可以用一個更加簡便的方法:

使用 out-of-source 方式構建
?

????????我們需要將構建過程生成的文件與源文件分離開來, 不讓它們混雜在一起,也就是使用 out-of-source 方式構建。

????????將 cmake 編譯生成的文件清理下,然后在工程目錄下創建一個 build 目錄

然后我們進入build文件夾進行編譯:

利用

cmake ../

可以編譯上級文件夾

日后如果要清除,直接返回上級目錄 執行:

rm -rf build/*

這樣子編譯文件就刪光啦!

使用示例二:多個源文件
?

????????我們再加入一個 hello.h 頭文件和 hello.c 源文件。在 hello.c 文件中定義了一個函數 hello,然后在 main.c 源文件中將會調用該函數

touch hello. c hello.h生成倆文件

hello.h 文件內容

#ifndef __TEST_HELLO_
#define __TEST_HELLO_
void hello(const char *name);
#endif //__TEST_HELLO_

hello.c 文件內容(注意,%s指的是將name換成字符串,!在后面)
?

#include <stdio.h>
#include "hello.h"
void hello(const char *name)
{
printf("Hello %s!\n", name);
}

main.c 文件內容

#include "hello.h"
int main(void)
{
hello("World");
return 0;
}

然后準備好 CMakeLists.txt 文件
(如果你默認環境是gcc,想要在開發板運行,你只要把gcc換成你的編譯工具鏈就行,比如set(CMAKE_C_COMPILER "?arm-linux-gnueabihf-gcc"))

set(CMAKE_C_COMPILER "gcc")
set(CMAKE_CXX_COMPILER "g++")
project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST})

set(SRC_LIST main.c hello.c) 是 CMakeLists.txt 文件中的一條命令,用于定義一個變量并給它賦值。在這個例子中,SRC_LIST 變量被設置為包含兩個源文件 main.chello.c

SRC_LIST

  • SRC_LIST 是變量名。你可以使用任何合適的名稱來代表你的變量。
  • 這個變量通常用來存儲源文件列表,以便在后續命令中引用。

add_executable(hello ${SRC_LIST})這行代碼定義了一個名為 hello 的可執行文件,并使用 SRC_LIST 變量中的源文件來構建該可執行文件。add_executable 函數將 main.chello.c 編譯并鏈接為一個名為 hello 的可執行文件。

cmake ../

make,file hello查看文件

編譯成功。

使用示例三:生成庫文件

????????在本例中,除了生成可執行文件 hello 之外,我們還需要將 hello.c 編譯為靜態庫文件或者動態庫文件,在示例二的基礎上對 CMakeLists.txt 文件進行修改,如下所示:

set(CMAKE_C_COMPILER "gcc")
set(CMAKE_CXX_COMPILER "g++")project(HELLO)
add_library(libhello hello.c)
add_executable(hello main.c)
target_link_libraries(hello libhello)

????????進入到 build 目錄下,執行 cmake、再執行 make 編譯工程,編譯完成之后,在 build 目錄下就會生成可執行文件 hello 和庫文件,如下所示:

本例中我們使用到了 add_library 命令和 target_link_libraries 命令。

????????add_library 命令用于生成庫文件,在本例中我們傳入了兩個參數,第一個參數表示庫文件的名字,需要注意的是,這個名字是不包含前綴和后綴的名字; 在 Linux 系統中,庫文件的前綴是 lib,動態庫文件的后綴是.so,而靜態庫文件的后綴是.a; 所以,意味著最終生成的庫文件對應的名字會自動添加上前綴和后綴。

????????第二個參數表示庫文件對應的源文件。

????????本例中, add_library 命令生成了一個靜態庫文件 liblibhello.a,如果要生成動態庫文件,可以這樣做:

add_library(libhello SHARED hello.c) #生成動態庫文件
add_library(libhello STATIC hello.c) #生成靜態庫文件

????????target_link_libraries 命令為目標指定依賴庫,在本例中, hello.c 被編譯為庫文件, 并將其鏈接進 hello 程序

總結

  • add_library(libhello hello.c):定義一個名為 libhello 的庫,使用 hello.c 源文件。

  • add_executable(hello main.c):定義一個名為 hello 的可執行文件,使用 main.c 源文件。
  • target_link_libraries(hello libhello):將 libhello 庫鏈接到 hello 可執行文件,使得可執行文件可以調用庫中的函數。

作用是什么呢?

代碼復用

  • 靜態庫(Static Library):將常用的函數和邏輯封裝在一個靜態庫中,可以在多個項目中復用這些函數,而不需要每次都復制代碼。
  • 動態庫(Dynamic Library):動態庫在不同的程序之間共享庫中的代碼,節省內存空間,并且可以在程序運行時加載和更新。

如果在CMakeLists.txt文件中添加下面這條命令:

set_target_properties(libhello PROPERTIES OUTPUT_

可以將生成的庫為 liblibhello.a改成libhello.a。

使用示例四:將源文件組織到不同的目錄
?

????????上面的示例中,我們已經加入了多個源文件,但是這些源文件都是放在同一個目錄下,這樣還是不太正規,我們應該將這些源文件按照類型、功能、模塊給它們放置到不同的目錄下,于是筆者將工程源碼進行了整理,當前目錄結構如下所示:

├── build #build 目錄
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
├── CMakeLists.txt
└── main.c

????????在工程目錄下,我們創建了 src 和 libhello 目錄,并將 hello.c 和 hello.h 文件移動到 libhello 目錄下,將main.c 文件移動到 src 目錄下,并且在頂層目錄、 libhello 目錄以及 src 目錄下都有一個 CMakeLists.txt 文件。CMakeLists.txt 文件的數量從 1 個一下變成了 3 個,我們來看看每一個 CMakeLists.txt 文件的內容。


頂層 CMakeLists.txt
?
cmake_minimum_required(VERSION 3.5)
project(HELLO)
add_subdirectory(libhello)
add_subdirectory(src)

src 目錄下的 CMakeLists.txt
?

include_directories(${PROJECT_SOURCE_DIR}/libhello)
add_executable(hello main.c)
target_link_libraries(hello libhello)

libhello 目錄下的 CMakeLists.txt
?

add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

????????頂層 CMakeLists.txt 中使用了 add_subdirectory 命令, 該命令告訴 cmake 去子目錄中尋找新的CMakeLists.txt 文件并解析它;而在 src 的 CMakeList.txt 文件中,新增加了 include_directories 命令用來指明頭文件所在的路徑,并且使用到了 PROJECT_SOURCE_DIR 變量,該變量指向了一個路徑,從命名上可知,該變量表示工程源碼的目錄。

????????和前面一樣,進入到 build 目錄下進行構建、編譯,最終會得到可執行文件 hello(build/src/hello)和庫文件 libhello.a(build/libhello/libhello.a):

├── build
│ ├── libhello
│ │ └── libhello.a
│ └── src
│ └── hello
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
├── CMakeLists.txt
└── main.c

使用實例5:將生成的可執行文件和庫文件放置到單獨的目錄下
?

????????在默認情況下, make 編譯生成的可執行文件和庫文件會與 cmake 命令產生的中間文件(CMakeCache.txt、 CmakeFiles、 cmake_install.cmake 以及 Makefile 等)混在一起,也就是它們在同一個目錄下; 如果我想讓可執行文件單獨放置在 bin 目錄下,而庫文件單獨放置在 lib 目錄下,就像下面這樣:

├── build
├── lib
│ └── libhello.a
└── bin
└── hello

????????將庫文件存放在 build 目錄下的 lib 目錄中,而將可執行文件存放在 build 目錄下的 bin 目錄中,這個時候又該怎么做呢?這個時候我們可以通過兩個變量來實現,將 src 目錄下的 CMakeList.txt 文件進行修改,如下所示:

include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello main.c)
target_link_libraries(hello libhello)

然后再對 libhello 目錄下的 CMakeList.txt 文件進行修改,如下所示:
?

set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

????????修改完成之后,再次按照步驟對工程進行構建、編譯,此時便會按照我們的要求將生成的可執行文件hello 放置在 build/bin 目錄下、庫文件 libhello.a 放置在 build/lib 目錄下。 最終的目錄結構就如下所示:

├── build
│ ├── bin
│ │ └── hello
│ └── lib
│ └── libhello.a
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
├── CMakeLists.txt
└── main.c

????????其實實現這個需求非常簡單,通過對 LIBRARY_OUTPUT_PATH 和 EXECUTABLE_OUTPUT_PATH變 量 進 行 設 置 即 可 完 成 ; EXECUTABLE_OUTPUT_PATH 變 量 控 制 可 執 行 文 件 的 輸 出 路 徑 , 而LIBRARY_OUTPUT_PATH 變量控制庫文件的輸出路徑。

CMakeLists.txt 語法規則
?

篇幅較長,建議看手冊

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/42031.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/42031.shtml
英文地址,請注明出處:http://en.pswp.cn/web/42031.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

怎么將aac文件弄成mp3格式?把aac改成MP3格式的四種方法

怎么將aac文件弄成mp3格式&#xff1f;手頭有一些aac格式的音頻文件&#xff0c;但由于某些設備或軟件不支持這種格式&#xff0c;你希望將它們轉換成更為通用的MP3格式。而且音頻格式的轉換在現在已經是一個常見且必要的操作。aac是一種相對較新的音頻編碼格式&#xff0c;通常…

大模型增量預訓練新技巧-解決災難性遺忘

大模型增量預訓練新技巧-解決災難性遺忘 機器學習算法與自然語言處理 2024年03月21日 00:02 吉林 以下文章來源于NLP工作站 &#xff0c;作者劉聰NLP NLP工作站. AIGC前沿知識分享&落地經驗總結 轉載自 | NLP工作站 作者 | 劉聰NLP 目前不少開源模型在通用領域具有不錯…

G1 和 CMS

1、CMS CMS&#xff08;Concurrent Mark Sweep&#xff0c;并發標記清除&#xff0c;是為了解決早期垃圾收集器在執行垃圾回收時導致應用程序暫停時間過長的問題而設計的。 CMS的工作流程主要包括以下幾個階段&#xff1a; 初始標記&#xff08;Initial Mark&#xff09;&…

一體化運維監控平臺:賦能各行業用戶運維升級

在當今數字化轉型的大潮中&#xff0c;企業IT系統的復雜性和規模不斷攀升&#xff0c;對運維團隊提出了前所未有的挑戰。如何高效、精準地監控和管理IT基礎設施&#xff0c;確保業務連續性和穩定性&#xff0c;成為所有企業關注的焦點。美信&#xff0c;自2007年成立以來&#…

el-scrollbar實現自動滾動到底部(AI聊天)

目錄 項目背景 實現步驟 實現代碼 完整示例代碼 項目背景 chatGPT聊天消息展示滾動面板&#xff0c;每次用戶輸入提問內容或者ai進行流式回答時需要不斷的滾動到底部確保展示最新的消息。 實現步驟 采用element ui 的el-scrollbar作為聊天消息展示組件。 通過操作dom來實…

端、邊、云三級算力網絡

目錄 端、邊、云三級算力網絡 NPU Arm架構 OpenStack kubernetes k3s輕量級Kubernetes kubernetes和docker區別 DCI(Data Center Interconnect) SD/WAN TF 端、邊、云三級算力網絡 算力網絡從傳統云網融合的角度出發,結合 邊緣計算、網絡云化以及智能控制的優勢,通…

Qt開發 | Qt創建線程 | Qt并發-QtConcurrent

文章目錄 一、Qt創建線程的三種方法二、Qt并發&#xff1a;QtConcurrent介紹三、QtConcurrent run參數說明四、獲取QtConcurrent的返回值五、C其他線程技術介紹 一、Qt創建線程的三種方法 以下是Qt創建線程的三種方法&#xff1a; 方法一&#xff1a;派生于QThread 派生于QThre…

理解算法復雜度:空間復雜度詳解

引言 在計算機科學中&#xff0c;算法復雜度是衡量算法效率的重要指標。時間復雜度和空間復雜度是算法復雜度的兩個主要方面。在這篇博客中&#xff0c;我們將深入探討空間復雜度&#xff0c;了解其定義、常見類型以及如何進行分析。空間復雜度是衡量算法在執行過程中所需內存…

ceph mgr [errno 39] RBD image has snapshots (error deleting image from trash)

ceph mgr 報錯 debug 2024-07-08T09:25:56.512+0000 7f9c63bd2700 0 [rbd_support INFO root] execute_task: task={"sequence": 3, "id": "260b9fee-d567-4301-b7eb-b1fe1b037413", "message": "Removing image replicapool/8…

昇思25天學習打卡營第19天|Diffusion擴散模型

學AI還能贏獎品&#xff1f;每天30分鐘&#xff0c;25天打通AI任督二脈 (qq.com) Diffusion擴散模型 本文基于Hugging Face&#xff1a;The Annotated Diffusion Model一文翻譯遷移而來&#xff0c;同時參考了由淺入深了解Diffusion Model一文。 本教程在Jupyter Notebook上成…

python庫 - missingno

missingno 是一個用于可視化和分析數據集中缺失值的 Python 庫。它提供了一系列簡單而強大的工具&#xff0c;幫助用戶直觀地理解數據中的缺失模式&#xff0c;從而更好地進行數據清洗和預處理。missingno 庫特別適用于數據分析和數據科學項目&#xff0c;尤其是在處理缺失數據…

昇思MindSpore學習筆記5-02生成式--RNN實現情感分類

摘要&#xff1a; 記錄MindSpore AI框架使用RNN網絡對自然語言進行情感分類的過程、步驟和方法。 包括環境準備、下載數據集、數據集加載和預處理、構建模型、模型訓練、模型測試等。 一、概念 情感分類。 RNN網絡模型 實現效果&#xff1a; 輸入: This film is terrible 正…

放大鏡案例

放大鏡 <!DOCTYPE html> <html lang"zh-cn"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>商品放大鏡</title><link rel&qu…

如何使用allure生成測試報告

第一步下載安裝JDK1.8&#xff0c;參考鏈接JDK1.8下載、安裝和環境配置教程-CSDN博客 第二步配置allure環境&#xff0c;參考鏈接allure的安裝和使用(windows環境)_allure windows-CSDN博客 第三步&#xff1a; 第四步&#xff1a; pytest 查看目前運行的測試用例有無錯誤 …

如何使用 pytorch 創建一個神經網絡

我已發布在&#xff1a;如何使用 pytorch 創建一個神經網絡 SapientialM.Github.io 構建神經網絡 1 導入所需包 import os import torch from torch import nn from torch.utils.data import DataLoader from torchvision import datasets, transforms2 檢查GPU是否可用 dev…

ffmpeg濾鏡創建過程

1、創建一個濾鏡圖 AVFilterGraph *filter_graph avfilter_graph_alloc(); 2、創建濾鏡的輸入和輸出 AVFilterInOut *inputs avfilter_inout_alloc(); AVFilterInOut *outputs avfilter_inout_alloc(); 3、每個濾鏡創建上下文 AVFilterContext *filter1_ctx avfilter_…

Yolov10訓練,轉化onnx,推理

yolov10對于大目標的效果好&#xff0c;小目標不好 一、如果你訓練過yolov5&#xff0c;yolov8&#xff0c;的話那么你可以直接用之前的環境就行 目錄 一、如果你訓練過yolov5&#xff0c;yolov8&#xff0c;的話那么你可以直接用之前的環境就行 二、配置好后就可以配置文件…

android webview 遠程調試

打開遠程調試選項 MainActivity super.onCreate(savedInstanceState);// enable Cordova apps to be started in the backgroundBundle extras getIntent().getExtras();if (extras ! null && extras.getBoolean("cdvStartInBackground", false)) {moveT…

前端JS特效第24集:jquery css3實現瀑布流照片墻特效

jquery css3實現瀑布流照片墻特效&#xff0c;先來看看效果&#xff1a; 部分核心的代碼如下(全部代碼在文章末尾)&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8" /> <title>jquerycss3實現瀑…

Nginx:負載均衡小專題

運維專題 Nginx&#xff1a;負載均衡小專題 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/…