新闻  |   论坛  |   博客  |   在线研讨会
【cmake】CMakeList添加库|添加头文件|添加路径|add_executable、add_library、target_link_libraries|添加编译选项|宏开关
电子禅石 | 2022-01-26 19:53:26    阅读:16804   发布文章

目录


官网查阅


开胃菜例子


CMakeLists生成和添加依赖库


1、目录结构


2、CMakeLists.txt


3、configure and generate


4、截图:


5、其他设置


add_library(生成库),target_link_libraries(生成目标连接的库),set_target_properties


CMAKE 添加编译选项|-g编译参数/选项


包含文件的的目录include_directories


CMake设置编译参数/选项


如何在cmakelists中加入-ldl编译选项


CMake指定gcc,g++版本编译


CMake 关闭警告的方法


关闭编译器优化


Debug和Release 方案


About table


About question


CMakeLists 实现动态宏开关


去掉编译优化


CMake--List用法


CmakeLists.txt单行注释和多行注释 


官网查阅

Search — CMake 3.22.0-rc1 Documentation


开胃菜例子

生成一个可执行程序的 CMakeList


#添加包含文件的的目录

include_directories(${cppzmq_INCLUDE_DIR})             

 

#用${SOURCE_FILES}指定的文件,生成可执行文件sample_project 

add_executable(sample_project ${SOURCE_FILES}) 

 

#生成可执行文件sample_project 需要连接 ${CMAKE_THREAD_LIBS_INIT}指定的库

target_link_libraries (sample_project  ${CMAKE_THREAD_LIBS_INIT}) 

 

生成一个.so动态库的 CMakeList 


#用${SRC_LISTS}指定的所有的源文件生成一个库,名字叫libsugan

add_library(libsugan ${SRC_LISTS})   

 

#生成libsugan库需要链接 ${OpenCV_LIBS}、 ${PROJECT_SOURCE_DIR}/lib/libCommonUtilities.so、${PROJECT_SOURCE_DIR}/lib/libInuStreams.so

target_link_libraries(libsugan                 

    ${OpenCV_LIBS}

    ${PROJECT_SOURCE_DIR}/lib/libCommonUtilities.so

    ${PROJECT_SOURCE_DIR}/lib/libInuStreams.so

)


原文链接:https://blog.csdn.net/bandaoyu/article/details/115165199


CMakeLists生成和添加依赖库

原文;cmake之生成动态库 - mohist - 博客园


1、目录结构

│  CMakeLists.txt

│  index.txt

│  

├─build

├─include

│      hello.h

│      hi.h

│      

└─src

        hello.cxx

        hi.cxx

2、CMakeLists.txt

cmake_minimum_required(VERSION 3.1)


#项目名

project(libhello)


# 1、指定库的目录变量

set(libhello_src src/hello.cxx)

# 指定头文件搜索路径

include_directories("${PROJECT_SOURCE_DIR}/include")




# 2、添加库(对应的两个项目)

add_library( hello_shared SHARED ${libhello_src})

add_library( hello_static STATIC ${libhello_src})

#  按照一般的习惯,静态库名字跟动态库名字应该是一致的,只是扩展名不同;

# 即:静态库名为 libhello.a; 动态库名为libhello.so ;

# 所以,希望 "hello_static" 在输出时,不是"hello_static",而是以"hello"的名字显示,故设置如下

# SET_TARGET_PROPERTIES (hello_static PROPERTIES OUTPUT_NAME "hello")



# 3、cmake在构建一个新的target时,会尝试清理掉其他使用这个名字的库,

# 因此,在构建libhello.a时,就会清理掉libhello.so.

# 为了回避这个问题,比如再次使用SET_TARGET_PROPERTIES定义 CLEAN_DIRECT_OUTPUT属性。

SET_TARGET_PROPERTIES (hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

SET_TARGET_PROPERTIES (hello_shared PROPERTIES CLEAN_DIRECT_OUTPUT 1)



# 4、按照规则,动态库是应该包含一个版本号的,

# VERSION指代动态库版本,SOVERSION指代API版本。

SET_TARGET_PROPERTIES (hello_static PROPERTIES VERSION 1.1 SOVERSION 1)

SET_TARGET_PROPERTIES (hello_shared PROPERTIES VERSION 1.1 SOVERSION 1)



# 5、若将libhello.a, libhello.so.x以及hello.h安装到系统目录,才能真正让其他人开发使用,

# 本例中,将hello的共享库安装到<prefix>/lib目录;

# 将hello.h安装<prefix>/include/hello目录。

#INSTALL (TARGETS hello hello_shared LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

#INSTALL (TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

#INSTALL (FILES hello.h DESTINATION include/hello)

3、configure and generate

xxx/to/path


cd build

cmake ..

4、截图:

     mac没有电了, 来个Windows10的截图吧:




5、其他设置

  若需要指定输出路径,尝试下面的示例指令:


# 设置VS会自动新建Debug和Release文件夹

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Lib)

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Lib)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Bin)


# 设置分别设置Debug和Release输出目录

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/Lib)

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/Lib)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/../../build/Debug)


set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/Lib)

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/Lib)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/Bin)

简单例子:


一、生成.so共享库文件

下面是我的几个文件:


1hello.cpp


//hello.cpp

 int Calculate_sum_Of_Two_Number(int x,int y)

{

   int z=0;

   z=x+y;

   return (z);

}


2hello.hpp


//hello.hpp

#ifndef     __HELLO_H

#define     __HELLO_H

int Calculate_sum_Of_Two_Number(int x,int y);

#endif


3 main.cpp


//main.cpp

#include "hello.hpp"

#include <stdio.h>

int main(void)

{

   int a=0,b=0,c=0;

   printf("please input two parameter:");

   scanf("%d",&a);

   scanf("%d",&b);

   c=Calculate_sum_Of_Two_Number(a,b);

   printf("the sum is : %d",c);

   return 0;

}


4 CMakeLists.txt


#要求的Cmake最低版本

CMAKE_MINIMUM_REQUIRED( VERSION 2.8)

 

#工程名称

PROJECT(main)

 

#设置编译器编译模式:

set( CMAKE_BUILD_TYPE "Debug" )

 

#生成共享库

#get the shared package

#here needs no .hpp

add_library(calculate_shared SHARED  hello.cpp)

 

#生成可以执行的文件

add_executable(main main.cpp)

 

#连接共享库

target_link_libraries(main calculate_shared)


上面CmakeLists.txt里面, 共享库的名称是calculate_shared,这个是我们可以自己更改的。生成的可执行文件是main, 这个名称也是可以更改的。


不过需要注意的是,hello.cpp里面不用在包含hello.hpp 了。(汗,因为这个导致出错,提示说是重复定义函数了);


编译生成:


mkdir build

cd    build

cmake ..

make

我们就可以看到build生成了 如下的文件:


CMakeCache.txt  cmake_install.cmake     main

CMakeFiles      libcalculate_shared.so  Makefile


 libcalculate_shared.so就是生成的共享库文件。


他们的路径是:/home/fan/dev/cmake/4-exer/


下面有build文件夹,以及main.cpp, hello.cpp, hello.hpp, 


build文件夹下面有共享库 libcalculate_shared.so.so


二、调用共享库文件



所有的外部依赖库都是这样的,比如opencv ,openni, eigen等等,原理是一样的,只不过他们已经安装在系统里面了,可以查找,而这个则是需要我们自己去配置。


即我上面生成的共享库文件本质上和opencv的库是相同的。只不过这个共享库需要自己手动配置。


比如我又新建了一个工程,需要调用上面的共享库 libcalculate_shared.so。


main.cpp如下:


//main.cpp

#include <stdio.h>

#include <iostream>

#include "hello.hpp"

using namespace std;

int main(void)

{

   int x=2,y=3;

   int z=0;

   z=Calculate_sum_Of_Two_Number(x,y);

   cout<<"the result is:"<<z<<endl;

   return 0;

}


那么在CMakeLists.txt里面,我需要告诉CMake, 这个头文件可以在哪里找到,头文件所定义的函数又可以在哪里找到。


上面hello.hpp的路径是:/home/fan/dev/cmake/4-exer/hello.hpp


libcalculate_shared.so的路径是/home/fan/dev/cmake/4-exer/build/libcalculate_shared.so


则CMakeLists.txt如下:


CMAKE_MINIMUM_REQUIRED( VERSION 2.8)

 

PROJECT(main)

#设置编译器编译模式:

SET( CMAKE_BUILD_TYPE "Debug" )

 

SET(HELLO_INCLUE 

    /home/fan/dev/cmake/4-exer/)

 

SET(HELLO_SRC 

    /home/fan/dev/cmake/4-exer/build/libcalculate_shared.so)

 

INCLUDE_DIRECTORIES(${HELLO_INCLUE})

 

add_executable(main main.cpp)

 

target_link_libraries(main ${HELLO_SRC})


这里要注意一些细节(对于我这个渣渣来说的)


1、${   }这种形式代表一个变量,比如上面的,HELLO_INCLUE ,就是我自己定义的一个变量。


2、头文件包含到头文件所在的文件夹,即 /home/fan/dev/cmake/4-exer/


3、共享库要指明具体的共享库 ,精确到.so


其实主要的就是指明这个调用这个共享库的时候,使用的头文件,以及共享库本身所在的位置,然后包含链接就可以了。


安装过的共享库(例如opencv)就不用这么麻烦了,因为它的地址都放在了变量里面。


Opencv的依赖添加

比如Opencv, 它的头文件和.so文件都已经放在了系统变量里面,不用向上面自己定义了(上面例子里面的头文件和共享库文件的地址都是我自己设置的)


它的CMakeLists.txt如下:


find_package(OpenCV REQUIRED)


include_directories(${OPENCV_INCLUDE_DIRS})


target_link_libraries(MAIN ${OpenCV_LIBS})


只需要查找就可以了,OpenCV_LIBS  和  OPENCV_INCLUDE_DIRS  都是系统帮我们已经定义好的,所以比较容易


参考博客:


1、如何写自己的CmakeLists.txt   https://www.cnblogs.com/chaofn/p/10160555.html


2、 【OpenCV】使用CMake链接自己路径下面的OpenCV库 https://blog.csdn.net/twt520ly/article/details/81981473


原文链接:https://blog.csdn.net/qq_37761077/article/details/88750711


add_library(生成库),target_link_libraries(生成目标连接的库),set_target_properties

add_library(libsugan ${SRC_LISTS})    #用${SRC_LISTS}生成静态库libsugan


target_link_libraries(libsugan      #生成静态库libsugan还需链接依赖库${OpenCV_LIBS}…

    ${OpenCV_LIBS}

    ${PROJECT_SOURCE_DIR}/lib/libCommonUtilities.so

    ${PROJECT_SOURCE_DIR}/lib/libInuStreams.so

)


#上面的配置生成名字为libsugan的静态库,但Linux下对库的存储格式是lib+name.a,所以库libsugan存储出来的结果就是liblibsugan.a,看着很别扭。用下面这句,保证了存储出来的静态库叫做libsugan.a:


set_target_properties(libsugan PROPERTIES OUTPUT_NAME "sugan")


#但是请千万注意,在整个CmakeLists.txt里


#如果想链接生成的这个库必须使用    “add_library(libsugan ${SRC_LISTS})”指明的名字。

set_target_properties(libsugan PROPERTIES OUTPUT_NAME "sugan")


add_executable(demo ./src/main.cpp)

target_link_libraries(demo libsugan)


原例子:


add_library,target_link_libraries,set_target_properties,target_link_libraries使用联系_michaelhan3的博客-CSDN博客


#工程名字

project(Camera_sugan)                  

 

#编译最低cmake版本

cmake_minimum_required(VERSION 2.6)    

 

#设置c++编译器

set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )  

 

#在整个电脑上找opencv包

find_package(OpenCV REQUIRED)    

 

#包含头文件路径

include_directories(             

    ./include/inudev/

    ./src/

)

 

#将所有的源文件列为一个集合,集合名字叫做SRC_LISTS

set(SRC_LISTS                   

    ./src/inuitive.cpp

    ./src/runCamera_Qfeeltech.cpp

)

 

#将集合里的所有的源文件生成一个静态库,该静态库的名字libsugan,

注意,在整个CmakeLists里都要用libsugan这个

add_library(libsugan ${SRC_LISTS})   

 

#名字来代替之前那个集合生成的库。

target_link_libraries(libsugan    #链接静态库需要的依赖库

    ${OpenCV_LIBS}

    ${PROJECT_SOURCE_DIR}/lib/libCommonUtilities.so

    ${PROJECT_SOURCE_DIR}/lib/libInuStreams.so

)


原文链接:https://blog.csdn.net/michaelhan3/article/details/69568362


CMAKE 添加编译选项|-g编译参数/选项

add_definitions 和add_compile_options,二者添加的编译选项是针对所有编译器的(包括c和c++编译器)。


add_definitions 和add_compile_options的区别是:


add_definitions 可用于添加任何标志,但旨在添加预处理器定义。


此命令已被替代方案取代:

使用 add_compile_definitions() 添加预处理器定义。

使用 include_directories() 添加包含目录。

使用 add_compile_options() 添加其他选项。


add_definitions — CMake 3.22.0-rc1 Documentation


添加 -g编译参数/选项


方法一:add_definitions("-g")/ add_compile_options



在文件 CMakeLists.txt添加下面一条语句

add_definitions("-g")


添加其他编译参数/选项


例如下面的代码


#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持


if(CMAKE_COMPILER_IS_GNUCXX)

    add_compile_options(-std=c++11)

    message(STATUS "optional:-std=c++11")   

endif(CMAKE_COMPILER_IS_GNUCXX)

 




使用add_compile_options添加-std=c++11选项,是想在编译c++代码时加上c++11支持选项。但是因为add_compile_options是针对所有类型编译器的,所以在编译c代码时,就会产生如下warning


J:\workspace\facecl.gcc>make b64

[ 50%] Building C object libb64/CMakeFiles/b64.dir/libb64-1.2.1/src/cdecode.c.obj

cc1.exe: warning: command line option ‘-std=c++11’ is valid for C++/ObjC++ but not for C

[100%] Building C object libb64/CMakeFiles/b64.dir/libb64-1.2.1/src/cencode.c.obj

cc1.exe: warning: command line option ‘-std=c++11’ is valid for C++/ObjC++ but not for C

Linking C static library libb64.a

[100%] Built target b64

虽然并不影响编译,但看着的确是不爽啊,要消除这个warning,就不能使用add_compile_options,而是只针对c++编译器添加这个option。


方法二:set


所以如下修改代码,则警告消除。


#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持

if(CMAKE_COMPILER_IS_GNUCXX)

    set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")

    message(STATUS "optional:-std=c++11")   

endif(CMAKE_COMPILER_IS_GNUCXX)



原文链接:https://blog.csdn.net/qinglongzhan/article/details/80743731


包含文件的的目录include_directories

include_directories(${cppzmq_INCLUDE_DIR})  //添加包含文件的的目录


add_definitions 可用于添加任何标志,但旨在添加预处理器定义。


此命令已被替代方案取代:

使用 add_compile_definitions() 添加预处理器定义。

使用 include_directories() 添加包含目录。

使用 add_compile_options() 添加其他选项。


CMake设置编译参数/选项

而set命令设置CMAKE_C_FLAGS或CMAKE_CXX_FLAGS变量则是分别只针对c和c++编译器的


对c编译器的


set(CMAKE_C_FLAGS"-O3 -fopenmp -fPIC -Wno-deprecated -Wenum-compare -std=c++14")


针对c++编译器的


set(CMAKE_CXX_FLAGS "-O3 -fopenmp -fPIC -Wno-deprecated -Wenum-compare -std=c++14")


如何在cmakelists中加入-ldl编译选项

cmakelists.txt中,在增加可执行程序后增加TARGET_LINK_LIBRARIES

eg:



add_executable(xx ${ALL_F} ${WE_F})

TARGET_LINK_LIBRARIES(dl)

TARGET_LINK_LIBRARIES(m)


set(CMAKE_C_FLAGS "-ldl")


在add_executable(${PROJECT_NAME} "main.cpp")后面添加

target_link_libraries(${PROJECT_NAME} dl)


target_link_libraries(exe1 -Wl, - -whole-archive lib1 -Wl, -  no-whole-archive)

CMake指定gcc,g++版本编译

系统默认的gcc/g++在/usr/bin目录下。


我们升级安装的gcc目录在/usr/local/bin目录下,现在我们希望使用升级后的gcc。


通过百度搜索出来的结果,大多是如下操作:


在CMakeLists.txt中调用编译器之前添加:


1


2


SET(CMAKE_C_COMPILER "/usr/local/bin/gcc")


SET(CMAKE_CXX_COMPILER "/usr/local/bin/g++")


然而经过本人亲自实践,该方法不起作用,正确的做法是:


执行cmake命令之前,在shell终端先设置如下两个变量:


1


2


export CC=/usr/local/bin/gcc


export CXX=/usr/local/bin/g++


然后再执行cmake等后续命令,这样就可以用指定的编译器版本了。


【已解决】CMake指定gcc,g++版本编译 | 勤奋的小青蛙


CMake 关闭警告的方法

在CMakeLists.txt中添加add_definitions(-w)


应用于单个target


  if(CMAKE_COMPILER_IS_GNUCC)

 target_compile_options(main PRIVATE"-Wall")

 endif()

 if(MSVC)

 target_compile_options(main PRIVATE"/ W4")

 endif()

  

应用于所有target


  if(CMAKE_COMPILER_IS_GNUCC)

 set(CMAKE_CXX_FLAGS"$ {CMAKE_CXX_FLAGS} -Wall")

 endif()

 if(MSVC)

 set(CMAKE_CXX_FLAGS"$ {CMAKE_CXX_FLAGS} / W4")

 endif()

  

注意:为GCC或/ WX添加-Werror以便MSVC将所有警告视为错误。这会将所有警告视为错误。这对于新项目来说可以方便地执行严格的警告。


另外, -Wall 并不意味着"所有错误";从历史意义上讲,它意味着"每个人都可以达成一致的所有错误""。从 -Wall -Wextra 开始,然后仔细阅读您的版本的GCC手册,并找到 else 编译器可以为您提供关于警告的信息。


CMake和编译器警告 - IT屋-程序员软件开发技术分享社区


关闭编译器优化

(未验证)


1)add_compile_options(-fno-elide-constructors)    #关闭编译器优化


2)set(CMAKE_CXX_FLAGS "-fno-elide-constructors ${CMAKE_CXX_FLAGS}")


Debug和Release 方案

About table

Configurations in terms of gcc/clang compilers (CMake 3.4.1):


Debug: -g

Release: -O3 -DNDEBUG

RelWithDebInfo: -O2 -g -DNDEBUG

MinSizeRel: -Os -DNDEBUG

It means:


  +---------------+--------------+--------------+----------+

  |               | optimization | assert works | stripped |

  +---------------+--------------+--------------+----------|

  |     Debug     |     no       |     yes      |    no    |

  |    Release    |    full      |      no      |   yes    |

  | RelWithDebInfo|    good      |      no      |    no    |

  |   MinSizeRel  |    size      |      no      |   yes    |

  +---------------+--------------+--------------+----------+

So I don't agree with your MinSizeRel description because in this case I think both MinSizeRel and Release are stripped.


About question

As far as I understand you want no extra flags at all (no -g, -O* or -DNDEBUG). For Makefile-like generators:


> cmake -H. -B_builds -DCMAKE_BUILD_TYPE=MyConf -DCMAKE_CXX_FLAGS_MYCONF=""

> cmake --build _builds

CMakeLists 实现动态宏开关

去掉编译优化

在CMakeList中添加:


if(NOT CMAKE_BUILD_TYPE)

  set(CMAKE_BUILD_TYPE Release)

endif()

 

set(CMAKE_CXX_FLAGS "-Wall -Wextra")

set(CMAKE_CXX_FLAGS_DEBUG "-g")

set(CMAKE_CXX_FLAGS_RELEASE "-O3")

执行的时候


cmake  -DCMAKE_BUILD_TYPE=Release


也可以在上一层(调用本CMakeList.txt的)的CMakeList.txt中添加下面:


option (CMAKE_BUILD_TYPE "Use tutorial provided math implementation"  ON)


表示启用CMAKE_BUILD_TYPE 宏。


option (CMAKE_BUILD_TYPE "Use tutorial provided math implementation"  OFF) #表示关


参考:


c++ - Optimize in CMake by default - Stack Overflow


debugging - How to compile without optimizations -O0 using CMake - Unix & Linux Stack Exchange


例子


最近在工作中需要通过一份C代码控制逻辑走向,网上找了一下资料,发现可以通过在CMakeLists文件中动态定义宏开关,从而能够达到编译出不同逻辑流的代码。


具体步骤:


首先,我在src代码里编写了若干debug的输出:


#IFDEF DEBUG

 

    some print command;

 

#ENDIF

然后,在CMakeLists文件中添加DEBUG的定义:


IF (CMAKE_BUILD_TYPE STREQUAL DEBUG)

    ADD_DEFINITIONS(-DDEBUG)

ENDIF()

最后,在cmake的时候设置参数 -DCMAKE_BUILD_TYPE 为 DEBUG:


$ cmake .. -DCMAKE_BUILD_TYPE=DEBUG

$ make -j4

这样再运行可执行文件时就会打印出some print command的debug信息了。如果不想看到debug信息,只需在参数中不设置DEBUG参数,或者将DEBUG参数设置为其它值即可(以下两种方式二者选其一):


$ cmake ..

$ cmake .. -DCMAKE_BUILD_TYPE=RELEASE

到此 CMakeLists 实现动态宏开关介绍完成。


原文链接:https://blog.csdn.net/qq_19734597/article/details/104461963


CMake--List用法

CMake--List用法 - narjaja - 博客园


CmakeLists.txt单行注释和多行注释 

单行注释:使用“#”

多行注释:使用“#[[ ]]”


————————————————

版权声明:本文为CSDN博主「bandaoyu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/bandaoyu/article/details/115165199


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
属于自己的技术积累分享,成为嵌入式系统研发高手。
推荐文章
最近访客