用 cmake 來構建 c/c++ 專案是業內的主流做法。最近,我們的專案**做了一些拆分和合併:引入其他倉庫**,並且將公共部分拆分以供多個倉庫同時使用。為此,就得修改專案中的 cmake 以滿足需求。
在做這件事情時,過程是相當痛苦的,修改的難度超過了我的預期。這份痛苦的回憶,讓我陷入了沉思:這 cmake 咋這麼不好使,是我的使用姿勢不對嗎?cmake 的最佳實踐是啥?
在經過一番搜尋和學習,我開始了解 modern cmake 的一些用法與理念,它主張放棄傳統的基於變數的方法,而採用基於 target 的結構化模式,使其成為乙個更可維護、更直觀、更易整合、更具意義的方案。
在這裡對自己的學習做乙個總結,主要內容包括:
介紹 modern cmake 的基礎語法與工具,讓你對 cmake 能做些啥有更清楚的認識
介紹 modern cmake 理念與最佳實踐,並給出具體例項
這部分內容是 an introduction to modern cmake 的總結,並不會講的非常詳細,希望通過幾句話來高度總結各個用法,旨在了解 cmake 有哪能力,如果對某些部分感興趣請大家自行查閱具體內容。
為什麼一定是 cmake?其他工具不行嗎?
為什麼要用現代 cmake?
macos
linux
設定cc
和cxx
環境變數來選擇 c/c++ 編譯器
~/package/build $ cc=clang cxx=clang++ cmake ..
選擇不同的工具進行構建
通過-d
來設定選項,例如cmake -s . -b build -dcmake_install_prefix=dist
--trace
列印 cmake configure 階段的輸出,例如cmake -s . -b build --trace
良好的 cmake 用法
project
project(myproject version 1.0
description "very nice project"
languages cxx)
生成可執行檔案
add_executable(one two.cpp three.h)
生成庫
add_library(one static two.cpp three.h)
給 target 新增屬性
# public 表示外部也需要這個 include 目錄
target_include_directories(one public include)
add_library(another static another.cpp another.h)
# 由於具有傳遞性,another 可以連線 one 的 include 目錄
target_link_libraries(another public one)
快取變數
關於區域性變數與緩衝變數的示例,請參考 cmake-變數和全域性變數快取
屬性
if(variable)
# if variable is `on`, `yes`, `true`, `y`, or non zero number
else()
# if variable is `0`, `off`, `no`, `false`, `n`, `ignore`, `notfound`, `""`, or ends in `- notfound`
endif()
# if variable does not expand to one of the above, cmake will expand it then try again
if(not target liba or exists "test.xml")
# if liba or test.xml exist
endif()
生成器表示式, generator-expressions
target_include_directories(mytarget
public
$$)
巨集與函式
引數。可以通過cmake_parse_arguments
來解析函式引數
- project
- .gitignore
- readme.md
- licence.md
- cmakelists.txt
- cmake
- findsomelib.cmake
- something_else.cmake
- include
- project
- lib.hpp
- src
- cmakelists.txt
- lib.cpp
- cmakelists.txt
- tests
- cmakelists.txt
- testlib.cpp
- docs
- cmakelists.txt
- extern
- googletest
- scripts
- helper.py
find_package(git quiet)
if(git_found and exists "$/.git")
execute_process(command $ submodule update --init --recursive
working_directory $
result_variable git_submod_result)
if(not git_submod_result equal "0")
message(fatal_error "git submodule update --init failed with $, please checkout submodules")
endif()
endif()
在 build 階段執行命令
find_package(pythoninterp required)
add_custom_command(output "$/include/generated.hpp"
command "$" "$/scripts/generateheader.py" --argument
depends some_target)
add_custom_target(generate_header all
depends "$/include/generated.hpp")
install(files $/include/generated.hpp destination include)
cmake -e
執行內建的一些命令,例如解壓、複製等,具體參看 run a command-line tool
cmake 3.1+: 全域性和屬性設定
全域性變數設定
set(cmake_cxx_standard 11)
set(cmake_cxx_standard_required on)
set(cmake_cxx_extensions off)
小型庫interprocedural optimization,執行時優化(link time optimization),即-flto
在 cmake 中可以配合其他工具
cmake modules 非常有用,簡單介紹一些常用的
除錯 cmake **
介紹了引入 cuda、openmp、boost、mpi、root、minuit2 等庫的標準姿勢
Visual Unit 簡明教程
visual unit,簡稱vu,是新一代單元測試工具,功能強大,使用簡單,完全視覺化,不需編寫測試 vu的測試結果使程式行為一目了然,有助於整理程式設計思路,提高程式設計效率和正確性,並能快速排錯 vu還增強偵錯程式功能 如自由後退 用例切換 提高除錯的效率 vu能達到空前的測試完整性,輕鬆完成語...
MYSQL簡明教程
dos進入mysql命令 c mysql h 127.0.0.1 u root p enter password mysql 進入完成 建立資料庫 create database databasename 使用指定資料庫進行操作 方法1 use database databasename 方法2 m...
Struts Hibernate簡明教程
jboss 資助的開源專案,當前比較流行的持久層框架,是一種先進的 jdbc 封裝框架。優點 提高了資料訪問層的開發效率,使我們不必直接呼叫 jdbc 來訪問關係型資料庫。hibernate 建立在物件導向的基礎之上,開發人員只需針對物件進行操作,不必再關心資料庫的連線關閉,sql的執行,以及 re...