zoukankan      html  css  js  c++  java
  • cmake学习

    cmake小练习:https://github.com/ME-TWM/cmake_practice

    make工具通过调用makefile文件中的命令便可以对大型程序进行编译,而makefile文件中就包含了调用gcc去编译多个源文件的命令。

    但是,有一个问题,如果我们的程序是跨平台的,如果换个平台makefile又要重新修改,这会很麻烦,所以就出现了cmake这个工具,通过cmake我们就可以快速创建出不同平台的makefile文件。

    所以,cmake根据CMakeLists.txt来生成makefile文件。为了编译一个大型程序,你首先编写CMakeLists.txt。然后,通过cmake命令就可以生成makefile文件。然后通过make命令就可以使用这个makefile文件从而生成可执行文件。

    一个CMakelists.txt就创建一个project(使用project(name)命令),一个project可以包含多个subproject,一般在顶层project(toplevel CMakeLists.txt,在最外围的目录)里生成一个可执行文件(add_executable),一个project里可以创建多个target(add_library或add_executable),一个target可能是一个静态库/动态库/二进制文件,在project里会把有依赖关系的target链接起来(target_link_libraries)

    project(NAME)
    这个命令会创建一个名称为NAMEproject,同时也会创建一个全局变量${PROJECT_NAME},其值为NAME,
    下面截取自02-subproject
    When a project is created using the `project()` command, CMake will automatically
    create a number of variables which can be used to reference details about the project.
    These variables can then be used by other sub-projects or the main project. For exampe,
    to reference the source directory for a different project you can use.

    [source,cmake]
    ----
        ${sublibrary1_SOURCE_DIR}
        ${sublibrary2_SOURCE_DIR}
    ----

    The variables created by CMake are:

    [cols=",",options="header",]
    |=======================================================================
    |Variable |Info
    |PROJECT_NAME | The name of the project set by the current `project()`.

    |CMAKE_PROJECT_NAME |the name of the first project set by the `project()`
    command, i.e. the top level project.

    |PROJECT_SOURCE_DIR |The source director of the current project.(当前这个cmakelists所在的路径)

    |PROJECT_BINARY_DIR |The build directory for the current project.

    |name_SOURCE_DIR | The source directory of the project called "name".
    In this example the source directories created would be `sublibrary1_SOURCE_DIR`,
    `sublibrary2_SOURCE_DIR`, and `subbinary_SOURCE_DIR`

    |name_BINARY_DIR | The binary directory of the project called "name".
    In this example the binary directories created would be `sublibrary1_BINARY_DIR`,
    `sublibrary2_BINARY_DIR`, and `subbinary_BINARY_DIR`

    |=======================================================================


    CMAKE_BINARY_DIR
    PROJECT_BINARY_DIR
    <projectname>_BINARY_DIR
    这三个变量指代的内容是一致的,如果是 in source 编译,指得就是工程顶层目录,如果是 out-of-source 编译,指的是工程编译发生的目录。PROJECT_BINARY_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。
    in source 编译:直接在工程顶层目录运行cmake命令
    out-of-source 编译:在其他任何目录下运行cmake命令。

    比如:out-of-source build一般在源文件的顶层目录中 新建build目录

    cd build

    然后  cmake .. -G"MinGW Makefiles"即可

    这样所有的临时文件 都会放在build目录下不会和source有任何的瓜噶。


    in source 编译:
    指定编译所要求的最低cmake版本:
    cmake_minimum_required(VERSION 2.6)
    project (hello_cmake)
    add_executable(${PROJECT_NAME} main.cpp)


    add_executable(hello_cmake main.cpp)
    会生成一个名为hello_cmake 的可执行文件,该文件通过main.cpp等源文件(可以是多个文件)编译而来

    add_library()
    function is used to create a library from some source files.
    Eg:
    add_library(hello_library STATIC
        src/Hello.cpp
    )
    This will be used to create a static library with the name libhello_library.a with
    the sources in the +add_library+ call.(使用static时即生成.a格式的静态库)
    除了static外,其实一共有这几种:
    SHARED,动态库(.so)
    STATIC,静态库(.a)
    MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。
    如果我们想改生成的库的名字,可以用这个(被改为hello):
    SET_TARGET_PROPERTIES(hello_library PROPERTIES OUTPUT_NAME "hello")

    Eg2:
    add_library(hello::library ALIAS hello_library)
    just like "typedef".
    hello::library is the same as hello_library now. They are 2 names of the same thing.
    And please note that "hello::library" is just a name !!! NO namespace in CMake!!!!
    SHARED:  generate the shared library from the library sources
    ALIAS:   just like "typedef".

    add_library() 用于创建库(生成的target是library文件),他的入参一般是纯粹定义了一堆函数(而没有类似main的执行入口)的源文件(对add_library()和target_include_libraries()而言,cmakelists中先调用add_library()来生成库A,再对库A调用target_include_libraries()来让库A生成的时候包含指定的路径(否则没生成库A的话也没办法把库A的名称当做target_include_libraries()的入参),同理也是先用add_executable()生成可执行文件,再调用target_include_libraries()来给欲生成的可执行文件链接其他库)

    add_executable()用于创建可执行文件(生成的target是Binary文件)
    (入参是带有main函数的源文件,一般手法是在其他cmakelists中调用add_library()来生成库,然后在调用调用add_executable()的cmakelists里面调用target_link_libraries来使用这些库)



    target_include_directories()
    When you have different include folders, you can make your compiler aware of them using function

    eg:
    target_include_directories(target  PRIVATE  路径A)
    (对target(无论是用add_executable还是add_library生成)使用这个函数时,他自己的源代码(当前即当前这个project中add_library或add_executable指定的源文件)就能看见target_include_directories指定的路径A,相当于在这些源文件所在的目录中增加了路径A的内容!如果其他project使用target_link_libraries链接了这个target,则也会像在自己的cmakelists中加了这段代码一样(如果设置为 PUBLIC 的话),根据PRIVATE/INTERFACE/PUBLIC的设定,在其他project所对应的代码也能看见或看不见路径A,相当于 每个链接了当前这个target的project的源代码所在的目录都拥有了一份路径A的内容的拷贝!这样在这些project的源代码(即add_library中指定的源文件)就能像这个目录的内容直接拷贝到了这里一样来编码!)
    The +PRIVATE+ identifier specifies the scope of the include.
    The meaning of scopes are:
     +PRIVATE+ - the directory is added to this target's include directories
    (比如这个target tar是由a.cpp生成,a.cpp里有这段代码:#include “include/lib.h”,使用target_include_directories(tar  PRIVATE  A/B)后,类似上面的#include代码编译器会解释为#include “A/B/include/lib.h”(lib.h这个头文件实际路径是A/B/include/lib.h))正如下面所言:
    The directory passed to +target_include_directories+ will be the root of your
    include directory tree and your C++ files should include the path from there to your header.
    For this example you can see that we do it as follows in the cpp files:
    #include "static/Hello.h"

    * +INTERFACE+ - the directory is added to the include directories for any targets that link this library.
    * +PUBLIC+ - As above, it is included in this library and also any targets that link this library.
    (也就是相当于使用target_link_libraries()链接这个target的其他target也加上了这个函数代码(如即生成这个其他target的源文件的include代码路径前也加上了这个路径))

    target_link_libraries()
    When creating an executable that will use your library you must tell the compiler
    about the library. This can be done using this function
    eg:
    target_link_libraries( hello_binary
        PRIVATE  
            hello_library
    )
    This tells CMake to link the hello_library against the hello_binary executable
    during link time(注意第一个hello_binary是一个add_executable生成的可执行文件,第二个hello_library是一个add_library生成的lib库). It will also propagate any include directories with +PUBLIC+ or +INTERFACE+ scope
     from the linked library target.
    An example of this being called by the compiler is
    ```
    /usr/bin/c++ CMakeFiles/hello_binary.dir/src/main.cpp.o -o hello_binary -rdynamic libhello_library.a
    ```


    为了打印出make命令执行时的完整信息,可以在后面加上参数verbose=1:
    $ make VERBOSE=1


    Create a sources variable with a link to all cpp files to compile
    eg:
    set(SOURCES
        src/Hello.cpp
        src/main.cpp
    )




    CMake offers the ability to add a `make install` target to allow a user to
    install binaries, libraries and other files. The base install location is controlled
    by the variable +CMAKE_INSTALL_PREFIX+ which can be set using ccmake or by calling
    cmake with:
    $cmake .. -DCMAKE_INSTALL_PREFIX=/install/location

    CMAKE_INSTALL_PREFIX是这么一个变量:这个变量初始为空,由用户设定,里面保存一些路径,以分号分隔,在调用以下这些命令时,会在这些路径中搜索相应的入参:
    find_package(), find_program(), find_library(), find_file(), find_path()
    CMAKE_MODULE_PATH:概念和CMAKE_INSTALL_PREFIX一样,在调用以下命令时会在这个变量的路径中搜索:
    include(),find_package()
    在下面的install命令中,也会用到CMAKE_INSTALL_PREFIX




    The files that are installed are controlled by the function:
    install()
    install用于指定在安装时运行的规则。它可以用来安装很多内容,可以包括目标二进制、动态库、静态库以及文件、目录、脚本等.执行完cmake ..      make    之后,还要执行 make install才能真正安装东西到指定路径(注意要以管理员身份执行,因为默认的写入路径需要写入权限)
    eg:
    install (TARGETS cmake_examples_inst_bin
        DESTINATION bin)
    Install the binary generated from the target cmake_examples_inst_bin target to
    the destination +${CMAKE_INSTALL_PREFIX}/bin+
    (注意是TARGETS,因此后面可以带多个target做入参)
    eg2:
    install (TARGETS cmake_examples_inst
        LIBRARY DESTINATION lib)
    Install the shared library generated from the target cmake_examples_inst target to
    the destination +${CMAKE_INSTALL_PREFIX}/lib+
    eg3:
    install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
        DESTINATION include)
    ----
    Install the header files for developing against the +cmake_examples_inst+ library
    into the +${CMAKE_INSTALL_PREFIX}/include+ directory.
    Eg4:
    install (FILES cmake-examples.conf
        DESTINATION etc)
    ----
    Install a configuration file to the destination +${CMAKE_INSTALL_PREFIX}/etc+

    After `make install` has been run, CMake generates an install_manifest.txt file
    which includes details on all installed files.
    当CMakeLists.txt中有install命令时,需要在命令行执行完cmake,make命令后,还要(用超级权限)再执行 make install命令,CMakeLists.txt中的install命令才会真正执行

    As mentioned the default install location is set from the +CMAKE_INSTALL_PERFIX+,
    which defaults to `/usr/local/`
    eg:
    if( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
      message(STATUS "Setting default CMAKE_INSTALL_PREFIX path to ${CMAKE_BINARY_DIR}/install")
      set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE STRING "The path to use for make install" FORCE)
    endif()
    ----
    This example sets the default install location to under your build directory.


    If you wish to stage your install to confirm that all files are included the
    `make install` target supports the DESTDIR argument.
    ```
    make install DESTDIR=/tmp/stage
    ```
    This will create the install path `${DESTDIR}/${CMAKE_INSTALL_PREFIX}` for all
    your installation files.
    In this example, it would install all files under the
    path `/tmp/stage/usr/local`
    即:
    $cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local  
    (注:/usr/local是CMAKE_INSTALL_PREFIX的默认值,后面这个参数不加也罢)
    $make install DESTDIR=/tmp/stage





    The build type can be set using the following methods.

      - Using a gui tool such as ccmake / cmake-gui

    image::cmake-gui-build-type.png[cmake-gui build type]

      - Passing into cmake

    [source,cmake]
    ----
    cmake .. -DCMAKE_BUILD_TYPE=Release
    ----

    ## Set Default Build Type

    The default build type provided by CMake is to include no compiler flags for
    optimization. For some projects you may want to
    set a default build type so that you do not have to remember to set it.

    To do this you can add the following to your top level CMakeLists.txt

    [source,cmake]
    ----
    if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
      message("Setting build type to 'RelWithDebInfo' as none was specified.")
      set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
      # Set the possible values of build type for cmake-gui
      set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
        "MinSizeRel" "RelWithDebInfo")
    endif()

    设置 compile flags 的几种方式:
    第一种:
    target_compile_definitions(cmake_examples_compile_flags
        PRIVATE EX3
    )
    This will cause the compiler to add the definition +-DEX3+ when compiling the target.

    第二种:
    using the +CMAKE_C_FLAGS+ or +CMAKE_CXX_FLAGS+ variables.
    Eg:
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)
    The values `CACHE STRING "Set C++ Compiler Flags" FORCE` from the above command
    are used to force this variable to be set in the CMakeCache.txt file.
    Once set the +CMAKE_C_FLAGS+ and +CMAKE_CXX_FLAGS+ will set a compiler flag / definition globally for all targets in this directory or any included sub-directories. This method is not recommended for general usage now and the +target_compile_definitions+ function is preferred.
    第三种:
    cmake .. -DCMAKE_CXX_FLAGS="-DEX3"

    第四种:
    add_compile_options
    (参考:https://blog.csdn.net/10km/article/details/51731959)

    注意!在cmakelists中,设置选项时-D后面的才是参数!前面的D是用来说明后面的是参数!
    例如:
    cmake .. -DCMAKE_CXX_FLAGS="-DEX3"
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)
    target_compile_definitions(cmake_examples_compile_flags
        PRIVATE EX3
    )
    同理,为了说明这是一个库,会在库名前面加上lib
    上面的编译选项EX2,EX3只是一个标识符,没有什么特殊含义,在源文件中可能会这样使用,例如:
    int main(int argc, char *argv[])
    {
       std::cout << "Hello Compile Flags!" << std::endl;

       // only print if compile flag set
    #ifdef EX2
      std::cout << "Hello Compile Flag EX2!" << std::endl;
    #endif

    #ifdef EX3
      std::cout << "Hello Compile Flag EX3!" << std::endl;
    #endif

       return 0;
    }


    find_package()
    This will search for CMake modules in the format
    "FindXXX.cmake" from the list of folders in `CMAKE_MODULE_PATH`. On linux the
    default search path will include `/usr/share/cmake/Modules`.
    Most included packages will set a variable `XXX_FOUND`, which can be used to check
    if the package is available on the system.
    Eg:
    find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)
    it will search for CMake modules Boost  in the formant FindBoost .cmake from the list of folders in `CMAKE_MODULE_PATH`.
    Boost_FOUND was used in the Cmakelists like this:
    ---------------
    if(Boost_FOUND)
        message ("boost found")
        include_directories(${Boost_INCLUDE_DIRS})
    else()
        message (FATAL_ERROR "Cannot find Boost")
    endif()
    -----------------
    The arguments are:
      * Boost - Name of the library. This is part of used to find the module file FindBoost.cmake
      * 1.46.1 - The minimum version of boost to find
      * REQUIRED - Tells the module that this is required and to fail it it cannot be found
    * COMPONENTS - The list of libraries to find.


    When building with CMake it is possible to set the C and C++ compiler.
    CMake exposes options to control the programs used to compile and link your code. These
    programs include:

      * CMAKE_C_COMPILER - The program used to compile c code.
      * CMAKE_CXX_COMPILER - The program used to compile c++ code.
    * CMAKE_LINKER - The program used to link your binary.
    Eg:
    cmake .. -DCMAKE_C_COMPILER=clang-3.6 -DCMAKE_CXX_COMPILER=clang++-3.6
    After setting these options, when your run `make` clang will be used to compile your binary.


    To call a CMake generator you can use the `-G` command line switch, for example:
    ----
    cmake .. -G Ninja

    After doing the above CMake will generate the required Ninja build files, which can be run
    from using the `ninja` command.
    (Ninja 是一个构建系统,与 Make 类似。作为输入,你需要描述将源文件处理为目标文件这一过程所需的命令。 Ninja 使用这些命令保持目标处于最新状态。与其它一些构建系统不同,Ninja 的主要设计目标是速度。 )


    3 CHECK_CXX_COMPILER_FLAG
    检查CXX编译器是否支持给定的flag
    必须先include(CheckCXXCompilerFlag)
    include(CheckCXXCompilerFlag)
    CHECK_CXX_COMPILER_FLAG(<flag> <var>)
    eg:
    CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
    if(COMPILER_SUPPORTS_CXX11)#
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
    else()
        message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
    endif()
    就是在检查当前编译器是否支持c++11
    CHECK_CXX_COMPILER_FLAG 赋值给的var是个bool型
    `include(CheckCXXCompilerFlag)` tells CMake to include this function to make it available for use.

    指定编译时的C++版本:
    # set the C++ standard to C++ 11
    set(CMAKE_CXX_STANDARD 11)
    The `CMAKE_CXX_STANDARD` variable falls back to the closest appropriate standard without a failure. For example, if you request `-std=gnu++11` you may end up with `-std=gnu++0x`.
    This can result in an unexpected failure at compile time.



    指定在CMake目标中使用的C++功能
    Calling the function target_compile_features on a target will look at the passed in feature and determine the correct compiler flag to use for your target.
    target_compile_features look at the passed in feature and determine the correct compiler flag to use for your target.
    The list of available features can be found from the CMAKE_CXX_COMPILE_FEATURES
    eg:
    # set the C++ standard to the appropriate standard for using auto
    target_compile_features(hello_cpp11 PUBLIC cxx_auto_type)
    message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}")

    • add_subdirectory (source_dir [binary_dir] [EXCLUDE_FROM_ALL])

      添加一个子目录并构建该子目录。

    • 命令解析

      • source_dir
        必选参数。该参数指定一个子目录,子目录下应该包含CMakeLists.txt文件和代码文件。子目录可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前目录的一个相对路径。
      • binary_dir
        可选参数。该参数指定一个目录,用于存放输出文件。可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前输出目录的一个相对路径。如果该参数没有指定,则默认的输出目录使用source_dir
      • EXCLUDE_FROM_ALL
        可选参数。当指定了该参数,则子目录下的目标不会被父目录下的目标文件包含进去,父目录的CMakeLists.txt不会构建子目录的目标文件,必须在子目录下显式去构建。例外情况:当父目录的目标依赖于子目录的目标,则子目录的目标仍然会被构建出来以满足依赖关系(例如使用了target_link_libraries)
  • 相关阅读:
    本地向GitHub提交403错误解决办法(自己的创建的项目)
    zepto-ajax跨域请求接口 jsonp 静态页面数据展示
    自定义获取url方法
    使用swiper 轮播插件ajax 请求加载图片时,无法滑动问题
    背景透明,文字不透明解决办法
    js DOM Element属性和方法整理----转载
    图像处理作业5——SIFT算法与全景图像生成
    应用连续高斯模糊后得到的σ是多少?
    Pandas学习笔记——综合练习
    Pandas学习笔记5——合并
  • 原文地址:https://www.cnblogs.com/tan-wm/p/14669096.html
Copyright © 2011-2022 走看看