Cmake 实例学习 一
一. 第一個簡單的例子
在一個目錄下面實現一個簡單的 hello world 程序
使用cmake進行構建的時候,每個目錄下面都要有一個 CMakeLists.txt 的文件
如果是一個稍微大的工程,有多級目錄,在上級目錄中的 CMakeLists.txt 中會有定義要求編譯子目錄的邏輯
當前目錄中定義了一個main.c 和 CMakeLists.txt 文件,兩個文件的內容分別如下
main.c
#include <stdio.h>
int main()
{printf("hello world!\n");return 0;
}
CMakeLists.txt
project (hello)
set(SRC_LIST main.c)
message(STATUS "this is binary dir" ${HELLO_BINARY_DIR})
message(STATUS "this is source dir" ${HELLO_SOURCE_DIR})
add_executable(hello ${SRC_LIST})
重點解釋 CMakeLists.txt 中的內容
project 定義工程名成set 定義一個變量,把后面的 mian.c 賦值給了 SRC_LIST ,這樣做的好處是,
如果需要編譯多個文件構成同一個可執行程序的時候,
在后面用到的時候,不需要每次都寫多個文件,只需要使用這個變量名就可以了message 打印一些信息,這里可以打印多種信息,上文中需要打印出來的信息就是一個狀態信息
后面可能會用到的打印信息包括,
SEND_ERROR,產生錯誤,生成過程被跳過。FATAL_ERROR,立即終止所有 cmake 過程.等add_executable 添加可執行程序,hello 是生成的可執行程序名
后面的符號表示生成這個可執行程序需要依賴的源文件注意其中的變量,使用set定義了變量之后,后面在使用的時候一般是需要加上 ${} 符號的
但是在 IF 判斷語句中,如果使用 ${} 判斷指令的話,就是不正確的,
因為那個樣子的話,IF 判斷的就是變量本身的內容另外注意的是,工程名project中的hello和可執行程序名中 add_executable
中的 hello 是沒有直接關系的,即兩處的名稱可以不同
二. 第二個例子,使hello更像一個工程
本小結將完成如下工作
1,為工程添加一個子目錄 src,用來放置工程源代碼;
2,添加一個子目錄 doc,用來放置這個工程的文檔 hello.txt
3,在工程目錄添加文本文件 COPYRIGHT, README;
4,在工程目錄添加一個 runhello.sh 腳本,用來調用 hello 二進制
4,將構建后的目標文件放入構建目錄的 bin 子目錄;
5,最終安裝這些文件:將 hello 二進制與 runhello.sh 安裝至/usr/bin,將 doc 目錄
的內容以及 COPYRIGHT/README 安裝到/usr/share/doc/cmake/t2,將
我們需要在上一節的基礎之上,將文件改一下
首先新建一個目錄t2,將上一個工程中的所有文件添加到這個文件中
在當前目錄下面新建目錄src。這個src專門用于存放文件程序的源代碼
把 main.c 移動到 src 目錄下面
上文提到每個目錄下面需要增加CMakeLists.txt文件
所以需要在src目錄下面新建一個CMakeLists.txt 文件,文件中寫入如下內容
add_executable(hello main.c)
因為在工程中增加了子目錄,我們需要在相應的父目錄中的CMakeLists.txt 中增加相關的配置
在父目錄下面的CMakeLists.txt 中修改最后的add,改成
add_subdirectory(src bin)
父目錄中 CMakeLists 全文如下
project (hello)
set(SRC_LIST main.c)
message(STATUS "this is binary dir" ${HELLO_BINARY_DIR})
message(STATUS "this is source dir" ${HELLO_SOURCE_DIR})
#add_executable(hello ${SRC_LIST})
add_subdirectory(src bin)
這里解釋一下最后一句
因為增加了子目錄,這里需要將子目錄增加進來,并且將子目錄編譯的結果放到了 bin目錄下面
這里的重點是,將整個子目錄將入到工程中,從而這個父目錄和這個子目錄整體構成了一個工程
另外我們也可以通過修改內置的隱式變量來指定程序輸出的位置,簡要如下
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
三 . 添加共享庫
有了上面的基礎,添加動態庫也是如此的簡單
創建一個新的目錄,用于存放新的工程t3
將之前t2的內容拷貝到t3中
新建一個lib目錄,在lib目錄下面創建三個文件,分別是 hello.c 和 hello.h 和 CMakeLists.txt
hello.c
#include "hello.h"
void HelloFunc()
{printf("hello world\n");
}
hello.h
#ifndef HELLO_H
#define HELLO_H#include <stdio.h>
void HelloFunc();#endif
CMakeLists
set(LIBHELLO_SRC hello.c)
add_library(hello SHARED ${LIBHELLO_SRC})
這里解釋一下子目錄中的定義,其實很簡單,就是生成一個庫文件,這里hello是庫文件的名稱 ,SHARED 表示生成的是動態庫,如果要生成靜態庫,使用的是STATIC,后面表示生成庫文件需要的源文件是什么
在父目錄中,修改 CMakeLists如下
cmake_minimum_required(VERSION 2.6)
project (hellolib)
#add_executable(hello ${SRC_LIST})
#add_subdirectory(src bin)
add_subdirectory(lib)
父目錄中的CMakeLists就是添加一個子目錄,子目錄執行的任務在子目錄中會定義
四. 生成一個庫文件,并鏈接他
在同一個一個工程中,我們既需要生成一個庫文件,又需要鏈接這個庫文件
在上面 二 和 三 的基礎之上,即既保留了 src 目錄,又保留了 lib 目錄的基礎之上,
保持 lib 中的CMakeLists不變,需要修改父目錄中的 CMakeLists如下
cmake_minimum_required(VERSION 2.6)
project (hellolib)
#add_executable(hello ${SRC_LIST})
#add_subdirectory(src bin)
add_subdirectory(lib)
add_subdirectory(src bin)
父目錄中實際只是在 生成 lib 的基礎之上,增加了而一個新的子目錄 src
進入到 src 目錄中,修改源代碼,我們需要在 main.c 中增加頭文件和修改函數,如下所示
#include <stdio.h>
#include "hello.h"
int main()
{HelloFunc();return 0;
}
重點在 src 中的 CMakeLists 的編寫,這里因為需要鏈接到庫文件,所以需要注意兩個內容,
一個是頭文件,一個是庫文件
src 中 CMakeLists 的書寫如下所示
include_directories("${PROJECT_SOURCE_DIR}/lib")
add_executable(main main.c)
target_link_libraries(main hello)
第一行,增加頭文件的查找目錄,這里使用了 變量 , PROJECT_SOURCE_DIR 是 cmake 的內置變量,表示工程的目錄所在位置,加上這個頭文件目錄的選項之后,程序在編譯的時候,就會到這個目錄下面去尋找頭文件
第二行 不在贅述
第三行 表示,編譯源文件 main 的時候,需要鏈接的庫文件,這個庫文件就是之前在 lib 中生成的庫文件 hello
綜上,在一個程序編譯的時候,需要使用庫文件的時候,需要注意兩個內容,一個是頭文件,一個就是庫文件
五. 使用 cmake 和 程序代碼,決定是否調用自制庫文件
在 四 的基礎之上,我們需要改變一些CMakeLists的配置,通過判斷是否需要一些條件來執行一些函數
在頂層的CMakeLists中,修改如下
cmake_minimu_required(VERSION 2.6)
project (hellolib)
#add_executable(hello ${SRC_LIST})
#add_subdirectory(src bin)
option(USE_MYLIB "Use my lib" ON)
add_subdirectory(lib)
add_subdirectory(src bin)
此處在中間加了一個options的選項,定義了一個選項USE_MYLIB 并默認為打開的
如果需要不想要一些邏輯的話,我們直接可以通過修改這個 ON 為OFF就可以關掉一些功能了
在 src 的CMakeLists中需要修改如下
if (USE_MYLIB)add_definitions(-DUSE_MYLIB)include_directories("${PROJECT_SOURCE_DIR}/lib")set(EXTRA_LIBS ${EXTRA_LIBS} hello)
endif (USE_MYLIB)message(STATUS "extra libs: " ${EXTRA_LIBS})
add_executable(main main.c)
target_link_libraries(main ${EXTRA_LIBS})
這里開始就是一個判斷,就是判斷這個 USE_MYLIB 是否為真,注意這里的 USE_MYLIB 不需要加 ${} 如果加上的,就表示取 他的值了
如果這個判斷為真,就執行如下的操作 ,這個值在頂層的 CMakeLists 中,已經定義為 ON了,所以此處會判斷為真
在這個 if 為真的判斷中,需要加上一個宏定義,定義了 一個東西,這個宏是可以傳遞到代碼中的
此外,如果這個判斷為真,還是加上需要鏈接的頭文件,和需要鏈接的庫文件,這里沒有直接鏈接上庫文件,而是通過將庫文件賦值給了一個變量,這個變量是cmake內置的變量
最后,編譯這個程序,如果上面的判斷為真,就會鏈接到了這個庫文件,如果為假,則這個內置變量就是空的,具體是不是cmake內置的變量還有待考證
修改了 CMakeLists之后,還需要在代碼中進行修改 ,src 中修改之后的代碼如下
#include <stdio.h>
#ifdef USE_MYLIB
#include "hello.h"
#endifint main()
{
#ifdef USE_MYLIBHelloFunc();
#elseprintf("AAA\n");
#endifreturn 0;
}
前面已經說過,如果在src 中的CMakeLists中的判斷為真,就會加上一個宏,這個宏可以傳遞到代碼里面的,在代碼中,我們就可以通過判斷這個宏是否為真的方式,來決定是否使用自己定義的庫文件了
總結
以上是生活随笔為你收集整理的Cmake 实例学习 一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 元气骑士瓦尔基里之羽怎么获得?
- 下一篇: 急!!!在线求电影名