cmake学习二

一、静态库与动态库的构建、安装和使用

项目链接 t3 t4文件夹

  • 动态库后缀是 .so 静态库后缀是 .a
  • 具体内容:
1、建立一个静态库和动态库,提供 HelloFunc 函数供其他程序编程使用,HelloFunc向终端输出 Hello World 字符串。
2、安装头文件与共享库。
  • 指定链接库或者可执行文件的位置。有两种方法:

    # 在 src/lib文件夹下的CMakeLists.txt中添加以下内容
    SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
    SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
    

    或者:

    # 在主工程文件CMakeLists.txt中添加
    ADD_SUBDIRECTORY(bin lib)
    
    • ADD_LIBRARY指令

      ADD_LIBRARY(libname [SHARED|STATIC|MODULE]
      	[EXCLUDE_FROM_ALL]
      		source1 source2 ... sourceN)
      

      类型有三种:
      SHARED,动态库
      STATIC,静态库
      MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建。
      按照一般的习惯,静态库名字跟动态库名字应该是一致的。
      注意以下命令:hello上面已经作为动态库的名字,生成了libhello.so,hello是一个target,所以静态库名字不能与target名字(这里就是hello)相同,否则静态库构建指令无效。

ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})

上面命令生成了libhello_static.a

静态库和动态库的名字不同,不符合预期,于是引入下面的指令:

  • SET_TARGET_PROPERTIES

    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/CMakeLists.txt中添加:
GET_TARGET_PROPERTY(OUTPUT_VALUE hello_static OUTPUT_NAME)
MESSAGE(STATUS “This is the hello_static OUTPUT_NAME:”${OUTPUT_VALUE})
#-- This is the hello_static OUTPUT_NAME:hello

如果没有这个属性定义,则返回 NOTFOUND.

需要注意的一个问题是:cmake 在构建一个新的 target 时,会尝试清理掉其他使用这个名字的库, 有可能在构建 libhello.a 时,就会清理掉 libhello.so.为了避免这个问题,再次使用 SET_TARGET_PROPERTIES 定义CLEAN_DIRECT_OUTPUT 属性。(本人在构建的时候没有出现这个问题)

  • # 向 lib/CMakeLists.txt 中添加:
    SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    
  • 动态库版本号,按照规则,动态库是应该包含一个版本号的,下系统的动态库,一般情况是:

libhello.so.1.2
libhello.so ->libhello.so.1
libhello.so.1->libhello.so.1.2

为了实现动态库版本号,我们仍然需要使用 SET_TARGET_PROPERTIES 指令。具体使用方法如下:

#VERSION 指代动态库版本,SOVERSION 指代 API 版本。
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

将上述指令加入 lib/CMakeLists.txt 中,重新构建,在build/lib目录生成上述内容。

  • 安装共享库和头文件

    以上面的例子,需要将 libhello.a, libhello.so.x 以及 hello.h 安装到系统目录,才能真正让其他人开发使用,在本例中将 hello 的共享库安装到/lib目录,将 hello.h 安装到/include/hello 目录。

利用INSTALL指令,向 lib/CMakeLists.txt 中添加如下指令:

# 安装动态库和静态库  注意,静态库要使用 ARCHIVE 关键字
INSTALL(TARGETS hello hello_static
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
# 安装hello.h文件
INSTALL(FILES hello.h DESTINATION include/hello)

执行以下命令:

#将头文件和共享库安装到系统目录/tmp/t3/usr/li和/tmp/t3/usr/include/hello 
cmake -DCMAKE_INSTALL_PREFIX=/tmp/t3/usr ..  #或者
#将头文件和共享库安装到系统目录/usr/lib 和/usr/include/hello 安装到系统目录中可以方便使用
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make
make install
  • 使用外部共享库和头文件

为了让工程找到 hello.h 头文件(上面我们安装过的),引入一个新的指令INCLUDE_DIRECTORIES

INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)

这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割,如果路径中包含了空格,可以使用双引号将它括起来,默认的行为是追加到当前的头文件搜索路径的后面,可以通过两种方式来进行控制搜索路径添加的方式:

1,CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过 SET 这个 cmake 变量为 on,可以
将添加的头文件搜索路径放在已有路径的前面。

2,通过 AFTER 或者 BEFORE 参数,也可以控制是追加还是置前。

在 src/CMakeLists.txt 中添加一个头文件搜索路径:

INCLUDE_DIRECTORIES(/tmp/t3/usr/include/hello)

执行make重新构建,出现以下错误:

main.c:(.text+0xa):对‘HelloFunc’未定义的引用

原因:没有 link 到共享库 libhello 上。

  • 为target 添加共享库

    将目标文件链接到 libhello,这里我们需要引入两个新的指令LINK_DIRECTORIES 和 TARGET_LINK_LIBRARIES

#这个指令非常简单,添加非标准的共享库搜索路径,比如,在工程内部同时存在共享库和可执行二进制,在编译时就需要指定一下这些共享库的路径
LINK_DIRECTORIES(directory1 directory2 ...)
# 这个指令可以用来为 target 添加需要链接的共享库,本例中是一个可执行文件,但是同样可以用于为自己编写的共享库添加共享库链接。
TARGET_LINK_LIBRARIES(target library1
						<debug | optimized> library2
						...)

为了解决前面遇到的 HelloFunc 未定义错误,需要向src/CMakeLists.txt 中添加如下指令:

TARGET_LINK_LIBRARIES(main hello) 或者
TARGET_LINK_LIBRARIES(main libhello.so)

重新构建后再来看一下 main 的链接情况:

ldd src/main
linux-vdso.so.1 =>  (0x00007ffc7f9a2000)
libhello.so.1 => /usr/lib/libhello.so.1 (0x00007face90ab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007face8ce1000)
/lib64/ld-linux-x86-64.so.2 (0x00007face92ad000)

可以清楚的看到 main 确实链接了共享库 libhello,而且链接的是动态库libhello.so.1

链接到静态库:

TARGET_LINK_LIBRARIES(main libhello.a)

重新构建即可。

二、 环境变量 CMAKE_INCLUDE_PATH 和CMAKE_LIBRARY_PATH

注意,这两个是环境变量而不是 cmake 变量。使用方法是要在 bash 中用 export 或者在 csh 中使用 set 命令设置或者CMAKE_INCLUDE_PATH=/home/include cmake …等方式。这两个变量主要是用来解决以前 autotools 工程中–extra-include-dir 等参数的支持的。

也就是,如果头文件没有存放在常规路径(/usr/include, /usr/local/include 等),则可以通过这些变量进行弥补。本例中的 hello.h 为例,它存放在/usr/include/hello 目录,所以直接查找肯定是找不到的。前面直接使用绝对路径 INCLUDE_DIRECTORIES(/usr/include/hello)告诉工程这个头文件目录。

为了将程序更智能一点,可以使用 CMAKE_INCLUDE_PATH 来进行,使用 bash 的方法如下:

export CMAKE_INCLUDE_PATH=/usr/include/hello

然后在src/CMakeLists.txt中:

INCLUDE_DIRECTORIES(/usr/include/hello)替换为:

FIND_PATH(myHeader hello.h)
IF(myHeader)
INCLUDE_DIRECTORIES(${myHeader})
ENDIF(myHeader)

FIND_PATH 用来在指定路径中搜索文件名,比如:

FIND_PATH(myHeader NAMES hello.h PATHS /usr/include
/usr/include/hello)

这里没有指定路径,但是,cmake 仍然可以帮我们找到 hello.h 存放的路径,就是因为设置了环境变量 CMAKE_INCLUDE_PATH。

注意:如果不使用 FIND_PATH,CMAKE_INCLUDE_PATH 变量的设置是没有作用的。

以此为例,CMAKE_LIBRARY_PATH 可以用在 FIND_LIBRARY 中。同样,因为这些变量直接为 FIND指令所使用,所以所有使用 FIND_指令的 cmake 模块都会受益。

下一节会详细介绍cmake 常用变量和常用环境变量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值