2019-09-23-c-cmake-依赖库

我想念泉州的夏天了

CMake

接着上一篇,这篇介绍依赖库,在介绍依赖库之前,先看看如何添加源代码子目录。

添加源代码子目录

当前所在位置

test04# pwd
/tmp/c/2019-09-12-cmaketest/test04

当前目录中的文件/文件夹,我们新建了一个src目录并将helloworld.cpp放在其中

test04# tree
.
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── helloworld.cpp

test04/build是用来存放中间文件的空文件夹,test04/CMakeLists.txt是项目的配置文件,test04/src/CMakeLists.txt是src文件夹的配置文件,test04/src/helloworld.cpp则还是那个只打印一句helloworld的程序。

test04/CMakeLists.txt的内容

test04# vi CMakeLists.txt 
# CMAKE最低版本需求
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
# 项目名称
PROJECT (HELLOWORLD)
# 打印二进制目录和源代码目录
MESSAGE (STATUS "this is BINARY dir " ${HELLOWORLD_BINARY_DIR})
MESSAGE (STATUS "this is SOURCE dir " ${HELLOWORLD_SOURCE_DIR})
# 注释掉生成可执行程序的这一句
# ADD_EXECUTABLE (helloworld helloworld.cpp)
# 添加子目录
ADD_SUBDIRECTORY (src)

test04/src/CMakeLists.txt的内容

test04# vi src/CMakeLists.txt 
# 生成可执行程序
ADD_EXECUTABLE (helloworld helloworld.cpp)
# 设置可执行程序输出路径
SET (EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

test04/src/helloworld.cpp中的内容

test04# cat src/helloworld.cpp 
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * args[]) {
  printf("hello world\n");
}

进入到build目录进行编译

test04# cd build

test04/build# cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - 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
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- this is BINARY dir /tmp/c/2019-09-12-cmaketest/test04/build
-- this is SOURCE dir /tmp/c/2019-09-12-cmaketest/test04
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/c/2019-09-12-cmaketest/test04/build

build# make
Scanning dependencies of target helloworld
[ 50%] Building CXX object src/CMakeFiles/helloworld.dir/helloworld.cpp.o
[100%] Linking CXX executable ../bin/helloworld
[100%] Built target helloworld

运行可执行程序,注意当前可执行程序路径为test04/build/bin/helloworld

test04/build# ./bin/helloworld 
hello world

看看当前的目录结构,helloworld的所在位置

test04/build# cd ..

test04# tree -F -L 3 -I CMakeFiles
.
├── build/
│   ├── bin/
│   │   └── helloworld*
│   ├── CMakeCache.txt
│   ├── cmake_install.cmake
│   ├── Makefile
│   └── src/
│       ├── CMakeFiles/
│       ├── cmake_install.cmake
│       └── Makefile
├── CMakeLists.txt
└── src/
    ├── CMakeLists.txt
    └── helloworld.cpp

test04/CMakeLists.txt解析

test04# vi CMakeLists.txt 
# CMAKE最低版本需求
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
# 项目名称
PROJECT (HELLOWORLD)
# 打印二进制目录和源代码目录
MESSAGE (STATUS "this is BINARY dir " ${HELLOWORLD_BINARY_DIR})
MESSAGE (STATUS "this is SOURCE dir " ${HELLOWORLD_SOURCE_DIR})
# 注释掉生成可执行程序的这一句
# ADD_EXECUTABLE (helloworld helloworld.cpp)
# 添加子目录
ADD_SUBDIRECTORY (src)

在这个配置文件中,将ADD_EXECUTABLE注释掉了,因为当前test04目录下是没有hellworld.cpp文件的,这个文件已经移动到test04/src目录中了。

add_subdirectory 添加存放源文件的子目录

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL]) 

这个指令用于

  • source_dir 向当前工程添加存放源文件的子目录,
  • binary_dir 并可以指定中间二进制和目标二进制存放的位置。
  • EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除,比如,工程的 example,可能就需要工程构建完成后,再进入 example 目录单独进行构建(当然,你也可以通过定义依赖来解决此类问题)。
ADD_SUBDIRECTORY (src bin)

上面的例子定义了将 src 子目录加入工程,并指定编译输出(包含编译中间结果)路径为 bin 目录。如果不进行 bin 目录的指定,那么编译结果(包括中间结果)都将存放在 src 目录下,指定 bin 目录后,相当于在编译时 将 src 重命名为 bin,所有的中间结果和目标二进制都将存放在 bin 目录。

此例使用到了ADD_SUBDIRECTORY (src)表示将向当前工程添加src目录作为存放源文件的子目录

至于为什么cmake要使用这种每个源文件的目录都需要放一个CMakeLists.txt文件,而不是如maven一样,只需要一个pom.xml文件,暂未深究。是不是因为C/C++项目中的东西太杂了,不好弄?。。。

test04/src/CMakeLists.txt解析

test04# vi src/CMakeLists.txt 
# 生成可执行程序
ADD_EXECUTABLE (helloworld helloworld.cpp)
# 设置可执行程序输出路径
SET (EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

由于helloworld.cpp在该目录下,所以理所当然是这个配置文件指定可执行程序ADD_EXECUTABLE (helloworld helloworld.cpp)

接着有两个新东西,SET 和 EXECUTABLE_OUTPUT_PATH

set 设置变量

SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

SET 指令可以用来显式的定义变量。

EXECUTABLE_OUTPUT_PATH 可执行程序的输出路径

这个用来指定可执行文件的输出目录,这个例子指定在编译目录的bin目录下

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

所以最后生成的可执行程序helloworld的路径为test04/build/bin/helloworld

test04# ll build/bin/helloworld 
-rwxr-xr-x 1 root root 8.5K Oct 27 14:56 build/bin/helloworld*

创建依赖库

接着来看看在CMake中使用依赖库的例子。

当前目录

test05# pwd
/tmp/c/2019-09-12-cmaketest/test05

当前目录下的文件/文件夹。我们将helloworld.cpp放到了test05/src/main中,又新建了一个test05/src/math作为一个库。

test05# tree -F
.
├── build/
├── CMakeLists.txt
└── src/
    ├── CMakeLists.txt
    ├── main/
    │   ├── CMakeLists.txt
    │   └── helloworld.cpp
    └── math/
        ├── CMakeLists.txt
        ├── math.cpp
        └── math.h

4 directories, 7 files

接着来看看各个文件的内容

test05/CMakeLists.txt的内容

test05# cat CMakeLists.txt 
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
PROJECT (HELLOWORLD)
MESSAGE (STATUS "this is BINARY dir " ${HELLOWORLD_BINARY_DIR})
MESSAGE (STATUS "this is SOURCE dir " ${HELLOWORLD_SOURCE_DIR})
ADD_SUBDIRECTORY (src)

test05/src/CMakeLists.txt的内容,其中就是添加了两个子目录

test05# cat src/CMakeLists.txt 
ADD_SUBDIRECTORY (main)
ADD_SUBDIRECTORY (math)

test05/src/main/CMakeLists.txt的内容,指定生成可执行程序,设置了可执行程序存放的目录,还有设置链接库。

test05# cat src/main/CMakeLists.txt 
ADD_EXECUTABLE (helloworld helloworld.cpp)
SET (EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 链接库,可执行程序helloworld需要库math
TARGET_LINK_LIBRARIES (helloworld math)

test05/src/main/helloworld.cpp的内容,做了修改,使用了math库,注意其中引用math.h的方式是使用相对路径的–#include "../math/math.h"

test05# cat src/main/helloworld.cpp 
#include <stdio.h>
#include <stdlib.h>
#include "../math/math.h"

int main(int argc, char * args[]) {
  printf("hello world\n");
  int n1 = 5;
  int n2 = 10;
  int nRet = add(5, 10);
  printf("%d + %d = %d\n", n1, n2, nRet);
}

test05/src/math/CMakeLists.txt的内容,添加了一个库,并指定生成这个库的路径。

test05# cat src/math/CMakeLists.txt 
# 指定生成库
ADD_LIBRARY (math math.cpp)
# 指定生成库的存放路径
SET (LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

test05/src/math/math.h的内容,这个库比较简单,就定义了一个方法add。

test05# cat src/math/math.h 
#ifndef MATH_H__20191027
#define MATH_H__20191027

#include <stdio.h>
#include <stdlib.h>

int add(int n1, int n2);

#endif // MATH_H__20191027

test05/src/math/math.h的内容。

test05# cat src/math/math.cpp 
#include "math.h"

int add(int n1, int n2) {
  return n1 + n2;
}

编译

test05# cd build/

test05/build# cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - 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
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- this is BINARY dir /tmp/c/2019-09-12-cmaketest/test05/build
-- this is SOURCE dir /tmp/c/2019-09-12-cmaketest/test05
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/c/2019-09-12-cmaketest/test05/build

test05/build# make
Scanning dependencies of target math
[ 25%] Building CXX object src/math/CMakeFiles/math.dir/math.cpp.o
[ 50%] Linking CXX static library ../../lib/libmath.a
[ 50%] Built target math
Scanning dependencies of target helloworld
[ 75%] Building CXX object src/main/CMakeFiles/helloworld.dir/helloworld.cpp.o
[100%] Linking CXX executable ../../bin/helloworld
[100%] Built target helloworld

运行

test05/build# ./bin/helloworld 
hello world
5 + 10 = 15

编译后的目录情况,由于CMakeFiles目录中的东西过多,所以此处将其隐去。

test05# tree -F -L 3 -I CMakeFiles
.
├── build/
│   ├── bin/
│   │   └── helloworld*
│   ├── CMakeCache.txt
│   ├── cmake_install.cmake
│   ├── lib/
│   │   └── libmath.a
│   ├── Makefile
│   └── src/
│       ├── cmake_install.cmake
│       ├── main/
│       ├── Makefile
│       └── math/
├── CMakeLists.txt
└── src/
    ├── CMakeLists.txt
    ├── main/
    │   ├── CMakeLists.txt
    │   └── helloworld.cpp
    └── math/
        ├── CMakeLists.txt
        ├── math.cpp
        └── math.h

9 directories, 14 files

注意其中libmath.a库文件的路径为test05/build/lib/libmath.a。同时生成的是静态库说明cmake默认是生成静态库的。

test05/src/math/CMakeLists.txt解析

test05# cat src/math/CMakeLists.txt 
ADD_LIBRARY (math math.cpp)
SET (LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

add_library 添加库

ADD_LIBRARY(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
  • libname:你不需要写全 libhello.so,只需要填写 hello 即可,cmake 系统会自动为你生成 libhello.X
  • 生成的库类型,有三种:
    • SHARED,动态库
    • STATIC,静态库
    • MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。
ADD_LIBRARY(common math.cpp) # 默认生成静态库
ADD_LIBRARY(common STATIC math.cpp) # 生成静态库
ADD_LIBRARY(common SHARED math.cpp) # 生成动态库

上面配置对应分别生成:

libmath.a
libmath.a
libmath.so
  • EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建。
  • source1 source2 … sourceN 源文件列表

配置文件中的ADD_LIBRARY (math math.cpp)代表根据math.cpp源文件生成名为libmath.a的静态库

LIBRARY_OUTPUT_PATH 设置库存放路径

和EXECUTABLE_OUTPUT_PATH类似的,LIBRARY_OUTPUT_PATH指定了库输出的目录

这里指定编译目录下的lib作为库输出的目录

SET (LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

所以可以看到math库的路径为test05/build/lib/libmath.a

test05# ll build/lib/libmath.a 
-rw-r--r-- 1 root root 1.4K Oct 27 16:13 build/lib/libmath.a

test05/src/main/CMakeLists.txt解析

使用了TARGET_LINK_LIBRARIES用于指示链接库math。可以指定全名用于链接动态库或者静态库,如果libmath.a则链接静态库,libmath.so则链接动态库

test05# cat src/main/CMakeLists.txt 
ADD_EXECUTABLE (helloworld helloworld.cpp)
SET (EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
TARGET_LINK_LIBRARIES (helloworld math)
TARGET_LINK_LIBRARIES(target library1 <debug | optimized> library2 ...)

这个指令可以用来为 target 添加需要链接的共享库,本例中是一个可执行文件,但是同样可以用于为自己编写的共享库添加共享库链接。

TARGET_LINK_LIBRARIES(helloworld math)

也可以写成

TARGET_LINK_LIBRARIES(helloworld libmath.a)

同时生成静态依赖库和动态依赖库

从上面知道默认生成的是静态库,但有时候我们希望同时生成静态库和动态库,可以如下操作。

当前路径

test06# pwd
/tmp/c/2019-09-12-cmaketest/test06

当前目录情况

test06# tree -F
.
├── build/
├── CMakeLists.txt
└── src/
    ├── main/
    │   ├── CMakeLists.txt
    │   └── helloworld.cpp
    └── math/
        ├── CMakeLists.txt
        ├── math.cpp
        └── math.h

4 directories, 6 files

上面内容都是test05的拷贝,这次只修改test06/src/math/CMakeLists.txt文件

test06# vi src/math/CMakeLists.txt 
ADD_LIBRARY (math_static STATIC math.cpp)
ADD_LIBRARY (math SHARED math.cpp)
# 设置静态库别名
SET_TARGET_PROPERTIES (math_static PROPERTIES OUTPUT_NAME "math")
GET_TARGET_PROPERTY (OUTPUT_VALUE math_static OUTPUT_NAME)

MESSAGE (STATUS "this is math_static OUTPUT_NAME:" ${OUTPUT_VALUE})
# 设置生成库目录
SET (LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

编译

test06# cd build/

test06/build# cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - 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
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- this is BINARY dir /tmp/c/2019-09-12-cmaketest/test06/build
-- this is SOURCE dir /tmp/c/2019-09-12-cmaketest/test06
-- this is math_static OUTPUT_NAME:math
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/c/2019-09-12-cmaketest/test06/build

test06/build# make
Scanning dependencies of target math
[ 16%] Building CXX object src/math/CMakeFiles/math.dir/math.cpp.o
[ 33%] Linking CXX shared library ../../lib/libmath.so
[ 33%] Built target math
Scanning dependencies of target helloworld
[ 50%] Building CXX object src/main/CMakeFiles/helloworld.dir/helloworld.cpp.o
[ 66%] Linking CXX executable ../../bin/helloworld
[ 66%] Built target helloworld
Scanning dependencies of target math_static
[ 83%] Building CXX object src/math/CMakeFiles/math_static.dir/math.cpp.o
[100%] Linking CXX static library ../../lib/libmath.a
[100%] Built target math_static

运行

test06/build# ./bin/helloworld 
hello world
5 + 10 = 15

查看目录,可以看到test06/build/lib下生成了libmath.a(静态库)和libmath.so(动态库)。

test06/build# cd ..

test06# tree -F -L 3 -I CMakeFiles
.
├── build/
│   ├── bin/
│   │   └── helloworld*
│   ├── CMakeCache.txt
│   ├── cmake_install.cmake
│   ├── lib/
│   │   ├── libmath.a
│   │   └── libmath.so*
│   ├── Makefile
│   └── src/
│       ├── cmake_install.cmake
│       ├── main/
│       ├── Makefile
│       └── math/
├── CMakeLists.txt
└── src/
    ├── CMakeLists.txt
    ├── main/
    │   ├── CMakeLists.txt
    │   └── helloworld.cpp
    └── math/
        ├── CMakeLists.txt
        ├── math.cpp
        └── math.h

9 directories, 15 files

test06/src/math/CMakeLists.txt解析

来看看test06/src/math/CMakeLists.txt配置文件

test06# vi src/math/CMakeLists.txt 
ADD_LIBRARY (math_static STATIC math.cpp)
ADD_LIBRARY (math SHARED math.cpp)
# 设置静态库别名
SET_TARGET_PROPERTIES (math_static PROPERTIES OUTPUT_NAME "math")
GET_TARGET_PROPERTY (OUTPUT_VALUE math_static OUTPUT_NAME)

MESSAGE (STATUS "this is math_static OUTPUT_NAME:" ${OUTPUT_VALUE})
# 设置生成库目录
SET (LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)             

注意这里如果使用如下的语法,那么只会生成动态库,因为如果静态库取名math,那么为静态库根本没有被构建,仍然只生成一个动态库。因为 math 作为一个 target 是不能重名的,导致静态库构建指令无效。

ADD_LIBRARY (math STATIC math.cpp)
ADD_LIBRARY (math SHARED math.cpp)

所以此处将静态库使用的名称为math_static

ADD_LIBRARY (math_static STATIC math.cpp)
ADD_LIBRARY (math SHARED math.cpp)

但是我们又想要静态库和动态库出来之后的样子是:libmath.a和libmath.so,而不是libmath_static.a和libmath.so。所以此处用到了SET_TARGET_PROPERTIES和GET_TARGET_PROPERTY

set_target_properties 设置目标属性

SET_TARGET_PROPERTIES(target1 target2 ... PROPERTIES prop1 value1 prop2 value2 ...)

这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本。

在本例中,我们需要做的是向 t06/src/CMakeLists.txt 中添加一条:

SET_TARGET_PROPERTIES (math_static PROPERTIES OUTPUT_NAME "math")

这样,我们就可以同时得到libmath.a和libmath.so两个库了。 与该命令对应的指令是:

get_target_property 获取目标属性

GET_TARGET_PROPERTY(VAR target property) 

具体用法如

SET_TARGET_PROPERTIES (math_static PROPERTIES OUTPUT_NAME "math")
GET_TARGET_PROPERTY (OUTPUT_VALUE math_static OUTPUT_NAME)

MESSAGE (STATUS "this is math_static OUTPUT_NAME:" ${OUTPUT_VALUE})

界面就会输出

-- this is math_static OUTPUT_NAME:math

设置动态库版本

前面知道SET_TARGET_PROPERTIES还可以指定动态库版本,偷懒一下,直接修改上个例子,添加SET_TARGET_PROPERTIES(math PROPERTIES VERSION 1.2 SOVERSION 1)这么一句,其中 VERSION 指代动态库版本,SOVERSION 指代 API 版本。

test06# vi src/math/CMakeLists.txt 
DD_LIBRARY (math math.cpp)
ADD_LIBRARY (math_static STATIC math.cpp)
ADD_LIBRARY (math SHARED math.cpp)
# 添加动态库版本
SET_TARGET_PROPERTIES(math PROPERTIES VERSION 1.2 SOVERSION 1)

SET_TARGET_PROPERTIES (math_static PROPERTIES OUTPUT_NAME "math")
GET_TARGET_PROPERTY (OUTPUT_VALUE math_static OUTPUT_NAME)

MESSAGE (STATUS "this is math_static OUTPUT_NAME:" ${OUTPUT_VALUE})

SET (LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

最后编译生成如下,可以看到lib中的动态库已经变成带版本的了。

test06/build# tree -F -L 3 -I CMakeFiles
.
├── bin/
│   └── helloworld*
├── CMakeCache.txt
├── cmake_install.cmake
├── lib/
│   ├── libmath.a
│   ├── libmath.so -> libmath.so.1*
│   ├── libmath.so.1 -> libmath.so.1.2*
│   └── libmath.so.1.2*
├── Makefile
└── src/
    ├── cmake_install.cmake
    ├── main/
    │   ├── cmake_install.cmake
    │   └── Makefile
    ├── Makefile
    └── math/
        ├── cmake_install.cmake
        └── Makefile

5 directories, 14 files

添加外部依赖库

前面的例子使用是项目内的依赖库。现在将helloworld程序中的math库移到外部。因为install下一次才讲,所以此处就直接将math库的头文件和动态库静态库直接拷到middleware目录下。

middleware所在路径

middleware# pwd
/tmp/c/2019-09-12-cmaketest/middleware

middleware中内容

middleware# tree
.
├── include
│   └── math
│       └── math.h
└── lib
    ├── libmath.a
    ├── libmath.so
    ├── libmath.so.1
    └── libmath.so.1.2

当前目录,相对于上一个例子test06,已将math模块移除,并且做了一些修改

test07# pwd
/tmp/c/2019-09-12-cmaketest/test07
test07# tree
.
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── main
        ├── CMakeLists.txt
        └── helloworld.cpp

3 directories, 4 files

test07/CMakeLists.txt的内容,添加了INCLUDE_DIRECTORIES和LINK_DIRECTORIES,分别指向头文件和库文件所在的目录

test07# vi CMakeLists.txt 
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
PROJECT (HELLOWORLD)
MESSAGE (STATUS "this is BINARY dir " ${HELLOWORLD_BINARY_DIR})
MESSAGE (STATUS "this is SOURCE dir " ${HELLOWORLD_SOURCE_DIR})
# ADD_EXECUTABLE (helloworld helloworld.cpp)

# 包含头文件
INCLUDE_DIRECTORIES (/tmp/c/2019-09-12-cmaketest/middleware/include)
# 包含库文件
LINK_DIRECTORIES (/tmp/c/2019-09-12-cmaketest/middleware/lib)

ADD_SUBDIRECTORY (src)

test07/src/CMakeLists.txt的内容,现在只有main一个子目录了

test07# vi src/CMakeLists.txt 
ADD_SUBDIRECTORY (main)

test07/src/main/CMakeLists.txt的内容没有改变

test07# vi src/main/CMakeLists.txt 
ADD_EXECUTABLE (helloworld helloworld.cpp)
SET (EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
TARGET_LINK_LIBRARIES (helloworld math)

test07/src/main/helloworld.cpp的内容,注意将引入头文件math.h的方式由 #include "../math/math.h" 改为 #include "math/math.h"

test07# vi src/main/helloworld.cpp 
#include <stdio.h>
#include <stdlib.h>
#include "math/math.h"

int main(int argc, char * args[]) {
  printf("hello world\n");
  int n1 = 5;
  int n2 = 10;
  int nRet = add(5, 10);
  printf("%d + %d = %d\n", n1, n2, nRet);
}

编译

test07# cd build/

test07/build# cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - 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
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- this is BINARY dir /tmp/c/2019-09-12-cmaketest/test07/build
-- this is SOURCE dir /tmp/c/2019-09-12-cmaketest/test07
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/c/2019-09-12-cmaketest/test07/build

build# make
Scanning dependencies of target helloworld
[ 50%] Building CXX object src/main/CMakeFiles/helloworld.dir/helloworld.cpp.o
[100%] Linking CXX executable ../../bin/helloworld
[100%] Built target helloworld

运行

build# ./bin/helloworld 
hello world
5 + 10 = 15

test07/CMakeLists.txt解析

test07# vi CMakeLists.txt 
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
PROJECT (HELLOWORLD)
MESSAGE (STATUS "this is BINARY dir " ${HELLOWORLD_BINARY_DIR})
MESSAGE (STATUS "this is SOURCE dir " ${HELLOWORLD_SOURCE_DIR})
# ADD_EXECUTABLE (helloworld helloworld.cpp)

# 包含头文件
INCLUDE_DIRECTORIES (/tmp/c/2019-09-12-cmaketest/middleware/include)
# 包含库文件
LINK_DIRECTORIES (/tmp/c/2019-09-12-cmaketest/middleware/lib)

ADD_SUBDIRECTORY (src)

该文件添加了INCLUDE_DIRECTORIES和LINK_DIRECTORIES指令。我们也可以将这两个命令写在test07/src/main/CMakeLists.txt中,但是这种一般是写在项目根目录中的CMakeLists.txt中

include_directories 包含头文件目录

用来指定需要的头文件路径

INCLUDE_DIRECTORIES (/tmp/c/2019-09-12-cmaketest/middleware/include)

此处指定了包含的目录为/tmp/c/2019-09-12-cmaketest/middleware/include,但是math.h的路径是/tmp/c/2019-09-12-cmaketest/middleware/include/math/math.h,所以在helloworld.cpp中使用如下方式来引用。

#include "math/math.h"

我们也可以直接指定/tmp/c/2019-09-12-cmaketest/middleware/include/math,这样就直接如下引用即可

#include "math.h"

但因为我们到时候可能使用的不止一个库,可能是多个在middleware下的库,所以该路径到include即可。

用来指定第三方库所在的路径,可以理解为gcc中的-L

注意,加载库的顺序是从右到左。如下,会先加载b库,再加载a库,所以要确保b不依赖a。

xxx -la -lb

参考