cmake构建系统初初探

官方网站

www.cmake.org

源码包下载地址:http://www.cmake.org/cmake/resources/software.html

Wiki:https://gitlab.kitware.com/cmake/community/-/wikis/home

特点

优点:

  • 开源代码,使用类BSD许可发布
  • 跨平台,并可以生成native编译配置文件,在linux/Unix平台,生成makefile,在苹果平台可以生成Xcode,在windows平台,可以生成MSVC的工程文件
  • 能够管理大型项目
  • 简化编译构建过程和编译过程,cmake的工具链:cmake+make,cmake+ninja
  • 高效率,因为cmake在工具链中没有libtool
  • 可扩展,可以为cmake编写特定功能的模块,扩展cmake功能

缺点:

  • cmake只是看起来比较简单,使用并不简单
  • 每个项目使用一个CMakeLists.txt(每个目录一个),使用的是cmake语法
  • cmake跟已有体系配合不是特别的理想,比如pkgconfig

安装

ubuntu下:

sudo apt install -y cmake

如何编译一个项目?

编译方式

内部编译

在当前目录进行编译,无须建立build目录。但是,这种做法会将所有生成的中间文件和源代码混在一起,而且cmake生成的makefile无法跟踪所有的中间文件,即无法使用”make distclean”命令将所有的中间文件删除

外部编译

建立build目录进行编译,所有的中间文件都会生成在build目录下,需要删除时直接清空该目录即可。这就是所谓的外部编译方式

以mjpeg-streamer为例说明:

代码组成如下:

fuqiang@ubuntu:~/workspace/mjpg-streamer/mjpg-streamer-experimental$ tree -L 1
.
├── cmake
├── CMakeLists.txt
├── Dockerfile
├── docker-start.sh
├── LICENSE
├── makedeb.sh
├── Makefile
├── mjpg_streamer.c
├── mjpg_streamer.h
├── mjpg_streamer@.service
├── plugins
├── postinstall.sh
├── README.md
├── scripts
├── start.sh
├── TODO
├── utils.c
├── utils.h
└── www

4 directories, 15 files

代码中不仅有CMakeLists.txt,还有Makefile,所有它可以使用2种方式进行构建,我们这里只看通过CMakeLists.txt的构建方式

执行如下命令:

mkdir out
cd out
cmake ..

out目录下生成如下内容,主要是Makefile:

fuqiang@ubuntu:~/workspace/mjpg-streamer/mjpg-streamer-experimental/out$ tree -L 1
.
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── Makefile
└── plugins

2 directories, 3 files


fuqiang@ubuntu:~/workspace/mjpg-streamer/mjpg-streamer-experimental/out$ find . -name Makefile
./Makefile
./plugins/input_opencv/Makefile
./plugins/output_http/Makefile
./plugins/input_file/Makefile
./plugins/output_viewer/Makefile
./plugins/output_rtsp/Makefile
./plugins/output_zmqserver/Makefile
./plugins/input_ptp2/Makefile
./plugins/output_udp/Makefile
./plugins/input_uvc/Makefile
./plugins/input_http/Makefile
./plugins/output_file/Makefile
./plugins/input_raspicam/Makefile

继续编译,会生成动态库和执行程序:

make

安装:

sudo make install

如何编写CMakeLists.txt?

常用基本命令扫盲

  • cmake_minimum_required (VERSION 3.14.1) : 指定所需cmake的最小版本
  • project(demo C) : 项目名称,这个会影响PROJECT_SOURCE_DIR
  • add_executable(main main.c) : 最终要生成的elf文件的名字叫main,使用的源文件是main.c
  • add_executable(main main.c testFunc.c):最终要生成的elf文件的名字叫main,使用的源文件是main.c和testFunc.c
  • aux_source_directory(. SRC_LIST) add_executable(main ${SRC_LIST}) : 使用aux_source_directory把当前目录下的源文件存列表存放到变量SRC_LIST里,然后在add_executable里调用SRC_LIST(注意调用变量时的写法)
  • set( SRC_LIST ./main.c ./testFunc1.c ./testFunc.c) add_executable(main ${SRC_LIST}) : aux_source_directory()也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用set命令去新建变量来存放需要的源文件
  • include_directories (test_func test_func1) : 向工程添加多个指定头文件的搜索路径,路径之间用空格分隔
  • add_subdirectory (src) : 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置
  • set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) : 命令set,是用于定义变量的,EXECUTABLE_OUT_PATH和PROJECT_SOURCE_DIR是CMake自带的预定义变量
  • EXECUTABLE_OUTPUT_PATH :目标二进制可执行文件的存放位置
  • PROJECT_SOURCE_DIR:工程的根目录
  • add_library (testFunc_shared SHARED ${SRC_LIST}) add_library (testFunc_static STATIC ${SRC_LIST}):生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件)
  • set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc") set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc") : 设置最终生成的库的名称,还有其它功能,如设置库的版本号等
  • find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib) : 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径
  • target_link_libraries (main ${TESTFUNC_LIB}) : 把目标文件与库文件进行链接
  • add_compile_options(-std=c++11 -Wall) : 添加编译选项
  • option(MYDEBUG "enable debug compilation" OFF) if (MYDEBUG) add_executable(main2 main2.c) else() message(STATUS "Currently is not in debug mode") endif() : 使用了if-else来根据option来决定是否编译main2.c , cmake .. -DMYDEBUG=ON

常用变量

  • CMAKE_C_FLAGS : 指定gcc编译选项,如-02 ,-g,当然也可用通过add_definitions设置
  • CMAKE_CXX_FLAGS:指定g++编译选项
  • CMAKE_C_FLAGS_DEBUG:指定debug版本编译选项
  • CMAKE_EXE_LINKER_FLAGS,CMAKE_MODILE_LINKER_FLAGS,CMAKE_SHARED_LINKER_FLAGS,CMAKE_STATIC_LINKER_FLAGS:指定链接选项
  • CMAKE_C_COMPILER : 指定C编译器,如gcc
  • CMAKE_CXX_COMPILER : 指定C++编译器,如g++
  • BUILD_SHARED_LIBS : 指定默认生成库文件类型,on:动态库,off 静态
  • CMAKE_BUILD_TYPE : 设置编译类型,如Debug、Release
  • LIBRARY_OUTPUT_PATH : 库文件的默认输出路径,这里设置为工程目录下的lib目录
  • CMAKE_CURRENT_BINARY_DIR :用于指定当前的二进制文件生成路径
  • CMAKE_CURRENT_SOURCE_DIR:指定当前CMAKEFILE文件所在目录
  • PROJECT_SOURCE_DIR 工程顶层目录,也就是顶层 CMakeLists.txt 源码所在目录
  • PROJECT_BINARY_DIR 工 程 BINARY_DIR , 也 就 是 顶 层 CMakeLists.txt 源 码 的BINARY_DIRCMAKE_SOURCE_DIR 与 PROJECT_SOURCE_DIR 等价
  • CMAKE_BINARY_DIR 与 PROJECT_BINARY_DIR 等价
  • CMAKE_CURRENT_SOURCE_DIR 当前源码所在路径
  • CMAKE_CURRENT_BINARY_DIR 当前源码的 BINARY_DIR
  • CMAKE_MAJOR_VERSION cmake 的主版本号
  • CMAKE_MINOR_VERSION cmake 的次版本号
  • CMAKE_VERSION cmake 的版本号(主+次+修订)
  • PROJECT_VERSION_MAJOR 工程的主版本号
  • PROJECT_VERSION_MINOR 工程的次版本号
  • PROJECT_VERSION 工程的版本号
  • CMAKE_PROJECT_NAME 工程的名字
  • PROJECT_NAME 工程名,与 CMAKE_PROJECT_NAME 等价
  • BUILD_SHARED_LIBS 控制 cmake 是否生成动态库
  • CMAKE_BUILD_TYPE 指定工程的构建类型, release 或 debug
  • CMAKE_SYSROOT 对应编译器的在–sysroot 选项
  • CMAKE_IGNORE_PATH 设置被 find_xxx 命令忽略的目录列表
  • CMAKE_INCLUDE_PATH 为 find_file()和 find_path()命令指定搜索路径的目录列表CMAKE_INCLUDE_DIRECTORIES_BEFORE 用于控制 include_directories()命令的行为
  • CMAKE_LIBRARY_PATH 指定 find_library()命令的搜索路径的目录列表
  • CMAKE_MODULE_PATH 指定要由 include()或 find_package()命令加载的CMake 模块的搜索路径的目录列表
  • CMAKE_PROGRAM_PATH 指定 find_program()命令的搜索路径的目录列表
  • CMAKE_HOST_SYSTEM_NAME 运行 cmake 的操作系统的名称(其实就是 uname -s)CMAKE_HOST_SYSTEM_PROCESSOR 运行 cmake 的操作系统的处理器名称(uname -p)
  • CMAKE_HOST_SYSTEM 运行 cmake 的操作系统(复合信息)
  • CMAKE_HOST_SYSTEM_VERSION 运行 cmake 的操作系统的版本号(uname -r)
  • CMAKE_HOST_UNIX 如果运行 cmake 的操作系统是 UNIX 和类 UNIX,则该变量为 true,否则是空值
  • CMAKE_HOST_WIN32 如果运行 cmake 的操作系统是 Windows,则该变量为 true,否则是空值
  • CMAKE_SYSTEM_NAME 目标主机操作系统的名称
  • CMAKE_SYSTEM_PROCESSOR 目标主机的处理器名称
  • CMAKE_SYSTEM 目标主机的操作系统(复合信息)
  • CMAKE_SYSTEM_VERSION 目标主机操作系统的版本号
  • ENV 用于访问环境变量
  • UNIX 与 CMAKE_HOST_UNIX 等价
  • WIN32 与 CMAKE_HOST_WIN32 等价

寻找外部模块

在开发软件的时候我们会用到一些函数库,这些函数库在不同的系统中安装的位置可能不同,编译的时候需要首先找到这些软件包的头文件以及链接库所在的目录以便生成编译选项。例如一个需要使用博克利数据库项目,需要头文件db_cxx.h 和链接库 libdb_cxx.so ,现在该项目中有一个源代码文件 main.cpp ,放在项目的根目录中

第一步 程序库说明文件

在项目的根目录中创建目录 cmake/modules/ ,在 cmake/modules/ 下创建文件 Findlibdb_cxx.cmake ,内容如下:

 MESSAGE(STATUS "Using bundled Findlibdb.cmake...")
 FIND_PATH(
   LIBDB_CXX_INCLUDE_DIR
   db_cxx.h 
   /usr/include/ 
   /usr/local/include/ 
   )
 
 FIND_LIBRARY(
   LIBDB_CXX_LIBRARIES NAMES  db_cxx
   PATHS /usr/lib/ /usr/local/lib/
   )

文件 Findlibdb_cxx.cmake 的命名要符合规范: FindlibNAME.cmake ,其中NAME 是函数库的名称。Findlibdb_cxx.cmake 的语法与 CMakeLists.txt 相同。这里使用了三个命令: MESSAGE , FIND_PATH 和 FIND_LIBRARY

  • 命令 FIND_PATH 指明头文件查找的路径,原型如下:find_path( name1 [path1 path2 …]) 该命令在参数 path* 指示的目录中查找文件 name1 并将查找到的路径保存在变量 VAR中。清单5第3-8行的意思是在 /usr/include/ 和 /usr/local/include/ 中查找文件db_cxx.h ,并将db_cxx.h 所在的路径保存在 LIBDB_CXX_INCLUDE_DIR中
  • 命令 FIND_LIBRARY 同 FIND_PATH 类似,用于查找链接库并将结果保存在变量中。清单5第10-13行的意思是在目录 /usr/lib/ 和 /usr/local/lib/ 中寻找名称为 db_cxx 的链接库,并将结果保存在 LIBDB_CXX_LIBRARIES

第二步 项目的根目录中的 CmakeList.txt

PROJECT(main)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
SET(CMAKE_SOURCE_DIR .)
SET(CMAKE_MODULE_PATH ${CMAKE_ROOT}/Modules ${CMAKE_SOURCE_DIR}/cmake/modules)
AUX_SOURCE_DIRECTORY(. DIR_SRCS)
ADD_EXECUTABLE(main ${DIR_SRCS})
FIND_PACKAGE( libdb_cxx REQUIRED)
MARK_AS_ADVANCED(
LIBDB_CXX_INCLUDE_DIR
LIBDB_CXX_LIBRARIES
)
 
IF (LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES)
MESSAGE(STATUS "Found libdb libraries")
INCLUDE_DIRECTORIES(${LIBDB_CXX_INCLUDE_DIR})
MESSAGE( ${LIBDB_CXX_LIBRARIES} )
TARGET_LINK_LIBRARIES(main ${LIBDB_CXX_LIBRARIES}18 )
ENDIF (LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES)

在该文件中第4行表示到目录 ./cmake/modules 中查找 Findlibdb_cxx.cmake ,8-19 行表示查找链接库和头文件的过程。第8行使用命令 FIND_PACKAGE 进行查找,这条命令执行后 CMake 会到变量 CMAKE_MODULE_PATH 指示的目录中查找文件 Findlibdb_cxx.cmake 并执行。第13-19行是条件判断语句,表示如果 LIBDB_CXX_INCLUDE_DIR 和 LIBDB_CXX_LIBRARIES 都已经被赋值,则设置编译时到 LIBDB_CXX_INCLUDE_DIR 寻找头文件并且设置可执行文件 main 需要与链接库 LIBDB_CXX_LIBRARIES 进行连接

具体项目分析

ROCKCHIP MPP

根目录CMakeLists.txt

目录结构如下:

fuqiang@ubuntu:~/workspace/rk3588/rk3588/external/mpp$ tree -L 1
.
├── build
├── CMakeLists.txt
├── debian
├── doc
├── inc
├── LICENSE.md
├── mpp
├── osal
├── pkgconfig
├── readme.txt
├── test
├── tools
└── utils

10 directories, 3 files

CMakeLists.txt脚本分析:

# ----------------------------------------------------------------------------
#  Root CMake file for Rockchip Media Process Platform (MPP)
#
#   - 10:34 2015/7/27: Initial version <herman.chen@rock-chips.com>
#
# ----------------------------------------------------------------------------

# vim: syntax=cmake

CMAKE_BUILD_TYPE:
1.Debug:用于在没有优化的情况下,使用带有调试符号构建库和可执行文件
2.Release:用于构建优化的库或可执行文件,不包含调试符号
3.RelWithDebInfo:用于构建较少的优化库或可执行文件,包含调试符号
4.MinSizeRel:用于不增加目标代码大小的优化方式,来构建库或可执行文件
if(NOT CMAKE_BUILD_TYPE)
    # default to Release build for GCC builds

set使用方法:
1.一般变量(Set Normal Variable):set(<variable> <value>... [PARENT_SCOPE])
2.缓存变量(Set Cache Entry):set(<variable> <value>... CACHE <type> <docstring> [FORCE])
3.环境变量(Set Environment Variable):set(ENV{<variable>} [<value>])
    set(CMAKE_BUILD_TYPE Debug CACHE STRING
        "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel."
        FORCE)
endif()
message:
格式:message([<mode>] "message text" ...)
mode:包括FATAL_ERROR、WARNING、AUTHOR_WARNING、STATUS、VERBOSE等,我主要使用其中的 2 个FATAL_ERROR、STATUS
FATAL_ERROR:产生 CMake Error,会停止编译系统的构建过程
STATUS:最常用的命令,常用于查看变量值,类似于编程语言中的 DEBUG 级别信息
message text:为显示在终端的内容

CMMAKE_VERSION:
message("CMAKE_VERSION: ${CMAKE_VERSION}")
message("CMAKE_MAJOR_VERSION: ${CMAKE_MAJOR_VERSION}")
message("CMAKE_MINOR_VERSION: ${CMAKE_MINOR_VERSION}")
message("CMAKE_PATCH_VERSION: ${CMAKE_PATCH_VERSION}")
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
    message("Please consider to switch to CMake 3.11.0 or Later")
endif()
message(STATUS "cmake version ${CMAKE_VERSION}")

# Search packages for host system instead of packages for target system
# in case of cross compilation these macro should be defined by toolchain file
if:
if(TARGET target-name):判断target-name是否存在,target-name主要是通过add_executable(), add_library(), add_custom_target()这3个命令执行输出的目标
if(COMMAND command-name):判断宏或者函数等可以调用

macro(<name> [<arg1> ...])
  <commands>
endmacro()
类似宏定义
macro(csdn_addr)
    message("csdn addr: https://blog.csdn.net/fengbingchun")
endmacro()
csdn_addr()
if(NOT COMMAND find_host_package)
    macro(find_host_package)
        find_package(${ARGN})
    endmacro()
endif()

if(NOT COMMAND find_host_program)
    macro(find_host_program)
        find_program(${ARGN})
    endmacro()
endif()

project:项目名称
project (rk_mpp)

cmake_minimum_required:指定所需cmake的最小版本
cmake_minimum_required (VERSION 2.8.8) # OBJECT libraries require 2.8.8
include(CheckIncludeFiles)
...
check_include_files(cxxabi.h HAVE_CXXABI)
if(HAVE_CXXABI)
   ...
else(HAVE_CXXABI)
   ...
endif(HAVE_CXXABI)
include(CheckIncludeFiles)
include(CheckFunctionExists)
check_function_exists (pow HAVE_POW)
if(HAVE_POW)
   ...
else(HAVE_POW)
   ...
endif(HAVE_POW)
include(CheckFunctionExists)
check_symbol_exists(<symbol> <files> <variable>)
include(CheckSymbolExists)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x"COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
  add_definitions(-DCOMPILEDWITHC11)
  message(STATUS "Using flag -std=c++11.") 
elseif(COMPILER_SUPPORTS_CXX0X)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
  add_definitions(-DCOMPILEDWITHC0X)
  message(STATUS "Using flag -std=c++0x.")
else()
  message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
include(CheckCXXCompilerFlag)

# setup output library name
# Linux   default name - rockchip_mpp and rockchip_vpu
# Android default name - mpp and vpu
# For historical reason libraries on Android is named as mpp and vpu. But for
# better naming rule on Linux it should add vendor prefix.
# So we use this ugly method to avoid massive maintain issue.
设置一些变量
if (NOT MPP_PROJECT_NAME)
    set(MPP_PROJECT_NAME rockchip_mpp)
endif()
set(MPP_STATIC ${MPP_PROJECT_NAME}_static)
set(MPP_SHARED ${MPP_PROJECT_NAME})

if (NOT VPU_PROJECT_NAME)
    set(VPU_PROJECT_NAME rockchip_vpu)
endif()
set(VPU_STATIC ${VPU_PROJECT_NAME}_static)
set(VPU_SHARED ${VPU_PROJECT_NAME})

# ----------------------------------------------------------------------------
# set property to classify library kinds
# ----------------------------------------------------------------------------
set_property(<GLOBAL                              |
                DIRECTORY [dir]                   |
                TARGET    [target1 [target2 ...]] |
                SOURCE    [src1 [src2 ...]]       |
                TEST      [test1 [test2 ...]]     |
                CACHE     [entry1 [entry2 ...]]>
               [APPEND][APPEND_STRING]
               PROPERTY <name>[value1 [value2 ...]])
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMakeTargets")
# ----------------------------------------------------------------------------
# enable test in this project
# ----------------------------------------------------------------------------
option(<variable> "<help_text>" [value]):
variable:定义选项名称
help_text:说明选项的含义
value:定义选项默认状态,一般是OFF或者ON,除去ON之外,其他所有值都为认为是OFF
option(BUILD_TEST "enable test binary building)" ON)

# ----------------------------------------------------------------------------
# System architecture detection
# ----------------------------------------------------------------------------
string:
string(FIND <string> <substring> <output_variable> [REVERSE]):在<string>中查找<substring>,返回值存放于<output_variable>,找到则返回在<string>中的下标,找不到返回-1。默认为首次出现的匹配,如果使用了REVERSE则为最后一次匹配。注:下标从0开始,以字节做为单位,因此遇到中文时下标表示字符编码第一字节的位置
string(REPLACE <match_string> <replace_string> 
<output_variable> <input> [<input>...])
string(APPEND <string_variable> [<input>...])
string(PREPEND <string_variable> [<input>...])
string(JOIN <glue> <output_variable> [<input>...])
string(TOLOWER <string> <output_variable>)
string(TOUPPER <string> <output_variable>)
string(LENGTH <string> <output_variable>)
string(SUBSTRING <string> <begin> <length> <output_variable>)
string(REPEAT <string> <count> <output_variable>)
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" SYSPROC)
set(X86_ALIASES x86 i386 i686 x86_64 amd64)
list:
list (LENGTH <list> <output variable>)
list (GET <list> <element index> [<element index> ...] <output variable>)
list (JOIN <list> <glue> <output variable>)
list (SUBLIST <list> <begin> <length> <output variable>)
list (FIND <list> <value> <output variable>)
list(FIND X86_ALIASES "${SYSPROC}" X86MATCH)
MATCHES:正则表达式匹配
-[^/]+$:非/的1-多个字符结尾
if("${CMAKE_C_COMPILER}" MATCHES "-buildroot-[^/]+$")
    message(STATUS "Detected Buildroot toolchain")
    # Use buildroot toolchain's default architecture settings
STREQUAL:比较字符串,相同返回true
GREATER:比较数字大小
elseif("${SYSPROC}" STREQUAL "" OR X86MATCH GREATER "-1")
    message(STATUS "Detected x86 system processor")
    set(X86 true)
    add_definitions(-DARCH_X86=1)
    if("${CMAKE_SIZEOF_VOID_P}" MATCHES 8)
        set(X64 true)
        add_definitions(-DARCH_X64=1)
        message(STATUS "Define X86_64 to 1")
    endif()
elseif(${SYSPROC} STREQUAL "armv6l")
    message(STATUS "Detected ARMv6 system processor")
    set(ARM true)
    set(ARMEABI_V6 true)
elseif(${SYSPROC} STREQUAL "armv7-a")
    message(STATUS "Detected ARMv7 system processor")
    set(ARM true)
    set(ARMEABI_V7A true)
elseif(${SYSPROC} STREQUAL "armv7-a_hardfp" OR ${SYSPROC} STREQUAL "armv7l")
    message(STATUS "Detected ARMv7 system processor")
    set(ARM true)
    set(ARMEABI_V7A_HARDFP true)
elseif(${SYSPROC} STREQUAL "aarch64" OR ${SYSPROC} STREQUAL "armv8-a")
    message(STATUS "Detected ARMv8 system processor")
    set(ARM true)
    set(ARMEABI_V8 true)
else()
    message(STATUS "CMAKE_SYSTEM_PROCESSOR value `${CMAKE_SYSTEM_PROCESSOR}` is unknown")
    message(STATUS "Please add this value near ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE}")
endif()

if(UNIX)
    SET(PLATFORM_LIBS pthread)
    if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
        SET(PLATFORM_LIBS ${PLATFORM_LIBS} rt)
    endif()
endif(UNIX)

# ----------------------------------------------------------------------------
# Compiler detection
# ----------------------------------------------------------------------------
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
    set(CLANG true)
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
    set(INTEL_CXX true)
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    set(GCC true)
endif()

if(INTEL_CXX AND UNIX)
    # treat icpc roughly like gcc
    set(GCC true)
    add_definitions(-Wall -Wextra -Wshadow)
elseif(CLANG)
    # treat clang roughly like gcc
    set(GCC true)
add_definitions():添加编译选项
-Wall:非常常用的编译选项,用于启用一批比较常见且易于修改的警告,这些选项都是对代码进行基本的检查
-Wextra:只有-Wall可能还不够严格,GCC还有-Wextra作为补充,包括另外一些没有被-Wall包含的警告类型
-Werror:用于将所有警告视为错误
-Wshadow:当局部变量屏蔽(shadow)已有已有变量时发出警告
-ffast-math:提高浮点运算的速度
-Wno-narrowing:不禁止长字节类型到短字节类型的转换
-mstackrealign:这个选项会为所有函数增加堆栈修正的PROLOG代码,以保证函数栈帧一定是按照16字节或用户指定大小对齐
    add_definitions(-Wall -Wextra -Wshadow -ffast-math)
elseif(CMAKE_COMPILER_IS_GNUCXX)
    add_definitions(-Wall -Wextra -Wshadow -ffast-math)
    check_cxx_compiler_flag(-Wno-narrowing GCC_HAS_NO_NARROWING)
    check_cxx_compiler_flag(-mstackrealign GCC_HAS_STACK_REALIGN)
    if (GCC_HAS_STACK_REALIGN)
        add_definitions(-mstackrealign)
    endif()
-dumpversion:显示编译程序自身的版本号,不做其他任何动作
    execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
endif()

-march:架构 armv6 armv7-a armv8-a i686
-mfloat-abi:浮点运算方式 hard soft softfp
-mfpu:vfp neon
if(GCC)
    if(ARM)
        if(ARMEABI_V6)
            add_definitions(-march=armv6 -mfloat-abi=hard -mfpu=vfp)
        elseif(ARMEABI_V7A)
            add_definitions(-march=armv7-a -mfloat-abi=softfp -mfpu=neon)
        elseif(ARMEABI_V7A_HARDFP)
            add_definitions(-march=armv7-a -mfloat-abi=hard -mfpu=neon)
        elseif(ARMEABI_V8)
            add_definitions(-march=armv8-a)
        endif()
    else()
        if(X86 AND NOT X64)
            add_definitions(-march=i686)
        endif()
    endif()

    if(NOT ${CMAKE_BUILD_TYPE} MATCHES "Release")
-g:创建调试符号表,关闭优化
        add_definitions(-g)
    endif()

    # disable multichar warning
-Wno-multichar:多字符常量不发出警告
    add_definitions(-Wno-multichar)
    # add PIC flag
-fPIC:指定编译器应该生成位置独立的代码
    add_definitions(-fPIC)
    # disable exception for C++
-fno-rtti: 禁用运行时类型信息
-fno-exceptions: 禁用异常机制
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")

    # for libary linking
-Wl:后面的东西是作为参数传递给链接器ld的,gcc -Wl,aaa,bbb,ccc  最后会被解释为:ld aaa bbb ccc
    set(BEGIN_WHOLE_ARCHIVE -Wl,--whole-archive)
    set(END_WHOLE_ARCHIVE -Wl,--no-whole-archive)

    option(ASAN_CHECK "enable Address Sanitizer (Asan)" OFF)
    if(ASAN_CHECK)
        add_definitions(-fsanitize=address -static-libasan -g)
        set(ASAN_LIB libasan.a dl rt m)
        set(ASAN_BIN dl rt m)
    endif(ASAN_CHECK)
endif(GCC)

# ----------------------------------------------------------------------------
# Create git version information
# ----------------------------------------------------------------------------
set(VERSION_CNT         0)
set(VERSION_MAX_CNT     9)
set(VERSION_INFO        "\"unknown mpp version for missing VCS info\"")
foreach(<loop_var> <items>)
	<command>
endeach()
foreach (CNT RANGE ${VERSION_MAX_CNT})
    set(VERSION_HISTORY_${CNT} "NULL")
endforeach(CNT)

if(EXISTS "${PROJECT_SOURCE_DIR}/.git")
    find_host_package(Git)
GIT_FOUND是前面的find_host_package的返回值
    if(GIT_FOUND)
        # get current version info
        set(GIT_LOG_FORMAT "%h author: %<|(30)%an %cd %s")
execute_process(COMMAND <cmd1> [args1...]]
                 [COMMAND <cmd2> [args2...] [...]]
                 [WORKING_DIRECTORY <directory>]  命名目录将被设置为子进程的当前工作目录
                 [TIMEOUT <seconds>] 在指定的秒数(允许分数)之后,所有未完成的子进程将被终止
                 [RESULT_VARIABLE <variable>] 该变量将被设置为包含最后一个子进程的结果
                 [RESULTS_VARIABLE <variable>] 该变量将按照给定的COMMAND参数的顺序,以分号分隔的列表的形式包含所有进程的结果
                 [OUTPUT_VARIABLE <variable>]
                 [ERROR_VARIABLE <variable>] 变量名将分别用标准输出管道和标准错误管道的内容设置
                 [INPUT_FILE <file>]
                 [OUTPUT_FILE <file>]
                 [ERROR_FILE <file>] 命名的文件将分别附加到第一个进程的标准输入、最后一个进程的标准输出或所有进程的标准错误
                 [OUTPUT_QUIET]
                 [ERROR_QUIET] 标准输出或标准错误结果将被悄悄地忽略
                 [OUTPUT_STRIP_TRAILING_WHITESPACE]
                 [ERROR_STRIP_TRAILING_WHITESPACE]

git log:
-1:显示最近的1条提交记录
--oneline:一个提交记录只显示1行
        execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --oneline --date=short --pretty=format:${GIT_LOG_FORMAT}
            WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
            OUTPUT_VARIABLE EXEC_OUT
            ERROR_VARIABLE EXEC_ERROR
            RESULT_VARIABLE EXEC_RET
            OUTPUT_STRIP_TRAILING_WHITESPACE
            ERROR_STRIP_TRAILING_WHITESPACE)

        if (NOT EXEC_RET)
            set(VERSION_INFO ${EXEC_OUT})
            message(STATUS "current version:")
            message(STATUS "${VERSION_INFO}")
            string(REPLACE "\"" "\\\"" VERSION_INFO ${VERSION_INFO})
            set(VERSION_INFO "\"${VERSION_INFO}\"")
        else()
            message(STATUS "git ret ${EXEC_RET}")
            message(STATUS "${EXEC_ERROR}")
        endif()

        set(GIT_LOG_FORMAT "%h author: %<|(30)%an %cd %s %d")

        # get history version information
        # setup logs
        message(STATUS "git version history:")
        foreach (CNT RANGE ${VERSION_MAX_CNT})
            execute_process(COMMAND ${GIT_EXECUTABLE} log HEAD~${CNT} -1 --oneline --date=short --pretty=format:${GIT_LOG_FORMAT}
                WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
                OUTPUT_VARIABLE EXEC_OUT
                ERROR_VARIABLE EXEC_ERROR
                RESULT_VARIABLE EXEC_RET
                OUTPUT_STRIP_TRAILING_WHITESPACE
                ERROR_STRIP_TRAILING_WHITESPACE)

            if (NOT EXEC_RET)
                set(VERSION_LOG ${EXEC_OUT})
                string(REPLACE "\"" "\\\"" VERSION_LOG ${VERSION_LOG})
                message(STATUS ${VERSION_LOG})
                set(VERSION_HISTORY_${CNT} "\"${VERSION_LOG}\"")
math(EXPR <output variable> <math expression>) : 计算表达式
                math(EXPR VERSION_CNT "${VERSION_CNT}+1")
            endif()
        endforeach(CNT)
        message(STATUS "total ${VERSION_CNT} git version recorded")
    endif()

    # add git hooks
    if (EXISTS "${PROJECT_SOURCE_DIR}/tools/hooks/")
        set(GIT_HOOK_SRC "${PROJECT_SOURCE_DIR}/tools/hooks/")
        if(EXISTS "${PROJECT_SOURCE_DIR}/.git/hooks")
            set(GIT_HOOK_DST "${PROJECT_SOURCE_DIR}/.git/hooks/")
Reading
  file(READ <filename> <out-var> [...])
  file(STRINGS <filename> <out-var> [...])
  file(<HASH> <filename> <out-var>)
  file(TIMESTAMP <filename> <out-var> [...])
 
Writing
  file({WRITE | APPEND} <filename> <content>...)
  file({TOUCH | TOUCH_NOCREATE} [<file>...])
  file(GENERATE OUTPUT <output-file> [...])
 
Filesystem
  file({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...])
  file(RENAME <oldname> <newname>)
  file({REMOVE | REMOVE_RECURSE } [<files>...])
  file(MAKE_DIRECTORY [<dir>...])
  file({COPY | INSTALL} <file>... DESTINATION <dir> [...])
  file(SIZE <filename> <out-var>)
  file(READ_SYMLINK <linkname> <out-var>)
  file(CREATE_LINK <original> <linkname> [...])

            file(COPY ${GIT_HOOK_SRC} DESTINATION ${GIT_HOOK_DST})
            message(STATUS "Install git hooks done")
        endif(EXISTS "${PROJECT_SOURCE_DIR}/.git/hooks")
    endif(EXISTS "${PROJECT_SOURCE_DIR}/tools/hooks/")
endif(EXISTS "${PROJECT_SOURCE_DIR}/.git")

configure_file(input output options):将一个文件(由input参数指定)拷贝到指定位置(由output参数指定),并根据options修改其内容
configure_file(
    "${PROJECT_SOURCE_DIR}/build/cmake/version.in"
    "${PROJECT_SOURCE_DIR}/mpp/version.h"
)

# ----------------------------------------------------------------------------
# Build options
# ----------------------------------------------------------------------------
find_package(PkgConfig)
INCLUDE(GNUInstallDirs)
pkg_search_module(PTHREAD pthread)

# ----------------------------------------------------------------------------
# Set Warning as Error
# ----------------------------------------------------------------------------
option(WARNINGS_AS_ERRORS "Stop compiles on first warning" OFF)
if(WARNINGS_AS_ERRORS)
    if(GCC)
        add_definitions(-Werror)
    elseif(MSVC)
        add_definitions(/WX)
    endif()
endif(WARNINGS_AS_ERRORS)

# ----------------------------------------------------------------------------
# look for stdint.h
# ----------------------------------------------------------------------------
if(MSVC)
    check_include_files(stdint.h HAVE_STDINT_H)
    if(NOT HAVE_STDINT_H)
        include_directories(osal/windows)
    endif(NOT HAVE_STDINT_H)
endif(MSVC)

# ----------------------------------------------------------------------------
# Share library option
# ----------------------------------------------------------------------------
option(ENABLE_STATIC "Build shared library" ON)
option(ENABLE_SHARED "Build shared library" OFF)

# ----------------------------------------------------------------------------
# scan all LOG_TAG for log information and generate module header file
# ----------------------------------------------------------------------------
set( module_list "" )
file(GLOB variable [RELATIVE path] [globbingexpressions]...):GLOB 会产生一个由所有匹配globbing表达式的文件组成的列表,并将其保存到变量中。Globbing 表达式与正则表达式类似,但更简单

file ( GLOB_RECURSE ALL_SRC . *.c;*.cpp )
foreach( files ${ALL_SRC} )
file(STRINGS <filename> <out-var> [...]):STRINGS 从文件中解析出ASCII字符串列表并存储在变量中 

MODULE_TAG( )+\".+\": MODULE_TAG + 1-n个空格 + " + 1-n个字符 + "
    file( STRINGS ${files} module_tag_line REGEX "MODULE_TAG( )+\".+\"" )
    if(module_tag_line)
        string( REGEX REPLACE "^(.)* MODULE_TAG( )+\"(.*)\"" \\3 module_tag ${module_tag_line} )
        list( APPEND module_list ${module_tag} )
    endif()
endforeach()
list( SORT module_list )
list( LENGTH module_list module_size )
#message(STATUS "module_list: ${module_list}")
#message(STATUS "module_size: ${module_size}")

# ----------------------------------------------------------------------------
#  Start module definition
# ----------------------------------------------------------------------------
# project overall include file
include_directories(inc)
# small utile functions for test case
include_directories(utils)

# ----------------------------------------------------------------------------
#  osal library
# ----------------------------------------------------------------------------
# Operation System Abstract Layer (OSAL) include
include_directories(osal/inc)
# OSAL is needed on all platform, do not need option
add_subdirectory(osal)

# ----------------------------------------------------------------------------
#  utils for test case
# ----------------------------------------------------------------------------
add_subdirectory(utils)

# ----------------------------------------------------------------------------
#  Media Process Platform library
# ----------------------------------------------------------------------------
# Media Process Platform include
include_directories(mpp/inc)
add_subdirectory(mpp)

# ----------------------------------------------------------------------------
#  test / demo
# ----------------------------------------------------------------------------
add_subdirectory(test)

# ----------------------------------------------------------------------------
#  install headers
# ----------------------------------------------------------------------------
install(DIRECTORY dirs...
        TYPE <type> | DESTINATION <dir>
        [FILE_PERMISSIONS permissions...]
        [DIRECTORY_PERMISSIONS permissions...]
        [USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>] [EXCLUDE_FROM_ALL]
        [FILES_MATCHING]
        [[PATTERN <pattern> | REGEX <regex>]
         [EXCLUDE] [PERMISSIONS permissions...]] [...])
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/inc/
        DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rockchip"
        FILES_MATCHING PATTERN "*.h"
        )

# ----------------------------------------------------------------------------
#  pkgconfig
# ----------------------------------------------------------------------------
configure_file(<input> <output>
               [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
               [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
官方CMake教程对它的解释是:将文件复制到另一个位置并修改其内容
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/pkgconfig/rockchip_mpp.pc.cmake"
                "${CMAKE_BINARY_DIR}/rockchip_mpp.pc" @ONLY)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/pkgconfig/rockchip_vpu.pc.cmake"
                "${CMAKE_BINARY_DIR}/rockchip_vpu.pc" @ONLY)
install(FILES "${CMAKE_BINARY_DIR}/rockchip_mpp.pc"
        DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/")
install(FILES "${CMAKE_BINARY_DIR}/rockchip_vpu.pc"
        DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/")

mpp目录CMakeLists.txt

目录结构如下:

fuqiang@ubuntu:~/workspace/rk3588/rk3588/external/mpp/mpp$ tree -L 1
.
├── base
├── CMakeLists.txt
├── codec
├── codecs.cmake
├── common
├── hal
├── inc
├── legacy
├── mpi.cpp
├── mpp.cpp
├── mpp_impl.cpp
├── mpp_info.cpp
├── vproc
└── vproc.cmake

7 directories, 7 files

CMakeLists.txt脚本分析:

# vim: syntax=cmake
# ----------------------------------------------------------------------------
# setup mpp codec config first
# ----------------------------------------------------------------------------
include(codecs.cmake)
include(vproc.cmake)

# ----------------------------------------------------------------------------
# add include directory
# ----------------------------------------------------------------------------
include_directories(inc)
include_directories(common)
include_directories(base/inc)
include_directories(codec/inc)
include_directories(hal/inc)
include_directories(hal/common)
include_directories(vproc/inc)

# ----------------------------------------------------------------------------
# add mpp base component
# ----------------------------------------------------------------------------
add_subdirectory(base)

# ----------------------------------------------------------------------------
# add codec parsers
# ----------------------------------------------------------------------------
add_subdirectory(codec)

# ----------------------------------------------------------------------------
# add video processor
# ----------------------------------------------------------------------------
add_subdirectory(vproc)

# ----------------------------------------------------------------------------
# add register generation hal
# ----------------------------------------------------------------------------
add_subdirectory(hal)

# ----------------------------------------------------------------------------
# add mpp implement
# ----------------------------------------------------------------------------
set (MPP_SRC
    mpp_info.cpp
    mpp.cpp
    mpp_impl.cpp
    mpi.cpp
    )

set(MPP_VERSION "0")
set(MPP_ABI_VERSION "1")

创建动态库,${MPP_SHARED}在根目录的CMakeLists.txt中创建
add_library(${MPP_SHARED} SHARED ${MPP_SRC})
set_target_properties(target1 target2 ...
                      PROPERTIES prop1 value1
                      prop2 value2 ...)
set_target_properties(${MPP_SHARED} PROPERTIES FOLDER "mpp")
cmake在构建一个新的target时,会尝试清理掉其他使用这个名字的库,
因此,在构建libhello.a时,就会清理掉libhello.so.
为了回避这个问题,设置CLEAN_DIRECT_OUTPUT属性为1
set_target_properties(${MPP_SHARED} PROPERTIES CLEAN_DIRECT_OUTPUT 1)
target_link_libraries(<target> 
                      <PRIVATE|PUBLIC|INTERFACE> <item>... 
                      [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
为target链接到对应的库
BEGIN_WHOLE_ARCHIVE:根目录CMakeLists.txt中定义,链接使用参数,仅针对mpp_base使用
target_link_libraries(${MPP_SHARED} mpp_codec mpp_hal mpp_vproc ${ASAN_LIB}
                      ${BEGIN_WHOLE_ARCHIVE} mpp_base ${END_WHOLE_ARCHIVE})
set_target_properties(${MPP_SHARED} PROPERTIES C_VISIBILITY_PRESET default)
set_target_properties(${MPP_SHARED} PROPERTIES CXX_VISIBILITY_PRESET default)

# NOTE: due to legacy libray naming issue we can not support version on Android
if (NOT ANDROID)
set_target_properties(${MPP_SHARED} PROPERTIES VERSION ${MPP_VERSION})
set_target_properties(${MPP_SHARED} PROPERTIES SOVERSION ${MPP_ABI_VERSION})
endif()


add_subdirectory(legacy)

install(TARGETS ${MPP_SHARED} LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")

codecs.cmake脚本分析:

# This file setup the enable flag of all supported codecs

# AVS decoder
option(ENABLE_AVSD   "Enable avs decoder" ON)
if( ENABLE_AVSD AND
    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/codec/dec/avs" )
    set(HAVE_AVSD true)
    set(CODEC_AVSD codec_avsd)
    set(HAL_AVSD hal_avsd)
    add_definitions(-DHAVE_AVSD)
endif()

# H.263 decoder
option(ENABLE_H263D  "Enable h.263 decoder" ON)
if( ENABLE_H263D )
    set(HAVE_H263D true)
    set(CODEC_H263D codec_h263d)
    set(HAL_H263D hal_h263d)
    add_definitions(-DHAVE_H263D)
endif()

# H.264 decoder
option(ENABLE_H264D  "Enable h.264 decoder" ON)
if( ENABLE_H264D )
    set(HAVE_H264D true)
    set(CODEC_H264D codec_h264d)
    set(HAL_H264D hal_h264d)
    add_definitions(-DHAVE_H264D)
endif()

# H.265 decoder
option(ENABLE_H265D  "Enable h.265 decoder" ON)
if( ENABLE_H265D )
    set(HAVE_H265D true)
    set(CODEC_H265D codec_h265d)
    set(HAL_H265D hal_h265d)
    add_definitions(-DHAVE_H265D)
endif()

...

解码路径分析

顺着上面的H.265 decoder来分析,看看是如何贯穿起来的

codec中的CMakeLists.txt:

# vim: syntax=cmake

# ----------------------------------------------------------------------------
# add mpp_dec implement
# ----------------------------------------------------------------------------

编译mpp_codec的静态库
add_library(mpp_codec STATIC
    mpp_enc_impl.cpp
    mpp_enc_v2.cpp
    enc_impl.cpp
    mpp_dec.cpp
    mpp_parser.cpp
    )

编译mpp_rc的静态库
add_library(mpp_rc STATIC mpp_rc.cpp)

set_target_properties(mpp_codec PROPERTIES FOLDER "mpp/codec")

add_subdirectory(dec)

add_subdirectory(enc)

add_subdirectory(rc)

添加静态链接库
target_link_libraries(mpp_codec
                      enc_rc
                      ${CODEC_AVSD}
                      ${CODEC_H263D}
                      ${CODEC_H264D}
                      ${CODEC_H265D}
                      ${CODEC_MPEG2D}
                      ${CODEC_MPEG4D}
                      ${CODEC_VP8D}
                      ${CODEC_VP9D}
                      ${CODEC_JPEGD}
                      ${CODEC_AV1D}
                      ${CODEC_H264E}
                      ${CODEC_JPEGE}
                      ${CODEC_H265E}
                      ${CODEC_VP8E}
                      codec_dummy_enc
                      codec_dummy_dec
                      mpp_vproc
                      mpp_base)

进到dec目录的CMakeLists.txt:

# vim: syntax=cmake

add_subdirectory(dummy)

if( HAVE_AVSD )
    add_subdirectory(avs)
endif()

if( HAVE_H263D )
    add_subdirectory(h263)
endif()

if( HAVE_H264D )
    add_subdirectory(h264)
endif()

if( HAVE_H265D )
    add_subdirectory(h265)
endif()

...

进到h265的目录:

# vim: syntax=cmake
set(H265D_PARSER_HDR
    h265d_defs.h
    h265d_parser.h
    h265d_codec.h
    )

set(H265D_PARSER_SRC
    h265d_parser.c
    h265d_ps.c
    h265d_refs.c
    h265d_sei.c
    h265d_parser2_syntax.c
    )

add_library(${CODEC_H265D} STATIC
    ${H265D_PARSER_SRC}
    ${H265D_PARSER_HDR}
    )

set_target_properties(${CODEC_H265D} PROPERTIES FOLDER "mpp/codec")
target_link_libraries(${CODEC_H265D} mpp_base)

这里最终编译了h265的解码库

mjpeg-streamer

根目录CMakeLists.txt:

cmake最小版本号
cmake_minimum_required(VERSION 2.8.3)
添加当前工作目录的cmake目录,用分号分隔的目录列表,用于在检查CMake附带的默认模块之前,由include或find_package命令加载的CMake模块的搜索路径。默认情况下,它为空
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})

project(<PROJECT-NAME> [<language-name>...])
project("mjpg-streamer" C)

设置CMAKE_BUILD_TYPE,默认为Release
# If the user doesn't manually specify a build type, use 'Release'
message("CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
  SET(CMAKE_BUILD_TYPE "Release")
endif()

SET(COMPILE_DEFINITIONS -Werror -Wall)

include(CheckLibraryExists) 
include(CheckIncludeFiles)
include(FeatureSummary)

include(<file|module> [OPTIONAL] [RESULT_VARIABLE <VAR>] [NO_POLICY_SCOPE]):Load and run CMake code from the file given. 
include(mjpg_streamer_utils)

#
# Get the current git hash
#
execute_process(
  COMMAND git rev-parse HEAD
  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  RESULT_VARIABLE GIT_RESULT
  OUTPUT_VARIABLE GIT_HASH
  OUTPUT_STRIP_TRAILING_WHITESPACE
)

if(GIT_RESULT EQUAL 0)
  add_definitions("-DGIT_HASH=\"${GIT_HASH}\"")
endif()

#
# Options
#
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")

add_feature_option(WXP_COMPAT "Enable compatibility with WebcamXP" OFF)

if (WXP_COMPAT)
    add_definitions(-DWXP_COMPAT)
endif (WXP_COMPAT)

set (MJPG_STREAMER_PLUGIN_INSTALL_PATH "lib/mjpg-streamer")

#
# Global dependencies
#
find_library (<VAR> name [path1 path2 ...]):获取库的全路径并保存在变量
find_library(JPEG_LIB jpeg)


#
# Input plugins
#

add_subdirectory(plugins/input_file)
add_subdirectory(plugins/input_http)
add_subdirectory(plugins/input_opencv)
add_subdirectory(plugins/input_raspicam)
add_subdirectory(plugins/input_ptp2)
add_subdirectory(plugins/input_uvc)

#
# Output plugins
#

add_subdirectory(plugins/output_file)
add_subdirectory(plugins/output_http)
add_subdirectory(plugins/output_rtsp)
add_subdirectory(plugins/output_udp)
add_subdirectory(plugins/output_viewer)
add_subdirectory(plugins/output_zmqserver)

#
# mjpg_streamer executable
#

# This adds the plugin installation directory to the default DT_RUNPATH, so
# that the user shouldn't need to set LD_LIBRARY_PATH if using 'make install'
# ... however, DT_RUNPATH allows overriding via LD_LIBRARY_PATH if you really
#     need to do it

set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--enable-new-dtags")
set (CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
set (CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${MJPG_STREAMER_PLUGIN_INSTALL_PATH})
set (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)


add_executable(mjpg_streamer mjpg_streamer.c
                             utils.c)

target_link_libraries(mjpg_streamer pthread dl)
install(TARGETS mjpg_streamer DESTINATION bin)

#
# www directory
#

install(DIRECTORY www DESTINATION share/mjpg-streamer)


#
# Show enabled/disabled features
#

feature_summary(WHAT ALL)

#
# Final warning
#

if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
  message(WARNING "The source directory is the same as binary directory. \"make clean\" may damage the source tree")
endif()

  • 31
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码论斤卖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值