深入理解CMake(2):初步解讀Caffe的CMake腳本

預(yù)備說明

分析的是官方Caffe(https://github.com/BVLC/caffe)的CMake腳本,主要分析了根目錄的CMakeLists.txt卖局。
Caffe代碼的commit id為99bd99795dcdf0b1d3086a8d67ab1782a8a08383

所謂CMake腳本這里指的是CMakeLists.txt和xxx.cmake的統(tǒng)稱。

$CAFFE_ROOT/CMakeLists.txt解讀

cmake_minimum_required(VERSION 2.8.7)

設(shè)定cmake最低版本染坯。高版本cmake提供更多的功能(例如cmake3.13開始提供target_link_directories())或解決bug(例如OpenMP的設(shè)定問題),低版本有更好的兼容性仲锄。VERSION必須大寫儒喊,否則不識別而報(bào)錯怀愧。非必須但常規(guī)都寫肛搬。放在最開始一行。


if(POLICY CMP0046)
  cmake_policy(SET CMP0046 NEW)
endif()

cmake中也有if判斷語句,需要配對的endif()待秃。
POLICY是策略的意思章郁,cmake中的poilcy用來在新版本的cmake中開啟志衍、關(guān)閉老版本中逐漸被放棄的功能特性:

Policies in CMake are used to preserve backward compatible behavior across multiple releases


project(Caffe C CXX)

project()指令暖庄,給工程起名字,很正常不過了楼肪。這列還寫明了是C/C++工程培廓,其實(shí)沒必要寫出來,因?yàn)镃Make默認(rèn)是開啟了這兩個的春叫。
這句命令執(zhí)行后,自動產(chǎn)生了5個變量:

  • PROJECT_NAME暂殖,值等于Caffe
  • PROJECT_SOURCE_DIR价匠,是CMakeLists.txt所在目錄,通常是項(xiàng)目根目錄(奇葩的項(xiàng)目比如protobuf呛每,把CMakeLists.txt放在cmake子目錄的也有)
  • PROJECT_BINARY_DIR踩窖,是執(zhí)行cmake命令時所在的目錄,通常是build一類的用戶自行創(chuàng)建的目錄晨横。
  • Caffe_SOURCE_DIR毙石,此時同PROJECT_SOURCE_DIR
  • Caffe_BINARY_DIR,此時同PROJECT_BINARY_DIR
    官方cmake文檔對PROJECT_SOURCE_DIRPROJECT_BINARY_DIR的解釋很晦澀:
    image.png
image.png

自行實(shí)踐驗(yàn)證下:


image.png

image.png


set(CAFFE_TARGET_VERSION "1.0.0" CACHE STRING "Caffe logical version")
set(CAFFE_TARGET_SOVERSION "1.0.0" CACHE STRING "Caffe soname version")

set()指令是設(shè)定變量的名字和取值,CACHE意思是緩存類型奶陈,是說在外部執(zhí)行CMake時可以臨時指定這一變量的新取值來覆蓋cmake腳本中它的取值:CMAKE -Dvar_name=var_value

而最后面的雙引號包起來的取值可以認(rèn)為是”注釋“烹玉。STRING是類型,不過據(jù)我目前看到和了解到的滤灯,CMake的變量99.9%是字符串類型,而且這個字符串類型變量和字符串?dāng)?shù)組類型毫無區(qū)分。

變量在定義的時候直接寫名字鳞骤,使用它的時候則需要用${VAR_NAME}的形式窒百。此外還可以使用系統(tǒng)的環(huán)境變量,形式為$ENV{ENV_VAR_NAME}豫尽,例如$ENV{PATH}篙梢,$ENV{HOME}等。

除了緩存變量美旧,option()指令設(shè)定的東西也可以被用CMake -Dxxx=ON的形式來覆蓋渤滞。


add_definitions(-DCAFFE_VERSION=${CAFFE_TARGET_VERSION})

add_definitions()命令通常用來添加C/C++中的宏,例如:

  • add_defitions(-DCPY_ONLY) 榴嗅,給編譯器傳遞了預(yù)定義的宏CPU_ONLY妄呕,相當(dāng)于代碼中增加了一句#define CPU_ONLY
  • add_defitions(-DMAX_PATH_LEN=256),則相當(dāng)于#define MAX_PATH_LEN 256
    根據(jù)文檔嗽测,實(shí)際上add_definitions()可以添加任意的編譯器flags绪励,只不過像添加頭文件搜索路徑等flags被交給include_directory()等命令了。

在這里具體的作用是唠粥,設(shè)定CAFFE_VERSION這一C/C++宏的值為CAFFE_TARGET_VERSION變量的取值疏魏,而這一變量在前面分析過,它是緩存變量晤愧,有一個預(yù)設(shè)的默認(rèn)值蠢护,也可以通過cmake .. -DCAFFE_TARGET_VERSION=x.y.z來指定為x.y.z


list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)

這里首先是list(APPEND VAR_NAME VAR_VALUE)這一用法养涮,表示給變量VAR_NAME追加一個元素VAR_VALUE葵硕。雖然我寫成VAR_NAME,但前面有提到贯吓,cmake中的變量幾乎都是字符串或字符串?dāng)?shù)組懈凹,這里VAR_NAME你就當(dāng)它是一個數(shù)組就好了,而當(dāng)后續(xù)使用${VAR_NAME}時輸出的是”整個數(shù)組的值“悄谐。(吐槽:這不就是字符串么介评?為什么用list這個名字呢?搞得像是在寫不純正的LIPS)

具體的說爬舰,這里是把項(xiàng)目根目錄(CMakeLists.txt在項(xiàng)目根目錄们陆,${PROJECT_SOURCE_DIR}表示CMakeLists.txt所在目錄)下的cmake/Modules子目錄對應(yīng)的路徑值,追加到CMAKE_MODULE_PATH中情屹;CMAKE_MODULE_PATH后續(xù)可能被include()find_package()等命令所使用坪仇。


include(ExternalProject)
include(GNUInstallDirs)

include()命令的作用:

  • 包含文件,
  • 或者垃你,包含模塊
    所謂包含文件椅文,例如include(utils.cmake)喂很,把當(dāng)前路徑下的utils.cmake包含進(jìn)來,基本等同于C/C++中的#include指令皆刺。通常少辣,include文件的話文件應(yīng)該是帶有后綴名的。
    所謂包含模塊羡蛾,比如include(xxx)漓帅,是說在CMAKE_MODULE_PATH變量對應(yīng)的目錄,或者CMake安裝包自帶的Modules目錄(比如mac下brew裝的cmake對應(yīng)的是/usr/local/share/cmake/Modules)里面尋找xxx.cmake文件痴怨。注意忙干,此時不需要寫".cmake"這一后綴。

具體的說腿箩,這里是把CMake安裝包提供的ExternalProject.cmake(例如我的是/usr/local/share/cmake/Modules/ExternalProject.cmake)文件包含進(jìn)來。ExternalProject劣摇,顧名思義珠移,引入外部工程,各種第三方庫什么的都可以考慮用它來弄;

GNUInstallDirs也是對應(yīng)到CMake安裝包提供的GNUInstallDirs.cmake文件末融,這個包具體細(xì)節(jié)還不太了解钧惧,可自行翻閱該文件。


include(cmake/Utils.cmake)
include(cmake/Targets.cmake)
include(cmake/Misc.cmake)
include(cmake/Summary.cmake)
include(cmake/ConfigGen.cmake)

這里是實(shí)打?qū)嵉陌嗽陧?xiàng)目cmake子目錄下的5各cmake腳本文件了勾习,是Caffe作者們(注意浓瞪,完整的Caffe不是Yangqing Jia一個人寫的)提供的,粗略看了下:

  • cmake/Utils.cmake: 定義了一些通用的(適用于其他項(xiàng)目的)函數(shù)巧婶,用于變量(數(shù)組)的打印乾颁、合并、去重艺栈、比較等(吐槽:cmake語法比較奇葩英岭,相當(dāng)一段時間之后我才發(fā)現(xiàn)它是lisp方式的語法,也就是函數(shù)(命令)是一等公民)
  • cmake/Targets.cmake: 定義了Caffe項(xiàng)目本身的一些函數(shù)和宏湿右,例如源碼文件組織诅妹、目錄組織等。
  • cmake/Misc.cmake:雜項(xiàng)毅人,比較摳細(xì)節(jié)的一些設(shè)定吭狡,比如通常CMAKE_BUILD_TYPE基本夠用了,但是這里通過CMAKE_CONFIGURATION_TYPES來輔助設(shè)定CMAKE_BUILD_TYPE丈莺,等等
  • cmake/Summary.cmake:定義了4個打印函數(shù)划煮,用來打印Caffe的一些信息,執(zhí)行CMake時會在終端輸出缔俄,相比于散落在各個地方的message()語句會更加系統(tǒng)一些
  • cmake/ConfigGen.cmake: 整個caffe編譯好之后般此,如果別的項(xiàng)目要用它蚪战,那它也應(yīng)該用cmake腳本提供配置信息。

這5個cmake腳本中具體的函數(shù)比較多铐懊,這里先放過邀桑,后續(xù)可能考慮逐一解讀。


caffe_option(CPU_ONLY  "Build Caffe without CUDA support" OFF) # TODO: rename to USE_CUDA
caffe_option(USE_CUDNN "Build Caffe with cuDNN library support" ON IF NOT CPU_ONLY)
caffe_option(USE_NCCL "Build Caffe with NCCL library support" OFF)
caffe_option(BUILD_SHARED_LIBS "Build shared libraries" ON)
caffe_option(BUILD_python "Build Python wrapper" ON)
set(python_version "2" CACHE STRING "Specify which Python version to use")
caffe_option(BUILD_matlab "Build Matlab wrapper" OFF IF UNIX OR APPLE)
caffe_option(BUILD_docs   "Build documentation" ON IF UNIX OR APPLE)
caffe_option(BUILD_python_layer "Build the Caffe Python layer" ON)
caffe_option(USE_OPENCV "Build with OpenCV support" ON)
caffe_option(USE_LEVELDB "Build with levelDB" ON)
caffe_option(USE_LMDB "Build with lmdb" ON)
caffe_option(ALLOW_LMDB_NOLOCK "Allow MDB_NOLOCK when reading LMDB files (only if necessary)" OFF)
caffe_option(USE_OPENMP "Link with OpenMP (when your BLAS wants OpenMP and you get linker errors)" OFF)

# This code is taken from https://github.com/sh1r0/caffe-android-lib
caffe_option(USE_HDF5 "Build with hdf5" ON)

這里是設(shè)定各種option科乎,也就是”開關(guān)“壁畸,然后后續(xù)根據(jù)開關(guān)的取值(布爾類型的變量,利用ifelse來判斷)茅茂,編寫各自的構(gòu)建規(guī)則捏萍。
其中caffe_option()cmake/Utils.cmake中定義的,它相比于cmake自帶的option()命令空闲,增加了可選的條件控制字段:

image.png

caffe_option()的具體實(shí)現(xiàn)還沒有看懂令杈,不過看一下所有用到的地方也都是很直觀的:

image.png

具體的說,這里就是設(shè)定一些“高層級的編譯選項(xiàng)開關(guān)”碴倾,比如是否編matlab接口逗噩、是否編python接口,是否用hdf5跌榔,是否用openmp异雁,等等。


include(cmake/Dependencies.cmake)

這里是包含Dependencies.cmake僧须,它里面配置了Caffe的絕大多數(shù)依賴庫:

Boost
Threads
OpenMP
Google-glog
Google-gflags
Google-protobuf
HDF5
LMDB
LevelDB
Snappy
CUDA
OpenCV
BLAS
Python
Matlab
Doxygen

其中每一個依賴庫庫都直接(在Dependencies.cmake中)或間接(在各自的cmake腳本文件中)使用find_package()命令來查找包纲刀。

使用find_package(),需要明確兩點(diǎn):

  1. find_package(Xxx)如果執(zhí)行成功担平,則提供相應(yīng)的Xxx_INCLUDE_DIR示绊、Xxx_LIBRARY_DIR等變量,看起來挺方便暂论,但其實(shí)并不是所有的庫都提供了同樣的變量后綴耻台,其實(shí)都是由庫的官方作者或第三方提供的xxx.cmake等腳本來得到的,依賴于生態(tài)空另。
  2. find_packge(Xxx)實(shí)際中往往是翻車重災(zāi)區(qū)盆耽。它其實(shí)有N大查找順序,而CSDN上的博客中往往就瞎弄一個扼菠,你照搬后還是不行摄杂。具體例子:
  • 系統(tǒng)包管理工具裝的OpenCV不帶contrib模塊,想使用自行編譯的OpenCV但是git clone下來的開源代碼執(zhí)行后找不到自己編譯的OpenCV循榆。其實(shí)只要知道N大查找順序析恢,設(shè)定CMAKE_PREFIX_PATH中包含OpenCV路徑后基本都能找到
  • Caffe基于cmake編譯秧饮,依賴于Boost映挂,系統(tǒng)里用apt或brew裝了Boost泽篮,同時也自行編譯了高版本Boost,現(xiàn)在Caffe編譯時cmake只認(rèn)自行編譯版的Boost柑船,指定N大查找順序也不能找到系統(tǒng)的Boost帽撑。切換已安裝的多個Boost給CMake find_package(),這時候需要看看FindBoost.cmake是怎么寫的鞍时,必須提供它里面說的字樣的變量(表示include和lib的查找路徑)亏拉,才能讓find_package()起作用。
  • CMake編譯安裝了多個版本的Caffe(比如官方Caffe逆巍、SSD的Caffe)及塘,~/.cmake目錄下會緩存一個caffe,而現(xiàn)在手頭有一個做人臉檢測的工程依賴Caffe锐极,而你希望它用官方Caffe而不是SSD-Caffe笙僚,這個緩存目錄很可能搗亂,這個我認(rèn)為是某些項(xiàng)目比如Caffe的export輸出是多余的灵再,反而容易造成混淆肋层。

這里暫時不逐一分析每一個包的find_package()情況,只需要注意如果某個包你安裝了但是cmake卻沒有找到檬嘀,那就需要在find_package()前進(jìn)行設(shè)定槽驶,以及之后排查责嚷。


if(UNIX OR APPLE)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall")
endif()

通過設(shè)定CMAKE_CXX_FLAGS鸳兽,cmake生成各自平臺的makefile、.sln或xcodeproject文件時設(shè)定同樣的CXXFLAGS給編譯器罕拂。如果是.c文件揍异,則由c編譯器編譯,對應(yīng)的是CMAKE_C_FLAGS爆班。

這里的set()指令設(shè)定CMAKE_CXX_FLAGS的值衷掷,加入了兩個新的flags:"-fPIC"和"-Wall"。實(shí)際上用list(APPEND CMAKE_CXX_FLAGS "-fPIC -Wall")是完全可以的柿菩。set()只不過是有時候可能考慮設(shè)定變量默認(rèn)值的時候用一用戚嗅。

-fPIC作用于編譯階段,告訴編譯器產(chǎn)生與位置無關(guān)代碼(Position-Independent Code)枢舶,則產(chǎn)生的代碼中懦胞,沒有絕對地址,全部使用相對地址凉泄,故而代碼可以被加載器加載到內(nèi)存的任意位置躏尉,都可以正確的執(zhí)行。這正是共享庫所要求的后众,共享庫被加載時胀糜,在內(nèi)存的位置不是固定的颅拦。
-Wall則是開啟所有警告。根據(jù)個人的開發(fā)經(jīng)驗(yàn)教藻,C編譯器的警告不能完全忽視距帅,有些wanring其實(shí)應(yīng)當(dāng)當(dāng)做error來對待,例如:

  • 函數(shù)未定義而被使用(忘記#include頭文件)
  • 指針類型不兼容(incompatible)
    都有可能引發(fā)seg fault怖竭,甚至bus error锥债。


caffe_set_caffe_link()

這里是設(shè)置Caffe_LINK這一變量,后續(xù)鏈接階段會用到痊臭。它定義在cmake/Targets.cmake中:

image.png

可以看到哮肚,如果是編共享庫(動態(tài)庫),則就叫caffe广匙;否則允趟,則增加一些鏈接器的flags:-Wl是告訴編譯器,后面緊跟的是鏈接器的flags而不是編譯器的flags(現(xiàn)在的編譯器往往是包含了調(diào)用連接器的步驟)鸦致。

這里的幾個鏈接器參數(shù)潮剪,目前我沒有細(xì)究過,具體看ld文檔:https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html


if(USE_libstdcpp)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
  message("-- Warning: forcing libstdc++ (controlled by USE_libstdcpp option in cmake)")
endif()

USE_libstdcpp這個變量的含義:
在前面已經(jīng)include(cmake/Dependencies.cmake)的情況下分唾,Dependencies.cmake中的include(cmake/Cuda.cmake)使得Cuda的設(shè)定也被載入抗碰。而Cuda.cmake中的最后,判斷如果當(dāng)前操作系統(tǒng)是蘋果系統(tǒng)并且>10.8绽乔、cuda版本小于7.0弧蝇,那么使用libstdc++而不是libc++

image.png

這時候想起來還沒畢業(yè)那會兒的一個新聞,說蘋果移除了libstdc++而讓大家換libc++的事情了折砸,這個USE_libstdcpp就是這個意思了:如果cuda版本老(<7.0)并且OSX版本高(>10.8)看疗,就應(yīng)該用libstdc++來兼容cuda。

這里還有一個小插曲:通常執(zhí)行cmake后最前面會輸出它所使用的C睦授、C++編譯器的可執(zhí)行文件完整路徑两芳,然后一個同事的機(jī)器上把CXX環(huán)境變量設(shè)為/usr/bin/gcc,導(dǎo)致編譯.cpp文件時是用CXX這一環(huán)境變量——也就是gcc——來編譯.cpp文件去枷。編譯.cpp怖辆,如果是C++編譯器來編譯,鏈接階段默認(rèn)會把標(biāo)準(zhǔn)庫鏈接進(jìn)去删顶,而現(xiàn)在是C編譯器竖螃,沒有明確指出要鏈接C++標(biāo)準(zhǔn)庫,就會導(dǎo)致鏈接出問題翼闹,雖然他的CMakeLists.txt中曾經(jīng)加入過libstdc++庫斑鼻,但是顯然這很容易翻車,CXX環(huán)境變量不應(yīng)該設(shè)定為/usr/bin/gcc猎荠。


caffe_warnings_disable(CMAKE_CXX_FLAGS -Wno-sign-compare -Wno-uninitialized)

這里添加的編譯器flags坚弱,是用來屏蔽特定類型的警告的蜀备。雖說眼不見心不煩,關(guān)掉后少些warning輸出荒叶,但是0error0warning不應(yīng)該是中級目標(biāo)嗎碾阁?


configure_file(cmake/Templates/caffe_config.h.in "${PROJECT_BINARY_DIR}/caffe_config.h")

這是設(shè)定configure file。configure_file()命令是把輸入文件(第一個參數(shù))里面的一些內(nèi)容做替換(比如${var}@var@替換為具體的值些楣,宏定義等)脂凶,然后放到指定的輸出文件(第二個參數(shù))。其實(shí)還有其他沒有列出的參數(shù)愁茁。

具體說蚕钦,這里生成了build/caffe_config.h,里面define了幾個變量:

image.png


set(Caffe_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
set(Caffe_SRC_DIR ${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_BINARY_DIR})

這里是設(shè)定兩個自定義變量Caffe_INCLUDE_DIRCaffe_SRC_DIR的值鹅很,只不過它倆比較特殊嘶居,想想:如果以后別人find_package(Caffe),其實(shí)就需要其中的Caffe_INCLUDE_DIR的值促煮。anyway邮屁,那些是后續(xù)export命令干的事情,這里忽略菠齿。

這里第三句include_directories()命令佑吝,把build目錄加入到頭文件搜索路徑了,其實(shí)就是為了確保caffe_config.h能被正常include(就一個地方用到它):

image.png


# cuda_compile() does not have per-call dependencies or include pathes
# (cuda_compile() has per-call flags, but we set them here too for clarity)
#
# list(REMOVE_ITEM ...) invocations remove PRIVATE and PUBLIC keywords from collected    definitions and include pathes
if(HAVE_CUDA)
  # pass include pathes to cuda_include_directories()
  set(Caffe_ALL_INCLUDE_DIRS ${Caffe_INCLUDE_DIRS})
  list(REMOVE_ITEM Caffe_ALL_INCLUDE_DIRS PRIVATE PUBLIC)
  cuda_include_directories(${Caffe_INCLUDE_DIR} ${Caffe_SRC_DIR}                         ${Caffe_ALL_INCLUDE_DIRS})

  # add definitions to nvcc flags directly
  set(Caffe_ALL_DEFINITIONS ${Caffe_DEFINITIONS})
  list(REMOVE_ITEM Caffe_ALL_DEFINITIONS PRIVATE PUBLIC)
  list(APPEND CUDA_NVCC_FLAGS ${Caffe_ALL_DEFINITIONS})
endif()

擦亮眼睛:Caffe的cmake腳本中分別定義了Caffe_INCLUDE_DIRCaffe_INCLUDE_DIRS兩個變量绳匀,只相差一個S芋忿,稍不留神容易混掉:不帶S的值是$Caffe_ROOT/include,帶S的值是各個依賴庫的頭文件搜索路徑(在Dependencies.cmake中多次list(APPEND得到的襟士。類似的盗飒,Caffe_DEFINITIONS也是在Dependencies.cmake中設(shè)定的嚷量。

這里判斷出如果有CUDA的話就把Caffe_INCLUDE_DIRS變量中的PUBLICPRIVATE都去掉陋桂,把Caffe_DEFINITIONS中的PUBLICPRIVATE也去掉。

add_definitions()中添加的宏蝶溶,用PUBLIC或PRIVATE修飾嗜历,有什么用?
以及抖所,set()或list(APPEND來設(shè)定梨州、更新的庫名字,用PUBLIC田轧、PRIVATE或INTERFACE修飾暴匠,有什么用?這里比較疑惑傻粘,盡管我找到了stack overflow上的這篇回答每窖,但是仍然一頭霧水:https://stackoverflow.com/questions/26037954/cmake-target-link-libraries-interface-dependencies

anyway帮掉,反正這里最后都做了list(REMOTE_ITEM操作,把PUBLICPRIVATE去掉了窒典。


add_subdirectory(src/gtest)
add_subdirectory(src/caffe)
add_subdirectory(tools)
add_subdirectory(examples)
add_subdirectory(python)
add_subdirectory(matlab)
add_subdirectory(docs)

使用add_subdirectory()蟆炊,意思是說把子目錄中的CMakeLists.txt文件加載過來執(zhí)行,從這個角度看似乎等同于include()命令瀑志。實(shí)則不然涩搓,因?yàn)樗税唇o定目錄名字后需要追加"/CMakeLists.txt"來構(gòu)成完整路徑外,往往都是包含一個target(類似于git中的submodule了)劈猪,同時還可以設(shè)定別的一些參數(shù):

  • 指定binary_dir
  • 設(shè)定EXCLUDE_FROM_ALL昧甘,也就是”搞一個獨(dú)立的子工程“,此時需要有project()指令战得,并且不被包含在生成的.sln工程的ALL目標(biāo)中疾层,需要單獨(dú)構(gòu)建。

粗略看看各個子目錄都是做什么的:

  • src/gtest贡避,googletest的源碼
  • src/caffe痛黎,caffe的源碼構(gòu)建,因?yàn)榍懊孀隽撕芏嗖僮鳎ㄒ蕾噹旃伟伞⒙窂胶ィ琫tc),這里寫的就比較少杀捻。任務(wù)只有2個:構(gòu)建一個叫做caffe的庫井厌,以及test
  • tools致讥,這一子目錄下每一個cpp文件都生成一個xxx.bin的目標(biāo)仅仆,而最常用的就是caffe訓(xùn)練接口build/caffe這個可執(zhí)行文件了。
  • examples垢袱,這一子目錄下有cpp_classification的C++代碼墓拜,以及mnist,cifar10请契,siamse這三個例子的數(shù)據(jù)轉(zhuǎn)換的代碼咳榜,這四個都是C++文件,每一個都被編譯出一個可執(zhí)行
  • python爽锥,pycaffe接口涌韩,python/caffe/_caffe.cpp編譯出動態(tài)庫
  • matlab,matlab接口氯夷,./+caffe/private/caffe_.cpp編譯出臣樱?編譯出一個定制的目標(biāo),至于是啥類型,也許是動態(tài)庫吧雇毫,玩過matlab和C/C++混編的都知道奢啥,用mex編譯C/C++為.mexa文件,然后matlab調(diào)用.mexa文件嘴拢,其實(shí)就是動態(tài)庫
  • docs桩盲,文檔,doxygen席吴、jekyll都來了赌结,以及拷貝每一個.ipynb文件。沒錯孝冒,add_custom_command()能定制各種target柬姚,只要你把想要執(zhí)行的shell腳本命令用cmake的語法來寫就可以了,很強(qiáng)大庄涡。

add_custom_target(lint COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/lint.cmake)

這里依然是定制的target量承,具體看來是調(diào)用scripts/cpplint.py(谷歌官方C++代碼風(fēng)格檢查工具)來執(zhí)行代碼風(fēng)格檢查。(個人覺得G家的C++風(fēng)格有一點(diǎn)不太好:縮進(jìn)兩個空格太少了穴店,費(fèi)眼睛撕捍,強(qiáng)烈建議和Visual Studio保持一致,用tab并且tab寬度為4個空格)泣洞。

所謂linter就是語法檢查器忧风,除了cpplint其實(shí)還可以用cpp_checkgcc球凰、clang等狮腿,我的vim中配置的就是用cpp_checkgcc,不妨試試:https://github.com/zchrissirhcz/dotvim


if(BUILD_python)
  add_custom_target(pytest COMMAND python${python_version} -m unittest discover -s caffe/test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/python )
  add_dependencies(pytest pycaffe)
endif()

如果開啟了BUILD_python開關(guān)呕诉,那么執(zhí)行一個定制的target(執(zhí)行pytest)缘厢。
add_dependencies()意思是指定依賴關(guān)系,這里要求pycaffe目標(biāo)完成后再執(zhí)行pytest目標(biāo)甩挫,因?yàn)?code>pytest需要用到pycaffe生成的caffe模塊贴硫。pycaffe在前面提到的add_subdirectory(python)中被構(gòu)建。


configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Uninstall.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/cmake/Uninstall.cmake
    IMMEDIATE @ONLY)

add_custom_target(uninstall
    COMMAND ${CMAKE_COMMAND} -P
    ${CMAKE_CURRENT_BINARY_DIR}/cmake/Uninstall.cmake)

這里是添加”uninstall"這一target捶闸,具體定制的target其實(shí)就是執(zhí)行cmake/Uninstall.cmake腳本夜畴。這個腳本根據(jù)cmake/Uninstall.cmake.in做變量取值替換等來生成得到拖刃。


# ---[ Configuration summary
caffe_print_configuration_summary()

# ---[ Export configs generation
caffe_generate_export_configs()

在Caffe根目錄的CMakeLists.txt的最后删壮,是打印各種配置的總的情況,以及輸出各種配置(后者其實(shí)包含了install()指令的調(diào)用)

(2019-03-03 00:31:09 本篇寫之前覺得不難兑牡,但是斷斷續(xù)續(xù)分析下來竟然用了大半天時間央碟,對于CMake的一些指令細(xì)節(jié)重新查過,發(fā)現(xiàn)之前的掌握確實(shí)還不夠)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市亿虽,隨后出現(xiàn)的幾起案子菱涤,更是在濱河造成了極大的恐慌,老刑警劉巖洛勉,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粘秆,死亡現(xiàn)場離奇詭異,居然都是意外死亡收毫,警方通過查閱死者的電腦和手機(jī)攻走,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來此再,“玉大人昔搂,你說我怎么就攤上這事∈淠矗” “怎么了摘符?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長策吠。 經(jīng)常有香客問我逛裤,道長,這世上最難降的妖魔是什么猴抹? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任别凹,我火速辦了婚禮,結(jié)果婚禮上洽糟,老公的妹妹穿的比我還像新娘炉菲。我一直安慰自己,他們只是感情好坤溃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布拍霜。 她就那樣靜靜地躺著,像睡著了一般薪介。 火紅的嫁衣襯著肌膚如雪祠饺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天汁政,我揣著相機(jī)與錄音道偷,去河邊找鬼。 笑死记劈,一個胖子當(dāng)著我的面吹牛勺鸦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播目木,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼换途,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起军拟,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤剃执,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后懈息,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肾档,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年辫继,在試婚紗的時候發(fā)現(xiàn)自己被綠了阁最。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡骇两,死狀恐怖速种,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情低千,我是刑警寧澤配阵,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站示血,受9級特大地震影響棋傍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜难审,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一瘫拣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧告喊,春花似錦麸拄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至秆吵,卻和暖如春淮椰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背纳寂。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工主穗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毙芜。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓忽媒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親爷肝。 傳聞我的和親對象是個殘疾皇子猾浦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容