天天看點

CMakeList.txt編寫踩坑記錄

target_link_libraries中PRIVATE/PUBLIC/INTERFACE的了解

cmake-target-include-directories-meaning-of-scope

specification-and-usage-requirements

Generally, a dependency should be specified in a use of target_link_libraries() with the PRIVATE keyword if it is used by only the implementation of a library, and not in the header files. If a dependency is additionally used in the header files of a library (e.g. for class inheritance), then it should be specified as a PUBLIC dependency. A dependency which is not used by the implementation of a library, but only by its headers should be specified as an INTERFACE dependency.

add_dependencies的基本作用

假設我們需要生成一個可執行檔案,該檔案生成需要連結a.so b.so c.so d.so四個動态庫

正常來講,我們一把隻需要以下兩條指令即可:

ADD_EXECUTABLE(main main.cpp)
TARGET_LINK_LIBRARIES(main a.so b.so c.so d.so)
           
但是編譯的時候報錯,一些符号的定義找不到,而這些符号恰恰就在這幾個庫中,假設在a.so 和 b.so中,在上述兩條指令之間加上一條指令即可編譯通過:
ADD_DEPENDENCIES(main a.so b.so)
           

原因比較簡單,生成main需要依賴a.so和b.so中的符号定義,然而a.so和b.so庫的生成是在main編譯生産之後的,添加這條語句就是提醒編譯器需要先生成main的依賴(a.so,b.so),然後再去生成main.

include_directories與target_include_directories的差別

what-is-the-difference-between-include-directories-and-target-include-directorie

可以認為一個是全局的,一個是針對于指定target的

cmake find_package的了解

對于找不到包的情況,如果用的是CMAKE-GUI,則會提示設定對應的DIR,或者手動在CMakeLists.txt中添加。可以參考這個連結和這個cmake find_package找不到opencv

當執行find_package()這條指令後,Cmake 就會從某些路徑中找這Findxxx.cmake檔案或者xxxConfig.cmake檔案,Cmake找到任意一個之後就會執行這個檔案,然後這個檔案執行後就會設定好一些Cmake變量。比如下面的變量(NAME表示庫的名字 比如可以用Opencv 代表Opencv庫)

<NAME>_FOUND
<NAME>_INCLUDE_DIRS or <NAME>_INCLUDES
<NAME>_LIBRARIES or <NAME>_LIBRARIES or <NAME>_LIBS
<NAME>_DEFINITIONS
           

“輕松搞定CMake”系列之find_package用法詳解

這裡面能看到怎麼在cmake中輸出變量的值

https://blog.csdn.net/zhanghm1995/article/details/105466372

常用變量和常用環境變量的引用

一、變量的引用方式是使用“ ” , 在 I F 中 , 不 需 要 使 用 這 種 方 式 , 直 接 使 用 變 量 名 即 可 二 、 自 定 義 變 量 使 用 S E T ( O B J N A M E x x x x ) , 使 用 時 {}”,在IF中,不需要使用這種方式,直接使用變量名即可 二、自定義變量使用SET(OBJ_NAME xxxx),使用時 ”,在IF中,不需要使用這種方式,直接使用變量名即可二、自定義變量使用SET(OBJN​AMExxxx),使用時{OBJ_NAME}

三、cmake的常用變量:

CMAKE_BINARY_DIR, PROJECT_BINARY_DIR :這兩個變量内容一緻,如果是内部編譯,就指的是工程的頂級目錄,如果是外部編譯,指的就是工程編譯發生的目錄。

CMAKE_SOURCE_DIR, PROJECT_SOURCE_DIR:這兩個變量内容一緻,都指的是工程的頂級目錄。

CMAKE_CURRENT_BINARY_DIR:外部編譯時,指的是target目錄,内部編譯時,指的是頂級目錄

CMAKE_CURRENT_SOURCE_DIR:CMakeList.txt所在的目錄

CMAKE_CURRENT_LIST_DIR:CMakeList.txt的完整路徑

CMAKE_CURRENT_LIST_LINE:目前所在的行

CMAKE_MODULE_PATH:如果工程複雜,可能需要編寫一些cmake子產品,這裡通過SET指定這個變量

LIBRARY_OUTPUT_DIR, BINARY_OUTPUT_DIR:庫和可執行的最終存放目錄

PROJECT_NAME, CMAKE_PROJECT_NAME:前者是目前CMakeList.txt裡設定的project_name,後者是整個項目配置的project_name

cmake中調用環境變量
Using $ENV{NAME} : 調用系統環境變量,我們也可以使用 "SET(ENV{NAME} value)".  需要注意的是這裡"ENV"沒有"$".

CMAKE_INCLUDE_CURRENT_DIR 等同于 INCLUDE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
           
其他的内置變量
  • BUILD_SHARED_LIBS: set the default value when using ADD_LIBRARY()
  • CMAKE_C_FLAGS: set compiler for c language
  • CMAKE_CXX_FLAGS: set compiler for c++ language
區分debug和release

在工程build目錄下執行

cmake .. -DCMAKE_BUILD_TYPE=DEBUG|RELEASE

,再執行make, 或者在頂級CMakeList.txt裡加入:

set(CMAKE_BUILD_TYPE Debug|Release|MinSizeRel|RelWithDebInfo)

指定編譯32bit或64bit程式

SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")

通過cmake列印能擷取到的所有系統環境變量
# 在CMakeList.txt中使用
execute_process(
  COMMAND ${CMAKE_COMMAND} -E environment
)
           
# 在終端中使用
cmake -E environment
           
設定install路徑
// 指令行裡設定
cmake -DCMAKE_INSTALL_PREFIX=<install_path>

// 或者在根cmake裡設定
SET(CMAKE_INSTALL_PREFIX <install_path>)
           

預設安裝路徑是/usr/local

擷取絕對路徑和父目錄
# 擷取檔案絕對路徑
get_filename_component(FULL_NAME "${FILE}" ABSOLUTE)

# 擷取檔案父路徑
get_filename_component(PARENT_DIR "${FULL_NAME}" PATH)
           
判斷作業系統平台及Win是否為32位
if(CMAKE_SYSTEM_NAME MATCHES "Linux")  // 注意區分大寫
  message(STATUS "Linux platorm!")
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
if(CMAKE_CL_64)
  message(STATUS "Windows Win64 platform!")
  else()
    message(STATUS "Windows Win32 platform!")
  endif(CMAKE_CL_64)
elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
  message(STATUS "FreeBSD platform!")
else()
  message(STATUS "other platform!")
endif(CMAKE_SYSTEM_NAME MATCHES "Linux")
           

生成器表達式(generator expressions)

在寫CMakeList.txt時,如何列印生成器表達式的值?

生成器表達式的值是在編譯時确定的。如果一定要這麼做,可以參考編寫以下指令:

add_custom_command(TARGET yourtarget POST_BUILD 
COMMAND ${CMAKE_COMMAND} -E echo "value = $<TARGET_FILE_DIR:yourtarget>")
           

cmake的add_custom_command和add_custom_target指令

連結