添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

三、添加构建目录

增加 cmake 子目录,用于建立 Cmakelists.txt 文件层级的依赖

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])
  • source_dir:该参数指定一个子目录,子目录下应该包含 CMakeLists.txt 文件和代码文件
  • binary_dir:指定输出目录,如果没有指定,默认生成到 source_dir 目录
    # 指定 cmake 子目录
    add_subdirectory(deps/)
    

    四、添加宏定义(-Dxxx)

      为编译目标或者所有目标增加宏定义

    # 为当前路径的所有源文件和target增加编译定义
    # 方式1
    add_definitions(-DFOO -DBAR ...)
    # 方式2
    add_compile_definitions(<definition> ...)
    # 为指定的target指定宏定义
    target_compile_definitions(<target>
                              <INTERFACE|PUBLIC|PRIVATE> [definition1...]
                              [<INTERFACE|PUBLIC|PRIVATE> [definition2...] ...])
    
  • target:宏定义所属的目标,可以有 add_executable() 或 add_library() 定义
  • definition:指定的宏定义,不需要带 -D
    add_definitions(-DFOO=1 -DBAR)
    add_compile_definitions(FOO=1 BAR)
    target_compile_definitions(target PRIVATE FOO=1 PUBLIC BAR)
    

      target_compile_definitions 可以指定目标进行宏定义,例如代码中有宏进行隔离的部分,可以通过为 target 指定不同的宏,配合 add_library() 来生成不同的库文件。

    五、生成可执行文件

      增加一个目标用于生成可执行文件

    add_executable(<target> [EXCLUDE_FROM_ALL] [source1] [source2 ...])
    
  • target:可执行目标的名称
  • EXCLUDE_FROM_ALL:当使用这个选项时指定的文件将不参与构建
  • source:源文件列表,也可以通过 target_sources() 为可执行目标文件添加源文件,要求是在调用 target_sources 之前,可执行目标文件必须已经通过 add_executable() 或 add_library() 定义了。
    # 直接指定源文件
    add_executable(main main.c)
    # 通过 target_sources 追加源文件
    add_executable(main)
    target_sources(main PUBLIC main.c other.c)
    

    六、生成库文件

    普通库生成

      生成普通的静态库或者是动态库文件

    add_library(<name> [STATIC | SHARED | MODULE]
    [EXCLUDE_FROM_ALL]
    [<source>...])
    
  • name:库的名称
  • STATIC|SHARED|MOUDLE:库的类型
  • source:构建库的文件,也可以通过 target_sources() 继续为可执行目标文件添加源文件
    # 生成静态库
    add_library(main STATIC ${libs_src})
    # 生成动态库
    add_library(list SHARED ${libs_src})
    

    对象库生成

      只编译,但是不会进行库的打包

    add_library(<name> OBJECT [<source>...])
    

      只编译 source 列表的文件,但不将生成的目标文件打包为库,而是在其他 add_library() 或者 add_executable() 生成目标的时候,可以使用形如$<TARGET_OBJECTS:objlib>的表达式将对象库作为源引入。

  • name:库的名称
  • OBJECT:库的类型
  • source:构建库的文件,也可以通过target_sources()继续为可执行目标文件添加源文件
    add_library(list OBJECT ./list.c)
    add_library(mylist $<TARGET_OBJECTS:list>)
    

    七、指定头文件目录(gcc -I):

      为所有目标或者指定的目标增加头文件搜索路径

    # 为所有target 添加头文件路径
    include_directories([AFTER|BEFORE] dir1 [dir2 ...])
    # 为指定目标添加头文件路径
    target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
                              <INTERFACE|PUBLIC|PRIVATE> [dir1...]
                              [<INTERFACE|PUBLIC|PRIVATE> [dir1...] ...])
    

      include_directories 会为当前 CMakeLists.txt 的所有目标,以及之后添加的所有子目录的目标添加头文件搜索路径。

  • AFTER、BEFORE:指定的路径添加到搜索列表前面还是后面,默认 AFTER;
  • dir:指定要搜索的头文件目录,目录是当前源码路径(当前 CMakeLists.txt)的相对路径;
  • target: 要添加头文件的目标,target由 add_library 和 add_executable 添加;
  • dir 指定的源文件或者头文件,地址是相对于 CMAKE_CURRENT_SOURCE_DIR 的地址;
    include_directories(${CMAKE_SOURCE_DIR}/include)
    target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
    

    八、收集源文件:

      收集指定目录下的源文件

    aux_source_directory(<dir> <variable>)
    
  • dir:指定的目录;
  • variable:把源文件列表保存到指定的变量中;
    aux_source_directory(../src LOCAL_SRC)
    # 排除 src 路径下的 test.c 文件
    list(REMOVE_ITEM LOCAL_SRC "../src/test.c")
    # 使用 file 收集源文件
    file(GLOB LOCAL_SRC src/*.c)
    

    九、指定库文件目录(gcc -L):

      为所有目标或指定目标添加库文件搜索路径

    link_directories(dir1 dir2 ...)
    # 为指定目标添加库文件搜索目录
    target_link_directories(<target> [BEFORE]
                            <INTERFACE|PUBLIC|PRIVATE> [items1...]
                            [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
    
  • AFTER、BEFORE:指定的路径添加到搜索列表前面还是后面,默认AFTER;
  • dir:指定要搜索的库文件目录,目录是当前源码路径(当前 CMakeLists.txt)的相对路径;
  • target: 要添加头文件的目标,target 由 add_library() 和 add_executable() 添加;
  • items 指定的源文件或者头文件,地址是相对于 CMAKE_CURRENT_SOURCE_DIR 的地址;
    link_directories(${CMAKE_SOURCE_DIR}/lib)
    target_link_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/lib)
    

      如果在使用 target_link_libraries 时库已经包含了绝对路径时也可以不需要指定库的搜索路径。

    十、指定库文件(gcc -l)

      为目标添加链接是需要的库文件

    target_link_libraries(<target> ... <item>... ...) # link_libraries 已经弃用
    
  • target: 要增加的目标,必须先通过 或 指定;
  • item:依赖的的库名称;
    # 三种写法功能相同,在使用前必须通过命令指定 target
    target_link_libraries(main -Wl,--start-group eng mx -Wl,--end-group)
    target_link_libraries(main -Wl,--start-group -leng -lmx -Wl,--end-group)
    target_link_libraries(main -Wl,--start-group libeng.so libmx.so -Wl,--end-group)
    

    十一、增加编译选项:

      增加编译选项

    add_compile_options(<option> ...)
    
  • option:编译选项
    # 增加针对所有编译器的选项
    add_compile_options(-g -Os
    -Wall
    -Wno-unused-variable
    -fno-strict-aliasing
    -ffunction-sections -fdata-sections
    # 增加针对指定编译器的选项
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-exceptions -fno-rtti -fno-threadsafe-statics")
    

      add_compile_options 是为所有编译器增加链接选项,但是有些选项需要区分编译器,例如 c 和 c++ 中特有的选项,则需要使用set 设置指定的宏。

    十二、增加链接选项:

      增加链接选项

    add_link_options(<option> ...)
    
  • option:链接选项
    add_link_options(-Wl,-Map=${PROJECT_NAME}.map
    -Wl,--gc-sections
    

    十三、定义全局属性:

      有些时候需要在 cmake 多个层级之间传递内容,则可以使用自定义的全局属性

    # 定义 MY_LIBRARIES 用于收集所有的打包后库文件
    function(add_globle_libraries)
    get_property(TIDE_LIBRARIES GLOBAL PROPERTY MY_LIBRARIES)
    set_property(GLOBAL PROPERTY MY_LIBRARIES ${MY_LIBRARIES} ${ARGN})
    endfunction()
    # 获取 MY_LIBRARIES 中库文件列表
    get_property(MY_LIBRARIES GLOBAL PROPERTY MY_LIBRARIES)
    

    十四、执行命令:

      用来在 cmake 中执行命令或是调用其他程序

    execute_process(COMMAND <cmd1> [<arguments>]
    [COMMAND <cmd2> [<arguments>]]...
    [WORKING_DIRECTORY <directory>]
    [TIMEOUT <seconds>]
    [RESULT_VARIABLE <variable>]
    [RESULTS_VARIABLE <variable>]
    [OUTPUT_VARIABLE <variable>]
    [ERROR_VARIABLE <variable>]
    [INPUT_FILE <file>]
    [OUTPUT_FILE <file>]
    [ERROR_FILE <file>]
    [OUTPUT_QUIET]
    [ERROR_QUIET]
    [COMMAND_ECHO <where>]
    [OUTPUT_STRIP_TRAILING_WHITESPACE]
    [ERROR_STRIP_TRAILING_WHITESPACE]
    [ENCODING <name>]
    [ECHO_OUTPUT_VARIABLE]
    [ECHO_ERROR_VARIABLE]
    [COMMAND_ERROR_IS_FATAL <ANY|LAST>])
    

      命令 COMMAND 会并行执行,每个子进程的标准输出映射到下一个进程的标准输入上,所有进程共用 standard error 管道。

  • COMMAND: 子进程的命令行,直接使用操作系统api执行
  • WORKING_DIRECTORY:在指定的目录下执行 COMMAND 命令
  • TIMEOUT:超时时间
  • RESULT_VARIABLE:最后一个子进程的返回值(正常是0,异常是其他整数)
  • OUTPUT_VARIABLE:对应于standard output的内容
  • ERROR_VARIABLE:对应于standard error的内容
  • OUTPUT_STRIP_TRAILING_WHITESPACE/ERROR_STRIP_TRAILING_WHITESPACE:删除空白字符
    # 执行 echo 命令
    execute_process(COMMAND echo "hello world"
                    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
                    TIMEOUT 3
                    RESULT_VARIABLE result_var
                    OUTPUT_VARIABLE output_var
                    ERROR_VARIABLE error_var
                    OUTPUT_STRIP_TRAILING_WHITESPACE
                    ERROR_STRIP_TRAILING_WHITESPACE
    message(STATUS "result: ${result_var}")
    message(STATUS "output: ${output_var}")
    message(STATUS "error: ${error_var}")
    # 获取当前环境下 gcc 中 libgcc.a 的完整路径
    execute_process(COMMAND gcc --print-file-name libgcc.a
                    OUTPUT_VARIABLE TIDE_LIBGCC_FILE
                    OUTPUT_STRIP_TRAILING_WHITESPACE
    

    十五、定制化构建规则

    add_custom_target:
      添加一个伪目标(没有输出的目标),主要是通过依赖中的命令和依赖的依赖来进行相关动作,一般配合 add_custom_command 使用,通过 add_custom_command 的 OUTPUT 来作为 DEPENDS 依赖。

    add_custom_target(Name [ALL] [command1 [args1...]]
    [COMMAND command2 [args2...] ...]
    [DEPENDS depend depend depend ... ]
    [BYPRODUCTS [files...]]
    [WORKING_DIRECTORY dir]
    [COMMENT comment]
    [JOB_POOL job_pool]
    [VERBATIM] [USES_TERMINAL]
    [COMMAND_EXPAND_LISTS]
    [SOURCES src1 [src2...]])
    
  • Name:target 目标名称
  • ALL:说明该目标需要添加到默认目标的构建中,所以命令每次都会被执行
  • COMMAND:构建时执行的命令
  • COMMENT:注释信息,会在命令执行前打印出来
  • DEPENDS:通常以同一 CMakeLists.txt 文件中的 add_custom_command() 命令生成的文件作为依赖
    # 例子中通过 add_custom_target 设置一个没有输出的目标,通过目标的依赖来创建一个名称为 log.txt 的文件
    set(TEST_FILE "log.txt")
    # 产生 FILE_TEST 文件,FILE_TEST 文件通过命令 copy 产生,并依赖 CMAKE_CURRENT_LIST_FILE
    add_custom_command(OUTPUT ${TEST_FILE}
                      COMMAND echo "Generating log.txt file..."
                      COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_FILE} ${TEST_FILE}
                      DEPENDS ${CMAKE_CURRENT_LIST_FILE}
                      COMMENT "This is a test"
    # 创建一个伪目标 Test,这个伪目标依赖 TEST_FILE 文件
    add_custom_target(Test
                      COMMAND echo "execute a custom target..."
                      DEPENDS ${TEST_FILE}
    

      add_custom_target 的最大作用就是通过一个虚拟的 target 形成依赖关系,依赖关系可以无限,例如:依赖1-->依赖2-->依赖3,从而形成一系列的串行动作,来产生输出。

    add_custom_command:
    用法一:生成文件
      增加一个定制化的命令用来产生一个输出,这个输出一般被 add_custom_target 作为 DEPENDS 依赖。

    add_custom_command(OUTPUT output1 [output2 ...]
    COMMAND command1[ARGS] [args1...]
    [COMMAND command2 [ARGS] [args2...] ...]
    [MAIN_DEPENDENCY depend]
    [DEPENDS[depends...]]
    [IMPLICIT_DEPENDS<lang1> depend1 ...]
    [WORKING_DIRECTORYdir]
    [COMMENT comment] [VERBATIM] [APPEND])
    
  • OUTPUT:指定输出(一般是一个中间文件)
  • COMMAND:产生输出时执行的命令
  • COMMENT:注释信息,会在命令执行前打印出来
  • DEPENDS:命令执行的依赖,依赖发生修改就会执行 COMMAND 产生新的 OUTPUT。依赖可以是某个 target(通过add_library/add_executable/add_custom_target创建的)或者直接是某个文件
    # 例子中通过 add_custom_target 设置一个没有输出的目标,通过目标的依赖来创建一个名称为 log.txt 的文件
    set(TEST_FILE "log.txt")
    # 产生 FILE_TEST 文件,FILE_TEST 文件通过命令 copy 产生,并依赖 CMAKE_CURRENT_LIST_FILE
    add_custom_command(OUTPUT ${TEST_FILE}
                      COMMAND echo "Generating log.txt file..."
                      COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_FILE} ${TEST_FILE}
                      DEPENDS ${CMAKE_CURRENT_LIST_FILE}
                      COMMENT "This is a test"
    # 创建一个伪目标 Test,这个伪目标依赖 TEST_FILE 文件
    add_custom_target(Test
                      COMMAND echo "execute a custom target..."
                      DEPENDS ${TEST_FILE}
      add_custom_command 的 makefile 的表现形式如下,就是检查依赖,在依赖变动的情况下通过命令生成输出。

    OUTPUT: MAIN_DEPENDENCY DEPENDS
            COMMAND
    

      add_custom_command(OUTPUT xxx) 不能单独使用,否则命令将不会被执行,所以他所产生的 OUTPUT 输出必须要被作为其他目标的依赖,这也是为什么必须要和 add_custom_target 配合的原因。

    用法二:添加命令
      为某个目标如库或可执行程序添加一个命令,并可以指明命令执行的时机,如果该目标已经构建,命令将不会执行。

    add_custom_command(TARGET target
    PRE_BUILD | PRE_LINK| POST_BUILD
    COMMAND command1[ARGS] [args1...]
    [COMMAND command2[ARGS] [args2...] ...]
    [WORKING_DIRECTORYdir]
    [COMMENT comment][VERBATIM])
    
  • TARGET:指定要为那个 target 创建命令
  • PRE_BUILD:在所有规则执行前执行
  • PRE_LINK:在源文件编译后且链接前执行
  • POST_BUILD:在所有规则执行后执行命令
  • COMMAND:需要执行的命令
  • COMMENT:注释信息,会在命令执行前打印出来
    set(TEST_FILE "log.txt")
    # 作为依赖产生文件
    add_custom_command(OUTPUT ${TEST_FILE}
    COMMAND echo "Generating log.txt file..."
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_FILE} ${TEST_FILE}
    DEPENDS ${CMAKE_CURRENT_LIST_FILE}
    COMMENT "This is a test"
    # 创建一个没有输出的目标,注意是通过依赖来执行命令
    add_custom_target(Test1
    COMMAND pwd
    DEPENDS ${TEST_FILE})
    # 为目标 Test1 增加一条定制化命令
    add_custom_command(TARGET Test1
    PRE_BUILD
    COMMAND echo "executing a fake command"
    COMMENT "This command will be executed before building target Test1"
    

    十六、设置库输出路径:

    # 设置静态库文件目录
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
    # 动态库文件目录
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
    # 可执行文件目录
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
    

    十七、文件操作:

    file(CMD <filename> [...])
    

    https://cmake.org/cmake/help/latest/command/file.html

  • CMD:文件操作命令,包括读、写、增、删、改等,具体参数见链接下的具体 CMD
  • filename:文件名称
    # 拷贝文件
    file(COPY_FILE ./test.txt ./test2.txt)
    

    十八、程序查找

    find_program (
              name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
              [HINTS [path | ENV var]... ]
              [PATHS [path | ENV var]... ]
              [REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
              [PATH_SUFFIXES suffix1 [suffix2 ...]]
              [DOC "cache documentation string"]
              [NO_CACHE]
              [REQUIRED]
              [NO_DEFAULT_PATH]
              [NO_PACKAGE_ROOT_PATH]
              [NO_CMAKE_PATH]
              [NO_CMAKE_ENVIRONMENT_PATH]
              [NO_SYSTEM_ENVIRONMENT_PATH]
              [NO_CMAKE_SYSTEM_PATH]
              [NO_CMAKE_INSTALL_PREFIX]
              [CMAKE_FIND_ROOT_PATH_BOTH |
               ONLY_CMAKE_FIND_ROOT_PATH |
               NO_CMAKE_FIND_ROOT_PATH]
    
  • VAR:寻找程序或者变量后结果的缓存
  • NAMES:除了name 以外可以指定更多可能得名称
  • HINTS:除了系统路径外,还需要搜索的路径,先搜索指定路径,后搜索系统路径
  • PATHS:除了系统路径外,还需要搜索的路径,先搜索系统路径,后搜索指定路径
  • REGISTRY_VIEW:指定必须要查询的注册表视图,仅用于windows,例如查找安装的一些软件路径
  • REQUIRED:搜索不到会报错并停止搜索
  • NO_DEFAULT_PATH:默认搜索路径将失效,只会搜索PATHS和HINTS指定的路径
    # 搜索指定前缀的 gcc 程序
    find_program(TIDE_C_COMPILER   ${CROSS_COMPILE}gcc     REQUIRED)
    # 搜索window下cmd 控制台程序
    find_program(MY_PROGRAM cmd NAMES cmd.exe)
    

    十九、目标属性设置:

    set_target_properties(target1 target2 ...
                          PROPERTIES 
                          prop1 value1
                          prop2 value2 ...)
    
  • target:需要设置属性的目标,在使用前 target 需要使用 add_library()或者 add_executable() 指定atrget。
  • PROPERTIES:属性标识,后面紧接着时属性和属性值
  • prop:属性标识
  • value:属性值
    # 对目标设置宏定义
    set(BUILD_FLAGS "-DBUILD_DLL" )
    set_target_properties(main PROPERTIES COMPILE_FLAGS ${BUILD_FLAGS})
    # 更改目标输出名称
    add_library (libiwasm SHARED ${WAMR_RUNTIME_LIB_SOURCE})
    set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm)
    # 设置目标文件输出目录
    set_target_properties(iwasm PROPERTIES LIBRARY_OUTPUT_DIRECTORY 
        ${PROJECT_SOURCE_DIR}/build/lib
    # 设置 include 目录搜索目录
    set_target_properties(iwasm PROPERTIES INCLUDE_DIRECTORIES ${LIB_RATS_DIR})
    # 设置debug模式目标后缀
    set_target_properties(iwasm PROPERTIES DEBUG_POSTFIX dbg)
    # 设置生成地址无关码的可执行目标或者库目标
    set_target_properties(wamrc PROPERTIES POSITION_INDEPENDENT_CODE ON)
    # 自定义目标属性
    set_target_properties(<target> PROPERTIES <custom_property_name> <value>)
    

    二十、获取目标属性

    get_target_property(<variable> 
    										<target>
                        <property>)
    
  • variable:存储属性的变量
  • target:获取属性的目标
  • property:属性标识
    # 获取 debug 目标文件的后缀名
    get_target_property(postfix iwasm DEBUG_POSTFIX)
    
  •