【参考】
http://blog.csdn.net/dbzhang800/article/details/6314073
http://www.cnblogs.com/lidabo/p/3976947.html
http://www.cnblogs.com/hzhida/archive/2012/08/06/2624998.html//ubuntu下设置环境变量
windows里有visual studio 这个强大的IDE环境来帮助我们建立工程、编译程序,可是到了ubuntu下就犯了难,好在有cmake这个工具来帮忙。CMakeLists.txt只用来生成makefile
【00】CMake简介
CMake说白了就是一个为CMakeLists.txt的工程脚本配置文件。CMake可以针对不同操作系统和IDE环境生成不同的脚本或工程文件,如VS解决方案、Mac OSX的XCode文件、Unix/Linux系统的Makefile文件等等。试图直接使用子目录的CMakeList.txt是无效的,因为系统找不到许多在根目录的CMakeLists文件中配置的参数和宏,因而会产生错误提示,无法继续执行。
总之,如果工程用CMake来配置,然后一个命令就可以整齐地输出链接库和可执行文件。
以下介绍几个关于CMake的基本概念:
CMake脚本代码和配置参数的载体,源代码目录中没有它的话,工程就不可能使用CMake的配置程序来完成自动Makefile脚本的生成工作
源码树(Source Tree)和二进制树(Binary Tree)含义很好理解:
Source Tree表达了一个工程的所有
头文件(.h,.hxx,.hh,无扩展名等等)、
源文件(.c,.cc,.cpp,.cxx,等等)、
CMake脚本(CMakeLists.txt),以及它们目录树结构;
Binary Tree则包括平台相关的解决方案或Makefile脚本,目标文件(.obj),编译后的动态/静态库和可执行文件,以及其它编译过程中生成的文件等。
CMake允许“源码树内生成”(in-source build)和“源码树外生成”(out-of-source build)这两种方式。前者将会在源代码的同一目录下生成对应的Makefile脚本,目标文件以及结果;后者则是在不同的目录下执行编译生成工作,源代码树则保持原样,十分有利于代码的版本更新,搜索管理以及打包再发布
对于windows用户,可在CMake-GUI的"where to build binaries"栏中输入新的工作路径以实现out-of-source的模式;Linux用户则可简单地在外部目录执行cmake指令,例如:cmake /home/myproject -DCMAKE_BUILD_TYPE=Release
这里的/home/myproject即是工程的根目录,其中必须包含有CMakeLists.txt文件
一个工程需要依赖于另一个工程的头文件和库文件(.lib),无论对商业还是开源软件的开发流程来说这都是不可或缺的一部分:GUI开发库Qt的部分功能依赖于libJPEG、libPNG;商业GIS引擎Skyline依赖于GDAL;就连微软的一些大型游戏都会依赖于开源工程OpenAL。
那么,如何告诉我们的工程,这些头文件和LIB文件的位置呢?VS中在工程属性的“C/C++” 和“连接器”选项卡中可分别设置它们的路径;而Linux编程时,则需要在脚本中手动添加
-I以及
-L、
-I参数,保证#include宏不致无所适从,以及编译器不会产生该死的LINK2001、LINK2019错误。而对于使用CMake生成自动脚本的开发者来说,寻找头文件和库文件的工作就交给CMakeModules中的各个模块来完成。
因此,可以在目录文件中,建立一个CMakeModules文件夹,里面存放自动获取依赖库的路径信息(并不会主动将它们追加到工程属性中),不然,智能设置FREETYPE_INCLUDE_DIR,GDAL_LIBRARY等选项。这些自动搜索脚本的扩展名为.cmake
前文描述linux下CMake命令行时,有一个未做介绍的宏参数:-DCMAKE_BUILD_TYPE=Release。它可被简单地分给为三个部分:-D是命令前缀词,CMAKE_BUILD_TYPE是宏命令的关键字,而Release则是对其赋值。这个内置宏标志代表了设置了工程即将采用的编译类型,可使用的值通常包括Debug、Release、RelWithDebInfo和MinSizeRel四种。和VS等工具中所做设置类似,这将改变工程的调试等级和编译生成的信息等诸多内容。
除了CMAKE_BUILD_TYPE之外,CMake中还包含了一些基本的内置宏指令,典型的如:
CMAKE_MODULE_PATH,设置搜索CMakeModules模块(.cmake)的额外路径。
CMAKE_INCLUDE_PATH,设置自动查找依赖工程头文件的额外路径,默认为脚本中指定的搜索路径
CMAKE_LIBRARY_PATH,设置自动查找依赖工程库文件的额外路径,默认为脚本中指定的搜索路径
CMAKE_INSTALL_PREFIX,设置安装时的路径。这是一个重要的配置参数,当链接库和可执行文件的生成工作完毕时,往往需要将这些.lib,.dll,.exe和头文件拷贝到一个独立的文件夹下,以备调用和再次复制。在VS环境下通过INSTALL工程来完成这一安装工作,而Unix/Linux下则是熟悉的make install。默认安装目录为/usr/local或者C:/Program Files/。
当我们使用CMake生成了工程的解决方案或Makefile脚本之后,再进入二进制树目录,也就是编译过程文件存储的位置(in-source模式为源代码同一目录,out-of-source模式为用户自行指定的文件夹),可看到新生成CMakeCache.txt文件,即缓存信息文件。
CMakeCache.txt中存储了所有自动搜索或者手动配置的路径和脚本参数。当更新了工程的源代码并准备重新进行编译时,使用这种缓存信息文件可有效地加速CMake配置过程,方法是直接将这个文件拖动到CMake-GUI窗口中,或在命令行方式下执行:cmake -C CMakeCache.txt
此时,系统将自动读入上一次配置的所有信息,使用CMake-GUI的用户可在对话框中再次进行参数的修改,并生成新的解决方案或者Makefile文件,以供下一步的工程编译生成工作。
【01】CMake安装
到CMake主页(https://cmake.org/)下载对应系统的cmake版本。
主页上,CMake版本有两种:一种需要在本地进行make,一种不需要make
- cmake-3.8.0-rc1-linux-x86_64:
1)这个版本已经下载编译好了,只需解压到需要的目录即可使用:tar xzvf cmake-3.8.0-rc1-Linux-x86_64.tar.gz -C /usr/local
2)设置环境变量:sudo gedit ~/.bashrc,在打开文件后添加:export PATH=$PATH:/usr/local/cmake-3.8.0-rc1-Linux-x86_64/bin
在 Ubuntu 系统中有两种设置环境变量 PATH 的方法。第一种适用于为单一用户设置 PATH,第二种是为全局设置 PATH。
第一种方法: 在用户主目录下有一个 .bashrc 文件,可以在此文件中加入 PATH 的设置如下:
export PATH=”$PATH:/your path1/:/your path2/…..”
注意:每一个 path 之间要用 “:“ 分隔。 注销重启 X 就可以了。
第二种方法: 在 /etc/profile中增加。
PATH="$PATH:/home/zhengb66/bin"
export PATH
环境变量时通过shell命令来设置,设置好的环境变量又可以被所有当前用户所运行的程序所使用。对于bash这个shell程序来说,可通过变量名来访问相应的 环境变量,通过export来设置环境变量
3)有的时候需要创建链接, ln -s /usr/local/cmake-3.8.0-rc1-Linux-x86_64/bin/* /usr/bin/
4)执行命令检查是否安装成功
cmake --version
cmake version 3.8.0
注:在嵌入式平面可能不能用这种方法来安装,因为按照上述方法装时可能会提示:cannot execute binary file: Exec format error,只能下载另外一个版本,在本地make
1)将文件解压tar xzvf cmake-3.8.0-r1-tar.gz
2) 进入文件夹中
./bootstrap
make
make install//如果显示没有权限,则用sudo make install
3)检查是否安装成功cmake --version
【02】CMake实例
以下实例都是在ubuntu下编译
- 简单地例子 --单个cpp文件工程
目标:在本地新建一个CMakeListsSample文件夹,编写一个.cpp文件,用CMakeLists.txt管理,实现编译
实现:用out-of-source构建
CMakeLIstsSample __main.cpp
|__CMakeLists.txt
|__+build文件夹
//main.cpp
#include <iostream>
int main()
{
std::cout << "Hello World!\n" << std::endl;
return 0;
}
//CMakeLists.txt
project(HELLO)
set(SRC_LIST main.cpp)
add_executable(hello ${SRC_LIST})
在build文件夹执行
cmake ..
make
总结:
CMakeLists.txt,
首先,CMakeLists.txt中,名称有s
齐次,CMakeLists.txt中命名名字是不区分大小写,而参数和变量时大小写相关的
第三,第一行project不是强制性的,但最好都始终加上,加后,第一行会引入两个变量:HELLO_BINARY_DIR和HELLO_SOURCE_DIR,同时cmake自动定义了两个等价变量PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR,因为是out-of-source 方式构建,故要时刻区分这两个变量对应的目录。可通过message来输出变量值
message(${PROJECT_SOURCE_DIR})
第四,set命令用来设置变量
第五,add_executable告诉工程生成一个可执行文件,add_library则告诉生成一个库文件
cmake命令后跟一个路径(..),用来指出CMakeLists.txt所在位置;
由于系统中可能有多套构建环境,可通过-G来指定生成那种工程文件,如cmake .. -G"NMake Makefiles"、cmake .. -G"MinGW Makefile",再通过cmake -h可得到详细信息;
要显示执行构建过程中详细信息(比如为了得到更详细的出错信息),可在CMakeLists.txt内加入:
SET(CMAKE_VERBOSE_MAKEFILE on)
或执行make时, make VERBOSE=1
或export VERBOSE=1
make
2.稍微复杂点的--多个.cpp文件和头文件
//hello.h 头文件
#ifndef DB_HELLO_
#define DB_HELLO_
void hello(const char* name);
#endif
//hello.cpp
#include <iostream>
void hello(const char* name)
{
std::cout << name << std::endl;
}
//main.cpp
#include <iostream>
int main()
{
hello("Hello_World!\n");
return 0;
}
//CMakeLists.txt文件
project(HELLO)
set(SRC_LIST main.cpp hello.cpp)
add_executable(hello ${SRC_LIST})
3.接着上面,将hello.cpp生成一个库,然后再使用
只用修改CMakeLists.txt文件:
project(HELLO)
set(LIB_SRC hello.cpp)
set(APP_SRC main.cpp)
add_library(libhello ${LIB_SRC})
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)
想要生成hello.lib(或hello.a)文件,直接添加一行
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
4.生成的库与源代码各方不同的路径下
+
|
+--- CMakeList.txt
+--+ src/
| |
| +--- main.cpp
| /--- CMakeList.txt
|
+--+ libhello/
| |
| +--- hello.h
| +--- hello.cpp
| /--- CMakeList.txt
|
/--+ build/
这需要3个CMakeLists.txt文件,每个源文件目录都需要一个。
project(HELLO)
add_subdirectory(src)
add_subdirectory(libhello)
include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(APP_SRC main.cpp)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)
- libhello中的CMakeLists.txt文件
set(LIB_SRC hello.cpp)
add_library(libhello ${LIB_SRC})
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
编写完后,在顶层文件夹内新建一个build文件夹,
cmake ..
make
5.在之前的基础上增加:让编译出的可执行文件在bin目录下,库文件在lib目录下:
+ build/
|
+--+ bin/
| |
| /--- hello.exe
|
/--+ lib/
|
/--- hello.lib
- 一种方法:修改顶级的CMakeLists.txt文件
project(HELLO)
add_subdirectory(src bin)
add_subdirectory(libhello lib)
这样build中的目录默认和源代码中结构一样,也可指定其对应目录在build中的名字,当然还有其他中间产物。
- 另外一种方法:不修改顶级文件,修改其他两个文件。 使用该种方法不会有其他中间产物
src/CMakeLists.txt文件:
include_directories(${PROJECT_SOURCE_DIR}/libhello)
#link_directories(${PROJECT_BINARY_DIR}/lib)
set(APP_SRC main.cpp)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)
libhello/CMakeLists.txt文件:
set(LIB_SRC hello.cpp)
add_library(libhello ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
6.上面生成的都是静态库,下面实现动态库生成。
.a文件为静态库,.so为动态链接库
如果不考虑windows下,只需在上面例子libhello/CMakeLists.txt文件中的add_library命令加入一个SHARED参数:
add_library(libhello SHARED ${LIB_SRC})
使用CMake的特性就是能兼顾不同平台,因此做如下修改:
#ifndef DB_HELLO_
#define DB_HELLO_
#if defined _WIN32
#if LIBHELLO_BUILD
#define LIBHELLO_API_declspec(dllexport)
#else
#define LIBHELLO_API_declspec(dllimport)
#endif
#else
#define LIBHELLO_API
#endif
LIBHELLO_API void hello(const char* name);
#endif
- 修改libhello/CMakeList.txt文件
set(LIB_SRC hello.cpp)
add_definitions("-DLIBHELLO_BUILD")
add_library(libhello SHARED ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")