一、环境安装
- win10安装wsl ubuntu2004
#windows c盘工程目录建立软链
ln
-s
/mnt/c
/home/vrviu/
- 安装cmake、c++编译工具
apt
install
-y cmake g++
二、CMakeLists.txt讲解
- 准备工作
首先,在/home/vrviu 目录建立一个 cmake 目录
以后我们所有的 cmake 练习都会放在cmake 的子目录下
然后在 cmake 建立第一个练习目录 t1
cd cmake
mkdir t1
cd t1
在 t1 目录建立 main.c 和 CMakeLists.txt(注意文件名大小写):
main.c 文件内容:
//main.c
#include <stdio.h>
int
main()
{
printf
(“Hello World from t1 Main!\n”);
return
0;
}
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)
-
开始构建
指令: cmake .
成功建立如下:包括:CMakeCache.txt、CMakeFiles、cmake_install.cmake、Makefile等中间文件。
指令:makePS:可以使用make VERBOSE=1来查看make构建的详细过程。
这个时候已经生成了hello.
指令:./hello以上是cmake构建的全部过程。
- 详细解释
CMakeLists.txt,是cmake 的构建定义文件,文件名
是大小写相关的,如果工程存在多个目录,需要确保每个要管理的目录都存在一个
CMakeLists.txt。
PROJECT 指令的语法是:
PROJECT(projectname [CXX] [C] [Java])
同时 cmake 系统也帮助我们预定义了 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR
变量,他们的值分别跟 HELLO_BINARY_DIR 与 HELLO_SOURCE_DIR 一致。
建议以后直接使用 PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即
使修改了工程名称,也不会影响这两个变量。如果使用了
<projectname>_SOURCE_DIR,修改工程名称后,需要同时修改这些变量。
SET 指令的语法是:
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
现阶段,你只需要了解 SET 指令可以用来显式的定义变量即可。
比如我们用到的是 SET(SRC_LIST main.c),如果有多个源文件,也可以定义成:
SET(SRC_LIST main.c)
MESSAGE 指令的语法是:
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display"
...)
这个指令用于向终端输出用户定义的信息,包含了三种类型:
SEND_ERROR,产生错误,生成过程被跳过。
SATUS,输出前缀为—的信息。FATAL_ERROR,立即终止所有 cmake 过程.
我们在这里使用的是 STATUS 信息输出,演示了由 PROJECT 指令定义的两个隐式变量
HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR。
ADD_EXECUTABLE(hello ${SRC_LIST})
定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是 SRC_LIST 中
定义的源文件列表
指令是大小写无关的,参数和变量是大小写相关的。但,推荐你全部使用大写指令。
上面的 MESSAGE 指令我们已经用到了这条规则:
MESSAGE(STATUS “This is BINARY dir” ${HELLO_BINARY_DIR})
这里需要特别解释的是作为工程名的 HELLO 和生成的可执行文件 hello 是没有任何关系的。
hello 定义了可执行文件的文件名,你完全可以写成:
ADD_EXECUTABLE(t1 main.c)编译后会生成一个 t1 可执行文件。
-
清理工程
可以使用make clean清理makefile产生的中间的文件,但是,不能使用make distclean清除cmake产生的中间件。如果需要删除cmake的中间件,可以采用rm -rf ***来删除中间件。 - 外部构建
在目录下建立一个build文件用来存储cmake产生的中间件,不过需要使用cmake …来运行。其中外部编译,PROJECT_SOURCE_DIR仍然指代工程路径,即/vrviu/cmake/t1,而PROJECT_BINARY_DIR指代编译路径,即/vrviu/cmake/t1/build。
三、动态库、静态库编译,安装
本节建立一个静态库和动态库,提供HelloFunc函数供其他程序编程使用,HelloFunc向终端输出Hello World字符串。安装头文件和共享库。
- 准备工作
在/vrviu/cmake中建立t3,用于存放工程文件。 - 建立共享库
指令:
cd /cmake/t3
mkdir lib
在t2目录下建立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,内容如下:
SET(LIBHELLO_SRC hello.c)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}
/lib
)
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 VERSION 1.2 SOVERSION 1)
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
INSTALL(FILES hello.h DESTINATION include
/hello
)
- 外部构建
在build目录下:
cmake ..
make
编译成功后,在build文件下的lib文件下可以发现存在一个libhello.so的动态链接库
ADD_LIBRARY(libname [SHARED|STATIC|MODULE][EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
不需要在全libhello.so,只需要填写hello即可,cmake系统会自动为你生成libhello.X
类型有三种:
SHARED,动态库
STATIC,静态库
MODULE,在使用dyld的系统有效,如果不支持dyld,则被当做SHARED对待。
EXCLUDE_FROM_ALL参数的意思是这个不会被默认构建,除非有其他的组件依赖或者手工构建。 - 添加静态库
在以上的基础上再添加一个静态库,按照一般的习惯,则这个静态库的名字的后缀为.a。
我们往lib/CMakeLists.txt中添加一条:SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
这样就可以同时得到libhello.so/libhello.a两个库了。ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})
使用语句,hello作为target是不能重名的。所以会造成静态库的构建指令无效。SET_TARGET_PROPERTIES(target1 target2 ...PROPERTIES prop1 value1 prop2 value2 ...)
这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库的版本和API版本。与他对应的指令是:
GET_TARGET_PROPERTY(VAR target property)
举例:向lib/CMakeLists.txt中添加:GET_TARGET_PROPERTY(OUTPUT_VALUE hello_static OUTPUT_NAME)
MESSAGE(STATUS "This is the hello_static OUTPUT_NAME:"${OUTPUT_VALUE})
如果没有这个属性则会返回NOTFOUND.而使用以上的例子会出现一个问题,那就是会发现libhello.a存在,但是libhello.so会消失,因为cmake在构建一个新的target时,会尝试清理掉其他使用这个名字的库。解决方案如下:
向lib/CMakeLists.txt中添加SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_PUTPUT 1)
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
这个时候再进行构建,会发现build/lib目录中同时生成了libhello.so和libhello.a。 - 增加动态库的版本号
SET_TARGET_PROPERTIES(hello PROPERTIES VERION 1.2 SOVERSION 1)
VERSION指代动态库版本,SOVERSION指代API版本。此时,会生成三个文件,其中,libhello.so.1.2为动态库的文件名(realname),libhello.so.1为动态库的别名(soname),libhello.so为动态库的链接名(linkname)。
在makefile中-lthello时,makefile会寻找libhello.so,然后将libhello.so.1写入到可执行文件的链接信息中
-
安装共享库和头文件
以上面的例子,将libhello.a、libhello.so以及hello.h安装到系统目录,才能真正让其他人开发使用。例如将共享库安装到/usr/local/lib目录,将hello.h安装到/usr/local/include/hello目录。在lib/CMakeLists.txt中添加指令:
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
INSTALL(FILES hello.h DESTINATION include/hello)
编译指令:cmake ..
make
make install
这样就可以将头文件和共享库安装到系统目录/usr/lib和/usr/local/include/hello中了
四、SDK集成
- 准备工作
在cmake中创建t4用来存储这一节的资源,在t4目录下创建src目录 - 编码
在src目录下编写源文件main.c如下:
t4下的CMakeLists.txt如下:#include <hello.h>
int
main()
{
HelloFunc();
return
0;
}
t4下的src下的CMakeLists.txt如下:PROJECT(NEWHELLO)
ADD_SUBDIRECTORY(src bin)
INCLUDE_DIRECTORIES(
/usr/local/include/hello
)
ADD_EXECUTABLE(main main.c)
#TARGET_LINK_LIBRARIES(main hello)
TARGET_LINK_LIBRARIES(main libhello.a)
- 引入头文件搜索路径
在src/CMakeLists.txt添加一个头文件搜索路径,如下:INCLUDE_DIRECTORIES(
/usr/local/include/hello
)
- 配置共享库目录
echo
“
/usr/local/lib
” >>
/etc/ld
.so.conf
#更新/etc/ld.so.cache文件
ldconfig
- 编译执行
在build目录下:
cmake ..
make - 判断链接sdk
指令:
ldd src/main(在目录build下)
静态库:
动态库: