cmake 常用变量和常用环境变量查表手册

cmake 常用变量和常用环境变量查表手册

一,cmake 变量引用的方式:

前面我们已经提到了,使用${}进行变量的引用。在 IF 等语句中,是直接使用变量名而不通过${}取值

二,cmake 自定义变量的方式:

主要有隐式定义和显式定义两种,前面举了一个隐式定义的例子,就是 PROJECT 指令,他会隐式的定义<projectname>_BINARY_DIR 和<projectname>_SOURCE_DIR 两个变量。
显式定义的例子我们前面也提到了,使用 SET 指令,就可以构建一个自定义变量了。
比如:
SET(HELLO_SRC main.SOURCE_PATHc),就 PROJECT_BINARY_DIR 可以通过${HELLO_SRC}来引用这个自定义变量了.

三,cmake 常用变量:

1,CMAKE_BINARY_DIR
  PROJECT_BINARY_DIR
 <projectname>_BINARY_DIR
这三个变量指代的内容是一致的,如果是 in source 编译,指得就是工程顶层目录,如果是 out-of-source 编译,指的是工程编译发生的目录。PROJECT_BINARY_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。
2,CMAKE_SOURCE_DIR
   PROJECT_SOURCE_DIR
   <projectname>_SOURCE_DIR
这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录。
也就是在 in source 编译时,他跟 CMAKE_BINARY_DIR 等变量一致。
PROJECT_SOURCE_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。

3,CMAKE_CURRENT_SOURCE_DIR
指的是当前处理的 CMakeLists.txt 所在的路径,比如上面我们提到的 src 子目录。

4,CMAKE_CURRRENT_BINARY_DIR
如果是 in-source 编译,它跟 CMAKE_CURRENT_SOURCE_DIR 一致,如果是 out-of-source 编译,他指的是 target 编译目录。
使用我们上面提到的 ADD_SUBDIRECTORY(src bin)可以更改这个变量的值。
使用 SET(EXECUTABLE_OUTPUT_PATH <新路径>)并不会对这个变量造成影响,它仅仅修改了最终目标文件存放的路径。

5,CMAKE_CURRENT_LIST_FILE

输出调用这个变量的 CMakeLists.txt 的完整路径

6,CMAKE_CURRENT_LIST_LINE

输出这个变量所在的行

7,CMAKE_MODULE_PATH
这个变量用来定义自己的 cmake 模块所在的路径。如果你的工程比较复杂,有可能会自己编写一些 cmake 模块,这些 cmake 模块是随你的工程发布的,为了让 cmake 在处理CMakeLists.txt 时找到这些模块,你需要通过 SET 指令,将自己的 cmake 模块路径设置一下。
比如
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
这时候你就可以通过 INCLUDE 指令来调用自己的模块了。

8,EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH
分别用来重新定义最终结果的存放目录,前面我们已经提到了这两个变量。

9,PROJECT_NAME
返回通过 PROJECT 指令定义的项目名称。

四,cmake 调用环境变量的方式

使用$ENV{NAME}指令就可以调用系统的环境变量了。
比如
MESSAGE(STATUS “HOME dir: $ENV{HOME}”)
设置环境变量的方式是:
SET(ENV{变量名} 值)
1,CMAKE_INCLUDE_CURRENT_DIR
自动添加 CMAKE_CURRENT_BINARY_DIR 和 CMAKE_CURRENT_SOURCE_DIR 到当前处理
的 CMakeLists.txt。相当于在每个 CMakeLists.txt 加入:
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})

2,CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE
将工程提供的头文件目录始终至于系统头文件目录的前面,当你定义的头文件确实跟系统发生冲突时可以提供一些帮助。

3,CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH 我们在上一节已经提及。

五,系统信息

1,CMAKE_MAJOR_VERSION,CMAKE 主版本号,比如 2.4.6 中的 2
2,CMAKE_MINOR_VERSION,CMAKE 次版本号,比如 2.4.6 中的 4
3,CMAKE_PATCH_VERSION,CMAKE 补丁等级,比如 2.4.6 中的 6
4,CMAKE_SYSTEM,系统名称,比如 Linux-2.6.22
5,CMAKE_SYSTEM_NAME,不包含版本的系统名,比如 Linux
6,CMAKE_SYSTEM_VERSION,系统版本,比如 2.6.22
7,CMAKE_SYSTEM_PROCESSOR,处理器名称,比如 i686.
8,UNIX,在所有的类 UNIX 平台为 TRUE,包括 OS X 和 cygwin
9,WIN32,在所有的 win32 平台为 TRUE,包括 cygwin

六,主要的开关选项:

1,CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS,用来控制 IF ELSE 语句的书写方式,在
下一节语法部分会讲到。
2,BUILD_SHARED_LIBS
这个开关用来控制默认的库编译方式,如果不进行设置,使用 ADD_LIBRARY 并没有指定库
类型的情况下,默认编译生成的库都是静态库。
如果 SET(BUILD_SHARED_LIBS ON)后,默认生成的为动态库。
3,CMAKE_C_FLAGS
设置 C 编译选项,也可以通过指令 ADD_DEFINITIONS()添加。
4,CMAKE_CXX_FLAGS
设置 C++编译选项,也可以通过指令 ADD_DEFINITIONS()添加。
小结:
本章介绍了一些较常用的 cmake 变量,这些变量仅仅是所有 cmake 变量的很少一部分,目
前 cmake 的英文文档也是比较缺乏的,如果需要了解更多的 cmake 变量,更好的方式是阅
读一些成功项目的 cmake 工程文件,比如 KDE4 的代码。

八,cmake 常用指令

前面我们讲到了 cmake 常用的变量,相信“cmake 即编程”的感觉会越来越明显,无论如何,我们仍然可以看到 cmake 比 autotools 要简单很多。接下来我们就要集中的看一看cmake 所提供的常用指令。在前面的章节我们已经讨论了很多指令的用法,如
PROJECT,ADD_EXECUTABLE,INSTALL,ADD_SUBDIRECTORY,SUBDIRS,
INCLUDE_DIRECTORIES,LINK_DIRECTORIES,TARGET_LINK_LIBRARIES,SET 等。
本节会引入更多的 cmake 指令,为了编写的方便,我们将按照 cmake man page 的顺序来介绍各种指令,不再推荐使用的指令将不再介绍,INSTALL 系列指令在安装部分已经做了非常详细的说明,本节也不在提及。(你可以将本章理解成选择性翻译,但是会加入更多的个人理解)

一,基本指令
1,ADD_DEFINITIONS
向 C/C++编译器添加-D 定义,比如:
ADD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分割。

如果你的代码中定义了#ifdef ENABLE_DEBUG #endif,这个代码块就会生效。
如果要添加其他的编译器开关,可以通过 CMAKE_C_FLAGS 变量和 CMAKE_CXX_FLAGS 变量设置。

2,ADD_DEPENDENCIES
定义 target 依赖的其他 target,确保在编译本 target 之前,其他的 target 已经被构建。
ADD_DEPENDENCIES(target-name depend-target1
                 depend-target2 ...)

3,ADD_EXECUTABLE、ADD_LIBRARY、ADD_SUBDIRECTORY 前面已经介绍过了,这里不再罗唆。

4,ADD_TEST 与 ENABLE_TESTING 指令。
ENABLE_TESTING 指令用来控制 Makefile 是否构建 test 目标,涉及工程所有目录。语法很简单,没有任何参数,ENABLE_TESTING(),一般情况这个指令放在工程的主CMakeLists.txt 中.

ADD_TEST 指令的语法是:
ADD_TEST(testname Exename arg1 arg2 ...)
testname 是自定义的 test 名称,Exename 可以是构建的目标文件也可以是外部脚本等等。后面连接传递给可执行文件的参数。如果没有在同一个 CMakeLists.txt 中打开ENABLE_TESTING()指令,任何 ADD_TEST 都是无效的。
比如我们前面的 Helloworld 例子,可以在工程主 CMakeLists.txt 中添加
ADD_TEST(mytest ${PROJECT_BINARY_DIR}/bin/main)
ENABLE_TESTING()
生成 Makefile 后,就可以运行 make test 来执行测试了。

5,AUX_SOURCE_DIRECTORY
基本语法是:
AUX_SOURCE_DIRECTORY(dir VARIABLE)
作用是发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前 cmake 还不能自动发现新添加的源文件。
比如
AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(main ${SRC_LIST})
你也可以通过后面提到的 FOREACH 指令来处理这个 LIST

6,CMAKE_MINIMUM_REQUIRED
其语法为 CMAKE_MINIMUM_REQUIRED(VERSION versionNumber [FATAL_ERROR])
比如 CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR)
如果 cmake 版本小与 2.5,则出现严重错误,整个过程中止。

7,EXEC_PROGRAM
在 CMakeLists.txt 处理过程中执行命令,并不会在生成的 Makefile 中执行。

具体语法为:
EXEC_PROGRAM(Executable [directory in which to run]
                [ARGS <arguments to executable>]
                [OUTPUT_VARIABLE <var>]
                [RETURN_VALUE <var>])
用于在指定的目录运行某个程序,通过 ARGS 添加参数,如果要获取输出和返回值,可通过OUTPUT_VARIABLE 和 RETURN_VALUE 分别定义两个变量.

这个指令可以帮助你在 CMakeLists.txt 处理过程中支持任何命令,比如根据系统情况去修改代码文件等等。
举个简单的例子,我们要在 src 目录执行 ls 命令,并把结果和返回值存下来。
可以直接在 src/CMakeLists.txt 中添加:
EXEC_PROGRAM(ls ARGS "*.c" OUTPUT_VARIABLE LS_OUTPUT RETURN_VALUE
LS_RVALUE)
IF(not LS_RVALUE)
MESSAGE(STATUS "ls result: " ${LS_OUTPUT})
ENDIF(not LS_RVALUE)

在 cmake 生成 Makefile 的过程中,就会执行 ls 命令,如果返回 0,则说明成功执行,那么就输出 ls *.c 的结果。关于 IF 语句,后面的控制指令会提到。

8,FILE 指令
文件操作指令,基本语法为:
       FILE(WRITE filename "message to write"... )
       FILE(APPEND filename "message to write"... )
       FILE(READ filename variable)
       FILE(GLOB variable [RELATIVE path] [globbing expression_r_rs]...)
       FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expression_r_rs]...)
       FILE(REMOVE [directory]...)
       FILE(REMOVE_RECURSE [directory]...)
       FILE(MAKE_DIRECTORY [directory]...)
       FILE(RELATIVE_PATH variable directory file)
       FILE(TO_CMAKE_PATH path result)
       FILE(TO_NATIVE_PATH path result)
这里的语法都比较简单,不在展开介绍了。

9,INCLUDE 指令,用来载入 CMakeLists.txt 文件,也用于载入预定义的 cmake 模块.
       INCLUDE(file1 [OPTIONAL])
       INCLUDE(module [OPTIONAL])
OPTIONAL 参数的作用是文件不存在也不会产生错误。
你可以指定载入一个文件,如果定义的是一个模块,那么将在 CMAKE_MODULE_PATH 中搜索这个模块并载入。
载入的内容将在处理到 INCLUDE 语句是直接执行。
二,INSTALL 指令
INSTALL 系列指令已经在前面的章节有非常详细的说明,这里不在赘述,可参考前面的安装部分。
三,FIND_指令
FIND_系列指令主要包含一下指令:
FIND_FILE(<VAR> name1 path1 path2 ...)
VAR 变量代表找到的文件全路径,包含文件名
FIND_LIBRARY(<VAR> name1 path1 path2 ...)
VAR 变量表示找到的库全路径,包含库文件名
FIND_PATH(<VAR> name1 path1 path2 ...)
VAR 变量代表包含这个文件的路径。
FIND_PROGRAM(<VAR> name1 path1 path2 ...)
VAR 变量代表包含这个程序的全路径。
FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE]
                [[REQUIRED|COMPONENTS] [componets...]])
用来调用预定义在 CMAKE_MODULE_PATH 下的 Find<name>.cmake 模块,你也可以自己定义 Find<name>模块,通过 SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录中供工程使用,我们在后面的章节会详细介绍 FIND_PACKAGE 的使用方法和 Find 模块的编写。

FIND_LIBRARY 示例:
FIND_LIBRARY(libX X11 /usr/lib)
IF(NOT libX)
MESSAGE(FATAL_ERROR “libX not found”)
ENDIF(NOT libX)

四,控制指令:

1,IF 指令,基本语法为:
       IF(expression_r_r)
         # THEN section.
         COMMAND1(ARGS ...)
         COMMAND2(ARGS ...)
         ...
       ELSE(expression_r_r)
         # ELSE section.
         COMMAND1(ARGS ...)
         COMMAND2(ARGS ...)
         ...
       ENDIF(expression_r_r)
另外一个指令是 ELSEIF,总体把握一个原则,凡是出现 IF 的地方一定要有对应的ENDIF.出现 ELSEIF 的地方,ENDIF 是可选的。
表达式的使用方法如下:
IF(var),如果变量不是:空,0,N, NO, OFF, FALSE, NOTFOUND 或<var>_NOTFOUND 时,表达式为真。
IF(NOT var ),与上述条件相反。
IF(var1 AND var2),当两个变量都为真是为真。
IF(var1 OR var2),当两个变量其中一个为真时为真。
IF(COMMAND cmd),当给定的 cmd 确实是命令并可以调用是为真。
IF(EXISTS dir)或者 IF(EXISTS file),当目录名或者文件名存在时为真。
IF(file1 IS_NEWER_THAN file2),当 file1 比 file2 新,或者 file1/file2 其中有一个不存在时为真,文件名请使用完整路径。
IF(IS_DIRECTORY dirname),当 dirname 是目录时,为真。
IF(variable MATCHES regex)
IF(string MATCHES regex)
当给定的变量或者字符串能够匹配正则表达式 regex 时为真。比如:
IF("hello" MATCHES "ell")
MESSAGE("true")
ENDIF("hello" MATCHES "ell")
IF(variable LESS number)
IF(string LESS number)
IF(variable GREATER number)
IF(string GREATER number)
IF(variable EQUAL number)
IF(string EQUAL number)
数字比较表达式
IF(variable STRLESS string)
IF(string STRLESS string)
IF(variable STRGREATER string)
IF(string STRGREATER string)
IF(variable STREQUAL string)
IF(string STREQUAL string)
按照字母序的排列进行比较.
IF(DEFINED variable),如果变量被定义,为真。
一个小例子,用来判断平台差异:
IF(WIN32)
    MESSAGE(STATUS “This is windows.”)
    #作一些 Windows 相关的操作
ELSE(WIN32)
    MESSAGE(STATUS “This is not windows”)
    #作一些非 Windows 相关的操作
ENDIF(WIN32)
上述代码用来控制在不同的平台进行不同的控制,但是,阅读起来却并不是那么舒服,
ELSE(WIN32)之类的语句很容易引起歧义。
这就用到了我们在“常用变量”一节提到的 CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS 开关。
可以 SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
这时候就可以写成:
IF(WIN32)
ELSE()
ENDIF()
如果配合 ELSEIF 使用,可能的写法是这样:
IF(WIN32)
#do something related to WIN32
ELSEIF(UNIX)
#do something related to UNIX
ELSEIF(APPLE)
#do something related to APPLE
ENDIF(WIN32)
2,WHILE
WHILE 指令的语法是:
        WHILE(condition)
          COMMAND1(ARGS ...)
          COMMAND2(ARGS ...)
          ...
        ENDWHILE(condition)
其真假判断条件可以参考 IF 指令。
3,FOREACH
FOREACH 指令的使用方法有三种形式:
1,列表
        FOREACH(loop_var arg1 arg2 ...)
          COMMAND1(ARGS ...)
          COMMAND2(ARGS ...)
          ...
        ENDFOREACH(loop_var)
像我们前面使用的 AUX_SOURCE_DIRECTORY 的例子
AUX_SOURCE_DIRECTORY(. SRC_LIST)
FOREACH(F ${SRC_LIST})
    MESSAGE(${F})
ENDFOREACH(F)
2,范围
FOREACH(loop_var RANGE total)
ENDFOREACH(loop_var)
从 0 到 total 以1为步进
举例如下:
FOREACH(VAR RANGE 10)
MESSAGE(${VAR})
ENDFOREACH(VAR)
最终得到的输出是:
0
1
2
3
4
5
6
7
8
9
10
3,范围和步进
FOREACH(loop_var RANGE start stop [step])
ENDFOREACH(loop_var)
从 start 开始到 stop 结束,以 step 为步进,
举例如下
FOREACH(A RANGE 5 15 3)
MESSAGE(${A})
ENDFOREACH(A)
最终得到的结果是:
5
8
11
14
这个指令需要注意的是,知道遇到 ENDFOREACH 指令,整个语句块才会得到真正的执行。
小结:
本小节基本涵盖了常用的 cmake 指令,包括基本指令、查找指令、安装指令以及控制语句等,特别需要注意的是,在控制语句条件中使用变量,不能用${}引用,而是直接应用变量名。

掌握了以上的各种控制指令,你应该完全可以通过 cmake 管理复杂的程序了,下一节,我
们将介绍一个比较复杂的例子,通过他来演示本章的一些指令,并介绍模块的概念。

九,复杂的例子:模块的使用和自定义模块
你现在还会觉得 cmake 简单吗?

本章我们将着重介绍系统预定义的 Find 模块的使用以及自己编写 Find 模块,系统中提供了其他各种模块,一般情况需要使用 INCLUDE 指令显式的调用,FIND_PACKAGE 指令是一个特例,可以直接调用预定义的模块.

其实使用纯粹依靠 cmake 本身提供的基本指令来管理工程是一件非常复杂的事情,所以,cmake 设计成了可扩展的架构,可以通过编写一些通用的模块来扩展 cmake.

在本章,我们准备首先介绍一下 cmake 提供的 FindCURL 模块的使用。然后,基于我们前面的 libhello 共享库,编写一个 FindHello.cmake 模块.

一,使用 FindCURL 模块
在/backup/cmake 目录建立 t5 目录,用于存放我们的 CURL 的例子。
建立 src 目录,并建立 src/main.c,内容如下:
#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
FILE *fp;
int write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
int written = fwrite(ptr, size, nmemb, (FILE *)fp);
return written;
}
int main()
{
const char * path = “/tmp/curl-test”;
const char * mode = “w”;
fp = fopen(path,mode);
curl_global_init(CURL_GLOBAL_ALL);
CURLcode res;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, “http://www.linux-ren.org”);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
这段代码的作用是通过 curl 取回 www.linux-ren.org 的首页并写入/tmp/curl-test文件中。
建立主工程文件 CMakeLists.txt
PROJECT(CURLTEST)
ADD_SUBDIRECTORY(src)
建立 src/CMakeLists.txt
ADD_EXECUTABLE(curltest main.c)
现在自然是没办法编译的,我们需要添加 curl 的头文件路径和库文件。
方法 1:
直接通过 INCLUDE_DIRECTORIES 和 TARGET_LINK_LIBRARIES 指令添加:
我们可以直接在 src/CMakeLists.txt 中添加:
INCLUDE_DIRECTORIES(/usr/include)
TARGET_LINK_LIBRARIES(curltest curl)
然后建立 build 目录进行外部构建即可。
现在我们要探讨的是使用 cmake 提供的 FindCURL 模块。
方法 2,使用 FindCURL 模块。
向src/CMakeLists.txt 中添加:
FIND_PACKAGE(CURL)
IF(CURL_FOUND)
  INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
  TARGET_LINK_LIBRARIES(curltest ${CURL_LIBRARY})
ELSE(CURL_FOUND)
    MESSAGE(FATAL_ERROR ”CURL library not found”)
ENDIF(CURL_FOUND)
对于系统预定义的 Find<name>.cmake 模块,使用方法一般如上例所示:
每一个模块都会定义以下几个变量
    <name>_FOUND
  ?
    <name>_INCLUDE_DIR or <name>_INCLUDES
  ?
    <name>_LIBRARY or <name>_LIBRARIES
  ?
你可以通过<name>_FOUND 来判断模块是否被找到,如果没有找到,按照工程的需要关闭某些特性、给出提醒或者中止编译,上面的例子就是报出致命错误并终止构建。

如果<name>_FOUND 为真,则将<name>_INCLUDE_DIR 加入 INCLUDE_DIRECTORIES,
将<name>_LIBRARY 加入 TARGET_LINK_LIBRARIES 中。
我们再来看一个复杂的例子,通过<name>_FOUND 来控制工程特性:
SET(mySources viewer.c)
SET(optionalSources)
SET(optionalLibs)
FIND_PACKAGE(JPEG)
IF(JPEG_FOUND)
  SET(optionalSources ${optionalSources} jpegview.c)
  INCLUDE_DIRECTORIES( ${JPEG_INCLUDE_DIR} )
  SET(optionalLibs ${optionalLibs} ${JPEG_LIBRARIES} )
  ADD_DEFINITIONS(-DENABLE_JPEG_SUPPORT)
ENDIF(JPEG_FOUND)
IF(PNG_FOUND)
  SET(optionalSources ${optionalSources} pngview.c)
  INCLUDE_DIRECTORIES( ${PNG_INCLUDE_DIR} )
  SET(optionalLibs ${optionalLibs} ${PNG_LIBRARIES} )
  ADD_DEFINITIONS(-DENABLE_PNG_SUPPORT)
ENDIF(PNG_FOUND)
ADD_EXECUTABLE(viewer ${mySources} ${optionalSources} )
TARGET_LINK_LIBRARIES(viewer ${optionalLibs}
通过判断系统是否提供了 JPEG 库来决定程序是否支持 JPEG 功能。

二,编写属于自己的 FindHello 模块。
我们在此前的 t3 实例中,演示了构建动态库、静态库的过程并进行了安装。
接下来,我们在 t6 示例中演示如何自定义 FindHELLO 模块并使用这个模块构建工程:
请在建立/backup/cmake/中建立 t6 目录,并在其中建立 cmake 目录用于存放我们自己定义的 FindHELLO.cmake 模块,同时建立 src 目录,用于存放我们的源文件。

1,定义 cmake/FindHELLO.cmake 模块
FIND_PATH(HELLO_INCLUDE_DIR hello.h /usr/include/hello
/usr/local/include/hello)
FIND_LIBRARY(HELLO_LIBRARY NAMES hello PATH /usr/lib
/usr/local/lib)
IF (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
  SET(HELLO_FOUND TRUE)
ENDIF (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
IF (HELLO_FOUND)
  IF (NOT HELLO_FIND_QUIETLY)
     MESSAGE(STATUS "Found Hello: ${HELLO_LIBRARY}")
  ENDIF (NOT HELLO_FIND_QUIETLY)
ELSE (HELLO_FOUND)
  IF (HELLO_FIND_REQUIRED)
     MESSAGE(FATAL_ERROR "Could not find hello library")
  ENDIF (HELLO_FIND_REQUIRED)
ENDIF (HELLO_FOUND)
针对上面的模块让我们再来回顾一下 FIND_PACKAGE 指令:
       FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE]
                 [[REQUIRED|COMPONENTS] [componets...]])
前面的 CURL 例子中我们使用了最简单的 FIND_PACKAGE 指令,其实他可以使用多种参数,
QUIET 参数,对应与我们编写的 FindHELLO 中的 HELLO_FIND_QUIETLY,如果不指定这个参数,就会执行:
MESSAGE(STATUS "Found Hello: ${HELLO_LIBRARY}")

REQUIRED 参数,其含义是指这个共享库是否是工程必须的,如果使用了这个参数,说明这个链接库是必备库,如果找不到这个链接库,则工程不能编译。对应于
FindHELLO.cmake 模块中的 HELLO_FIND_REQUIRED 变量。
同样,我们在上面的模块中定义了 HELLO_FOUND,
HELLO_INCLUDE_DIR,HELLO_LIBRARY 变量供开发者在 FIND_PACKAGE 指令中使用。
OK,下面建立 src/main.c,内容为:
#include <hello.h>
int main()
{
    HelloFunc();
    return 0;
}
建立 src/CMakeLists.txt 文件,内容如下:
FIND_PACKAGE(HELLO)
IF(HELLO_FOUND)
   ADD_EXECUTABLE(hello main.c)
   INCLUDE_DIRECTORIES(${HELLO_INCLUDE_DIR})
   TARGET_LINK_LIBRARIES(hello ${HELLO_LIBRARY})
ENDIF(HELLO_FOUND)
为了能够让工程找到 FindHELLO.cmake 模块(存放在工程中的 cmake 目录)我们在主工程文件 CMakeLists.txt 中加入:
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)

三,使用自定义的 FindHELLO 模块构建工程
仍然采用外部编译的方式,建立 build 目录,进入目录运行:
cmake ..
我们可以从输出中看到:
Found Hello: /usr/lib/libhello.so
如果我们把上面的 FIND_PACKAGE(HELLO)修改为 FIND_PACKAGE(HELLO QUIET),则不会看到上面的输出。
接下来就可以使用 make 命令构建工程,运行:
./src/hello 可以得到输出
Hello World。
说明工程成功构建。
四,如果没有找到 hello library 呢?
我们可以尝试将/usr/lib/libhello.x 移动到/tmp 目录,这样,按照 FindHELLO 模块的定义,就找不到 hello library 了,我们再来看一下构建结果:
cmake ..
仍然可以成功进行构建,但是这时候是没有办法编译的。
修改 FIND_PACKAGE(HELLO)为 FIND_PACKAGE(HELLO REQUIRED),将 hello library 定义为工程必须的共享库。

这时候再次运行 cmake ..
我们得到如下输出:
CMake Error: Could not find hello library.
因为找不到 libhello.x,所以,整个 Makefile 生成过程被出错中止。
小结:
在本节中,我们学习了如何使用系统提供的 Find<NAME>模块并学习了自己编写
Find<NAME>模块以及如何在工程中使用这些模块。
后面的章节,我们会逐渐学习更多的 cmake 模块使用方法以及用 cmake 来管理 GTK 和 QT4工程。

转载自:http://blog.csdn.net/gubenpeiyuan/article/details/8667279

时间: 2024-10-08 23:45:18

cmake 常用变量和常用环境变量查表手册的相关文章

8.6 管道符和作业控制 8.7/8.8 shell变量 8.9 环境变量配置文件

8.6 管道符和作业控制 8.7/8.8 shell变量 8.9 环境变量配置文件 扩展 bashrc和bash_profile的区别 http://ask.apelearn.com/question/7719 # 8.6 管道符和作业控制 ![mark](http://oqxf7c508.bkt.clouddn.com/blog/20170816/214503952.png?imageslim) - 管道符的命令就是把前面输出的结果交给后面的命令 ``` [[email protected] 

系统环境变量和用户环境变量

环境变量分为系统环境变量和用户环境变量. 你所说的环境变量是指系统环境变量,对所有用户起作用 而用户环境变量只对当前用户起作用. 例如你要用java,那么你把java的bin目录加入到path变量下面,那么它就是系统环境变量,所用用户登陆,在命令行输入java都会有java的帮助信息出来.而如果你在某个用户的变量下面新建一个变量,那么它就只对这个用户有用,当你以其他用户登陆时这个变量就和不存在一样. 这个问题在linux下面就相对好理解一些,系统变量都在/etc/profile文件里面,而用户的

PATH环境变量和CLASSPATH环境变量详解

大凡装过JDK的人都知道要安装完成后要设置环境变量,可是为什么要设置环境变量呢?环境变量有什么作用? 1)PATH详解: 计算机安装JDK之后,输入“javac”“java”之类的命令是不能马上被计算机正确执行的,因为计算机不知道到哪里去找这两个命令. 计算机如何查找命令呢?Windows操作系统根据PATH环境变量来查找命令.PATH环境变量的值是一系列路径,Windows操作系统将在这一系列的路径中依次查找命令,如果能找到这个命令,则该命令是可执行的:否则将出现“‘XXX’不是内部命令或外部

Java环境变量和Android环境变量

Java环境变量和Android环境变量: JAVA_HOME D:\setup\Java\jdk1.6.0;D:\setup\Java\jdk1.7.0_55 CLASSPATH .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tool.jar ANDROID_SDK D:\setup\adt\sdk Path %JAVA_HOME%\bin;%ANDROID_SDK%\platforms;%ANDROID_SDK%\platform-tools; Andro

五周第四次课(1月11日) 8.6 管道符和作业控制 8.7/shell变量 8.8 shell变量 8.9 环境变量配置文件

五周第四次课(1月11日)8.6 管道符和作业控制8.7/shell变量8.8 shell变量8.9 环境变量配置文件扩展bashrc和bash_profile的区别 http://ask.apelearn.com/question/7719 简易审计系统: http://www.68idc.cn/help/server/linux/2014042190951.html 关于PROMPT_COMMAND环境变量的含义 http://www.linuxnote.org/prompt_command

Linux编程 13 (系统环境变量位置, 环境变量持久化)

一.系统环境变量位置 在上章中,知道了如何修改系统环境变量,如PATH变量,以及创建自己的全局环境变量和局部环境变量.这篇学习怎么让环境变量的作用持久化.在此之前,先了解下系统环境变量文件会在哪些位置,当使用bash shell时,bash是如何查找环境变量位置的.下面先来介绍几个文件,这些文件叫启动文件或叫环境文件. bash检查的启动文件(环境文件)取决于你启动bash shell的方式.启动bash shell有3种方式: (1) 登录时的默认登录shell. (2) 交互式shell.

在配置环境变量时是该用系统环境变量还是用户环境变量?

环境变量分为系统环境变量和用户环境变量. 正常所说的环境变量是指系统环境变量,对所有用户起作用,而用户环境变量只对当前用户起作用,如果此电脑登入了另外个用户账号,那配置之前账号的用户环境变量就对另外个用户账号不起作用. 例如你要用java,那么你把java的bin目录加入到path变量下面,那么它就是系统环境变量,所用用户登录,在命令行(cmd)输入java都会有java的帮助信息出来.而如果你在某个用户的环境变量下面新建一个变量,那么它就只对这个用户有用,当你以其他用户登录时这个变量就和不存在

Java基础(极客)——07、Java常用技巧-Java配制环境变量与常用技巧(大多都是概述,可以看视频)

1本课概要 2课程概述 3计算机语言概述 4Java入门 5JDK介绍(有用) 6设置环境变量(有用) 7编写第一个Java程序 8Java的程序结构 9Eclipse开发工具概述 10下载Eclipse(有用) 11Eclipse开发环境介绍(有用) 12创建Java项目 13给main方法的args参数赋值(有用) 14加运算 15Java的项目结构 16项目的导出 17项目的导入 18修改项目名.包名和类名 19Math类(有用) 20Java程序的书写规范 21常见错误 22常用技巧(有

gcc 添加include环境变量和lib环境变量(转载)

对所有用户有效在/etc/profile增加以下内容.只对当前用户有效在Home目录下的.bashrc或.bash_profile里增加下面的内容:(注意:等号前面不要加空格,否则可能出现 command not found) #在PATH中找到可执行文件程序的路径.export PATH =$PATH:$HOME/bin #gcc找到头文件的路径C_INCLUDE_PATH=/usr/include/libxml2:/MyLibexport C_INCLUDE_PATH #g++找到头文件的路