Administrator
Published on 2024-04-20 / 32 Visits
0
0

cmake生成和使用so库

概述

cmake生成和使用so库,主要用到了add_library,target_link_libraries这两个命令。

测试项目1(指定so库位置)

概述

我们首先在/home/SOTest路径下创建两个项目,demo1和demo2,其中build为文件夹,格式如下:
1713592828322.png

demo1

该项目为生成一个测试的so库,供demo2调用使用。

代码

hello.c文件,提供hello方法,可打印hello:

#include <stdio.h>

void hello() {
    printf("hello\n");
}

CMakeLists.txt:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (HelloSharedLib)

# 创建共享库,SHARED代表为生成动态库
add_library(hello_shared_lib SHARED hello.c)
生成

cd build
cmake ..
make

执行后,可以在build中看到生成so文件:
1713593355603.png

demo2

该项目为应用程序,调用demo1生成的so库。

代码

main.c文件:

// main.c
#include <stdio.h>

// 前置声明hello函数
void hello();

int main() {
    hello();
    return 0;
}

CMakeLists.txt:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (HelloApp)

# 添加可执行文件
add_executable(hello_app main.c)

# 链接共享库到主程序
target_link_libraries(hello_app "/home/SOTest/demo1/build/libhello_shared_lib.so")
生成

cd build
cmake ..
make

执行后,运行程序,可以看到输出hello代表调用so库成功:
1713593544564.png

测试项目2(指定系统库)

概述

观察测试项目1的demo2的CMakeLists.txt的target_link_libraries,可以看到是指定了so库的绝对路径,其实target_link_libraries也可以直接链接系统的库,本项目将demo1生成so库安装到系统,然后demo2直接链接系统库。

demo1

代码

CMakeLists.txt:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (HelloSharedLib)

# 创建共享库
add_library(hello_shared_lib SHARED hello.c)

# 设置库的安装路径
# 其中lib为要安装的路径,最好是全路径,如果仅指定了目录名称,默认会输出到/usr/local/XXX目录下
install(TARGETS hello_shared_lib LIBRARY DESTINATION lib)

生成

cd build
cmake ..
make
make install

需要执行make install才行,执行后make install后,可以看到/usr/local/lib下有so文件:
1713594817473.png

demo2

代码

CMakeLists.txt:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (HelloApp)

# 添加可执行文件
add_executable(hello_app main.c)

# 找系统的库,实际库的文件名为libhello_shared_lib.so,下面是支持/不支持的名称:
# 1.libhello_shared_lib.so 支持
# 2.hello_shared_lib.so 不支持
# 3.libhello_shared_lib 不支持
# 4.hello_shared_lib 支持
find_library(hello-lib hello_shared_lib)

# 链接共享库到主程序
target_link_libraries(hello_app ${hello-lib})
生成

cd build
cmake ..
make

执行后,运行程序,可以看到输出hello代表调用so库成功:
1713593544564.png

扩展

find_library不一定只能用到找系统的库上,也能支持指定路径,假设/home/SOTest/demo1/build中有libhello_shared_lib.so,格式如:
find_library(hello-lib hello_shared_lib HINTS /home/SOTest/demo1/build)

其中hello_shared_lib为库名,/home/SOTest/demo1/build为要找的目录路径。

疑问

观察上面的CMakeLists.txt,我们可以会想,如果去掉
find_library(hello-lib hello_shared_lib)
这一行代码,然后把
target_link_libraries(hello_app ${hello-lib})
直接替换成
target_link_libraries(hello_app hello_shared_lib)
这样可不可行?

通过测试,虽然能行make成功,但是运行时会报错:
1713596360707.png

测试项目3(so库链接so库)

概述

so库可以链接so库,再给程序调用。

demo1

demo1参考测试项目1

demo_transit

代码

hello.c

#include <stdio.h>

void hello();

void helloTransit() {
    hello();
}

CMakeLists.txt:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (HelloSharedLib)

# 创建共享库
add_library(hello_shared_lib_transit SHARED hello.c)

# 链接共享库
target_link_libraries(hello_shared_lib_transit "/home/SOTest/demo1/build/libhello_shared_lib.so")
生成

cd build
cmake ..
make

demo2

代码

main.c文件:

// main.c
#include <stdio.h>

// 前置声明helloTransit函数
void helloTransit();

int main() {
    helloTransit();
    return 0;
}

CMakeLists.txt:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (HelloApp)

# 添加可执行文件
add_executable(hello_app main.c)

# 链接共享库到主程序
target_link_libraries(hello_app "/home/SOTest/demo_transit/build/libhello_shared_lib_transit.so")
生成

cd build
cmake ..
make

疑问

demo_transit项目中,能不能不写helloTransit方法,只有hello方法,然后demo2直接去调用hello方法?
经过测试,不行,会报类似以下错误:

1713603140786.png

问题

so库如果有main方法,会不会跟调用该库的程序冲突?

通常,共享库不应该包含 main 函数。不过经测试,没有影响,调用该库的程序运行后,能执行该main。通常,链接器会使用可执行文件中的 main 函数作为程序的入口点,而忽略共享库中的 main 函数。


Comment