前两节简单的介绍了,cmake的简单使用和install的过程,本节将详细介绍构建动态库和静态库,以及共享动态库和静态库的过程
文件存放方式:
创建test根目录,然后创建lib和build,在根目录下创建CMakeLists.txt,,在lib目录下创建CMakeLists.txt、hello.cpp、hello.h, 其中hello.cpp、hello.h内容如下:
hello.h
#ifndef HELLO_H
#define HELLO_H
#include<iostream>
void helloFunc();
#endif
//#######################################################
hello.cpp
#include "hello.h"
void helloFunc()
{
std::cout<<"hello world"<<std::endl;
}
1.构建动态库和静态库
在根目录下面的CMakeLists.txt文件中添加如下代码:
因为根目录下的CMakeLists.txt无须构建文件,只需要启动子文件的CMakeLists.txt即可
# 版本判断
cmake_minimum_required(VERSION 3.0)
# 工程名
project(hellolib)
# 添加子目录,该目录为库目录,会调用子目录的cmake文件,进行构建库
add_subdirectory(lib)
主要的构建代码在lib/CMakeLists.txt里:
# 把所有源文件添加到列表
aux_source_directory(. DIR_LIB_SRCS)
# 如果文件很少,可以通过直接指定
# set(DIR_LIB_SRCS hello.cpp)
# 指定编译库输出的位置
set(LIBRARY_OUTPUT_PATH lib)
# 生成动态库
add_library(hello SHARED ${DIR_LIB_SRCS})
# 生成静态库
# 这样写会使得静态库没有构建,报错原因是动态库的名称也是hello即target不能重名
# add_library(hello STATIC ${DIR_LIB_SRCS})
# 修改名称后构建是可以成功的,会生成libhello_static.a和libhello.so两个文件,
# 但是同一种库我们希望名称一样
add_library(hello_static STATIC ${DIR_LIB_SRCS})
# 想要生成动态库和静态库相同名称的的库文件,则需要一个指令set_target_properties
# 这里只是通过重新命名的方法使其名字相同的,构建时还需不能相同
set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello")
# 获取相关属性也是通过set_target_properties
get_target_property(OUTPUT_VALUE hello_static OUTPUT_NAME)
message(STATUS "This is the hello_static OUTPUT_NAME:"${OUTPUT_VALUE})
# 动态库版本号设置 , VERSION指代动态库版本,SOVERSION 指代 API 版本。
set_target_properties(hello PROPERTIES VERSION 1.2 SOVERSION 1)
# 其中,libhello.so.1.2为动态库的文件名(realname),libhello.so.1为动态库的别名(soname),
# libhello.so为动态库的链接名(linkname)。
message(STATUS ${DIR_LIB_SRCS}"--构建库完成")
# 安装共享库和头文件
# 将动态库和静态库安装到<prefix>/lib
install(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
# 安装头文件
install(FILES hello.h DESTINATION include/hello)
进入build执行以下命令:
cmake -DCMAKE_INSTALL_PREFIX=/home/ubuntu/work/usr ..
make
make install
代码注释已经很相详细了,这里只需要强调几个指令和注意事项:
如果你要指定libhello.so生成的位置,可以通过在主工程文件CMakeLists.txt 中修改add_subdirectory(lib newdir)指令来指定一个编译输出位置或者在lib/CMakeLists.txt 中添加set(LIBRARY_OUTPUT_PATH newdir)来指定一个新的位置。newdir是相对路径,如下lib的lib里可以直接使用lib替换newdir
add_libraary指令:
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[<source>...])
name中你不需要写全libhello.so,只需要填写hello 即可,cmake系统会自动为你生成libhello.X
类型有三种:
SHARED,动态库
STATIC,静态库
MODULE,在使用 dyld 的系统有效,如果不支持dyld,则被当作SHARED对待。
EXCLUDE_FROM_ALL参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手
工构建。
动态库和静态库构建
# 生成动态库
add_library(hello SHARED ${DIR_LIB_SRCS})
# 生成静态库
# 这样写会使得静态库没有构建,报错原因是动态库的名称也是hello即target不能重名
# add_library(hello STATIC ${DIR_LIB_SRCS})
如果动态库和静态库的名称相同,会导致后一个库无法构建,按照我们的例子因为hello 作为一个target是不能重名的,所以,静态库构建指令无效。
如果把静态库的名称hello 修改为hello_static,则可以顺利的构建,会生成libhello.so和libhello_static.a库文件。
这种结果显示不是我们想要的,我们需要的是名字相同的静态库和动态库,因为 target 名
称是唯一的,所以,我们肯定不能通过 add_library指令来实现了。这时候我们需要用到
另外一个指令:
set_target_properties(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...)
这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API版本。
在本例中,我们需要作的是向lib/CMakeLists.txt 中添加一条:
set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello")
这样,我们就可以同时得到libhello.so/libhello.a 两个库了。
与他对应的指令是:
get_target_property(<VAR> target property)
具体用法如下例,我们向lib/CMakeListst.txt中添加:
get_target_property(OUTPUT_VALUE hello_static OUTPUT_NAME)
message(STATUS "This is the hello_static OUTPUT_NAME:"${OUTPUT_VALUE})
如果没有这个属性定义,则返回NOTFOUND.
动态库版本号的设置
按照规则,动态库是应该包含一个版本号的,我们可以看一下系统的动态库,一般情况是
libhello.so.1.2
libhello.so ->libhello.so.1
libhello.so.1->libhello.so.1.2
为了实现动态库版本号,我们仍然需要使用 set_target_properties指令。
具体使用方法如下:
set_target_properties(hello PROPERTIES VERSION 1.2 SOVERSION 1)
VERSION指代动态库版本,SOVERSION 指代 API 版本。其中,libhello.so.1.2为动态库的文件名(realname),libhello.so.1为动态库的别名(soname), libhello.so为动态库的链接名(linkname)。
将上述指令加入lib/CMakeLists.txt 中,重新构建看看结果。
在build/lib 目录会生成:
libhello.so.1.2
libhello.so.1->libhello.so.1.2
libhello.so ->libhello.so.1
安装共享库和头文件
安装过程和上一节类似,这里不过得解释。
后面测试调用共享库执行程序
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)