cmake安装、用法
- cmake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。
- 为何要使用cmake和autotools之类的项目构建工具?
- 任何一个软件项目,除了写代码之外,还有一个更为重要的任务,就是如何组织和管理这些代码,使项目代码层次结构清晰易读,这对以后的维护工作大有裨益。决定代码的组织方式及其编译方式,也是程序设计的一部分。因此,我们需要cmake和autotools这样的工具来帮助我们构建并维护项目代码。
- makefile不就是管理代码自动化编译的工具吗?为什么还要用别的构建工具?其实,cmake和autotools正是makefile的上层工具,它们的目的正是为了产生可移植的makefile,并简化自己动手写makefile时的巨大工作量。如果自己动手写过makefile,会发现,makefile通常依赖于你当前的编译平台,而且编写makefile的工作量比较大,解决依赖关系时也容易出错。
- 因此,对于大多数项目,应当考虑使用更自动化一些的 cmake或者autotools来生成makefile,而不是上来就动手编写。总之,项目构建工具能够帮我们在不同平台上更好地组织和管理我们的代码及其编译过程,这是我们使用它的主要原因。(告诉编译器如何去编译链接源代码)
- linux下安装cmake
- 下载源码包
https://cmake.org/download/
选择cmake-x.x.x.tar.gz - 找个目录解压缩
tar -xzvf cmake-x.x.x.tar.gz
cd cmake-x.x.x - 依次执行:
./bootstrap
make
make install - cmake 会默认安装在 /usr/local/bin 下面
- 检查版本
cmake –version
- 下载源码包
用cmake演示最经典的”Hello, world!”
- 为项目代码建立目录hello,与此项目有关的所有代码和文档都位于此目录下。
- 在hello目录下建立一个main.c文件,其代码如下:
//main.cpp文件
#include<iostream>
using namespace std;
int main(){
cout<<"hello world!"<<endl;
return 0;
}
- 在hello目录下建立一个新的文件CMakeLists.txt,它就是 cmake所处理的”代码”。在CMakeLists.txt文件中输入下面的代码(#后面的内容为代码行注释):
_executable(hello ${DIR_SRC})
#cmake最小需要版本
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
#项目名称
PROJECT (HELLOWORLD)
#包含原程序,即把给定的源程序复制给变量SRC_LIST
SET(SRC_LIST main.cpp)
#生成可执行文件
ADD_EXECUTABLE(helloworld ${SRC_LIST})
或者(注:CMakeList.txt 文件中,命令名字是不区分大小写的,而参数和变量是大小写相关的)
cmake_minimum_required(VERSION 2.8)
project(HELLOWORLD)
#查找在某个路径下的所有源文件,并赋给变量DIR_SRC
aux_source_directory(./ DIR_SRC)
add_executable(helloworld ${DIR_SRC})
- 编译项目
使用外部编译方式编译项目,需要先在目录hello下新建一个目录build(也可以是其他任何目录名)。现在,项目整体的目录结构为:
hello/
|– CMakeLists.txt
|– main.cpp
|– build /
- 然后执行如下命令:
cd build
cmake .. #用于根据CMakeLists.txt生成Makefile文件,注 cmake 命令后跟一个路径(..),用来指出 CMakeList.txt 所在的位置
make #用于执行Makefile文件,编译源代码、连接、生成目标文件、可执行文件;
./helloworld - 外部编译方式。其实,cmake还可以直接在当前目录进行编译,无须建立build目录。但是,这种做法会将所有生成的中间文件和源代码混在一起,而且cmake生成的makefile无法跟踪所有的中间文件,即无法使用”make distclean”命令将所有的中间文件删除。因此,推荐建立build目录进行编译,所有的中间文件都会生成在build目录下,需要删除时直接清空该目录即可。这就是所谓的外部编译方式。
- make clean 清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件。
- make install 将编译成功的可执行文件安装到系统目录中,一般为/usr/local/bin目录。
- make help 可以显示some of the valid targets for this Makefile
- 然后执行如下命令:
- 添加静态库或者动态库
假设我们程序用到了在/usr/lib下的一个静态库libmy.a,那么需要添加如下两个命令:
#库所在位置
link_directories(/usr/lib)
#程序编译时候链接库
target_link_libraries(helloworld my)
复杂化”Hello, world!”继续学习
例一
我们将main.cpp文件拆成三个:main.cpp, hello.cpp, hello.hpp,并将hello.cpp生成一个库然后再使用
- main.cpp
#include "hello.hpp"
int main(){
hello("World");
return 0;
}
- hello.cpp
#include<iostream>
#include "hello.hpp"
using namespace std;
void hello(const char * name)
{
cout << "Hello" << name << endl;
}
- hello.hpp
#ifndef DBZHANG_HELLO_
#define DBZHANG_HELLO_
void hello(const char* name);
#endif
- 改写前面的CMakeLists.txt文件
cmake_minimum_required(VERSION 3.2)
project(HELLOWORLD)
set(LIB_SRC hello.cpp)
set(DIR_SRC main.cpp)
add_library(libhello ${LIB_SRC})
add_executable(helloworld ${DIR_SRC})
target_link_libraries(helloworld libhello)
- 按上面一样运行cmake,可以看到build目录中生成了:liblibhello.a,这就是我们生成的库。因为我们add_library时用了libhello这个名字,导致生成的库名字为liblibhello.a,如果想生成libhello.a,则在CMakeLists.txt中添加
set_target_properties(libhello PROPERTIES OUTPUT_NAME “hello”)
例二
如果把源代码分开放在不同路径下,就像我们平时的文件组织结构一样
+
|
+--- CMakeList.txt
+--+ src/
| |
| +--- main.cpp
| /--- CMakeList.txt
|
+--+ lib/
| |
| +--- hello.hpp
| +--- hello.cpp
| /--- CMakeList.txt
|
/--+ build/
每个源文件目录都需要一个CMakeLists.txt文件:
- 顶层的CMakeList.txt
cmake_minimum_required(VERSION 3.2)
project(HELLOWORLD)
#告诉cmake去子目录寻找新的CMakeList.txt 子文件
add_subdirectory(src)
add_subdirectory(libhello)
- src 中的 CMakeList.txt
#用于指明头文件所在的路径
include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(DIR_SRC main.cpp)
add_executable(helloworld ${DIR_SRC})
target_link_libraries(helloworld libhello)
- libhello 中的 CMakeList.txt
set(LIB_SRC hello.cpp)
#这里用的静态库,如果用动态库只需在该命令中加入参数SHARED:
#add_library(libhello SHARED ${LIB_SRC})
add_library(libhello ${LIB_SRC})
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
例三
如何可执行文件在 bin 目录,库文件在 lib 目录,即build中的目录结构为
+ build/
|
+--+ bin/
| |
| /--- hello.exe
|
/--+ lib/
|
/--- hello.lib
- 修改顶级的 CMakeList.txt
cmake_minimum_required(VERSION 3.2)
project(HELLOWORLD)
#可以指定其对应的目录在build中的名字
add_subdirectory(src bin)
add_subdirectory(libhello lib)
- 或者,不修改顶级的文件,修改其他两个文件
#src/CMakeList.txt 文件
include_directories(${PROJECT_SOURCE_DIR}/libhello)
#link_directories(${PROJECT_BINARY_DIR}/lib)
set(DIR_SRC main.c)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(helloworld ${DIR_SRC})
target_link_libraries(helloworld libhello)
#libhello/CMakeList.txt 文件
set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
注:
- linux中静态库和动态库的区别
- 不同
-库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。库分静态库和动态库两种。
- 静态函数库
这类库的名字一般是libxxx.a;利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。 - 动态函数库
这类库的名字一般是libxxx.so;相对于静态函数库,动态函数库在编译的时候 并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。
- 静态函数库
- 相同
都是由*.o目标文件生成
- 不同
详细:
从简单到复杂的cmake学习: cmake学习笔记从(一)到(六): http://blog.csdn.net/dbzhang800/article/details/6314073