Cmake使用方法

Cmake使用方法

一、基础编译

  1. 项目与文件结构
    项目结构
    1
    2
    3
    4
    5
    6
    .
    ├── build
    ├── CMakeList.txt
    ├── main.c
    ├── testFunc.c
    └── testFunc.h
    main.c
    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>
    #include "testFunc.h"

    int main(void)
    {
    func(100);
    return 0;
    }
    testFunc.c
    1
    2
    3
    4
    5
    6
    7
    8

    #include <stdio.h>
    #include "testFunc.h"

    void func(int data)
    {
    printf("data is %d\n", data);
    }
    testFunc.h
    1
    2
    3
    4
    5
    6
    7

    #ifndef _TEST_FUNC_H_
    #define _TEST_FUNC_H_

    void func(int data);

    #endif
    CMakeLists.txt
    1
    2
    3
    4
    5
    6
    # CMake最低版本号要求
    cmake_minimum_required (VERSION 2.8)
    # 项目信息
    project (demo)
    # 指定生成目标
    add_executable(main main.c testFunc.c)
  2. 编译与运行
    1
    2
    3
    cd build && cmake ../
    make -j8
    ./main
  3. 思考与改进
    1. 如果在同一目录下有多个源文件,需要在add_executable里把所有源文件都添加进去,这太不优雅了。因此使用aux_source_directory(dir var)把指定目录下所有的源文件存储在一个变量中,第一个参数dir是指定目录,第二个参数var是用于存放源文件列表的变量名。

    2. 当程序文件比较多时,我们会进行分类管理,把代码根据功能放在不同的目录下,这样方便查找。这个时候头文件定位需要用以下命令来实现,不够优雅。

      1
      2
      #include "xxxxxx/testFunc.h"
      #include "xxxxxx/testFunc1.h"

      因此使用include_directories 方法添加多个指定头文件的搜索路径,路径之间用空格分隔。

    3. 源代码随意放置,不够优雅,统一放入src文件夹后要用add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])设置源代码目录。其中**source_dir 指定一个包含CMakeLists.txt和代码文件所在的目录;binary_dir二进制代码目录执行后的输出文件将会存放在此处;EXCLUDE_FROM_ALL标记,表示新增加的子目录将会排除在ALL目录之外。**

二、进阶编译

  1. 项目与文件结构
    项目结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    .
    ├── bin
    ├── build
    ├── CMakeList.txt
    ├── include1
    | └── testFunc1.h
    ├── include2
    | └── testFunc2.h
    └── src
    ├── main.c
    ├── testFunc1.c
    └── testFunc2.c

    main.c

    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>
    #include "testFunc.h"

    int main(void)
    {
    func(100);
    return 0;
    }

    testFunc.c

    1
    2
    3
    4
    5
    6
    7
    8

    #include <stdio.h>
    #include "testFunc.h"

    void func(int data)
    {
    printf("data is %d\n", data);
    }

    testFunc.h

    1
    2
    3
    4
    5
    6
    7

    #ifndef _TEST_FUNC_H_
    #define _TEST_FUNC_H_

    void func(int data);

    #endif

    CMakeLists.txt

    1
    2
    3
    4
    cmake_minimum_required (VERSION 2.8)
    project (demo)
    # 设置源代码目录
    add_subdirectory (src)

    这里指定src目录下存放了源文件,当执行cmake时,就会进入src目录下去找src目录下的CMakeLists.txt,所以在src目录下也建立一个CMakeLists.txt,内容如下:
    src/CMakeLists.txt

    1
    2
    3
    4
    5
    6
    7
    8
    # 将当前src/CMakeLists.txt同文件夹下所有文件添加进SRC_LIST变量
    aux_source_directory (. SRC_LIST)
    # 添加头文件目录
    include_directories (../include1 ../include2)
    # 制定生成目标
    add_executable (main ${SRC_LIST})
    # 设定目标二进制可执行文件的存放位置,其中PROJECT_SOURCE_DIR为工程根目录
    set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
  2. 编译与运行

    1. 编译
      1
      2
      3
      cd build
      cmake ..
      make -j8
      这样Makefile会在build目录下生成,二进制程序会在bin目录下生成,然后运行可执行程序:
      1
      2
      cd ../bin
      ./main
  3. 思考与改进

    只使用一个CMakeList.txt,把最外层的CMakeLists.txt内容改成如下
    CMakeLists.txt

    1
    2
    3
    4
    5
    6
    cmake_minimum_required (VERSION 2.8)
    project (demo)
    set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
    aux_source_directory (src SRC_LIST)
    include_directories (include1 include2)
    add_executable (main ${SRC_LIST})

    此时还需要把src目录下的CMakeList.txt删除即可

三、生成库文件

  1. 项目结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ├── bin
    ├── build
    ├── CMakeList.txt
    ├── include1
    | └── testFunc1.h
    ├── include2
    | └── testFunc2.h
    ├── lib
    └── src
    ├── main.c
    ├── testFunc1.c
    └── testFunc2.c

    CMakeList.txt

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    cmake_minimum_required (VERSION 3.5)
    project (demo)
    set (SRC_LIST1 ${PROJECT_SOURCE_DIR}/src/testFunc1.c)
    set (SRC_LIST2 ${PROJECT_SOURCE_DIR}/src/testFunc2.c)
    include_directories (../include1 ../include2)

    # add_library:生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件)
    add_library (testFunc_shared1 SHARED ${SRC_LIST1})
    add_library (testFunc_shared2 SHARED ${SRC_LIST2})
    add_library (testFunc_static1 STATIC ${SRC_LIST1})
    add_library (testFunc_static2 STATIC ${SRC_LIST2})

    # set_target_properties: 设置最终生成的库的名称,还有其它功能,如设置库的版本号等
    set_target_properties (testFunc_shared1 PROPERTIES OUTPUT_NAME "testFunc1")
    set_target_properties (testFunc_shared2 PROPERTIES OUTPUT_NAME "testFunc2")
    set_target_properties (testFunc_static1 PROPERTIES OUTPUT_NAME "testFunc1")
    set_target_properties (testFunc_static2 PROPERTIES OUTPUT_NAME "testFunc2")

    # LIBRARY_OUTPUT_PATH: 库文件的默认输出路径,这里设置为工程目录下的lib目录
    set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
  2. 运行查看编译好的库文件

    1
    2
    3
    4
    5
    cd build/
    cmake ..
    make
    cd ../lib/
    ls

    最后将会在lib文件夹下生成libtestFunc.alibtestFunc.so

四、链接库文件

  1. 项目结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ├── bin
    ├── build
    ├── CMakeList.txt
    ├── include1
    | └── testFunc1.h
    ├── include2
    | └── testFunc2.h
    ├── lib
    | ├── libtestFunc1.a
    | ├── libtestFunc1.so
    | ├── libtestFunc2.a
    | └── libtestFunc2.so
    └── src
    ├── main.c
    ├── testFunc1.c
    └── testFunc2.c

    main.c

    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>
    #include "testFunc.h"
    int main(void)
    {
    func(100);
    return 0;
    }

    CMakeLists.txt

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    cmake_minimum_required (VERSION 3.5)
    project (demo)
    set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
    set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.c)
    include_directories (${PROJECT_SOURCE_DIR}/testFunc/inc)

    # find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径
    find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib)
    add_executable (main ${SRC_LIST})

    # target_link_libraries: 把目标文件与库文件进行链接
    target_link_libraries (main ${TESTFUNC_LIB})
  2. 编译与运行

    1
    2
    3
    4
    5
    cd build/
    cmake ..
    make
    cd ../bin/
    ./main