CMake第五课--总结

CMake第五课  总结

  手把手教你学CMake,最后一节我们将前面学到的知识点综合应用。如果编译软件使用了外部库,事先并不知道它的头文件和链接库的位置,得在编译命令中加上包含它们的查找路径。CMake使用FIND_PACKAGE()命令来解决这个问题,FIND_PACKAGE() 命令会在模块路径中寻找 Find<name>.cmake 。首先CMake查看${CMAKE_MODULE_PATH} 中的所有目录,然后再查看它自己的模块目录。

  我们这一节有两个大模块,第一个是先介绍一下 cmake 提供的 FindCURL 模块的使用;第二个就是基于我们前面学的 libhello 共享库,编写一个 FindHello.cmake 模块。

===================================================================================

目标:

1.首先介绍一下 cmake 提供的 FindCURL 模块的使用。

2.基于我们前面的 libhello 共享库,编写一个 FindHello.cmake 模块。

==================================================================================== 

一.使用 FindCURL 模块

绝对路径:/home/guo/cmake_practice/5(工程目录)    标红的那部分改成自己的用户名

目录结构(按照下面结构添加文件夹和文件)

1.一个CMakeLists.txt文件(/home/guo/cmake_practice/5

CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )  # 声明要求的 cmake 最低版本
PROJECT(CURLTEST) # 声明一个 cmake 工程
ADD_SUBDIRECTORY(src)

2.一个src文件夹(/home/guo/cmake_practice/5/src),里面包含CMakeLists.txt和main.c

src/main.c内容:

//这段main.c代码的作用是通过curl取回 www.linux-ren.org 的首页并写入/home/guo/cmake_practice/5/test文件中
#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 = "/home/guo/cmake_practice/5/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); }

src/CMakeLists.txt内容:

CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) # 声明要求的 cmake 最低版本
ADD_EXECUTABLE(curltest main.c)
#INCLUDE_DIRECTORIES(/usr/include)
#TARGET_LINK_LIBRARIES(curltest curl)
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)

外部编译:

cd /home/guo/cmake_practice/5

mkdir build    (新建build文件夹)

cd build

cmake ..

make

执行二进制可执行文件

cd   /home/guo/cmake_practice/5/build/src

./curltest

执行完程序后,可以在 /home/guo/cmake_practice/5下看到有一个test文件 

-------------------------------------------------------------------------------

详细解释:

1.添加 curl 的头文件路径和库文件的两种方法。

方法一:直接通过 INCLUDE_DIRECTORIES 和 TARGET_LINK_LIBRARIES 指令添加

我们可以直接在 src/CMakeLists.txt 中添加:

INCLUDE_DIRECTORIES(/usr/include)
TARGET_LINK_LIBRARIES(curltest curl)

然后建立 build 目录进行外部构建即可。

方法二:使用 FindCURL 模块( 即: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)

2.对于系统预定义的 Find<name>.cmake 模块,使用方法一般如上例所示:

只要找到包,都会定义以下几个变量:

  • <name>_FOUND
  • <name>_INCLUDE_DIR or <name>_INCLUDES
  • <name>_LIBRARY          or <name>_LIBRARIES
  • <name>_DEFINITIONS

你可以通过<name>_FOUND 来判断模块是否被找到,如果没有找到,按照工程的需要关闭某些特性、给出提醒或者中止编译,上面的例子就是报出致命错误并终止构建。如果<name>_FOUND 为真,则  将<name>_INCLUDE_DIR 加入 INCLUDE_DIRECTORIES;   将<name>_LIBRARY 加入TARGET_LINK_LIBRARIES 中。

3.想知道更多关于FOUND_PACKAGE的内容可以参考这篇博客:https://blog.csdn.net/xs1102/article/details/78241291

==================================================================================== 

二.编写属于自己的 FindHello 模块

第一步,构建动态库、静态库并进行安装

绝对路径:/home/guo/cmake_practice/6(工程目录)

目录结构:

1.工程目录下(/home/guo/cmake_practice/6CMakeLists.txt  内容如下:

PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(lib)

2.一个lib文件夹(/home/guo/cmake_practice/6/lib)  建立两个源文件 hello.cpp 与 hello.h  和 一个CMakeLists.txt

lib/hello.h内容:

#ifndef HELLO_H         //防止别的头文件可能重复包含hello.h文件,防止重定义错误
#define HELLO_H
#include <iostream>
using namespace std;
int HelloFunc();
#endif

lib/hello.cpp内容:

#include "hello.h"
int HelloFunc()
{
    cout<<"Hello World!"<<endl;
    return 0;
}

lib/CMakeLists.txt内容:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)# 声明要求的 cmake 最低版本
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}
/lib)
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC}) SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME
"hello") SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1) SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1) INSTALL(TARGETS hello hello_static LIBRARY DESTINATION hello/lib ARCHIVE DESTINATION hello/lib) INSTALL(FILES hello.h DESTINATION hello/include)

外部编译:

cd  /home/guo/cmake_practice/6

mkdir  build    (新建build文件夹)

cd  build

cmake   -DCMAKE_INSTALL_PREFIX=/home/guo/cmake_practice/6   ..

make

sudo make install

我们就可以将头文件和共享库安装到<prefix>/hello/include 和<prefix>/hello/lib中了,即/home/guo/cmake_practice/6/hello/include和

/home/guo/cmake_practice/6/hello/lib。(<prefix>在这里就是指/home/guo/cmake_practice/6)

-------------------------------------------------------------------------------

第二步,构建工程调用刚才自己构建的模块

绝对路径:/home/guo/cmake_practice/7(工程目录)

目录结构:

1.工程目录下(/home/guo/cmake_practice/7CMakeLists.txt内容如下:

CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )   # 声明要求的cmake最低版本
PROJECT(HELLOTEST)                      # 声明一个 cmake 工程
SET(CMAKE_MODULE_PATH   ${PROJECT_SOURCE_DIR}/cmake) #为了让cmake能找到FindHello模块,设置路径
ADD_SUBDIRECTORY(src)

2.一个src文件夹 (/home/guo/cmake_practice/7/src) 建立源文件 main.cpp  和 一个CMakeLists.txt

src/main.cpp内容为:

#include <hello.h>
int main()
{
    HelloFunc();
    return 0;
}

src/CMakeLists.txt内容为:

FIND_PACKAGE(HELLO)
IF(HELLO_FOUND)
    LINK_DIRECTORIES(${HELLO_LIBRARY})
    INCLUDE_DIRECTORIES(${HELLO_INCLUDE_DIR})
    ADD_EXECUTABLE(hello main.cpp)
    TARGET_LINK_LIBRARIES(hello ${HELLO_LIBRARY})
ENDIF(HELLO_FOUND)

3.一个cmake文件夹 ,编写FindHELLO.cmake文件 (FindXXXX.cmake)

cmake/FindHELLO.cmake文件内容:

FIND_PATH(HELLO_INCLUDE_DIR hello.h  /home/guo/cmake_practice/6/hello/include )
FIND_LIBRARY(HELLO_LIBRARY NAMES hello PATHS /home/guo/cmake_practice/6/hello/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)

外部编译:

cd /home/guo/cmake_practice/7

mkdir build    (新建build文件夹)

cd build

cmake ..

make

执行二进制可执行文件

cd   /home/guo/cmake_practice/7/build/

./src/hello

===============================================================================

详细解释:

1.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 指令中使用。

2.为了能够让工程找到 FindHELLO.cmake 模块(存放在工程中的 cmake 目录),我们在主工程文件 CMakeLists.txt 中加入:

SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)

3.安装的头文件和库所在的路径,注意“名字的大小写”和“PATHS的‘S’别漏掉”

FIND_PATH(HELLO_INCLUDE_DIR   hello.h   /home/guo/cmake_practice/6/hello/include )
FIND_LIBRARY(HELLO_LIBRARY   NAMES  hello  PATHS  /home/guo/cmake_practice/6/hello/lib )

 4.在编写FindHELLO需要注意的问题!!!!!重要问题!!!!!

要保证src/CMakeLists.txt下的:

                    • FIND_PACKAGE(name)
                    • name_FOUND
                    • name_INCLUDE_DIR or name_INCLUDES
                    • name_LIBRARY          or name_LIBRARIES
                    • name_DEFINITIONS

cmake下的:

                    • Findname.cmake文件名  

这几个name一定要一致!!!!

并且确保程序引用的头文件和库一定要包含在name_INCLUDE_DIRname_LIBRARY所指示的路径里。  

 

posted @ 2018-09-07 15:15  小果子啊  阅读(563)  评论(0)    收藏  举报