2021-09-08 cmake之从可执行文件到库

cmake之从可执行文件到库

从可执行文件到库

  • 一些基础的注意事项

    # set minimum cmake version 项目构建的开始需要设置最小的cmake版本,并定义不满足这一要求时的cmake行为
    cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    
    # project name and language 项目名称和支持的编程语言
    project(recipe-01 LANGUAGES CXX)
    # 编译和链接源文件hell0-world.cpp以生成可执行文件hello-world
    add_executable(hello-world hello-world.cpp)
    
    • 上述文件命名为CMakeLists.txt,区分大小写,否则无法解析;

    • CMake语言不区分大小写,但是参数区分大小写;

    • CMake中,c++是默认编程语言,但最好使用LANGUAGES选项在project中显示声明项目的语言;

    • 一些基础指令:

      mkdir -p build # 创建生成构建器的位置
      cd build 
      cmake .. # 指定CMakeLists.txt所在位置
      

      为了不和源代码混淆,一般在源外创建生成构建其目录;

    • CMake是一个构建系统生成器,描述构建系统(VS, Ninja、Makefile等)如何操作才能编译代码;然后CMake为所选的构建系统生成相应的指令;

    • 如何切换生成器:

      • 通过生成器列表确定是否存在所需要的生成器:

        cmake -help
        
      • 切换生成器:

        ...
        cd build
        cmake -G Ninja .. # 即添加-G参数切换所需要使用的生成器
        cmake --build . 
        

        每个生成器都有自己的文件集,构建结果其生成的文件是不同的;

  • 构建和链接静态库和动态库

    • 构建所需要的CMakeLists.txt

      # ---准备操作---
      # set minimum cmake version
      cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
      
      # project name and language
      project(recipe-03 LANGUAGES CXX)
      
      # 创建目标-静态库
      # 生成必要的构建指令,将指定的源码编译到库中
      # 第二个参数为其他值时:
      # STATIC - 用于创建静态库,即编译文件的打包存档,用于在链接其他目标时使用;
      # SHARED - 用于创建动态库链接,并在运行时加载;
      # OBJECT - 将列表中的源码编译到目标文件,不将其进行归档到静态库和共享对象中;
      # MODULE - DSO组,不链接到项目中的任何目标,不过可以进行动态加载,用于构建运行时插件;
      add_library(message STATIC Message.hpp Message.cpp) 
      
      # 创建可执行文件
      # 将库链接到可执行文件,确保hello-world可执行文件正确依赖于message库
      add_executable(hello-world hello-world.cpp)
      
      # 目标库连接到可执行文件
      target_link_libraries(hello-world message)
      

      编译完成之后,会生成一个message.lib静态库文件;

    • 要保证编译的目标文件与生成位置无关, 可以通过使用 set_target_properties 命令;

      set_target_properties(message-objs
      	PROPERTIES
      	POSITION_INDEPENDENT_CODE 1
      )  
      
  • 条件语句控制编译

    • 条件结构为 if-else- else-endif ;

    • 如果需要在不同的行为之间进行切换,如构建静态库或动态库再生成可执行文件和直接生成可执行文件两种选择,则CMake中的文件条件语部分可以编写为:

      ...
      set(USE_LIBRARY OFF) # 设置变量
      message(STATUS "COMPILE SOURCE INTO A LIBRARY? ${USE_LIBRARY}")
      set(USE_SHARED_LIBS OFF)
      list(APPEND _source Message.hpp Message.cpp) # 将文件装入列表
      
      if(USED_LIBRARY)
          add_library(message ${_sources}) #_source是局部变量,前面加下划线,不应该再当前范围之外使用
          add_excutable(hello-world hello-world.cpp)
          target_link_libraries(hell-world message)
      else()
          add_excutable(hell-world hello-world.cpp ${_sources}) #添加方式有所不同
      endif()
      ...
      
  • 向用户显示选项,可以被用户选择性设置

    • 在CMake中使用option(),用于外部设置,从而切换构建系统的生成行为

    • 使用选项替换set(USE_LIBRARY OFF)命令,使得其在命令行可以被修改

      option(USE_LIBRARY "Compile sources into a library" OFF)
      # 三个参数:option(<option_variable> "help string" [initial value])
      # <option_variable> - 变量的名称
      # "help string" - 描述选项的字符段;
      # [initial value] - 选项的默认值
      
      # 编译时使用
      ...
      cd build
      cmake -D USE_LIBRARY=ON .. # -D开关用于为CMake设置任何类型的变量,如逻辑变量、路径等 
      cmake --build .
      
  • 指定编译器

    • CMake将语言的编译器存储在CMAKE__COMPILER 变量中,选择特定的编译器时,可以通过CMAKE__COMPILER进行选择,其中,可以是受支持的任意一种语言

      # 指定编译器的方式有两种
      # 第一种
      cmake -D CMKAE_CXX_COMPILER=clang++ ..
      
      # 第二种
      env CXX=clang++ cmake ..
      
    • 建议使用第二种编译器指定方式,因为环境变量可能被设定为不适合当前项目的值;

    • 可以通过命令cmake --system-information来查看可用的比那一起和对应的编译器的标志;

  • 切换构建类型

    • 构建类型如Debug、Release等;

    • 控制生成构建系统使用的配置变量为CMAKE_BUILD_TYPE,该变量默认为空;

    • 使用

      # 准备
      ...
      # 设置默认的构建类型,并打印一条消息
      if(NOT CMAKE_BUILD_TYPE)
          set(CMAKE_BUILD_TYPE Release CACHE STRING "BUILD_TYPE" FORCE) # 设置该变量为缓存变量,可以通过缓存进行编辑
      endif()
      message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
      
    • 切换构建类型时可以使用如下命令进行切换

      ...
      cmake -D CMAKE_BUILD_TYPE=Debug ..
      ..
      
  • 设置编译器选项,即控制项目的编译标志

    • 计算不同的形状面积的函数位于不同文件中

      在这里插入图片描述

    • CMakeLists

      # 控制编译器标志的第一种方法
      ...
      # 主要代码
      message("C++ compiler flags: ${CMAKE_CXX_FLAGS}")
      # 为目标准备标志列表
      list(APPEND flags "-fPIC" "-Wall")
      if(NOT Win32)
          list(APPEND flags "-Wextra" "-Wpedantic")
      endif()
      # 添加新的目标库并附加依赖源
      add_library(geometry
          STATIC
          geometry_circle.cpp
          geometry_circle.hpp
          geometry_polygon.cpp
          geometry_polygon.hpp
          geometry_rhombus.cpp
          geometry_rhombus.hpp
          geometry_square.cpp
          geometry_square.hpp
      )
      # 设置编译选项
      target_compile_options(geometry PRIVATE ${flags})
      # 创建可执行目标
      add_executable(compute-areas compute-areas.cpp)
      # 为可执行目标设置编译选项
      target_compille_options(compute-areas PRIVATE "-fPIC")
      
      #链接可目标文件与库文件
      target_link_libraries(compute-areas geometry)
      ...
      
    • 控制编译器标志的第二种方法:不用对CMakeLists.txt进行修改,修改geometry和compute-areas目标的编译器选项可以使用CMAKE的参数进行配置:

    ...
    cmake -D CMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" .. # 这个命令将编译项目, 禁用异常和运行时类型标识(RTTI)
    ...
    
    # 也可以使用全局标志,即使用CMakeLists.txt运行下面的命令
    cmake -D CMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" ..
    
  • 使用控制流

    • CMake提供了创建循环的语言工具: foreach-endforeach 和 while-endwhile,实际使用样例可以参考如下的foreach:

      # 准备
      ...
      add_library(geometry STATIC 文件列表)
      target_compile_options(PRIVATE -03)
      list(APPEND sources_with_lower_optimization geometry_circle.cpp geometry_rhombus.cpp)# 生成源文件列表
      
      # 循环以上文件列表中的文件,并将其优化级别调到-02
      message(STATUS "Setting source properties using IN LISTS syntax:")
      foreach(_source IN LISTS sources_with_lower_optimization)
      	set_source_files_properties(${_source} PROPERTIES COMPILE_FLAGS -02)
      	message(STATUS "Appending -02 flag for ${_source}")
      endforeach()
      
      # 检查是否设置正确
      message(STATUS "Querying source properties using IN plain syntax:")
      foreach(_source IN LISTS sources_with_lower_optimization)
      	get_source_file_property(${_source} PROPERTIES COMPILE_FLAGS)
      	message(STATUS "Source ${_source} has the following extra COMPILE_FLAGS:${_flags}")
      endforeach()
      ...
      
  • polo

[4]: http://adrai.github.io/flowchart.js/### 从可执行文件到库

  • 一些基础的注意事项

    # set minimum cmake version 项目构建的开始需要设置最小的cmake版本,并定义不满足这一要求时的cmake行为
    cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    
    # project name and language 项目名称和支持的编程语言
    project(recipe-01 LANGUAGES CXX)
    # 编译和链接源文件hell0-world.cpp以生成可执行文件hello-world
    add_executable(hello-world hello-world.cpp)
    
    • 上述文件命名为CMakeLists.txt,区分大小写,否则无法解析;

    • CMake语言不区分大小写,但是参数区分大小写;

    • CMake中,c++是默认编程语言,但最好使用LANGUAGES选项在project中显示声明项目的语言;

    • 一些基础指令:

      mkdir -p build # 创建生成构建器的位置
      cd build 
      cmake .. # 指定CMakeLists.txt所在位置
      

      为了不和源代码混淆,一般在源外创建生成构建其目录;

    • CMake是一个构建系统生成器,描述构建系统(VS, Ninja、Makefile等)如何操作才能编译代码;然后CMake为所选的构建系统生成相应的指令;

    • 如何切换生成器:

      • 通过生成器列表确定是否存在所需要的生成器:

        cmake -help
        
      • 切换生成器:

        ...
        cd build
        cmake -G Ninja .. # 即添加-G参数切换所需要使用的生成器
        cmake --build . 
        

        每个生成器都有自己的文件集,构建结果其生成的文件是不同的;

  • 构建和链接静态库和动态库

    • 构建所需要的CMakeLists.txt

      # ---准备操作---
      # set minimum cmake version
      cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
      
      # project name and language
      project(recipe-03 LANGUAGES CXX)
      
      # 创建目标-静态库
      # 生成必要的构建指令,将指定的源码编译到库中
      # 第二个参数为其他值时:
      # STATIC - 用于创建静态库,即编译文件的打包存档,用于在链接其他目标时使用;
      # SHARED - 用于创建动态库链接,并在运行时加载;
      # OBJECT - 将列表中的源码编译到目标文件,不将其进行归档到静态库和共享对象中;
      # MODULE - DSO组,不链接到项目中的任何目标,不过可以进行动态加载,用于构建运行时插件;
      add_library(message STATIC Message.hpp Message.cpp) 
      
      # 创建可执行文件
      # 将库链接到可执行文件,确保hello-world可执行文件正确依赖于message库
      add_executable(hello-world hello-world.cpp)
      
      # 目标库连接到可执行文件
      target_link_libraries(hello-world message)
      

      编译完成之后,会生成一个message.lib静态库文件;

    • 要保证编译的目标文件与生成位置无关, 可以通过使用 set_target_properties 命令;

      set_target_properties(message-objs
      	PROPERTIES
      	POSITION_INDEPENDENT_CODE 1
      )  
      
  • 条件语句控制编译

    • 条件结构为 if-else- else-endif ;

    • 如果需要在不同的行为之间进行切换,如构建静态库或动态库再生成可执行文件和直接生成可执行文件两种选择,则CMake中的文件条件语部分可以编写为:

      ...
      set(USE_LIBRARY OFF) # 设置变量
      message(STATUS "COMPILE SOURCE INTO A LIBRARY? ${USE_LIBRARY}")
      set(USE_SHARED_LIBS OFF)
      list(APPEND _source Message.hpp Message.cpp) # 将文件装入列表
      
      if(USED_LIBRARY)
          add_library(message ${_sources}) #_source是局部变量,前面加下划线,不应该再当前范围之外使用
          add_excutable(hello-world hello-world.cpp)
          target_link_libraries(hell-world message)
      else()
          add_excutable(hell-world hello-world.cpp ${_sources}) #添加方式有所不同
      endif()
      ...
      
  • 向用户显示选项,可以被用户选择性设置

    • 在CMake中使用option(),用于外部设置,从而切换构建系统的生成行为

    • 使用选项替换set(USE_LIBRARY OFF)命令,使得其在命令行可以被修改

      option(USE_LIBRARY "Compile sources into a library" OFF)
      # 三个参数:option(<option_variable> "help string" [initial value])
      # <option_variable> - 变量的名称
      # "help string" - 描述选项的字符段;
      # [initial value] - 选项的默认值
      
      # 编译时使用
      ...
      cd build
      cmake -D USE_LIBRARY=ON .. # -D开关用于为CMake设置任何类型的变量,如逻辑变量、路径等 
      cmake --build .
      
  • 指定编译器

    • CMake将语言的编译器存储在CMAKE__COMPILER 变量中,选择特定的编译器时,可以通过CMAKE__COMPILER进行选择,其中,可以是受支持的任意一种语言

      # 指定编译器的方式有两种
      # 第一种
      cmake -D CMKAE_CXX_COMPILER=clang++ ..
      
      # 第二种
      env CXX=clang++ cmake ..
      
    • 建议使用第二种编译器指定方式,因为环境变量可能被设定为不适合当前项目的值;

    • 可以通过命令cmake --system-information来查看可用的比那一起和对应的编译器的标志;

  • 切换构建类型

    • 构建类型如Debug、Release等;

    • 控制生成构建系统使用的配置变量为CMAKE_BUILD_TYPE,该变量默认为空;

    • 使用

      # 准备
      ...
      # 设置默认的构建类型,并打印一条消息
      if(NOT CMAKE_BUILD_TYPE)
          set(CMAKE_BUILD_TYPE Release CACHE STRING "BUILD_TYPE" FORCE) # 设置该变量为缓存变量,可以通过缓存进行编辑
      endif()
      message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
      
    • 切换构建类型时可以使用如下命令进行切换

      ...
      cmake -D CMAKE_BUILD_TYPE=Debug ..
      ..
      
  • 设置编译器选项,即控制项目的编译标志

    • 计算不同的形状面积的函数位于不同文件中

      image-20210908151927939
    • CMakeLists

      # 控制编译器标志的第一种方法
      ...
      # 主要代码
      message("C++ compiler flags: ${CMAKE_CXX_FLAGS}")
      # 为目标准备标志列表
      list(APPEND flags "-fPIC" "-Wall")
      if(NOT Win32)
          list(APPEND flags "-Wextra" "-Wpedantic")
      endif()
      # 添加新的目标库并附加依赖源
      add_library(geometry
          STATIC
          geometry_circle.cpp
          geometry_circle.hpp
          geometry_polygon.cpp
          geometry_polygon.hpp
          geometry_rhombus.cpp
          geometry_rhombus.hpp
          geometry_square.cpp
          geometry_square.hpp
      )
      # 设置编译选项
      target_compile_options(geometry PRIVATE ${flags})
      # 创建可执行目标
      add_executable(compute-areas compute-areas.cpp)
      # 为可执行目标设置编译选项
      target_compille_options(compute-areas PRIVATE "-fPIC")
      
      #链接可目标文件与库文件
      target_link_libraries(compute-areas geometry)
      ...
      
    • 控制编译器标志的第二种方法:不用对CMakeLists.txt进行修改,修改geometry和compute-areas目标的编译器选项可以使用CMAKE的参数进行配置:

    ...
    cmake -D CMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" .. # 这个命令将编译项目, 禁用异常和运行时类型标识(RTTI)
    ...
    
    # 也可以使用全局标志,即使用CMakeLists.txt运行下面的命令
    cmake -D CMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" ..
    
  • 使用控制流

    • CMake提供了创建循环的语言工具: foreach-endforeach 和 while-endwhile,实际使用样例可以参考如下的foreach:

      # 准备
      ...
      add_library(geometry STATIC 文件列表)
      target_compile_options(PRIVATE -03)
      list(APPEND sources_with_lower_optimization geometry_circle.cpp geometry_rhombus.cpp)# 生成源文件列表
      
      # 循环以上文件列表中的文件,并将其优化级别调到-02
      message(STATUS "Setting source properties using IN LISTS syntax:")
      foreach(_source IN LISTS sources_with_lower_optimization)
      	set_source_files_properties(${_source} PROPERTIES COMPILE_FLAGS -02)
      	message(STATUS "Appending -02 flag for ${_source}")
      endforeach()
      
      # 检查是否设置正确
      message(STATUS "Querying source properties using IN plain syntax:")
      foreach(_source IN LISTS sources_with_lower_optimization)
      	get_source_file_property(${_source} PROPERTIES COMPILE_FLAGS)
      	message(STATUS "Source ${_source} has the following extra COMPILE_FLAGS:${_flags}")
      endforeach()
      ...
      

1 [参考CMake Cookbook](CMake Cookbook )

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CLion是一款由JetBrains开发的集成开发环境(IDE),专门用于C和C++的开发。它提供了丰富的功能和工具,可以帮助开发者更高效地编写、调试和测试代码。 CMake是一个跨平台的构建工具,它可以自动生成用于不同编译器和操作系统的构建脚本。通过使用CMake,我们可以将项目的构建过程与具体的编译器和操作系统解耦,从而实现跨平台的构建。 在CLion中编写JNI(Java Native Interface)可执行文件,需要进行以下步骤: 1. 创建一个新的CMake项目:在CLion中选择"File" -> "New Project",然后选择"C++ Executable"作为项目类型。 2. 配置CMakeLists.txt文件CMakeLists.txt是CMake的配置文件,用于指定项目的构建规则。你可以在该文件中添加JNI相关的配置。 例如,你可以使用`add_library`命令来创建一个动态链接,并将JNI相关的源文件添加到该中。示例代码如下: ``` cmake_minimum_required(VERSION 3.10) project(MyJNIProject) # 添加JNI相关的源文件 add_library(MyJNI SHARED jni_source_file.cpp) # 链接JNI target_link_libraries(MyJNI ${JAVA_JVM_LIBRARY}) ``` 在上述示例中,`jni_source_file.cpp`是包含JNI代码的源文件。`${JAVA_JVM_LIBRARY}`是一个变量,用于指定Java虚拟机的文件。 3. 编写JNI代码:在CLion中创建一个新的C++文件,编写JNI相关的代码。JNI代码用于在Java和C/C++之间进行交互。 例如,你可以使用`JNIEnv`对象来调用Java方法,使用`jclass`对象来获取Java类的引用,使用`jmethodID`对象来表示Java方法的ID等。 4. 构建和运行项目:在CLion中点击"Build"按钮,CLion将自动执行CMake构建过程,并生成可执行文件。你可以通过点击"Run"按钮来运行生成的可执行文件。 以上是使用CLion和CMake编写JNI可执行文件的基本步骤。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值