Cmake常见指令介绍

433 阅读2分钟

一:常见指令及其解析

Cmake语法常见命令及作用

设置工程名字,message编译打印
set(LIB_NAME AudioJniEnv)
MESSAGE("load ${LIB_NAME}")
设置环境使用的环境是C++ 11
set(CMAKE_CXX_STANDARD 11)
#递归调用执行 test目录下的 cmakelist的文件进行编译
add_subdirectory(test)

将当前目录下面的文件全部添加到 某一个变量中,后续对此变量可以循环遍历或者直接增加到可执行文件中,但是注意如果目录线面有文件夹,不会到文件夹中进行进行遍历,如果需要对文件夹中也进行遍历,需要使用file命令

# 指定当前目录下面的文件到TEST_SRC_LIST 变量中
aux_source_directory(. TEST_SRC_LIST)

get_filename_component 此用法 后面的指令集有多种,具体如下

  • DICECTORY:没有文件名的目录,路径返回时带有正斜杠,并且没有尾部斜杠。
  • NAME:不带名录的文件名
  • EXT:文件名的最长扩展名
  • NAME_WE:不带目录或最长扩展名的文件名
  • LAST_EXT:文件名的最后扩展名
  • NAME_WLE:文件目录或最后扩展名的文件名
  • PATH:DIRECTORY的就别名(cmake <= 2.8.11)
#获取文件TEST_SRC 代表的文件,并且重命名为 TEST_EXE,且对${TEST_SRC} 此文件进行截取能采用NAME_WE 的方式,即 获取文件的名字,不包括扩展名
get_filename_component(TEST_EXE  ${TEST_SRC} NAME_WE)
#为当前指定的 target 添加编译选项 
target_compile_options(${TEST_EXE}
            PRIVATE ${COMPILE_OPTIONS_DEFAULT})
target_compile_definitions(${TEST_EXE} PRIVATE ${MK_COMPILE_DEFINITIONS})
设置头文件
include_directories(${FFMPEG_DIR}/include/)
//指定目录下的源文件设添加到指定目录下
aux_source_directory( . TEST_SRC_LIST)
#动态库地址, 会将目录下的so 加载进入当前项目依赖
link_directories(${FFMPEG_DIR}/lib)
MESSAGE("link_dir ${FFMPEG_DIR}/lib")
# 最后生成可执行文件时间 连接的动态库,用于本项目写的代码最后生成可执行文件时,连接使用
target_link_libraries(
        ${LIB_NAME}
        avcodec
        avfilter
        avformat
        avutil
        swresample
        swscale
)

编译结果:

C++文件编译结果只会有 动态库/静态库 和 可行行文件 2类,主要为以下的2个命令

#编译为动态库
add_library(
            ${LIB_NAME}
            SHARED
             ${SOURCES}
            ${SOURCELIST}
        )
#编译为可执行文件
add_executable(AudioJniEnv main.cpp)

在编译时会需要将源文件添加到可执行文件/静态库中 ,可使用下面命令

递归搜索全部文件夹,并将匹配到表达式的 文件 添加到变量 SOURCES 中
FILE(GLOB_RECURSE SOURCES
        "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c"
        "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc"
        "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h"
        )
        
#将 所有的源文件打包到 静态库中
add_library(
            ${LIB_NAME}
            SHARED
             ${SOURCES}
            ${SOURCELIST}
)
​

循环foreach用法

#循环执行针对 ${TEST_SRC_LIST} 中的每一个文件进行
foreach(TEST_SRC ${TEST_SRC_LIST})
   
   if(CMAKE_SYSTEM_NAME MATCHES "Linux")
        target_link_libraries( ${TEST_EXE} -Wl,--start-group ${MK_SELF_LINK_LIBRARIES} -Wl,--end-group )
    else()
        target_link_libraries(${TEST_EXE} ${MK_SELF_LINK_LIBRARIES})
    endif()
    
endforeach()

list 功能 主要有

read 功能有

LENGTH   
GET
JOIN
SUBLIST

Search 功能

find

modification

APPEND
FILTER
INSTERT
POP_BACK
等

ordering

reverse
Sort
# 将LIB_NAME 添加到 MK_SELF_LINK_LIBRARIES这个变量下面
list(APPEND MK_SELF_LINK_LIBRARIES ${LIB_NAME} )
message( STATUS "MK_SELF_LINK_LIBRARIES : ${MK_SELF_LINK_LIBRARIES}")
#在将 MK_SELF_LINK_LIBRARIES 连接到TEST_EXE这,相当于把外面主工程的依赖 增加到 test 文件夹下面
target_link_libraries(${TEST_EXE} ${MK_SELF_LINK_LIBRARIES})

Function 功能

#定义函数 update_cached_list 参数为 name 
function(update_cached_list name)
  set(_tmp_list "${${name}}")
  list(APPEND _tmp_list "${ARGN}")
  list(REMOVE_DUPLICATES _tmp_list)
  update_cached(${name} "${_tmp_list}")
endfunction()
#使用函数 
 if(PKG_CONFIG_FOUND)
    pkg_check_modules(AVUTIL QUIET IMPORTED_TARGET libavutil)
    if(AVUTIL_FOUND)
      update_cached_list(MK_LINK_LIBRARIES PkgConfig::AVUTIL)
      message(STATUS "found library: ${AVUTIL_LIBRARIES}")
    endif()
  endif()
​

二:常见功能指令

代码中经常遇到需要ffmpeg功能,因此需要将ffmpeg 功能导入到系统依赖中,此处给出2种方式

#方式1:通过pkg_config配置
#指定通过pkgconfig 来执行寻找头文件和依赖的库文件 使用宏开关
option(ENABLE_FFMPEG_PKG_CONFIG "Enable FFmpeg" ON)
​
#指定2个函数,更新库文件和库的头文件
FUNCTION(update_cache name value)
        set("${name}" "${value}" CACHE INTERNAL "*** Internal ***" FORCE)
endfunction()
​
FUNCTION(update_lib_path name)
   set(_tem_list "${${name}}")
   list(APPEND _tem_list "${ARGN}")
   list(REMOVE_DUPLICATES _tem_list)
   update_cache("${name}" "${_tem_list}")
endfunction()
​
#设置全局变量 MK_LINK_LIBRARIES
update_cache(MK_LINK_LIBRARIES "")
​
#查找ffmpeg的全局头文件和依赖库位置
if (ENABLE_FFMPEG_PKG_CONFIG)
    message(STATUS "ENABLE_FFMPEG_PKG_CONFIG")
    find_package(PkgConfig QUIET)
​
    message(STATUS "PkConfig QUIET end")
        if(PKG_CONFIG_FOUND)
                pkg_check_modules(AVUTIL QUIET IMPORTED_TARGET libavutil)
                message(STATUS "PKG_CONFIG_FOUND")
            if (AVUTIL_FOUND)
                update_lib_path(MK_LINK_LIBRARIES PkgConfig::AVUTIL)
                message(STATUS "found library: ${AVUTIL_LIBRARIES}")
            endif ()
        endif()
​
    # 查找 ffmpeg/libavcodec 是否安装
    if(PKG_CONFIG_FOUND)
        pkg_check_modules(AVCODEC QUIET IMPORTED_TARGET libavcodec)
        message(STATUS "PKG_CONFIG_FOUND")
        if(AVCODEC_FOUND)
            update_lib_path(MK_LINK_LIBRARIES PkgConfig::AVCODEC)
            message(STATUS "found library: ${AVCODEC_LIBRARIES}")
        endif()
    endif()
​
​
    # 查找 ffmpeg/libswscale 是否安装
    if(PKG_CONFIG_FOUND)
        pkg_check_modules(SWSCALE QUIET IMPORTED_TARGET libswscale)
        if(SWSCALE_FOUND)
#            include_directories(SYSTEM ${SWSCALE_INCLUDE_DIR})
            update_lib_path(MK_LINK_LIBRARIES PkgConfig::SWSCALE)
            message(STATUS "found library: ${SWSCALE_LIBRARIES}")
        endif()
    endif()
​
    # 查找 ffmpeg/libswresample 是否安装
    if(PKG_CONFIG_FOUND)
        pkg_check_modules(SWRESAMPLE QUIET IMPORTED_TARGET libswresample )
        if(SWRESAMPLE_FOUND)
#            include_directories(SYSTEM ${SWRESAMPLE_INCLUDE_DIRS})
            update_lib_path(MK_LINK_LIBRARIES PkgConfig::SWRESAMPLE)
            message(STATUS "found library: ${SWRESAMPLE_LIBRARIES}")
        endif()
    endif()
​
     # 查找 ffmpeg/libavformat 是否安装
    if(PKG_CONFIG_FOUND)
        pkg_check_modules(AVFORMAT QUIET IMPORTED_TARGET libavformat)
        if(AVFORMAT_FOUND)
            update_lib_path(MK_LINK_LIBRARIES PkgConfig::AVFORMAT)
            message(STATUS "found library: ${AVFORMAT_LIBRARIES}")
        else ()
            message(STATUS "not found library avformat")
        endif()
    endif()
​
endif ()
​
#指定连接库位置
if(  ENABLE_FFMPEG_PKG_CONFIG)
    message(STATUS "target_link_libraries MK_LINK_LIBRARIES IS  ${MK_LINK_LIBRARIES}")
​
    target_link_libraries( ${LIB_NAME}
            ${MK_LINK_LIBRARIES}
            )
endif()
​
#方式2 直接指定系统中的ffmpeg的当前位置
#指定ffmpeg的绝对路径,并通过ENABLE_FFMPEG_FIXED_PATH宏开关控制
option(ENABLE_FFMPEG_FIXED_PATH "ENABLE_FFMPEG_FIXED_PATH" OFF)
​
​
if (ENABLE_FFMPEG_FIXED_PATH)
    # FFmpeg的安装目录,可以通过命令"brew info ffmpeg"获取
    set(FFMPEG_DIR /opt/homebrew/Cellar/ffmpeg/6.0_1)
    MESSAGE("FFMPEG_DIR ${FFMPEG_DIR}")
​
    #头文件
    include_directories(${FFMPEG_DIR}/include/)
    MESSAGE("include_dir ${FFMPEG_DIR}/include")
​
​
    #动态库地址
    link_directories(${FFMPEG_DIR}/lib)
    MESSAGE("link_dir ${FFMPEG_DIR}/lib")
endif ()
​
#此处省略 add_library 或者 add_executable
# add_library(${LIB_NAME} SHARED ${SOURCES} )
        
#手动指定连接地址
if(ENABLE_FFMPEG_FIXED_PATH)
    message(STATUS "target_link_libraries ")
    target_link_libraries( ${LIB_NAME}
                    avcodec
                    avfilter
                    avformat
                    avutil
                    swresample
                    swscale
            )
endif()
#判断当前CPU类型
if(${CMAKE_ANDROID_ARCH_ABI} MATCHES "armeabi-v7a")
    include_directories(include/armeabi-v7a)
    message("This is armeabi-v7a")
elseif(${CMAKE_ANDROID_ARCH_ABI} MATCHES "arm64-v8a")
    include_directories(include/arm64-v8a)
    message("This is arm64-v8a")
endif()
​
#将mp3lame库动态库导入,且指定库的位置 在Android中指定
add_library( mp3lame
             SHARED
             IMPORTED )
set_target_properties( mp3lame
            PROPERTIES IMPORTED_LOCATION
            ../../../../libs/${CMAKE_ANDROID_ARCH_ABI}/libmp3lame.so )