VScode使⽤CMake⼊门
参考
在 linux 平台下使⽤ CMake ⽣成 Makefile 并编译的流程如下:
编写 CMake 配置⽂件 。
执⾏命令 cmake PATH 或者 ccmake PATH ⽣成 Makefile(ccmake 和 cmake 的区别在于前者提供了⼀个交互式的界⾯)。其中, PATH 是 所在的⽬录。使⽤ make 命令进⾏编译。
本⽂将从实例⼊⼿,⼀步步讲解 CMake 的常见⽤法,⽂中所有的实例代码可以在到。如果你读完仍觉得意犹未尽,可以继续学习⽂章末尾提供的其他资源。
基本语法
添加头⽂件⽬录INCLUDE_DIRECTORIES
语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
它相当于g++选项中的-I参数的作⽤,也相当于环境变量中增加路径到CPLUS_INCLUDE_PATH变量的作
⽤。
include_directories(../../../thirdparty/comm/include)
添加需要链接的库⽂件⽬录LINK_DIRECTORIES
语法:link_directories(directory1 directory2 ...)
它相当于g++命令的-L选项的作⽤,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作⽤。
link_directories("/home/server/third/lib")
查库所在⽬录FIND_LIBRARY
语法:
A short-hand signature is:
find_library (<VAR> name1 [path1 path2 ...])
The general signature is:
find_library (
<VAR>
name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
[HINTS path1 [path2 ... ENV var]]
[PATHS path1 [path2 ... ENV var]]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[DOC "cache documentation string"]
[NO_DEFAULT_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_CMAKE_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_SYSTEM_PATH]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
例⼦如下:
FIND_LIBRARY(RUNTIME_LIB rt /usr/lib /usr/local/lib NO_DEFAULT_PATH)
cmake会在⽬录中查,如果所有⽬录中都没有,值RUNTIME_LIB就会被赋为NO_DEFAULT_PATH
添加需要链接的库⽂件路径LINK_LIBRARIEScmake如何使用
语法:
link_libraries(library1 <debug | optimized> library2 ...)
# 直接是全路径
link_libraries(“/home/server/third/lib/libcommon.a”)
# 下⾯的例⼦,只有库名,cmake会⾃动去所包含的⽬录搜索
link_libraries(iconv)
# 传⼊变量
link_libraries(${RUNTIME_LIB})
# 也可以链接多个
link_libraries("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" "/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")
可以链接⼀个,也可以多个,中间使⽤空格分隔.
设置要链接的库⽂件的名称TARGET_LINK_LIBRARIES
语法:
target_link_libraries(<target> [item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)
# 以下写法都可以:
target_link_libraries(myProject comm)      # 连接libhello.so库,默认优先链接动态库
target_link_libraries(myProject libcomm.a)  # 显⽰指定链接静态库
target_link_libraries(myProject libcomm.so) # 显⽰指定链接动态库
# 再如:
target_link_libraries(myProject libcomm.so)  #这些库名写法都可以。
target_link_libraries(myProject comm)
target_link_libraries(myProject -lcomm)
为⼯程⽣成⽬标⽂件
语法:
add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
简单的例⼦如下:
add_executable(demo main.cpp )
设置⽂件变量
file(GLOB_RECURSE variable [RELATIVE path]** **[FOLLOW_SYMLINKS] [globbingexpressions]...)
GLOB_RECURSE 与GLOB类似,区别在于它会遍历匹配⽬录的所有⽂件以及⼦⽬录下⾯的⽂件。对于属于符号链接的⼦⽬录,只有FOLLOW_SYMLINKS指定⼀或者cmake策略CMP0009没有设置为NEW时,才会遍历这些⽬录。
Examples of recursive globbing include:
/dir/*.py- match all python files in /dir and subdirectories
构建库
add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
<name> :库的名字,直接写名字即可,不要写lib,会⾃动加上前缀的哈。
[STATIC | SHARED | MODULE] :类型有三种。
SHARED,动态库
STATIC,静态库
MODULE,在使⽤ dyld 的系统有效,如果不⽀持 dyld,则被当作 SHARED 对待。
EXCLUDE_FROM_ALL:这个库不会被默认构建,除⾮有其他的组件依赖或者⼿⼯构建。
例⼦:
SET(LIBHELLO_SRC hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
注意,⼀般我们使⽤的静态库/动态库只是后缀名不同⽽已,上⾯构建的libhello.so与libhello_static.a,显然名字不同。这时你会有⼀个想法,那我把hello_static改成hello,结果是不可⾏的,静态库⽆法构建。重名会忽略第⼆条指令。
解决⽅法:改libhello_static.a的属性的输出名字
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
关于动态库的版本号
#VERSION 指代动态库版本,SOVERSION 指代 API 版本。
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
动态库版本是什么,对外调⽤总是libxxx.so。
构建使⽤动态库例⼦
⽬录结构:
添加zmq⽀持
include_directories("F:/ZMQ/include") # 对应tasks的 "-I"参数  .h等
link_directories("F:/ZMQ/lib") # 对应tasks的 "-L"参数  .dll等
link_libraries("F:/ZMQ/lib/libzmq-v141-mt-4_3_2.lib") # 对应tasks的 "-l"参数 .lib
#将所有cpp添加成动态库
file(GLOB_RECURSE CPP_SRC "${PROJECT_SOURCE_DIR}/src/*.cpp")
#add_library(cpps_lib  ${CPP_SRC})——这是静态库
add_library(cpps_lib_shared SHARED ${CPP_SRC})
# 添加可执⾏程序
add_executable( Server ${PROJECT_SOURCE_DIR}/server.cpp )
add_executable( Client ${PROJECT_SOURCE_DIR}/client.cpp )
完整模板
cmake_minimum_required (VERSION 2.6)
INCLUDE_DIRECTORIES(../../thirdparty/comm)
FIND_LIBRARY(COMM_LIB comm ../../thirdparty/comm/lib NO_DEFAULT_PATH)
FIND_LIBRARY(RUNTIME_LIB rt /usr/lib  /usr/local/lib NO_DEFAULT_PATH)
link_libraries(${COMM_LIB} ${RUNTIME_LIB})
ADD_DEFINITIONS(
-O3 -g -W -Wall
-Wunused-variable -Wunused-parameter -Wunused-function -Wunused
-
Wno-deprecated -Woverloaded-virtual -Wwrite-strings
-D__WUR= -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DTIXML_USE_STL
)
add_library(lib_demo
cmd.cpp
global.cpp
md5.cpp
)
link_libraries(lib_demo)
add_executable(demo
main.cpp
)
# link library in static mode
target_link_libraries(demo libuuid.a)
指定 C++ 版本
# Enable C++11
set(CMAKE_CXX_STANDARD 11)
⼊门案例
单个源⽂件
本节对应的源代码所在⽬录:。
对于简单的项⽬,只需要写⼏⾏代码就可以了。例如,假设现在我们的项⽬中只有⼀个源⽂件 ,该程序的⽤途是计算⼀个数的指数幂。
#include <stdio.h>
#include <stdlib.h>
/**
* power - Calculate the power of number.
* @param base: Base value.
* @param exponent: Exponent value.
*
* @return base raised to the power exponent.
*/
double power(double base, int exponent)
{
int result = base;
int i;
if (exponent == 0) {
return 1;
}
for(i = 1; i < exponent; ++i){
result = result * base;
}
return result;
}
int main(int argc, char *argv[])
{
if (argc < 3){
printf("Usage: %s base exponent \n", argv[0]);
return 1;
}
double base = atof(argv[1]);
int exponent = atoi(argv[2]);
double result = power(base, exponent);
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}
编写
⾸先编写 ⽂件,并保存在与 源⽂件同个⽬录下:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项⽬信息
project (Demo1)
# 指定⽣成⽬标
add_executable()
< 的语法⽐较简单,由命令、注释和空格组成,其中命令是不区分⼤⼩写的。符号 # 后⾯的内容被认为是注释。命令由命令名称、⼩括号和参数组成,参数之间使⽤空格进⾏间隔。
对于上⾯的 ⽂件,依次出现了⼏个命令:
cmake_minimum_required:指定运⾏此配置⽂件所需的 CMake 的最低版本;
project:参数值是 Demo1,该命令表⽰项⽬的名称是 Demo1 。
add_executable:将名为的源⽂件编译成⼀个名称为 Demo 的可执⾏⽂件。
编译项⽬
之后,在当前⽬录执⾏ cmake . ,得到 Makefile 后再使⽤ make 命令编译得到 Demo1 可执⾏⽂件。
[ehome@xman Demo1]$ cmake .
-- The C compiler identification is GNU 4.8.2
-- The CXX compiler identification is GNU 4.8.2
-- Check for working C compiler: /usr/sbin/cc
-- Check for working C compiler: /usr/sbin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/sbin/c++
-
- Check for working CXX compiler: /usr/sbin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ehome/Documents/programming/C/power/Demo1
[ehome@xman Demo1]$ make
Scanning dependencies of target Demo
[100%] Building C object CMakeFiles/Demo.
Linking C executable Demo
[100%] Built target Demo
[ehome@xman Demo1]$ ./Demo 5 4
5 ^ 4 is 625
[ehome@xman Demo1]$ ./Demo 7 3
7 ^ 3 is 343
[ehome@xman Demo1]$ ./Demo 2 10
2 ^ 10 is 1024
多个源⽂件
同⼀⽬录,多个源⽂件
本⼩节对应的源代码所在⽬录:。
上⾯的例⼦只有单个源⽂件。现在假如把 power 函数单独写进⼀个名为 MathFunctions.c 的源⽂件⾥,使得这个⼯程变成如下的形式:
./Demo2
|
+---
|
+---
|
+--- MathFunctions.h
这个时候, 可以改成如下的形式:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项⽬信息
project (Demo2)
# 指定⽣成⽬标
add_executable( )
唯⼀的改动只是在 add_executable 命令中增加了⼀个 源⽂件。这样写当然没什么问题,但是如果源⽂件很多,把所有源⽂件的名字都加进去将是⼀件烦⼈的⼯作。更省事的⽅法是使⽤ aux_source_directory 命令,该命令会查指定⽬录下的所有源⽂件,然后将结果存进指定变量名。其语法如下:
aux_source_directory(<dir> <variable>)
因此,可以修改 如下:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项⽬信息
project (Demo2)
# 查当前⽬录下的所有源⽂件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定⽣成⽬标
add_executable(Demo ${DIR_SRCS})
这样,CMake 会将当前⽬录所有源⽂件的⽂件名赋值给变量 DIR_SRCS ,再指⽰变量 DIR_SRCS 中的源⽂件需要编译成⼀个名称为 Demo 的可执⾏⽂件。
多个⽬录,多个源⽂件
本⼩节对应的源代码所在⽬录:。
现在进⼀步将 MathFunctions.h 和 ⽂件移动到 math ⽬录下。
./Demo3
|
+---
|
+--- math/
|
+---
|
+--- MathFunctions.h
对于这种情况,需要分别在项⽬根⽬录 Demo3 和 math ⽬录⾥各编写⼀个 ⽂件。
使⽤静态链接库
为了⽅便,我们可以先将 math ⽬录⾥的⽂件编译成静态库再由 main 函数调⽤。
根⽬录中的 :
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项⽬信息
project (Demo3)
# 查当前⽬录下的所有源⽂件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 添加 math ⼦⽬录
add_subdirectory(math)
# 指定⽣成⽬标
add_executable()
# 添加链接库
target_link_libraries(Demo MathFunctions)
该⽂件添加了下⾯的内容: 第3⾏,使⽤命令 add_subdirectory 指明本项⽬包含⼀个⼦⽬录 math,这样 math ⽬录下的 ⽂件和源代码也会被处理 。第6⾏,使⽤命令 target_link_libraries 指明可执⾏⽂件 main 需要连接⼀个名为 MathFunctions 的链接库 。
⼦⽬录中的 :
# 查当前⽬录下的所有源⽂件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。