CMake的安装
一、下载
在linux环境下打开网页浏览器,输入网址:https://cmake.org/download/,找到最新版本的位置。一般开放源代码软件都会有两个版本发布:Source Distribution 和 Binary Distribution,前者是源代码版,你需要自己编译成可执行软件。后者是已经编译好的可执行版,直接可以拿来用的。
二、查询主机32位或64位
在linux环境下打开终端,输入:getconf LONG_BIT
如果结果是64表示该系统是linux64位的,如果结果是32则表示系统是linux32位。
三、安装cmake
由于Ubuntu14.04的cmake版本为2.8.x,而如果需要cmake3.x版本时,无法生成makefile,有两种方法可以安装cmake3.14.0:
3.1、源码安装
tar -xvf cmake-3.14.5.tar
cd cmake-3.14.5
./bootstrap
make
make install
cmake 会默认安装在 /usr/local/bin 下面
查询cmake --version
cmake version 3.14.5
3.2、binary安装
方法一
将下载的安装包放到 /usr路径下,并且解压;
tar zxvf cmake-2.8.9-Linux-i386.tar.gz
到了这里,可以看一下解压以后的目录结构,看解压是否成功
为cmake创建连接
ln -s /usr/cmake-2.8.9-Linux-i386/bin/* /usr/bin/
到这里,cmake就安装完成;
验证cmake的安装是否成功;
方法二
把下载好的包复制到指定路径,比如/home/bnu,在当前文件夹中打开终端,输入
tar zxvf cmake-3.6.0-Linux-x86 64.tar.gz
打开新的终端,输入vim .bashrc
该bashrc文件不用提前建立,路径也根据自己的情况改变,我定的路径与解压后的cmake包路径是一致的
此时会打开一个文件,找到export PATH=这些行,在这些行的下面另外添加一行,从而设置环境变量
export PATH=$PATH:/home/bnu/cmake-3.6.0-Linux-x86 64/bin
查看版本,测试是否安装成功:打开终端,输入cmake --version
结果是:cmake version 3.6.0(安装cmake成功!)
要知道,在根目录下安装cmake,那么不同用户都可以共享使用这个cmake.如果是安装其它软件如opencv/caffe等,需要设置环境变量路径,如果路径是根目录,那么不同用户都能使用这些软件,但如果环境变量路径只在一个用户路径下,那么只有这个用户能用这些软件。
CMake介绍
CMake是一个比make更高级的编译配置工具,它可以根据不同平台、不同的编译器,生成相应的Makefile或者vcproj项目。
通过编写CMakeLists.txt,可以控制生成的Makefile,从而控制编译过程。CMake自动生成的Makefile不仅可以通过make命令构建项目生成目标文件,还支持安装(make install)、测试安装的程序是否能正确执行(make test,或者ctest)、生成当前平台的安装包(make package)、生成源码包(make package_source)、产生Dashboard显示数据并上传等高级功能,只要在CMakeLists.txt中简单配置,就可以完成很多复杂的功能,包括写测试用例。
如果有嵌套目录,子目录下可以有自己的CMakeLists.txt。
1.CMake编译原理
CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object))。因此CMake的编译基本就两个步骤:cmake和make
cmake 指向CMakeLists.txt所在的目录,例如cmake .. 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件,所以一般建议新建一个新的目录,专门用来编译,例如
mkdir build
cd build
cmake ..
make
make根据生成makefile文件,编译程序。
示例一 b= sqrt(a)
a.准备程序文件
文件目录结构如下:
.
├── build
├── CMakeLists.txt
├── include
│ └── b.h
└── src
├── b.c
└── main.c
//b.h
#ifndef B_FILE_HEADER_INC
#define B_FIEL_HEADER_INC
#include<math.h>
double cal_sqrt(double value);
#endif
//b.c
#include "../include/b.h"
double cal_sqrt(double value)
{
return sqrt(value);
}
//main.c
#include "../include/b.h"
#include <stdio.h>
int main(int argc, char** argv)
{
double a = 49.0;
double b = 0.0;
printf("input a:%f\n",a);
b = cal_sqrt(a);
printf("sqrt result:%f\n",b);
return 0;
}
b.编写CMakeLists.txt
接下来编写CMakeLists.txt文件,该文件放在和src,include的同级目录。CMakeLists.txt文件,如下所示:
#1.cmake verson,指定cmake版本
cmake_minimum_required(VERSION 3.2)
#2.project name,指定项目的名称,一般和项目的文件夹名称对应
PROJECT(test_sqrt)
#3.head file path,头文件目录
INCLUDE_DIRECTORIES(include)
#4.source directory,源文件目录
AUX_SOURCE_DIRECTORY(src DIR_SRCS)
#5.set environment variable,设置环境变量,编译用到的源文件全部都要放到这里,否则编译能够通过,但是执行的时候会出现各种问题,比如"symbol lookup error xxxxx , undefined symbol"
SET(TEST_MATH ${DIR_SRCS})
#6.add executable file,添加要编译的可执行文件
ADD_EXECUTABLE(${PROJECT_NAME} ${TEST_MATH})
#7.add link library,添加可执行文件所需要的库,比如我们用到了libm.so(命名规则:lib+name+.so),就添加该库的名称
TARGET_LINK_LIBRARIES(${PROJECT_NAME} m)
CMakeLists.txt主要包含以上的7个步骤,具体的意义,请阅读相应的注释。
CMakeLists.txt由命令、注释和空格组成,其中命令是不区分大小写。符号#后的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。
示例二 Hello, world!
了解cmake的基本原理并在系统中安好cmake后,我们就可以用cmake来演示那个最经典的”Hello, world!”了。
第一步,我们给这个项目起个名字——就叫HELLO吧。因此,第一部为项目代码建立目录hello,与此项目有关的所有代码和文档都位于此目录下。
第二步,在hello目录下建立一个main.c文件,其代码如下:
#include <stdio.h>
int main(void)
{
printf(”Hello,World\n”);
return 0;
}
第三步,在hello目录下建立一个新的文件CMakeLists.txt,它就是 cmake所处理的“代码“。其实,使用cmake管理项目本身也是在编程,所以称之为“代码(或脚本)”并不为过。在CMakeLists.txt文件中输入下面的代码(#后面的内容为代码行注释):
#cmake最低版本需求,不加入此行会受到警告信息
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(HELLO) #项目名称
#把当前目录(.)下所有源代码文件和头文件加入变量SRC_LIST
AUX_SOURCE_DIRECTORY(. SRC_LIST)
#生成应用程序 hello (在windows下会自动生成hello.exe)
ADD_EXECUTABLE(hello ${SRC_LIST})
至此,整个hello项目就已经构建完毕,可以进行编译了。
第四步,编译项目。
为了使用外部编译方式编译项目,需要先在目录hello下新建一个目录build(也可以是其他任何目录名)。现在,项目整体的目录结构为:
hello/
|– CMakeLists.txt
|– build /
`– main.c
在windows下,cmake提供了图形界面,设定hello为source目录,build为二进制目录,然后点击configure即可开始构建,之后进入build目录运行make命令编译。
在linux命令行下,首先进入目录build,然后运行命令(注:后面的“..”不可缺少):
该命令使cmake检测编译环境,并生成相应的makefile。接着,运行命令make进行编译。编译后,生成的所有中间文件和可执行文件会在build目录下。 下面是我在ubuntu上的运行过程:
$ ls
hello
$ cd hello/build/
$ ls
$ cmake ..
– The C compiler identification is GNU
– The CXX compiler identification is GNU
– Check for working C compiler: /usr/bin/gcc
– Check for working C compiler: /usr/bin/gcc — works
– Detecting C compiler ABI info
– Detecting C compiler ABI info - done
– Check for working CXX compiler: /usr/bin/c++
– Check for working CXX compiler: /usr/bin/c++ — works
– Detecting CXX compiler ABI info
– Detecting CXX compiler ABI info - done
– Configuring done
– Generating done
– Build files have been written to: /home/kermit/Project/cmake/hello/build
$ make
Scanning dependencies of target hello
[100%] Building C object CMakeFiles/hello.dir/main.c.o
Linking C executable hello
[100%] Built target hello
$ ls
CMakeCache.txt CMakeFiles cmake_install.cmake hello Makefile
$ ./hello
Hello,World
外部编译方式。其实,cmake还可以直接在当前目录进行编译,无须建立build目录。但是,这种做法会将所有生成的中间文件和源代码混在一起,而且cmake生成的makefile无法跟踪所有的中间文件,即无法使用”make distclean”命令将所有的中间文件删除。因此,我们推荐建立build目录进行编译,所有的中间文件都会生成在build目录下,需要删除时直接清空该目录即可。这就是所谓的外部编译方式。
示例
#cmake verson,指定cmake版本
cmake_minimum_required(VERSION 3.6)#project name,指定项目的名称,一般和项目的文件夹名称对应
project(tboxapi)#设置变量
set(CMAKE_C_STANDARD 11)
set(CMAKE_VERBOSE_MAKEFILE on)
#set(CMAKE_C_VISIBILITY_PRESET hidden)#打印消息
message(INFO " 11${CMAKE_VERBOSE_MAKEFILE}22")#head file path,头文件目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
#打印消息
message(INFO " libpath =${CMAKE_CURRENT_SOURCE_DIR}/lib!")#source directory,源文件目录
#AUX_SOURCE_DIRECTORY(src DIR_SRCS)
set(SOURCE_FILES
src/test_api.c
src/otahelperHirain.h
)#设置变量
if (DEBUG)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
endif()#设置变量
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -rdynamic -ldl -lpthread")#add_library: 生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件)
#这个库放到一个叫做”tboxinterface”的子文件夹中,它包含一个只有一行内容的CMakeLists.txt文件:
#add_library(MathFunctions mysqrt.cxx)
#add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h)
#只需要编译出动态库和静态库
#add_library (testFunc_shared SHARED ${SRC_LIST})
#add_library (testFunc_static STATIC ${SRC_LIST})
#add_library (tboxinterface SHARED ${LIB_SOURCE})#设置最终生成的库的名称,还有其它功能,如设置库的版本号等等
#set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc")
#set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc")#在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径
#find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib)
#find_library(TESTFUNC_LIB libtestFunc.so ...
#find_library(TESTFUNC_LIB libtestFunc.a ...#add executable file,添加要编译的可执行文件
add_executable(test_api ${SOURCE_FILES})
#把目标文件与库文件进行链接,比如我们用到了libm.so(命名规则:lib+name+.so),就添加该库的名称
#TARGET_LINK_LIBRARIES(${PROJECT_NAME} m)
target_link_libraries(test_api PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/lib/libota_tbox_helper.so")#安装test_api可执行程序和配置库和头文件
install(TARGETS test_api RUNTIME DESTINATION bin)
install(FILES src/otahelperHirain.h DESTINATION include)
install(FILES lib/libota_tbox_helper.so DESTINATION lib)#设置变量
set(CMAKE_VERBOSE_MAKEFILE on)