預(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_DIR
和PROJECT_BINARY_DIR
的解釋很晦澀:
image.png
自行實(shí)踐驗(yàn)證下:
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)的取值(布爾類型的變量,利用if
和else
來判斷)茅茂,編寫各自的構(gòu)建規(guī)則捏萍。
其中caffe_option()
是cmake/Utils.cmake
中定義的,它相比于cmake自帶的option()
命令空闲,增加了可選的條件控制字段:
caffe_option()
的具體實(shí)現(xiàn)還沒有看懂令杈,不過看一下所有用到的地方也都是很直觀的:
具體的說,這里就是設(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):
-
find_package(Xxx)
如果執(zhí)行成功担平,則提供相應(yīng)的Xxx_INCLUDE_DIR
示绊、Xxx_LIBRARY_DIR
等變量,看起來挺方便暂论,但其實(shí)并不是所有的庫都提供了同樣的變量后綴耻台,其實(shí)都是由庫的官方作者或第三方提供的xxx.cmake等腳本來得到的,依賴于生態(tài)空另。 -
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
中:
可以看到哮肚,如果是編共享庫(動態(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++
:
這時候想起來還沒畢業(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了幾個變量:
set(Caffe_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
set(Caffe_SRC_DIR ${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_BINARY_DIR})
這里是設(shè)定兩個自定義變量Caffe_INCLUDE_DIR
和Caffe_SRC_DIR
的值鹅很,只不過它倆比較特殊嘶居,想想:如果以后別人find_package(Caffe)
,其實(shí)就需要其中的Caffe_INCLUDE_DIR
的值促煮。anyway邮屁,那些是后續(xù)export
命令干的事情,這里忽略菠齿。
這里第三句include_directories()
命令佑吝,把build
目錄加入到頭文件搜索路徑了,其實(shí)就是為了確保caffe_config.h
能被正常include(就一個地方用到它):
# 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_DIR
和Caffe_INCLUDE_DIRS
兩個變量绳匀,只相差一個S
芋忿,稍不留神容易混掉:不帶S的值是$Caffe_ROOT/include
,帶S的值是各個依賴庫的頭文件搜索路徑(在Dependencies.cmake
中多次list(APPEND
得到的襟士。類似的盗飒,Caffe_DEFINITIONS
也是在Dependencies.cmake
中設(shè)定的嚷量。
這里判斷出如果有CUDA的話就把Caffe_INCLUDE_DIRS
變量中的PUBLIC
和PRIVATE
都去掉陋桂,把Caffe_DEFINITIONS
中的PUBLIC
和PRIVATE
也去掉。
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
操作,把PUBLIC
和PRIVATE
去掉了窒典。
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_check
、gcc
球凰、clang
等狮腿,我的vim中配置的就是用cpp_check
和gcc
,不妨試試: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í)還不夠)