美文网首页
[Note] CMake的简单使用

[Note] CMake的简单使用

作者: 赶时间的闹钟 | 来源:发表于2019-03-30 16:50 被阅读0次

    当前环境 macOScmake 3.9.4

    一 gcc, make, cmake 的区别

    1. gcc 是一个编译器套件,用于编译多种语言的源文件
    2. gcc 需要编译多个文件时,编译指令很多时,则会使用 makefile 按照特定规则来对指令(gcc操作指令)进行整合,使用 make 工具来执行指令组。
    3. 由于 makefile 依赖于确定的编译器套件(如指令中的gcc ...),这时出现了通用工具CMake(根据实际的平台/环境选择编译套件并进行编译),与之搭配的是 CMakeLists.txt,输出是makefile
    4. 依次次进化和依赖的关系

    二 编译一个 .cpp/.c 文件

    随便在一个文件夹中新建两个文件,命令行cd到这个文件夹中

    $ touch CMakeLists.txt test.cpp # CMakeLists.txt 必须
    $ tree
    .
    ├── CMakeLists.txt
    └── test.cpp
    

    CMakeLists.txt

    # 添加需要编译的源文件 test.cpp 和 输出的可执行文件名字 exe_main
    ADD_EXECUTABLE(exe_main test.cpp)
    

    test.cpp

    #include<stdio.h>
    
    int main(int argc, char const *argv[])
    {
        printf("Using cmake ...\n");
        return 0;
    }
    

    文件准备完毕,接着就是编译了

    $ cmake ./
    $ make
    $./exe_main
    

    看到最后效果,其实也是$ gcc test.cpp -o exe_main 一样的效果嘛,不过像上面说的,cmake加入了跨平台/环境

    最后奉上全部材料


    一个简单的例子.png

    因为执行编译动作时,产生了很多文件,所以建议新建一个build目录,到里面执行编译指令,以免混乱了我们的源文件目录。也想说的是,这里的CMakeLists.txt写法并不标准哦,仅供学习 ~

    三 编译多个.c/.cpp文件

    经过上面简单粗暴的方法之后,总感觉文件一多了不稳妥,所以接下来吧源文件和头文件分开(注意:多文件连接,容易出现名字冲突:duplicate symbol ...

    新建文件u.cpp u.h 分别放到对应的文件夹中,最后目录结构为

    .
    ├── CMakeLists.txt
    ├── build
    ├── include
    │   └── u.h
    └── src
        ├── test.cpp
        └── u.cpp
    

    u.h 文件

    int add(int i, int j);
    

    u.cpp文件

    #include "../include/u.h"
    
    int add(int i, int j) {
        return i + j;
    }
    

    test.cpp文件

    #include<stdio.h>
    #include "../include/u.h"
    
    int main(int argc, char const *argv[])
    {
        printf("Using cmake ...%d\n", add(13, 14));
        return 0;
    }
    

    CMakeLists.txt 文件修改成

    # 指定 cmake 版本,预防某些用户使用较低版本的来编译该项目
    cmake_minimum_required(VERSION 3.2)
    
    # 指定一个项目名称,后面可以通过 `${PROJECT_NAME}` 来引用
    PROJECT(my_project)
    
    # 指定头文件目录,改参数为头文件所在的文件夹名字
    INCLUDE_DIRECTORIES(include)
    
    # 源文件目录
    AUX_SOURCE_DIRECTORY(src DIR_SRCS)
    
    # 选择性设置环境变量,然后通过 ${CUSTOM_VAR} 来引用
    # SET(CUSTOM_VAR ${DIR_SRCS})
    
    # 添加需要编译的源文件 test.cpp 和 输出的可执行文件名字 exe_main
    ADD_EXECUTABLE(${PROJECT_NAME} ${DIR_SRCS})
    

    文件准备完毕,cdbuild目录执行

    $ cmake ../
    $ make
    $ ./my_project
    Using cmake ...27 # 输出
    

    四 编译动态库态库

    在上面的基础上继续,当前的目录结构为($ tree -L 2)

    .
    ├── CMakeLists.txt
    ├── build
    │   ├── CMakeCache.txt
    │   ├── CMakeFiles
    │   ├── Makefile
    │   └── cmake_install.cmake
    ├── include
    │   └── u.h
    └── src
        ├── test.cpp
        └── u.cpp
    

    我们把 u.cpp 编译成动态库,则修改 CMakeLists.txt 如:

    # 指定 cmake 版本,预防某些用户使用较低版本的来编译该项目
    cmake_minimum_required(VERSION 3.2)
    
    # 指定一个项目名称,后面可以通过 `${PROJECT_NAME}` 来引用
    PROJECT(my_project)
    
    # 指定头文件目录,改参数为头文件所在的文件夹名字
    INCLUDE_DIRECTORIES(include)
    
    # 源文件目录
    AUX_SOURCE_DIRECTORY(src DIR_SRCS)
    
    # 选择性设置环境变量,然后通过 ${CUSTOM_VAR} 来引用
    # SET(CUSTOM_VAR ${DIR_SRCS})
    
    # 添加需要编译的源文件 test.cpp 和 输出的可执行文件名字 exe_main
    # ADD_EXECUTABLE(${PROJECT_NAME} ${DIR_SRCS})
    
    # 设置一个动态库名字,因为 `ADD_LIBRARY` 中的参数不给设置字符常量
    SET(DYLIB_NAME dytest)
    
    # 生成一个动态库
    ADD_LIBRARY(${DYLIB_NAME}
                SHARED
                src/u.cpp include/u.h)
    

    文件准备完毕,像上面在build目录进行编译就行。

    五 连接动态库

    同样是修改 CMakeLists.txt

    # 增加下面两行
    
    # 添加需要编译的源文件 test.cpp 和 输出的可执行文件名字 exe_main
    ADD_EXECUTABLE(exe_main src/test.cpp)
    
    # 连接
    TARGET_LINK_LIBRARIES(exe_main ${DYLIB_NAME})
    

    文件准备完毕,到 build 里编译

    六 编译并连接静态库(静态库部分合并了 四、五)

    和动态库的编译和链接只相差一个单词,那就是将 SHARED 改成 STATIC,然后改一下库的名字statictest,完结!

    这里提醒一下就是,产生的库就在执行 make 指令的目录,动态库是libxxx.dylib,静态库就是libstatictest.a

    七 连接现有的(第三方)静态库和动态库

    我们就就地取材,将上面输出的静态库和动态库直接拿来用,这里折腾了好久,因为导入第三方库时的语句选择问题,所以贴完整的 CMakeLists.txt 吧,静态库和动态库是差不多的,换一下名字就可以了

    # 指定 cmake 版本,预防某些用户使用较低版本的来编译该项目
    cmake_minimum_required(VERSION 3.2)
    
    # 指定一个项目名称,后面可以通过 `${PROJECT_NAME}` 来引用
    PROJECT(my_project)
    
    # 指定头文件目录,改参数为头文件所在的文件夹名字
    INCLUDE_DIRECTORIES(include)
    
    # 源文件目录
    AUX_SOURCE_DIRECTORY(src DIR_SRCS)
    
    # 选择性设置环境变量,然后通过 ${CUSTOM_VAR} 来引用
    # SET(CUSTOM_VAR ${DIR_SRCS})
    
    # 添加需要编译的源文件 test.cpp 和 输出的可执行文件名字 exe_main
    # ADD_EXECUTABLE(${PROJECT_NAME} ${DIR_SRCS})
    
    # 设置一个动态库名字,因为 `ADD_LIBRARY` 中的参数不给设置字符常量
    SET(LIB_NAME statictest)
    
    # 生成一个库
    # ADD_LIBRARY(${LIB_NAME}
    #           SHARED
    #           src/u.cpp include/u.h)
    
    # 连接一个现有的库
    # 这种方法是可以的
    LINK_DIRECTORIES(lib)
    
    # ADD_LIBRARY(${LIB_NAME}
    #           SHARED
    #           IMPORTED)
    
    # 这里以 `${CMAKE_CURRENT_SOURCE_DIR}` 为目录开始
    #SET_TARGET_PROPERTIES(${LIB_NAME}
    #        PROPERTIES IMPORTED_LOCATION 
    #        ${CMAKE_CURRENT_SOURCE_DIR}/lib/libdytest.dylib)
    
    # 添加需要编译的源文件 test.cpp 和 输出的可执行文件名字 exe_main
    ADD_EXECUTABLE(exe_main 
                src/test.cpp)
    
    # 连接
    TARGET_LINK_LIBRARIES(exe_main 
                        ${LIB_NAME})
    

    和目录 ($ tree -L 2)

    .
    ├── CMakeLists.txt
    ├── build
    │   ├── CMakeCache.txt
    │   ├── CMakeFiles
    │   ├── Makefile
    │   ├── cmake_install.cmake
    │   └── exe_main
    ├── include
    │   └── u.h
    ├── lib
    │   ├── libdytest.dylib
    │   └── libstatictest.a
    └── src
        ├── test.cpp
        └── u.cpp
    

    最后发现,macOS命令行上对.so文件链接不成功,总会报一个库没有加载的错误,这大概就是macOS.dylib 和 .so的不同处理吧!很多细节还需要补充,有空再继续吧 ~
    [Note] Android Studio 中的 CMake 简单使用
    Github

    相关文章

      网友评论

          本文标题:[Note] CMake的简单使用

          本文链接:https://www.haomeiwen.com/subject/sqgjbqtx.html