首页 > 其他分享 >CMake配置跨平台项目踩的坑

CMake配置跨平台项目踩的坑

时间:2023-02-08 05:11:06浏览次数:39  
标签:set CMAKE target testlib 配置 跨平台 test CMake 链接

  1. 当要在windows平台下使用MinGW作为cmake使用的make平台时,需要确保cmake能够在系统环境变量PATH中找到MinGW的bin目录,如果PATH中没有MinGW的话可以在CMakeLists文件中手动声明,但是必须在project的声明之前,比如:

    cmake_minimum_required(VERSION 3.10)
    if(WIN32)
    set(MINGW_HOME $ENV{MINGW_HOME}) #获取系统的环境变量MINGW_HOME,前提是系统环境变量中有这个变量,不然还是得手动添加绝对路径
    set(ENV{PATH} $ENV{MINGW_HOME}\\bin) #由于cmake过程中只需要编译链接的工具,所以就在作用域内直接把环境变量PATH设置为MinGW的bin目录
    endif()
    project("test") #声明完PATH后再声明project
    
  2. 当需要配置以下变量时,需要在project声明之后,否则cmake时会发生错误:

    CMAKE_MAKE_PROGRAM
    CMAKE_C_COMPILER
    CMAKE_CXX_COMPILER
    

    例如:

    project("test")
    set(MINGW_HOME $ENV{MINGW_HOME})
    set(CMAKE_MAKE_PROGRAM ${MINGW_HOME}/bin/make.exe)
    set(CMAKE_C_COMPILER ${MINGW_HOME}/bin/clang.exe)
    set(CMAKE_CXX_COMPILER ${MINGW_HOME}/bin/clang++.exe)
    #这几个变量的使用主要还是指定使用的编译器,平常也不会使用到
    
  3. 生成库或者可执行文件时,实际上是可以自定义输出文件名的,因为有时候我们需要同时产生静态库文件和动态库文件,但是生成的目标名却不能一样,比如说:

    #以下代码在MinGW和Linux Gnu下有效,可能因为Linux Gnu和MinGW都是Gnu的缘故
    add_library(testlib_shared SHARED ${CMAKE_SOURCE_DIR}/src/test.c ) #添加生成动态库的目标名称
    add_library(testlib_static STATIC ${CMAKE_SOURCE_DIR}/src/test.c ) #添加生成静态库的目标名称
    #上述的生成静态库和动态库的目标名称不一样,不会冲突
    set_target_properties(testlib_shared PROPERTIES OUTPUT_NAME test) #设置生成动态库的名称为test(最终产生libtest.so/libtest.dll+libtest.dll.a)
    set_target_properties(testlib_static PROPERTIES OUTPUT_NAME test) #设置生成静态库的名称为test(最终产生libtest.a)
    
    #这样就同时产生libtest.a和libtest.so/libtest.dll+libtest.dll.a
    
  4. 以3作为例子,当进行库链接时,如果能够获取库的目录的话,就能够直接链接库的目标名称,而不是库的文件名,这样链接的是静态库还是动态库就一目了然:

    add_executable(main ${CMAKE_SOURCE_DIR}/src/main.c) 
    target_link_libraries(main testlib_shared) #main链接动态库
    target_link_libraries(main testlib_static) #main链接静态库
    
  5. 生成动态库时,不同平台以及不同编译器生成的文件不一样,需要进行的行为也不一样,

    windows平台上使用VS作为编译器的话,就会直接产生VS项目,有需要的话直接使用VS配置编译即可;

    windows平台上使用MinGW作为编译器,会产生.dll文件和.dll.a文件,这个.a文件就是引导库文件,链接动态库的时候需要链接的是引导库文件;

    Linux平台上安装build-essential,然后是使用GNU作为编译器,会产生.so文件,链接动态库的时候就直接链接.so动态库文件;

    #如果是使用MinGW或者GNU进行cmake的话,生成目标需要进行的动态库链接和静态库链接是一样的,只要找到动态库所在的路径,然后target_link_libraries就可以,例如:
    add_library(testlib_shared SHARED ${CMAKE_SOURCE_DIR}/src/test.c ) #添加生成动态库
    target_link_libraries(main testlib_shared) #这里Linux会直接链接so动态库,MinGW会直接链接引导库dll.a
    
  6. 不同的make工具产生的库文件名称格式不一样:

    #linux平台上使用GNU进行编译产生的动态库或者静态库会在名称前面加上lib,例如:
    add_library(test SHARED ${CMAKE_SOURCE_DIR}/src/test.c ) #库名为test,而生成的动态库文件名为libtest.so
    #windows平台上使用MinGW进行编译产生的动态库或者静态库也会在文件的名称前面加上lib,以上面的生成库代码来看,库名为test,生成的动态库文件名为libtest.dll,另外还会生成一个libtest.dll.a的引导库文件用于其他生成目标可以链接动态库
    #windows平台上使用VS作为编译器的话,会直接产生VS项目,以上面生成库的代码来看,库名为test,生成动态库文件名为test.dll,没有生成引导库文件,而VS项目无法直接链接dll
    

    从4和6两个例子可以看出使用什么操作系统来进行编译需要进行判断固然重要,但是使用什么编译器来进行编译的判断更为重要。

  7. 由6的结论来进行编译器的判断

    在百度上找到了${CMAKE_COMPILER_IS_GNUCC}这个变量,可以判断使用的C编译器是不是GNU,
    然后顺藤摸瓜在cmake官网上找到了${CMAKE_<LANG>_COMPILER_ID}这个变量,<LANG>部分代入C或者CXX,变量的值就是编译器的标识,比如说GNU或者MSVC
    综合考虑了一下,决定使用${CMAKE_C_COMPILER_ID}这个变量作为对编译器的判断,扩展性比较高
    需要注意的是${CMAKE_C_COMPILER_ID}这个变量只有在project声明之后才会生效

    add_library(testlib_shared SHARED ${CMAKE_SOURCE_DIR}/src/test.c ) #添加生成动态库
    if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
    set_target_properties(testlib_shared PROPERTIES OUTPUT_NAME test) #GNU编译产生的库名前面会自己加上lib
    #如果是使用windows下的MinGW进行编译的话,动态库生成dll的同时还会产生一个dll.a的引导库文件
    elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
    set_target_properties(testlib_shared PROPERTIES OUTPUT_NAME libtest) #MSVC编译产生的库名就是原来指定的目标名
    endif()
    
  8. 对于3的补充,即便可以指定输出的库的名称,库的目标名称不会重复,但是在VS2019中编译cmake项目时仍然会报重复库的名称重复的错误,也就是说set_target_properties没办法在VS中逃过这个问题,对于这个问题,就保持静态库和动态库名称不一样应该是ok的,直接显式表示静态库或者动态库,如果觉得这样太傻可以像lua一样,静态库就叫liblua,动态库叫lua54,原因就是静态库不打算暴露出去,而动态库具有共享的性质故标明版本,这样使用的人也方便知道使用的库的版本信息。

    if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
    set_target_properties(testlib_shared PROPERTIES OUTPUT_NAME test10) #MSVC编译产生的库名就是原来的库名
    set_target_properties(testlib_static PROPERTIES OUTPUT_NAME libtest)
    endif()
    
  9. 虚位以待

  10. 虚位以待

  11. 虚位以待

最后的最后,附上完整的模板CMakeLists.txt文件,该文件在VS2019、MinGW、Linux GNU三种编译器下编译通过:

cmake_minimum_required(VERSION 3.10)
if(WIN32)
set(MINGW_HOME $ENV{MINGW_HOME}) #获取系统的环境变量MINGW_HOME,前提是系统环境变量中有这个变量,不然还是得手动添加绝对路径
set(ENV{PATH} $ENV{MINGW_HOME}\\bin) #由于cmake过程中只需要编译链接的工具,所以就在作用域内直接把环境变量PATH设置为MinGW的bin目录
endif()
project("test")
include_directories(${CMAKE_SOURCE_DIR}/include )
#aux_source_directory(${CMAKE_SOURCE_DIR}/src SRCFILES)

add_library(testlib_shared SHARED ${CMAKE_SOURCE_DIR}/src/test.c ) #添加生成动态库
add_library(testlib_static STATIC ${CMAKE_SOURCE_DIR}/src/test.c ) #添加生成静态库

if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
set_target_properties(testlib_shared PROPERTIES OUTPUT_NAME test) #GNU编译产生的库名前面会自己加上lib
set_target_properties(testlib_static PROPERTIES OUTPUT_NAME test) 
#如果是使用windows下的MinGW进行编译的话,动态库生成dll的同时还会产生一个dll.a的引导库文件
elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
set_target_properties(testlib_shared PROPERTIES OUTPUT_NAME test10) #MSVC编译产生的库名就是原来的库名
set_target_properties(testlib_static PROPERTIES OUTPUT_NAME libtest)
else()
#其他情况下没试过,手头没有MacOS设备,半夜三更的也懒得装个黑苹果试试
endif()

add_executable(main ${CMAKE_SOURCE_DIR}/src/main.c) 

#target_link_libraries(main testlib_static) #静态库链接就直接链接上,不是很麻烦

if(CMAKE_C_COMPILER_ID STREQUAL "GNU") #GNU时
target_link_libraries(main testlib_shared) #直接链接生成库的目标名,Linux下会自动链接到so库,而windows下会自动链接引导库文件
elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
target_link_libraries(main testlib_static) #MSVC下暂时链接静态库,看看能不能找到除了添加导出接口以外的出路
else()
#其他情况下没试过,手头没有MacOS设备,半夜三更的也懒得装个黑苹果试试
endif()

说明:test.h头文件包括一个函数声明,test.c文件中包含了头文件中声明函数的定义,main.c文件中包含了test.h头文件并调用了该函数。

标签:set,CMAKE,target,testlib,配置,跨平台,test,CMake,链接
From: https://www.cnblogs.com/thankvincisdaily/p/17100351.html

相关文章

  • 支持配置版本的flannel 服务
    我已经介绍了一个修改版本的flannel(主要是0.7.1版本的),当时是修改了一个固定版本,不方便如果我们的节点需要运行更多的flannel服务基于配置的就比较方便了参考修改核......
  • 解决INTELLIJ IDEA配置MAVEN速度缓慢的问题
    解决方法:采用阿里云提供的镜像地址加快下载速度。详细操作步骤:一、下载并配置APACHE-MAVEN1.访问Apache-Maven官方网站,选择apache-maven-x.x.x-bin.zip下载2.将压缩包解......
  • 002_springboot项目中 pom.xml 配置的作用
    parent:用以定义一系列的常用坐标版本;定义一系列的常用坐标组合;比如在pom.xml文件中引入一个javax.servlet,<version>那里是可以不写的,也就是不写版本,而决定采用哪个版本......
  • 688~689 Servlet生命周期的详解 AND Servlet3.0注解配置
    Servlet生命周期方法:1.被创建:执行一次init方法,只执行一次Servlet什么时候被创建默认情况下,第一次被访问时,Servlet被创建可以配置......
  • MyBatis核心配置文件
    <?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTDConfig3.0//EN""http://mybatis.org/dtd/mybatis-3-confi......
  • jupyterLab的配置
    更改jupynotebook的默认打开路径一般默认打开在C盘,但是我想放在其他盘,这样C盘的内存压力会小一些。可以参考这条博客 https://blog.csdn.net/yukinoai/article/details/......
  • Zookeeper 集群安装配置,超详细,速度收藏!
    今天,栈长分享下Zookeeper的集群安装及配置。下载下载地址:http://zookeeper.apache.org/下载过程就不说了,我们下载了最新的zookeeper-3.4.11。安装1、上传安装包......
  • MT6873/MT6853/MT6785项目SD卡配置注意事项
    内容:6360有个引脚SDCARD_DET_N,实现硬件的autooff,sd的中断pin连接到6360的这个引脚。cust_mtxxxx_msdc.dtsi中,cd_level表示插入卡中断Pin电平,默认配置为是低电平(MSDC_CD_L......
  • Spring23 - 基于XML配置的AOP
    基于XML的AOP准备工作参考基于注解的AOP环境实现在.xml文件中对AOP进行配置<context:component-scanbase-package="com.atguigu.aop.xml"></context:component-s......
  • 配置LAMP
    一、安装apache服务器启动服务二、安装mysql服务器,启动服务器设置账户密码三、安装php依赖程序,配置php服务和zend加速,配置php和apache协同工作测试访问四、搭建dns服务器部......