cmake 02 static lib


原文链接: cmake 02 static lib

组织为静态和动态库
通常的项目都会划分模块,模块以库的形式进行链接(动态或静态),在 cmake 中进行这一构建操作也是比较简单。

还是原来的 helloworld 项目,现在从 helloworld3 拷贝到 helloworld4 。原来直接写在 main 中的输出部分,现在提取出一个 sayHello 函数供重复调用。

增加一个 lib 目录,里面增加 hello.h 和 hello.c ,内容分别为 ::

#ifndef HELLO_H
#define HELLO_H

void sayHello();

#endif
和 ::

#include <stdio.h>
#include "hello.h"

void sayHello()
{
    printf("Hello, world!\n");
}

在 lib 中增加一个 CMakeLists.txt ::

SET(SRC_LIST hello.c)

ADD_LIBRARY(hello_shared SHARED ${SRC_LIST})
SET_TARGET_PROPERTIES(hello_shared PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello_shared PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(hello_shared PROPERTIES VERSION 1.2 SOVERSION 1)

ADD_LIBRARY(hello_static STATIC ${SRC_LIST})
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(hello_static PROPERTIES VERSION 1.2 SOVERSION 1)

INSTALL(TARGETS hello_shared;hello_static
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib)

INSTALL(FILES hello.h DESTINATION include)

ADD_LIBRARY 指令指示生成一个库目标文件,可指定库的类型为 SHARED 或 STATIC 。

SET_TARGET_PROPERTIES 指令设置目标的属性,其中 CLEAN_DIRECT_OUTPUT 部分用于指示在生成具有相同名字的(OUTPUT_NAME)的目标时,是否清理上次生成的内容。由于这罗的动态和静态库都使用 hello 这个名字,因此需要设置此不见标志。

这个配置文件同时生成了动态连接库和静态连接库,并把头文件安装到 include 目录。

引用动态库
修改 src 中的 main.c ::

#include
#include "hello.h"

int main(int argc, char* argv[]){

sayHello();
return 0;

}
并在 src 中的 CMakeLists.txt 中,包含 lib 目录,以及让 hello 可执行文件链接到生成的库 ::

ADD_SUBDIRECTORY(lib)
INCLUDE_DIRECTORIES(lib)

ADD_EXECUTABLE(hello main.c)
TARGET_LINK_LIBRARIES(hello hello_shared)

INSTALL(TARGETS hello DESTINATION bin)
INCLUDE_DIRECTORIES 指定 include 时要包含的头文件搜索路径。

TARGET_LINK_LIBRARIES 指示链接到目标库。由于我们的库与源代码在同一个 cmake 构建系统中,可直接用目标名 hello_shared 或 hello_static,否则应该用库文件名。链接时,如果链接库放在非系统特定的库目录下,那么需要通过 LINK_DIRECTORIES(路径) 指定库的搜索路径,或者直接用绝对路径。

如果无法在 CMakeLists.txt 中指定 INCLUDE_DIRECTORIES 和 LINK_DIRECTORIES ,还可以通过 shell 变量 CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH,在 cmake 构建时传递给 cmake 。

然后,在 CMakeLists.txt 中通过 FIND_PATH 指令来判断是否找到相应的头文件路径,并包含进来 ::

FIND_PATH(myHeader hello.h)
IF(myHeader)

INCLUDE_DIRECTORIES(${myHeader})

ENDIF(myHeader)
FIND_PATH 用法为 ::

FIND_PATH(变量名 NAMES 需要查找的文件名列表 PATHS 待查找的路径列表)
类似地,可用 CMAKE_LIBRARY_PATH 和 FIND_LIBRARY 判断库是否存在。

顶层目录中的 CMakeLists.txt 保持不变,用来构建其它文件。

同样,在 build 目录中,进行构建 ::

(mkdir -p build; cd build; cmake -DCMAKE_INSTALL_PREFIX=$PWD/usr; make install)
生成后,看 build 中的 usr ,有以下的目录树 ::

usr/
├── bin
│ ├── hello
│ └── runhello.sh
├── include
│ └── hello.h
├── lib
│ ├── libhello.a
│ ├── libhello.so -> libhello.so.1
│ ├── libhello.so.1 -> libhello.so.1.2
│ └── libhello.so.1.2
└── share

└── doc
    └── HELLO
        ├── hello.txt
        └── README

要注意,直接运行 ./usr/bin/hello 时,会报告无法找到 libhello.so.1 的错误(如果是链接到静态库 hello_static 则不会出现此错误) ::

/usr/bin/hello: error while loading shared libraries: libhello.so.1: cannot open shared object file: No such file or directory
这是由于系统默认的库搜索路径在 /etc/ld.so.config 中指定,可通过 LD_LIBRARY_PATH 变量暂时指定一个路径,即在 build 目录下 ::

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/usr/lib ./usr/bin/hello
就会正确地运行和输出。

`