cmake_practice - yuhannah/skills_map GitHub Wiki
资料:
环境:
- ubuntu 16.04
- CLion 2018.2.6
- cmake version 3.5.1
- 描述使用CMake构建Hello World程序的全过程,内部编译
- 介绍
PROJECT/MESSAGE/ADD_EXECUTABLE
指令 - 介绍变量调用方法,以及两个隐式变量
<projectname>_SOURCE_DIR
和<projectname>_BINARY_DIR
的调用方法
-
建立一个 cmake 目录(自定义目录),用来放置所有的练习
mkdir -p /backup/cmake
-
在 cmake 目录下建立第一个练习目录 t1
cd /backup/cmake mkdir t1 cd t1
-
在 t1 目录建立
main.c
和CMakeLists.txt
(注意文件名大小写)// main.c #include <stdio.h> int main() { printf(“Hello World from t1 Main!\n”); return 0; }
# t1的CMakeLists.txt PROJECT (HELLO) SET(SRC_LIST main.c) MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR}) MESSAGE(STATUS "This is SOURCE dir "${HELLO_SOURCE_DIR}) #ADD_EXECUTABLE(hello SRC_LIST) # 例程中错误的地方 ADD_EXECUTABLE(hello ${SRC_LIST}) # 正确的写法
所有的文件创建完成后,t1 目录中应该存在 main.c
和 CMakeLists.txt
两个文件。在 t1 目录下运行以下命令:
cmake .
命令后面的点号,代表本目录。输出大概是这个样子:
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Check size of void*
-- Check size of void* - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- This is BINARY dir /backup/cmake/t1
-- This is SOURCE dir /backup/cmake/t1
-- Configuring done
-- Generating done
-- Build files have been written to: /backup/cmake/t1
再让我们看一下 t1 目录中的内容,系统自动生成了:CMakeFiles
,CMakeCache.txt
,cmake_install.cmake
等文件,并且生成了Makefile
。现在不需要理会这些文件的作用,最关键的是,它自动生成了Makefile
。
然后进行工程的实际构建,在 t1 目录输入make
命令,大概会得到如下的彩色输出:
Scanning dependencies of target hello
[100%] Building C object CMakeFiles/hello.dir/main.o
Linking C executable hello
[100%] Built target hello
如果你需要看到 make 构建的详细过程,可以使用make VERBOSE=1
或者VERBOSE=1 make
命令来进行构建。
目标文件hello
已经构建完成,位于当前目录 t1 ,尝试运行一下:
./hello
得到输出:
Hello World from t1 Main!
创建目录 cmakePractice ,新建main.cpp
和CMakeLists.txt
,如下所示:
- cmakePractie
- cmake-build-debug
- CMakeFiles
- cmake_install.cmake
- CMakeCache.txt
- CMakeLists.txt
- main.cpp
- Makefile
// main.cpp
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
CMakeLists.txt
的文件中的PROJECT()
名可以取与工程目录不同的名字,比如当前工程目录为 cmakePractice ,PROJECT()
名为HELLO
。
**ADD_EXECUTABLE()
生成的可执行文件名也可以是任意的,此处是hello
。**作为工程名的 HELLO
和生成的可执行文件 hello
是没有任何关系的。
cmake 系统帮助我们预定义了 PROJECT_BINARY_DIR
和 PROJECT_SOURCE_DIR
变量,他们的值分别跟 HELLO_BINARY_DIR
与 HELLO_SOURCE_DIR
一致。为了统一起见,建议以后直接使用 PROJECT_BINARY_DIR
,PROJECT_SOURCE_DIR
,即使修改了工程名称,也不会影响这两个变量。如果使用了<projectname>_SOURCE_DIR
,修改工程名称后,需要同时修改这些变量。
# cmakePractice的CMakeLists.txt
PROJECT(HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
MESSAGE(STATUS "This is PROJECT BINARY dir " ${PROJECT_BINARY_DIR})
MESSAGE(STATUS "This is PROJECT SOURCE dir " ${PROJECT_SOURCE_DIR})
ADD_EXECUTABLE(hello SRC_LIST) # 例程中错误的地方
执行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 /home/yu/CLionProjects/cmakePractice
-- This is SOURCE dir /home/yu/CLionProjects/cmakePractice
-- This is PROJECT BINARY dir /home/yu/CLionProjects/cmakePractice
-- This is PROJECT SOURCE dir /home/yu/CLionProjects/cmakePractice
-- Configuring done
CMake Error at CMakeLists.txt:7 (ADD_EXECUTABLE):
Cannot find source file:
SRC_LIST
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
CMake Error: CMake can not determine linker language for target: hello
CMake Error: Cannot determine link language for target "hello".
-- Generating done
-- Build files have been written to: /home/yu/CLionProjects/cmakePractice
出错原因:
The
IF(var)
orIF(NOT var)
command expectsvar
to be the name of a variable. This is stated in CMake's manual. So, for your situationIF(${libX})
is the same asIF(/usr/lib/xorg)
and then CMake will check the value of the variable named/usr/lib/xorg
.也就是说 IF 需要的是变量名而不是变量值
${}代表变量值,路径
--- from cmake's maillist
在本例我们使用了${}
来引用变量,这是 cmake 的变量应用方式。但是,在 IF 控制语句中,变量是直接使用变量名引用,而不需要${}
。如果使用了${}
,其实 IF 会去判断名为${}
所代表的值的变量,那当然是不存在的了。
如果需要清空以往的编译记录,重新开始编译,则删除工程目录 cmakePractice 下的 CMakeFiles 目录、cmake_install.cmake
、CMakeCache.txt
和Makefile
文件。
修改 cmakePractice 目录的CMakeLists.txt
文件ADD_EXECUTABLE(hello ${SRC_LIST})
后,重新执行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 /home/yu/CLionProjects/cmakePractice # MESSAGE的输出
-- This is SOURCE dir /home/yu/CLionProjects/cmakePractice # MESSAGE的输出
-- This is PROJECT BINARY dir /home/yu/CLionProjects/cmakePractice# MESSAGE的输出
-- This is PROJECT SOURCE dir /home/yu/CLionProjects/cmakePractice# MESSAGE的输出
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yu/CLionProjects/cmakePractice
执行make
命令后的结果:
Scanning dependencies of target hello
[ 50%] Building CXX object CMakeFiles/hello.dir/main.cpp.o
[100%] Linking CXX executable hello
[100%] Built target hello
执行make VERBOSE=1
命令的结果:
/usr/bin/cmake -H/home/yu/CLionProjects/cmakePractice -B/home/yu/CLionProjects/cmakePractice --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/yu/CLionProjects/cmakePractice/CMakeFiles /home/yu/CLionProjects/cmakePractice/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/yu/CLionProjects/cmakePractice'
make -f CMakeFiles/hello.dir/build.make CMakeFiles/hello.dir/depend
make[2]: Entering directory '/home/yu/CLionProjects/cmakePractice'
cd /home/yu/CLionProjects/cmakePractice && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/yu/CLionProjects/cmakePractice /home/yu/CLionProjects/cmakePractice /home/yu/CLionProjects/cmakePractice /home/yu/CLionProjects/cmakePractice /home/yu/CLionProjects/cmakePractice/CMakeFiles/hello.dir/DependInfo.cmake --color=
make[2]: Leaving directory '/home/yu/CLionProjects/cmakePractice'
make -f CMakeFiles/hello.dir/build.make CMakeFiles/hello.dir/build
make[2]: Entering directory '/home/yu/CLionProjects/cmakePractice'
make[2]: Nothing to be done for 'CMakeFiles/hello.dir/build'.
make[2]: Leaving directory '/home/yu/CLionProjects/cmakePractice'
[100%] Built target hello
make[1]: Leaving directory '/home/yu/CLionProjects/cmakePractice'
/usr/bin/cmake -E cmake_progress_start /home/yu/CLionProjects/cmakePractice/CMakeFiles 0
运行可执行文件hello
的结果:
./hello
Hello, World!
内部编译上面已经演示过了,它生成了一些无法自动删除的中间文件。外部编译的过程如下:
- 首先清除 t1 目录中除
main.c
,CMakeLists.txt
之外的所有中间文件,最关键的CMakeCache.txt
。 - 在 t1 目录中建立 build 目录,当然你也可以在任何地方建立 build 目录,不一定必须在工程目录中。
- 进入 build 目录,运行
cmake ..
(注意,..
代表父目录,因为父目录 t1 存在我们需要的CMakeLists.txt
,如果在其他地方建立了 build 目录,需要运行cmake <工程的全路径>)
,查看一下 build 目录,就会发现了生成了编译需要的Makefile
以及其他的中间文件。 - 运行
make
构建工程,就会在当前目录( build 目录)中获得目标文件hello
。
上述过程就是所谓的 out-of-source 外部编译,一个最大的好处是,对于原有的工程没有任何影响,所有动作全部发生在编译目录。通过这一点,也足以说服我们全部采用外部编译方式构建工程。
# 在cmakePractice目录下
mkdir build
cd build
# 在build目录下
cmake ..
外部编译的结果:
- cmakePractie
- build
- CMakeFiles
- cmake_install.cmake
- CMakeCache.txt
- Makefile
- cmake-build-debug
- CMakeLists.txt
- main.cpp
-- 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 /home/yu/CLionProjects/cmakePractice/build # MESSAGE输出
-- This is SOURCE dir /home/yu/CLionProjects/cmakePractice # MESSAGE输出
-- This is PROJECT BINARY dir /home/yu/CLionProjects/cmakePractice/build # MESSAGE输出
-- This is PROJECT SOURCE dir /home/yu/CLionProjects/cmakePractice # MESSAGE输出
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yu/CLionProjects/cmakePractice/build
发现此时SOURCE_DIR
仍然指代工程路径/home/yu/CLionProjects/cmakePractice
,而BINARY_DIR
则指代编译路径/home/yu/CLionProjects/cmakePractice/build
。
- 添加一个子目录 src,用来放置工程源代码
- 添加一个子目录 doc,用来放置这个工程的文档
hello.txt
- 在工程目录添加文本文件
COPYRIGHT
,README
- 在工程目录添加一个
runhello.sh
脚本,用来调用hello
二进制文件 - 将构建后的目标文件放入构建目录的 bin 子目录
- 安装这些文件:将
hello
二进制文件与runhello.sh
脚本安装至/usr/bin
,将 doc 目录的内容以及COPYRIGHT
,README
安装到/usr/share/doc/cmake/t2
-
在 cmake 目录下建立 t2 目录,将 t1 工程的
main.c
和CMakeLists.txt
拷贝到 t2 目录中。 -
在 t2 目录下添加子目录 src,现在 t2 目录下有一个 src 目录和
CMakeLists.txt
文件, src 目录中有main.c
文件mkdir src mv main.c src
-
上一节我们提到,需要为任何子目录建立一个
CMakeLists.txt
,进入子目录 src,编写CMakeLists.txt
如下:# src的CMakeLists.txt ADD_EXECUTABLE(hello main.c)
-
将 t2 工程的
CMakeLists.txt
修改为# t2的CMakeLists.txt PROJECT(HELLO) ADD_SUBDIRECTORY(src bin) # 添加二进制文件存放位置 /build/bin
所有的文件创建完成后,t2 目录中应该存在 src 目录和CMakeLists.txt
文件, src 目录中应该存在 main.c
和 CMakeLists.txt
两个文件。在 t2 目录建立 build 目录,进入 build 目录进行外部编译:
cmake ..
make
构建完成后,你会发现生成的目标文件 hello
位于 build/bin
目录中。
另外,将 t2 工程的CMakeLists.txt
修改为:
# t2的CMakeLists.txt
PROJECT(HELLO)
ADD_SUBDIRECTORY(src) # 不添加二进制文件存放位置 /build/src
构建完成后,你会发现生成的目标文件 hello
位于 build/src
目录中。
略
在目录 cmakePractice 下,新建 src 目录,保留CMakeLists.txt
文件,将原来在 cmakePractice 目录下的main.cpp
文件移动到 src 目录下,在 src 目录下新建CMakeLists.txt
文件,如下所示:
- cmakePractie
- cmake-build-debug
- src
- CMakeLists.txt
- main.cpp
- CMakeLists.txt
# cmakePractice的CMakeLists.txt
PROJECT(HELLO)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
MESSAGE(STATUS "This is PROJECT BINARY dir " ${PROJECT_BINARY_DIR})
MESSAGE(STATUS "This is PROJECT SOURCE dir " ${PROJECT_SOURCE_DIR})
ADD_SUBDIRECTORY(src bin) # 添加二进制文件存放位置 /build/bin
# src的CMakeLists.txt
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
MESSAGE(STATUS "This is PROJECT BINARY dir " ${PROJECT_BINARY_DIR})
MESSAGE(STATUS "This is PROJECT SOURCE dir " ${PROJECT_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
在目录 cmakePractice 下新建目录 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 /home/yu/CLionProjects/cmakePractice/build # MESSAGE
-- This is SOURCE dir /home/yu/CLionProjects/cmakePractice # MESSAGE
-- This is PROJECT BINARY dir /home/yu/CLionProjects/cmakePractice/build # MESSAGE
-- This is PROJECT SOURCE dir /home/yu/CLionProjects/cmakePractice # MESSAGE
-- This is BINARY dir /home/yu/CLionProjects/cmakePractice/build # MESSAGE
-- This is SOURCE dir /home/yu/CLionProjects/cmakePractice # MESSAGE
-- This is PROJECT BINARY dir /home/yu/CLionProjects/cmakePractice/build # MESSAGE
-- This is PROJECT SOURCE dir /home/yu/CLionProjects/cmakePractice # MESSAGE
CMake Warning (dev) in CMakeLists.txt:
No cmake_minimum_required command is present. A line of code such as
cmake_minimum_required(VERSION 3.5)
should be added at the top of the file. The version specified may be lower
if you wish to support older CMake versions for this project. For more
information run "cmake --help-policy CMP0000".
This warning is for project developers. Use -Wno-dev to suppress it.
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yu/CLionProjects/cmakePractice/build
发现在项目中的不同地方打印SOURCE_DIR
和BINARY_DIR
显示的路径是一致的。
并且有提示:请添加类似cmake_minimum_required(VERSION 3.5)
的语句,需要提供 cmake 的最小版本需求。其他的结果和[Example 1](#Example 1)一样。
继续执行 make
命令后,在 build/bin
目录下得到二进制文件 hello
。
- cmakePractie
- build
- bin
- CMakeFiles
- cmake_install.cmake
- hello
- Makefile
- CMakeFiles
- cmake_install.cmake
- CMakeCache.txt
- Makefile
- cmake-build-debug
- src
- CMakeLists.txt
- main.cpp
- CMakeLists.txt
如果修改 cmakePractice 目录下的 CMakeLists.txt
文件:
# cmakePractice的CMakeLists.txt
PROJECT(HELLO)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
MESSAGE(STATUS "This is PROJECT BINARY dir " ${PROJECT_BINARY_DIR})
MESSAGE(STATUS "This is PROJECT SOURCE dir " ${PROJECT_SOURCE_DIR})
ADD_SUBDIRECTORY(src) # 不添加二进制文件存放位置 /build/src
外部编译后得到的二进制文件将在 build/src
目录下:
- cmakePractie
- build
- CMakeFiles
- src
- CMakeFiles
- cmake_install.cmake
- hello
- Makefile
- cmake_install.cmake
- CMakeCache.txt
- Makefile
- cmake-build-debug
- src
- CMakeLists.txt
- main.cpp
- CMakeLists.txt
不论是 SUBDIRS()
还是 ADD_SUBDIRECTORY()
指令(不论是否指定编译输出目录),我们都可以通过 SET()
指令重新定义 EXECUTABLE_OUTPUT_PATH
和 LIBRARY_OUTPUT_PATH
变量来指定最终的目标二进制的位置(指最终生成的 hello
或者最终的共享库,不包含编译生成的中间文件)
在哪里 ADD_EXECUTABLE
或 ADD_LIBRARY
,如果需要改变目标存放路径,就在哪里加入上述的定义。
如果修改 src 目录下的 CMakeLists.txt
文件(不论目录 cmakePractice 的 CMakeLists.txt
中ADD_SUBDIRECTORY()
是否指定了二进制文件的存放目录):
# src的CMakeLists.txt
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
MESSAGE(STATUS "This is PROJECT BINARY dir " ${PROJECT_BINARY_DIR})
MESSAGE(STATUS "This is PROJECT SOURCE dir " ${PROJECT_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR})
SET()
命令将二进制文件hello
的生成路径设置成了PROJECT_BINARY_DIR
,即 build 目录下。
- cmakePractie
- build
- CMakeFiles
- src
- CMakeFiles
- cmake_install.cmake
- Makefile
- cmake_install.cmake
- CMakeCache.txt
- hello
- Makefile
- cmake-build-debug
- src
- CMakeLists.txt
- main.cpp
- CMakeLists.txt
继续添加目录 doc ,runhello.sh
脚本,和COPYRIGHT
和README
文件,如下所示:
- cmakePractie
- build
- bin
- CMakeFiles
- cmake_install.cmake
- hello
- Makefile
- CMakeFiles
- cmake_install.cmake
- CMakeCache.txt
- Makefile
- cmake-build-debug
- doc
- hello.txt
- src
- CMakeLists.txt
- main.cpp
- CMakeLists.txt
- COPYRIGHT
- README
- runhello.sh
添加二进制文件的相对安装路径,修改目录 src 下的CMakeLists.txt
文件:
# src的CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
ADD_EXECUTABLE(hello main.cpp)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
INSTALL(TARGETS hello
RUNTIME DESTINATION bin) # 二进制文件的相对安装路径为../bin
添加目录 doc 、COPYRIGHT
、README
和runhello.sh
脚本的相对安装路径,修改目录 cmakePractice 下的CMakeLists.txt
文件:
# cmakePractice的CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
PROJECT(HELLO)
#set(CMAKE_CXX_STANDARD 11)
MESSAGE(STATUS "This is BINARY dir " ${HELLOLIB_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLOLIB_SOURCE_DIR})
MESSAGE(STATUS "This is PROJECT BINARY dir " ${PROJECT_BINARY_DIR})
MESSAGE(STATUS "This is PROJECT SOURCE dir " ${PROJECT_SOURCE_DIR})
ADD_SUBDIRECTORY(src bin)
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake) # 普通文件的相对安装路径../share/doc/cmake
INSTALL(PROGRAMS runhello.sh DESTINATION bin) # 非目标文件的可执行程序(比如脚本)的相对安装路径../bin
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake) # 目录的相对安装路径../share/doc/cmake
在 cmakePractice/build
目录下执行cmake -DCMAKE_INSTALL_PREFIX=~/tmp/1 ..
命令,自定义路径为~/tmp/1
,并执行make
和make install
,在~/tmp/1
目录下查看安装结果:
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /home/yu/tmp/1/share/doc/cmake/COPYRIGHT
-- Installing: /home/yu/tmp/1/share/doc/cmake/README
-- Installing: /home/yu/tmp/1/bin/runhello.sh
-- Up-to-date: /home/yu/tmp/1/share/doc/cmake
-- Installing: /home/yu/tmp/1/share/doc/cmake/hello.txt
-- Installing: /home/yu/tmp/1/bin/hello
目录结构如下所示:
~/tmp/1/bin
~/tmp/1/bin/hello
~/tmp/1/bin/runhello.sh
~/tmp/1/share
~/tmp/1/share/doc
~/tmp/1/share/doc/cmake
~/tmp/1/share/doc/cmake/hello.txt
~/tmp/1/share/doc/cmake/COPYRIGHT
~/tmp/1/share/doc/cmake/README
对比实践,将整个目录 doc 安装到上述相对路径,而不是目录 doc 下的hello.txt
文件。修改上述 CMakeLists.txt
文件:
# cmakePractice的CMakeLists.txt
INSTALL(DIRECTORY doc DESTINATION share/doc/cmake) # 目录的相对安装路径../share/doc/cmake
目录结构如下所示:
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /home/yu/tmp/1/share/doc/cmake/COPYRIGHT
-- Installing: /home/yu/tmp/1/share/doc/cmake/README
-- Installing: /home/yu/tmp/1/bin/runhello.sh
-- Installing: /home/yu/tmp/1/share/doc/cmake/doc
-- Installing: /home/yu/tmp/1/share/doc/cmake/doc/hello.txt # 这里的结构发生了变化
-- Installing: /home/yu/tmp/1/bin/hello
上述是将目录 doc 通过安装目录的方式进行安装,简单的方法是将 doc 目录添加到工程中,并按照安装文件的方式直接将hello.txt
文件安装到对应的路径下。作如下修改:
在 cmakePractice 目录的CMakeLists.txt
文件中添加 doc 目录:
# cmakePractice的CMakeLists.txt
ADD_SUBDIRECTORY(doc)
在 doc 目录下新建CMakeLists.txt
文件:
# doc的CMakeLists.txt
INSTALL(FILES hello.txt DESTINATION share/doc/cmake)
重新安装的结果:
Install the project...
-- Install configuration: ""
-- Installing: /home/yu/tmp/1/share/doc/cmake/COPYRIGHT
-- Installing: /home/yu/tmp/1/share/doc/cmake/README
-- Installing: /home/yu/tmp/1/bin/runhello.sh
-- Installing: /home/yu/tmp/1/bin/hello
-- Installing: /home/yu/tmp/1/share/doc/cmake/hello.txt
PS:在执行./runhello.sh
脚本时,发现不可用,修改脚本内容hello
变成./hello
再次执行脚本,能够正常输出Hello World!
。
- 建立一个静态库和动态库,提供
HelloFunc
函数供其他程序编程使用,HelloFunc
向终端输出Hello World
字符串 - 安装头文件与共享库
-
在 cmake 目录下建立 t3 目录
-
在 t3 目录下建立共享库目录 lib
cd /backup/cmake/t3 mkdir lib
-
在 t3 目录下建立
CMakeLists.txt
# t3的CMakeLists.txt PROJECT(HELLOLIB) ADD_SUBDIRECTORY(lib)
-
在 lib 目录下建立两个源文件
hello.c
与hello.h
// hello.c #include “hello.h” void HelloFunc() { printf(“Hello World\n”); }
// hello.h #ifndef HELLO_H #define HELLO_H #include <stdio.h> void HelloFunc(); #endif
-
在 lib 目录下建立
CMakeLists.txt
,内容如下# lib的CMakeLists.txt SET(LIBHELLO_SRC hello.c) ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) # 动态库 # ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC}) # 静态库 # SET(LIBRARY_OUTPUT_PATH <路径>)# 指定库的存储目录
仍然采用 out-of-source 编译的方式,按照习惯,我们建立一个 build 目录,在 build 目录中:
cmake ..
make
在 lib 目录的CMakeLists.txt
中添加ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})
命令用于生成静态库。如果出现只生成了动态库,没有生成静态库,按照如下修改:
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) # 动态库
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC}) # 静态库
# SET(LIBRARY_OUTPUT_PATH <路径>)# 指定库的存储目录
先通过修改静态库的名称同时生成动态库libhello.so
和静态库libhello_static.a
,再重置静态库的名称,作如下修改:
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) # 动态库
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC}) # 静态库
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
# SET(LIBRARY_OUTPUT_PATH <路径>)# 指定库的存储目录
将生成的libhello_static.a
重新命名为libhello.a
。如果出现生成了静态库libhello.a
但是原来的动态库libhello.so
消失了,是动态库被清理掉了,按照如下修改:
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) # 动态库
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(LIBRARY_OUTPUT_PATH <路径>)# 指定库的存储目录
添加动态库版本号,作如下修改:
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) # 动态库
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(LIBRARY_OUTPUT_PATH <路径>)# 指定库的存储目录
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
在 build/lib
目录下生成多个带版本号的动态库libhello.so
,libhello.so.1
,libhello.so.1.2
略
在目录 cmakePractice 下,新建目录 lib 和CMakeLists.txt
,在目录 lib 下新建 hello.cpp
,hello.h
和CMakeLists.txt
文件,如下所示:
- cmakePractie
- cmake-build-debug
- lib
- CMakeLists.txt
- hello.cpp
- hello.h
- CMakeLists.txt
# cmakePractice的CMakeLists.txt
PROJECT(HELLOLIB)
MESSAGE(STATUS "This is BINARY dir " ${HELLOLIB_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLOLIB_SOURCE_DIR})
MESSAGE(STATUS "This is PROJECT BINARY dir " ${PROJECT_BINARY_DIR})
MESSAGE(STATUS "This is PROJECT SOURCE dir " ${PROJECT_SOURCE_DIR})
ADD_SUBDIRECTORY(lib)
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) # 动态库
# ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC}) # 静态库
在目录 cmakePractice 下新建目录 build ,执行cmake ..
和make
命令,在 build/lib
目录下得到动态库 libhello.so
:
- cmakePractie
- build
- CMakeFiles
- lib
- CMakeFiles
- cmake_install.cmake
- libhello.so
- Makefile
- cmake_install.cmake
- CMakeCache.txt
- Makefile
- cmake-build-debug
- lib
- CMakeLists.txt
- hello.cpp
- hello.h
- CMakeLists.txt
如果修改 lib 目录下的 CMakeLists.txt
文件,添加ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})
,在 在 build/lib
目录下得到静态库 libhello.a
:
- cmakePractie
- build
- CMakeFiles
- lib
- CMakeFiles
- cmake_install.cmake
- libhello.a
- libhello.so
- Makefile
- cmake_install.cmake
- CMakeCache.txt
- Makefile
- cmake-build-debug
- lib
- CMakeLists.txt
- hello.cpp
- hello.h
- CMakeLists.txt
在CLion中进行构建,能够同时在同一个目录下生成同名的动态库和静态库。没有出现教程中同名冲突的问题。
第二次实践时,同样的CMakeLists.txt
代码出现了无法生成同名库的问题:
-- This is BINARY dir /home/yu/CLionProjects/cmakePractice/build
-- This is SOURCE dir /home/yu/CLionProjects/cmakePractice
-- This is PROJECT BINARY dir /home/yu/CLionProjects/cmakePractice/build
-- This is PROJECT SOURCE dir /home/yu/CLionProjects/cmakePractice
CMake Error at lib/CMakeLists.txt:3 (ADD_LIBRARY):
add_library cannot create target "hello" because another target with the
same name already exists. The existing target is a shared library created
in source directory "/home/yu/CLionProjects/cmakePractice/lib". See
documentation for policy CMP0002 for more details.
-- Configuring incomplete, errors occurred!
See also "/home/yu/CLionProjects/cmakePractice/build/CMakeFiles/CMakeOutput.log".
需要重命名静态库,修改目录 lib 的CMakeLists.txt
如下:
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC}) # 生成时重命名
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello") # 生成后再次重命名
并没有发生构建静态库后自动清理掉原来的动态库的现象。但是出现原始的静态库libhello_static.a
和重命名后的静态库libhello.a
共存的现象。构建前没有清除上次的构建结果。
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
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)
- cmakePractie
- build
- CMakeFiles
- lib
- CMakeFiles
- cmake_install.cmake
- libhello.a
- libhello.so
- libhello_static.a
- Makefile
- cmake_install.cmake
- CMakeCache.txt
- Makefile
- cmake-build-debug
- lib
- CMakeLists.txt
- hello.cpp
- hello.h
- CMakeLists.txt
最后再添加版本号SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
命令,生成结果libhello.a
,libhello.so
,libhello.so.1
,libhello.so.1.2
:
- cmakePractie
- build
- CMakeFiles
- lib
- CMakeFiles
- cmake_install.cmake
- libhello.a
- libhello.so
- libhello.so.1
- libhello.so.1.2
- Makefile
- cmake_install.cmake
- CMakeCache.txt
- Makefile
- cmake-build-debug
- lib
- CMakeLists.txt
- hello.cpp
- hello.h
- CMakeLists.txt
继续安装共享库,将共享库安装到自定义目录~/tmp/1
下,目录结构如下所示:
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
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 lib
ARCHIVE DESTINATION lib)
INSTALL(FILES hello.h DESTINATION include/hello)
执行以下命令:
cmake -DCMAKE_INSTALL_PREFIX=~/tmp/1 ..
make
make install
结果如下:
[ 50%] Built target hello
[100%] Built target hello_static
Install the project...
-- Install configuration: ""
-- Installing: /home/yu/tmp/1/lib/libhello.so.1.2
-- Installing: /home/yu/tmp/1/lib/libhello.so.1
-- Installing: /home/yu/tmp/1/lib/libhello.so
-- Installing: /home/yu/tmp/1/lib/libhello.a
-- Installing: /home/yu/tmp/1/include/hello/hello.h
- 编写一个程序使用上一节构建的共享库
-
在 cmake 目录下建立 t4 目录
-
建立 src 目录,编写源文件
main.c
// main.c #include <hello.h> int main() { HelloFunc(); return 0; }
-
在 t4 目录新建
CMakeLists.txt
文件# t4的CMakeLists.txt PROJECT(NEWHELLO) ADD_SUBDIRECTORY(src)
-
在 src 目录新建
CMakeLists.txt
文件# src的CMakeLists.txt ADD_EXECUTABLE(main main.c)
仍然采用 out-of-source 编译的方式,在 t4 目录下建立一个 build 目录,在 build 目录中执行cmake ..
和make
命令。构建失败,用make VERBOSE=1
重新构建,显示错误信息:
/backup/cmake/t4/src/main.c:1:19: error: hello.h: 没有那个文件或目录
错误原因:hello.h
位于/usr/include/hello
目录中,并没有位于系统标准的头文件路径。
需要在 src 目录下的CMakeLists.txt
文件中添加一个头文件搜索路径,如下:
# src的CMakeLists.txt
ADD_EXECUTABLE(main main.c)
INCLUDE_DIRECTORIES(/usr/include/hello)
重新编译后,将会出现新的问题:
main.c:(.text+0x12): undefined reference to `HelloFunc'
错误原因:没有链接到共享库 libhello
上。
继续将目标文件链接到libhello
共享库上。
# src的CMakeLists.txt
ADD_EXECUTABLE(main main.c)
INCLUDE_DIRECTORIES(/usr/include/hello)
TARGET_LINK_LIBRARIES(main libhello.so)
重新构建得到一个链接到libhello.so
的可执行程序 main
,位于build/src
目录下。
最后在 build/src
目录下生成 main
可执行文件,运行结果:
./main
Hello World!
在目录 cmakePractice 下,新建目录 src 和CMakeLists.txt
,在目录 src 下新建 main.cpp
和CMakeLists.txt
文件,如下所示:
- cmakePractice
- cmake-build-debug
- src
- CMakeLists.txt
- main.cpp
- CMakeLists.txt
# cmakePractice的CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
PROJECT(NEWHELLO)
MESSAGE(STATUS "This is BINARY dir " ${NEWHELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${NEWHELLO_SOURCE_DIR})
MESSAGE(STATUS "This is PROJECT BINARY dir " ${PROJECT_BINARY_DIR})
MESSAGE(STATUS "This is PROJECT SOURCE dir " ${PROJECT_SOURCE_DIR})
ADD_SUBDIRECTORY(src)
# src的CMakeLists.txt
ADD_EXECUTABLE(main main.cpp)
第一次编译结果将找不到头文件hello.h
:
Scanning dependencies of target main
[ 50%] Building CXX object src/CMakeFiles/main.dir/main.cpp.o
/home/yu/CLionProjects/cmakePractice/src/main.cpp:5:19: fatal error: hello.h: No such file or directory # 错误,找不到头文件
compilation terminated.
src/CMakeFiles/main.dir/build.make:62: recipe for target 'src/CMakeFiles/main.dir/main.cpp.o' failed
make[2]: *** [src/CMakeFiles/main.dir/main.cpp.o] Error 1
CMakeFiles/Makefile2:85: recipe for target 'src/CMakeFiles/main.dir/all' failed
make[1]: *** [src/CMakeFiles/main.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
在 src 目录的CMakeLists.txt
文件中添加INCLUDE_DIRECTORIES()
命令后重新编译:
# src的CMakeLists.txt
INCLUDE_DIRECTORIES(~/tmp/1/include/hello)
ADD_EXECUTABLE(main main.cpp)
Scanning dependencies of target main
[ 50%] Building CXX object src/CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable main
CMakeFiles/main.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x5): undefined reference to `HelloFunc()'
collect2: error: ld returned 1 exit status # 错误,未定义函数
src/CMakeFiles/main.dir/build.make:94: recipe for target 'src/main' failed
make[2]: *** [src/main] Error 1
CMakeFiles/Makefile2:85: recipe for target 'src/CMakeFiles/main.dir/all' failed
make[1]: *** [src/CMakeFiles/main.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
继续链接库:
# src的CMakeLists.txt
INCLUDE_DIRECTORIES(~/tmp/1/include/hello)
ADD_EXECUTABLE(main main.cpp)
TARGET_LINK_LIBRARIES(main libhello.so)
还是出错,并没有找到libhello.so
库,并且提示在/usr/bin/ld
下没找到:
[ 50%] Linking CXX executable main
/usr/bin/ld: cannot find -lhello
collect2: error: ld returned 1 exit status
src/CMakeFiles/main.dir/build.make:94: recipe for target 'src/main' failed
make[2]: *** [src/main] Error 1
CMakeFiles/Makefile2:85: recipe for target 'src/CMakeFiles/main.dir/all' failed
make[1]: *** [src/CMakeFiles/main.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
说明共享库的路径还是不对。再次修改 src 目录的CMakeLists.txt
文件:
# src的CMakeLists.txt
INCLUDE_DIRECTORIES(~/tmp/1/include/hello)
LINK_DIRECTORIES(~/tmp/1/lib)
ADD_EXECUTABLE(main main.cpp)
TARGET_LINK_LIBRARIES(main libhello.so)
还是未定义的函数:
[ 50%] Linking CXX executable main
CMakeFiles/main.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x5): undefined reference to `HelloFunc()'
collect2: error: ld returned 1 exit status
src/CMakeFiles/main.dir/build.make:94: recipe for target 'src/main' failed
make[2]: *** [src/main] Error 1
CMakeFiles/Makefile2:85: recipe for target 'src/CMakeFiles/main.dir/all' failed
make[1]: *** [src/CMakeFiles/main.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
出现这个问题的原因,是库用.cpp
格式,但是内容是.c
的,main.cpp
调用时又用的.c
的方式,编译的时候会出错。
重新实践,首先验证原文中用 .c
写的库以及用.c
调用库。
重复[Example 3](#Example 3),编译生成并安装一个.c
的共享库:
// lib的hello.h
#ifndef PROJECT_HELLO_H
#define PROJECT_HELLO_H
#include <stdio.h>
void HelloFunc();
#endif //PROJECT_HELLO_H
// lib的hello.c
#include "hello.h"
void HelloFunc()
{
printf("Hello World\n");
}
# cmakePractice的CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(lib)
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) # 动态库
INSTALL(TARGETS hello
LIBRARY DESTINATION lib)
INSTALL(FILES hello.h DESTINATION include/hello)
在 build 目录下执行以下命令:cmake -DCMAKE_INSTALL_PREFIX=/home/yu/2 ..
,make
,make install
。编译生成并安装共享库到指定路径。
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /home/yu/2/lib/libhello.so
-- Installing: /home/yu/2/include/hello/hello.h
重复本次实践的内容,用.c
文件调用.c
库,链接上述共享库:
// src的main.c
#include <hello.h>
int main()
{
HelloFunc();
return 0;
}
# cmakePractice的CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
PROJECT(NEWHELLO)
ADD_SUBDIRECTORY(src)
# src的CMakeLists.txt
LINK_DIRECTORIES(/home/yu/2/lib)
INCLUDE_DIRECTORIES(/home/yu/2/include/hello)
ADD_EXECUTABLE(main main)
TARGET_LINK_LIBRARIES(main libhello.so)
清空已有的 build 目录,执行以下命令:cmake ..
,make
,编译成功。
因为 C++ 和 C 是两种完全不同的编译链接处理方式,所以如果直接在 C++ 里面调用 C 函数,这样链接起来是通不过的,会报链接错误,找不到函数体,所以要在 C++ 文件里面显示声明以下一些函数是 C 写的,要用C的方式来处理,这个在 C++ 设计初期就考虑到兼容性的问题,所以是可以解决的。
比如用 C 写了
A.h
和A.c
这两个文件,里面包括了void A_app(int)
这样的函数,那么在需要调用这个函数的 CPP 文件里面,就需要显示声明一下了。
引用头文件前需要加上
extern “C”
,如果引用多个,那么就如下所示 extern “C” { #include “A.h” #include “B.h” ... };C++调用C函数的方法,将用到的函数全部重新声明一遍
extern “C” { extern void A_app(int); extern void B_app(int); ... };
继续尝试,用.cpp
文件调用.c
的库,其他CMakeLists.txt
文件不变:
// src的main.cpp
extern "C"
{
#include <hello.h>
extern void HelloFunc();
}
int main()
{
HelloFunc();
return 0;
}
清空已有的 build 目录,执行以下命令:cmake ..
,make
,编译成功。
继续尝试,重复[Example 3](#Example 3),编译生成并安装一个.cpp
的共享库:
// lib的hello.h
#ifndef PROJECT_HELLO_H
#define PROJECT_HELLO_H
#include <iostream>
class hello
{
public:
void HelloFunc();
};
#endif //PROJECT_HELLO_H
// lib的hello.cpp
#include "hello.h"
using namespace std;
void hello::HelloFunc()
{
cout << "Hello World!" << endl;
}
# cmakePractice的CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(lib)
# lib的CMakeLists.txt
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) # 动态库
INSTALL(TARGETS hello
LIBRARY DESTINATION lib)
INSTALL(FILES hello.h DESTINATION include/hello)
在 build 目录下执行以下命令:cmake -DCMAKE_INSTALL_PREFIX=/home/yu/1 ..
,make
,make install
。编译生成并安装共享库到指定路径。
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /home/yu/1/lib/libhello.so
-- Installing: /home/yu/1/include/hello/hello.h
重复本次实践的内容,用.cpp
文件调用.cpp
库,链接上述共享库:
// src的main.cpp
#include <hello.h>
int main()
{
hello a;
a.HelloFunc();
return 0;
}
# cmakePractice的CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
PROJECT(NEWHELLO)
ADD_SUBDIRECTORY(src)
# src的CMakeLists.txt
LINK_DIRECTORIES(/home/yu/1/lib)
INCLUDE_DIRECTORIES(/home/yu/1/include/hello)
ADD_EXECUTABLE(main main)
TARGET_LINK_LIBRARIES(main libhello.so)
清空已有的 build 目录,执行以下命令:cmake ..
,make
,编译成功。
继续尝试,用.c
文件调用.cpp
的库。需要在.cpp
库文件中,加上extern "C"
,这样才能用.c
文件调用。
继续用环境变量CMAKE_INCLUDE_PATH
的方式指定头文件目录,修改 src 目录的CMakeLists.txt
文件:
# src的CMakeLists.txt
LINK_DIRECTORIES(/home/yu/1/lib)
FIND_PATH(myHeader hello.h)
if(myHeader)
INCLUDE_DIRECTORIES(${myHeader})
ENDIF(myHeader)
ADD_EXECUTABLE(main main)
TARGET_LINK_LIBRARIES(main libhello.so)
清空原始 build 目录,执行以下命令:CMAKE_INCLUDE_PATH=/home/yu/1/include/hello cmake ..
和make
,编译链接成功。
用bash
的方式结果是一样的:export CMAKE_INCLUDE_PATH=/home/yu/1/include/hello
。
- 编写
Find
模块.cmake
- 调用
INCLUDE
指令和FIND_PACKAGE
指令
-
在 cmake 目录下建立 t5 目录
-
建立 src 目录,编写源文件
main.c
// 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; } // 这段代码的作用是通过 curl 取回 www.linux-ren.org 的首页并写入/tmp/curl-test文件中 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); }
-
在 t5 目录新建
CMakeLists.txt
文件# t5的CMakeLists.txt PROJECT(CURLTEST) ADD_SUBDIRECTORY(src)
-
在 src 目录新建
CMakeLists.txt
文件# src的CMakeLists.txt 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)
-
在 cmake 目录下建立 t6 目录,在 t6 目录下新建 cmake 目录和 src 目录
-
在
t6/cmake
目录下新建FindHELLO.cmake
模块# t6的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)
-
在 src 目录新建
main.c
文件// src的main.c #include <hello.h> int main() { HelloFunc(); return 0; }
-
在 src 目录新建
CMakeLists.txt
文件# 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)
-
修改 t6 目录下的
CMakeLists.txt
文件,增加查找FindHELLO.cmake
命令# t6的CMakeLists.txt PROJECT(CURLTEST) ADD_SUBDIRECTORY(src) SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
仍然采用 out-of-source 编译的方式,在 t5 目录下建立一个 build 目录,在 build 目录中执行cmake ..
和make
命令。采用方法一和方法二编译成功。
添加自定义 cmake
模块后,清空原始 build 目录,重新执行 cmake ..
和make
命令,输出显示:
Found Hello: /usr/lib/libhello.so
如果把上面的 FIND_PACKAGE(HELLO)
修改为 FIND_PACKAGE(HELLO QUIET)
,则不会看到上面的输出。
在目录 cmakePractice 下,新建目录 src 和CMakeLists.txt
,在目录 src 下新建 main.c
和CMakeLists.txt
文件,如下所示:
- cmakePractice
- cmake-build-debug
- src
- CMakeLists.txt
- main.cpp
- CMakeLists.txt
# cmakePractice的CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
PROJECT(CURLTEST)
ADD_SUBDIRECTORY(src)
# src的CMakeLists.txt
# 方法一
INCLUDE_DIRECTORIES(/usr/include)
ADD_EXECUTABLE(curltest main.c)
TARGET_LINK_LIBRARIES(curltest curl)
第一次编译结果将找不到头文件curl/curl.h
:
Scanning dependencies of target curltest
[ 50%] Building C object src/CMakeFiles/curltest.dir/main.c.o
/home/yu/CLionProjects/cmakePractice/src/main.c:6:23: fatal error: curl/curl.h: No such file or directory
compilation terminated.
src/CMakeFiles/curltest.dir/build.make:62: recipe for target 'src/CMakeFiles/curltest.dir/main.c.o' failed
make[2]: *** [src/CMakeFiles/curltest.dir/main.c.o] Error 1
CMakeFiles/Makefile2:85: recipe for target 'src/CMakeFiles/curltest.dir/all' failed
make[1]: *** [src/CMakeFiles/curltest.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
出错原因:**没有安装libcurl4-openssl-dev
库。**安装后清空 build 目录,再次编译成功。
修改 src 目录的CMakeLists.txt
,采用方法二进行编译:
# src的CMakeLists.txt
# 方法二
ADD_EXECUTABLE(curltest main.c)
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)
在 build 目录下执行cmake ..
,发现输出多了一行显示-- Found CURL: /usr/lib/x86_64-linux-gnu/libcurl.so (found version "7.47.0")
,表示找到了curl
:
-- 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
-- Found CURL: /usr/lib/x86_64-linux-gnu/libcurl.so (found version "7.47.0") # 输出显示找到了curl
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yu/CLionProjects/cmakePractice/build
方法二编译成功。
接下来继续添加自定义FindHELLO.cmake
模块。在目录 cmakePractice 下,新建目录 cmake ,目录 src 和CMakeLists.txt
,在目录 src 下新建 main.c
和CMakeLists.txt
文件,在目录 cmake 下新建FindHELLO.cmake
文件,如下所示:
- cmakePractice
- cmake
- FindHELLO.cmake
- cmake-build-debug
- src
- CMakeLists.txt
- main.cpp
- CMakeLists.txt
注意查找的是[Example 4](#Example 4)中生成的.c
或者.cpp
类型的共享库hello
:
# cmake的FindHELLO.cmake
FIND_PATH(HELLO_INCLUDE_DIR hello.h /home/yu/2/include/hello) # 注意查找路径
FIND_LIBRARY(HELLO_LIBRARY NAMES hello PATH /home/yu/2/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)
# cmakePractice的CMakeLists.txt
PROJECT(CURLTEST)
ADD_SUBDIRECTORY(src)
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
// 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)
在 build 目录下构建的结果:
-- 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
CMake Warning at src/CMakeLists.txt:1 (FIND_PACKAGE):
By not providing "FindHELLO.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "HELLO", but
CMake did not find one. # 未提供FindHELLO.cmake文件
Could not find a package configuration file provided by "HELLO" with any of
the following names:
HELLOConfig.cmake
hello-config.cmake
Add the installation prefix of "HELLO" to CMAKE_PREFIX_PATH or set
"HELLO_DIR" to a directory containing one of the above files. If "HELLO"
provides a separate development package or SDK, be sure it has been
installed.
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yu/CLionProjects/cmakePractice/build
出错原因:目录 cmakePractice 中的CMakeLists.txt
命令的顺序错误,需要先指定自定义的FindHELLO.cmake
的路径,先找到hello
共享库,才能在main.c
文件中调用共享库中的函数。如果先执行了main.c
,会产生找不到库的输出。错误输出里明确提示了未提供FindHELLO.cmake
文件。
修改目录 cmakePractice 中的CMakeLists.txt
文件,调整命令的顺序:
# cmakePractice的CMakeLists.txt
PROJECT(CURLTEST)
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
ADD_SUBDIRECTORY(src)
构建没有报错,但是没有输出Found Hello:...
的路径。说明没有找到hello
库。需要添加更多的输出来定位问题:
# cmake的FindHELLO.cmake
FIND_PATH(HELLO_INCLUDE_DIR hello.h /home/yu/2/include/hello)
FIND_LIBRARY(HELLO_LIBRARY NAMES hello PATH /home/yu/2/lib)
IF (HELLO_INCLUDE_DIR) # 添加输出
MESSAGE(STATUS "HELLO_INCLUDE_DIR is ${HELLO_INCLUDE_DIR}")
ENDIF(HELLO_INCLUDE_DIR)
IF (HELLO_LIBRARY) # 添加输出
MESSAGE(STATUS "HELLO_LIBRARY is ${HELLO_LIBRARY}")
ENDIF(HELLO_LIBRARY)
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)
再次构建,结果如下:
-- HELLO_INCLUDE_DIR is /home/yu/2/include/hello # 只有第一句输出
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yu/CLionProjects/cmakePractice/build
从上看出HELLO_INCLUDE_DIR
找到了,但是HELLO_LIBRARY
没有找到,所以不满足IF (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
条件。继续解决问题:
查找 cmake 官网的FIND_LIBRARY
命令的帮助:
find_library (<VAR> name1 [path1 path2 ...]) # 简单的写法
find_library (
<VAR>
name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
[HINTS path1 [path2 ... ENV var]]
[PATHS path1 [path2 ... ENV var]] # 注意这里是PATHS
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[DOC "cache documentation string"]
[NO_DEFAULT_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_CMAKE_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_SYSTEM_PATH]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
) # 完整的写法
发现在完整写法中,参数PATHS
在教程中写错了。更正后重新构建,编译成功:
-- 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
-- HELLO_INCLUDE_DIR is /home/yu/2/include/hello # 输出头文件路径
-- HELLO_LIBRARY is /home/yu/2/lib/libhello.so # 输出库文件路径
-- Found Hello: /home/yu/2/lib/libhello.so # 输出找到共享库
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yu/CLionProjects/cmakePractice/build
- 使用 cmake 生成 debug 版和 release 版的程序
debug 版的项目生成的可执行文件需要有调试信息并且不需要进行优化,而 release 版的不需要调试信息但需要优化。这些特性在 gcc/g++ 中是通过编译时的参数来决定的,如果将优化程度调到最高需要设置参数-O3,最低是 -O0 即不做优化;添加调试信息的参数是 -g -ggdb ,如果不添加这个参数,调试信息就不会被包含在生成的二进制文件中。
CMake 中有一个变量 CMAKE_BUILD_TYPE
,可以的取值是 Debug
,Release
, RelWithDebInfo
和 MinSizeRel
。当这个变量值为 Debug
的时候,CMake 会使用变量 CMAKE_CXX_FLAGS_DEBUG
和 CMAKE_C_FLAGS_DEBUG
中的字符串作为编译选项生成 Makefile ,当这个变量值为 Release
的时候,工程会使用变量 CMAKE_CXX_FLAGS_RELEASE
和 CMAKE_C_FLAGS_RELEASE
选项生成 Makefile。
-
在 cmake 目录下建立 t6 目录
-
在 t6 目录,编写源文件
main.cpp
// main.cpp #include <iostream> int main() { std::cout << "Hello, World!" << std::endl; return 0; }
-
在 t6 目录新建
CMakeLists.txt
文件# t6的CMakeLists.txt PROJECT(main) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) SET(CMAKE_SOURCE_DIR .) SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") AUX_SOURCE_DIRECTORY(. DIR_SRCS) ADD_EXECUTABLE(main ${DIR_SRCS})
编辑 CMakeList.txt
后需要执行 ccmake
命令生成 Makefile 。在进入项目的根目录 t6 ,输入 ccmake .
进入一个图形化界面。
按照界面中的提示进行操作,按 "c" 进行 configure ,这时界面中显示出了配置变量 CMAKE_BUILD_TYPE
的条目。
下面我们首先生成 Debug
版的 Makefile :将变量 CMAKE_BUILD_TYPE
设置为 Debug
,按 "c" 进行 configure ,按 "g" 生成 Makefile 并退出。这时执行命令 find * | xargs grep "O0"
后结果如下:
CMakeFiles/main.dir/flags.make:CXX_FLAGS = -O0 -Wall -g -ggdb
CMakeFiles/main.dir/link.txt:/usr/bin/c++ -O0 -Wall -g -ggdb
CMakeFiles/main.dir/main.cpp.o -o main -rdynamic
CMakeLists.txt:SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
这个结果说明生成的 Makefile 中使用了变量 CMAKE_CXX_FLAGS_DEBUG
作为编译时的参数。
下面我们将生成 Release 版的 Makefile :再次执行命令 "ccmake ." 将变量``CMAKE_BUILD_TYPE设置为 Release ,生成 Makefile 并退出。执行命令
find * | xargs grep "O0" `后结果如下:
CMakeLists.txt:SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
而执行命令 find * | xargs grep "O3"
后结果如下:
CMakeCache.txt:CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
CMakeCache.txt:CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
CMakeFiles/main.dir/flags.make:CXX_FLAGS = -O3 -Wall
CMakeFiles/main.dir/link.txt:/usr/bin/c++ -O3 -Wall
CMakeFiles/main.dir/main.cpp.o -o main -rdynamic
CMakeLists.txt:SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
这两个结果说明生成的 Makefile 中使用了变量 CMAKE_CXX_FLAGS_RELEASE
作为编译时的参数。
略
add_library(freeglut_minimal ${G2O_LIB_TYPE}
freeglut_font.cpp
freeglut_stroke_mono_roman.cpp
freeglut_stroke_roman.cpp
)
target_link_libraries(freeglut_minimal PUBLIC ${G2O_OPENGL_TARGET} ${G2O_EIGEN3_EIGEN_TARGET})
set_target_properties(freeglut_minimal PROPERTIES OUTPUT_NAME ${LIB_PREFIX}ext_freeglut_minimal)
if (APPLE)
set_target_properties(freeglut_minimal PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib")
endif()
install(TARGETS freeglut_minimal
EXPORT ${G2O_TARGETS_EXPORT_NAME}
RUNTIME DESTINATION ${RUNTIME_DESTINATION} #可执行二进制文件
LIBRARY DESTINATION ${LIBRARY_DESTINATION} #动态库
ARCHIVE DESTINATION ${ARCHIVE_DESTINATION} #静态库
INCLUDES DESTINATION ${INCLUDES_DESTINATION}
)
file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp")
install(FILES ${headers} DESTINATION ${INCLUDES_INSTALL_DIR}/freeglut)
cmake_minimum_required(VERSION 2.6)
project(csparse)
#set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
add_library(csparse ${G2O_LGPL_LIB_TYPE}
cs_add.c
cs_amd.c
cs_chol.c
cs_cholsol.c
cs_compress.c
cs_counts.c
cs_cumsum.c
cs_dfs.c
cs_dmperm.c
cs_droptol.c
cs_dropzeros.c
cs_dupl.c
cs_entry.c
cs_ereach.c
cs_etree.c
cs_fkeep.c
cs_gaxpy.c
cs_happly.c
cs_house.c
cs_ipvec.c
cs_leaf.c
cs_load.c
cs_lsolve.c
cs_ltsolve.c
cs_lu.c
cs_lusol.c
cs_malloc.c
cs_maxtrans.c
cs_multiply.c
cs_norm.c
cs_permute.c
cs_pinv.c
cs_post.c
cs_print.c
cs_pvec.c
cs_qr.c
cs_qrsol.c
cs_randperm.c
cs_reach.c
cs_scatter.c
cs_scc.c
cs_schol.c
cs_spsolve.c
cs_sqr.c
cs_symperm.c
cs_tdfs.c
cs_transpose.c
cs_updown.c
cs_usolve.c
cs_util.c
cs_utsolve.c
cs_api.h
)
set_target_properties(csparse PROPERTIES OUTPUT_NAME ${LIB_PREFIX}ext_csparse)
if (APPLE)
set_target_properties(csparse PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib")
endif()
if (UNIX)
target_link_libraries(csparse PUBLIC m)
endif()
install(TARGETS csparse
EXPORT ${G2O_TARGETS_EXPORT_NAME}
RUNTIME DESTINATION ${RUNTIME_DESTINATION}
LIBRARY DESTINATION ${LIBRARY_DESTINATION}
ARCHIVE DESTINATION ${ARCHIVE_DESTINATION}
INCLUDES DESTINATION ${INCLUDES_DESTINATION}
)
file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp")
install(FILES ${headers} DESTINATION ${INCLUDES_INSTALL_DIR}/EXTERNAL/csparse)
# Set up the variables
set(CSPARSE_LIBRARY "$<TARGET_FILE:csparse>")
set(CSPARSE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Include directory for CSparse" FORCE)
set(CSPARSE_LIBRARY ${CSPARSE_LIBRARY} CACHE FILEPATH "CSparse library" FORCE)
add_subdirectory(data_fitting)
add_subdirectory(sphere)
# The condition on cholmod is required here because the cholmod solver
# is explicitly used in these examples.
if(CHOLMOD_FOUND)
add_subdirectory(target)
add_subdirectory(ba)
add_subdirectory(ba_anchored_inverse_depth)
endif(CHOLMOD_FOUND)
# Examples which explicitly use CSparse
if(CSPARSE_FOUND)
add_subdirectory(tutorial_slam2d)
add_subdirectory(icp)
add_subdirectory(calibration_odom_laser)
add_subdirectory(simple_optimize)
add_subdirectory(plane_slam)
add_subdirectory(line_slam)
endif()
if(CSPARSE_FOUND OR CHOLMOD_FOUND)
add_subdirectory(sba)
add_subdirectory(bal)
endif()
if(Qt5_FOUND AND QGLVIEWER_FOUND AND CSPARSE_FOUND)
add_subdirectory(slam2d)
endif()
add_subdirectory(data_convert)
add_subdirectory(interactive_slam)
add_subdirectory(g2o_test)
# Only build CSPARSE if we need to
if(BUILD_CSPARSE AND G2O_USE_CSPARSE)
add_subdirectory(csparse)
endif()
if (G2O_HAVE_OPENGL)
add_subdirectory(freeglut)
endif()