zoukankan      html  css  js  c++  java
  • cmake和CMakeLists.txt学习

    cmake和CMakeLists.txt学习

    工作需要,要学习cmake,于是学习一波,记录一下。

    掌握cmake的东西对于Linux下的运行提供便利,其次是编写makefile感觉有点难,内容多,而cmake简单,语法基本不多。

    首先cmake到底是什么呢?
    百度百科的介绍:CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名
    为 CMakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以
    用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是 CMake 和 SCons 等其他类似系统的区别之处。

    cmake的使用
    cmake的所有语句都写在一个CMakeLists.txt的文件中,CMakeLists.txt文件确定后,直接使用cmake命令进行运行,但是这个命令要指向CMakeLists.txt所在的目录,cmake之后就会产生我们想要的makefile文件。
    引用cmake的使用方法这篇文章http://www.cnblogs.com/lyq105/archive/2010/12/03/1895067.html,

    cmake执行的流程:

    $> ccmake directory
    $> cmake directory
    $> make
    

    其中directory为CMakeList.txt所在目录;
    第一条语句用于配置编译选项,如VTK_DIR目录 ,一般这一步不需要配置,直接执行第二条语句即可,但当出现错误时,这里就需要认为配置了,这一步才真正派上用场;
    第二条命令用于根据CMakeLists.txt生成Makefile文件;
    第三条命令用于执行Makefile文件,编译程序,生成可执行文件;

    1. 一个最简单的例子:
    输出hello world

    // main.c
    #include <stdio.h>
    int main()
    {
    printf("hello world");
    return 0;
    }
    

    CMakeLists.txt文件:

    project(HELLO)
    set(SRC_LIST main.c)
    add_executable(hello ${SRC_LIST}))
    

    就这几句,是不是很简单,由于执行cmake的时候会产生很多中间文件,我们采用out of source(外部编译)方式进行构建,我们建立一个build目录储存中间执行过程。

    例子目录下的文件,进入build目录,执行cmake ..,cmake执行指向上一个目录,也就是存储CMakeLists.txt的目录,完成后就会看到makefile文件,make过后就会看到执行文件。
    第一个行project不是强制性的,最好加上,这会引入两个变量:

    HELLO_BINARY_DIR, HELLO_SOURCE_DIR
    

    同时也会定义两个等价的变量:

    PROJECT_BINARY_DIR, PROJECT_SOURCE_DIR
    

    外部编译要时刻区分这两个变量对应的目录:
    可以通过message进行输出

    message(${PROJECT_SOURCE_DIR})
    

    set 命令用来设置变量:

    add_exectuable 告诉工程生成一个可执行文件。
    add_library 则告诉生成一个库文件。
    

    注意:CMakeList.txt 文件中,命令名字是不区分大小写的,而参数和变量是大小写相关的。

    2. 一个源文件的例子一似乎没什么意思,拆成3个文件再试试看:

    hello.h 头文件

    #ifndef _HELLO_H
    #define _HELLO_H
    
    void hello(const char* name);
    #endif
    

    hello.c

    #include <stdio.h>
    #include "hello.h"
    void hello(const char * name)
    {
    printf ("Hello %s!/n", name);
    }
    

    main.c

    #include "hello.h"
    int main()
    {
    hello("World");
    return 0;
    }
    

    然后准备好CMakeLists.txt 文件

    project(HELLO)
    set(SRC_LIST main.c hello.c)
    add_executable(hello ${SRC_LIST})
    

    执行cmake的过程同上

    3. 接前面的例子,我们将 hello.c 生成一个库,然后再使用会怎么样?
    改写一下前面的CMakeLists.txt文件试试:

    project(HELLO)
    set(LIB_SRC hello.c)
    set(APP_SRC main.c)
    add_library(libhello ${LIB_SRC})
    add_executable(hello ${APP_SRC})
    target_link_libraries(hello libhello)
    

    和前面相比,我们添加了一个新的目标 libhello,并将其链接进hello程序

    因为我的可执行程序(add_executable)占据了 hello 这个名字,所以 add_library 就不能使用这个名字了
    然后,我们去了个libhello 的名字,这将导致生成的库为 libhello.lib(或 liblibhello.a),很不爽
    想生成 hello.lib(或libhello.a) 怎么办?

    添加一行

    set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
    

    就可以了

    4. 在前面,我们成功地使用了库,可是源代码放在同一个路径下,还是不太正规,怎么办呢?
    分开放呗,现在需要3个CMakeLists.txt 文件了,每个源文件目录都需要一个,还好,每一个都不是太复杂

    顶层的CMakeLists.txt 文件

    project(HELLO)
    add_subdirectory(src)
    add_subdirectory(libhello)
    

    src 中的 CMakeLists.txt 文件

    include_directories(${PROJECT_SOURCE_DIR}/libhello)
    set(APP_SRC main.c)
    add_executable(hello ${APP_SRC})
    target_link_libraries(hello libhello)
    

    libhello 中的 CMakeLists.txt 文件

    set(LIB_SRC hello.c)
    add_library(libhello ${LIB_SRC})
    set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
    

    恩,和前面一样,建立一个build目录,在其内运行cmake,然后可以得到
    build/src/hello.exe
    build/libhello/hello.lib
    回头看看,这次多了点什么,顶层的 CMakeLists.txt 文件中使用 add_subdirectory 告诉cmake去子目录寻找新的CMakeLists.txt 子文件
    在 src 的CMakeLists.txt 文件中,新增加了include_directories,用来指明头文件所在的路径。

    5. 前面还是有一点不爽:如果想让可执行文件在 bin 目录,库文件在 lib 目录怎么办?
    一种办法:修改顶级的 CMakeLists.txt 文件

    project(HELLO)
    add_subdirectory(src bin)
    add_subdirectory(libhello lib)
    

    不是build中的目录默认和源代码中结构一样么,我们可以指定其对应的目录在build中的名字。
    这样一来:build/src 就成了 build/bin 了,可是除了 hello.exe,中间产物也进来了。还不是我们最想要的。

    另一种方法:不修改顶级的文件,修改其他两个文件

    src/CMakeList.txt 文件
    include_directories(${PROJECT_SOURCE_DIR}/libhello)
    #link_directories(${PROJECT_BINARY_DIR}/lib)
    set(APP_SRC main.c)
    set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
    add_executable(hello ${APP_SRC})target_link_libraries(hello libhello)
    libhello/CMakeList.txt 文件
    set(LIB_SRC hello.c)
    add_library(libhello ${LIB_SRC})
    set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
    set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
    

    6. 在例子三至五中,我们始终用的静态库,那么用动态库应该更酷一点吧。 试着写一下
    如果不考虑windows下,这个例子应该是很简单的,只需要在上个例子的 libhello/CMakeLists.txt 文件中的
    add_library命令中加入一个SHARED参数:

    add_library(libhello SHARED ${LIB_SRC})
    

    $cmake_learn tree
    .
    ├── build
    ├── CMakeLists.txt
    ├── libhello
    │?? ├── CMakeLists.txt
    │?? ├── hello.c
    │?? └── hello.h
    └── src
    ├── CMakeLists.txt
    └── main.c

    参考文档:

    1. https://www.jianshu.com/p/cb4f8136a265
    2. https://www.cnblogs.com/sddai/p/10328977.html
  • 相关阅读:
    用OKR让你的员工嗨起来
    用数据让我们的OKR变得“冷酷”却更有价值
    好的想法只是OKR的开始创业者谨记
    “OKR播种机”JOHN DOERR–目标是对抗纷乱思绪的一针疫苗
    用OKR提升员工的执行力
    OKR的两个基本原则
    《OKR工作法》| 一次说太多等于什么都没说
    《OKR工作法》–让所有人承担自己的职责
    《OKR工作法》——打造一支专一的团队
    Oracle wm_concat()函数的实际运用
  • 原文地址:https://www.cnblogs.com/michaelcjl/p/14814937.html
Copyright © 2011-2022 走看看