g++编写与使⽤动态链接库so(sharedobject)(附cmake⽣
成动态库)
最近在学习linux编程,确切的说应该是使⽤linux环境,我并不需要像了解windows api那样去了解linux相关api,然后去做linux开发,⽽是想⽤⼀写与平台⽆关的开元库开发服务器相关程序,从⽽实现⼀处开发处处运⾏的⽬的,所以使⽤linux仅仅是知道编译相关的基础功能。如下⽂章说明了如何将编写好的程序编译成⼀个类似于windows的dll动态链接库组建,linux叫做so⽂件(shared object),因为针对⼀个⼤⼯程,我不可能像真正的写makefile那样将⼯程所有⽂件编写到makefile⾥⾯,所以我们⼀般使⽤⼯程化管理的cmake⼯具做makefile⽣成、编译、安装等⼯作,在使⽤cmake之前,我们先了解⼀下最基础的so⽂件编译⽣成,然后在描述如何使⽤cmake⽣成⼀个so,具体如下:
⼀下两种⽅式的so动态链接库⽣成实例源码为mymath.h和mymath.cpp,我们将该库编译成libmymath.so,⾥⾯的源码如下:mymath.h ⽂件内容:
#ifndef _MYMATH_H
#define _MYMATH_H
int Add(int a, int b);
int Sub(int a, int b);
int Mul(int a, int b);
int Div(int a, int b);
#endif
mymath.cpp⽂件内容:
#include "mymath.h"
int Add(int a, int b)
{
return (a+b);
}
int Sub(int a, int b)
{
return (a-b);
}
int Mul(int a, int b)
{
return (a*b);
}
// 不做异常处理
int Div(int a, int b)
{
return (a/b);
}
测试程序main.cpp内容:
#include "mymath.h"
#include <stdio.h>
int main(int argc, char* argv[])
{
int a = 10, b = 5;
printf("%d + %d = %d\n", a, b, Add(a, b));
printf("%d - %d = %d\n", a, b, Sub(a, b));
printf("%d * %d = %d\n", a, b, Mul(a, b));
printf("%d / %d = %d\n", a, b, Div(a, b));
return 0;
}
1、⼿动使⽤g++(或gcc)⽣成so动态链接库
⾸先将mymath.cpp⽣成libmymath.so动态库,我们使⽤g++ 的-fpic -shared选项,-fpic使⽣成模块按照可重定位地址⽅式⽣成(⽣成与地址⽆关的库),-shared选项指定源⽂件⽣成.so的动态库⽂件,使⽤指令如下:
g++ -fpic -shared -o libmymath.so mymath.cpp
libmymath.so 为⽣成的⽬标⽂件(必须以lib打头),随后为源⽂件列表
⽣成后,隐式⽅式使⽤⽅式如main.cpp,直接包含头⽂件即可,但编译main的时候⽅式如下
(1)编译
g++ -l. -o main.o -c main.cpp
编译的时候⽣成main.o对象⽂件必须指定链接库⽬录,由于libmymath.so就在本⽬录使⽤“-l"后直接跟当
前⽬录”."即可,-o⽣成main.o ⽬标⽂件,-c指定源⽂件列表main.cpp
(2)链接
⽣成main.o后,下⼀步就是⽣成main可执⾏⽂件,使⽤-L指定库搜索⽬录,使⽤-l指定链接库名称(去掉前缀lib和.so之后的名字)
g++ -o main -L. main.o -lmymath
(编译链接两个步骤可以合成⼀个:g++ -L. main.cpp -o main -lmymath)
执⾏之后⽣成可执⾏⽂件main,但是运⾏./main,报错:error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory
引起运⾏错误的原因是:程序运⾏时并不知道动态库所在的路径,因此⾃然不到
解决⽅法有如下三种:
⽅法⼀:将动态库拷贝到/lib或/usr/lib或/etc/f⽂件内所列的⼀系列⽬录,这些⽬录成为“共享⽬录”,然后执⾏ldconfig(ldconfig命令的⽤途,主要是在默认搜寻⽬录(/lib和/usr/lib)以及动态库配置⽂件/e
tc/f内所列的⽬录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),进⽽创建出动态装⼊程序(ld.so)所需的连接和缓存⽂件.缓存⽂件默认为/etc/ld.so.cache,此⽂件保存已排好序的动态链接库名字列表. ldconfig通常在系统启动时运⾏,⽽当⽤户安装了⼀个新的动态链接库时,就需要⼿⼯运⾏这个命令.)
⽅法⼆:将动态链接库所在⽬录名追加到动态链接库配置⽂件/etc/f中.
# pwd >> /etc/f
# ldconfig
⽅法三:
利⽤动态链接库管理命令ldconfig,强制其搜索指定⽬录,并更新缓存⽂件,便于动态装⼊.
# ldconfig `pwd`
pwd前后有两个反引号`,其⽬的是取得pwd命令的输出,即当前⽬录
以上⽅法任选其⼀,配置好动态库之后运⾏./main即可得到输出结果:
[root@localhost dynamic]# ./main
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10 / 5 = 2
2、使⽤cmake脚本⽣成so动态链接库
(1)仅仅⽣成so⽂件
如果仅仅⽣成动态库⽂件,创建该库名的⼯程,并为该⼯程编写,假定⼯程⽬录为math⽬录这在⼯程⽬录下创建脚本⽂件,因为⼯程⽬录,所以脚本中必须指定cmake版本和项⽬信息,并设置该⼯程输出⽬标为动态库即可,如此脚本编写如下:
# 项⽬信息
project(DynamicLibDemon)
# 搜索本⽬录搜索源码并赋值给变量
aux_source_directory(. DIR_LIB_SRCS)
# 添加库⽂件
add_library(mymath SHARED ${DIR_LIB_SRCS})
add_library指定输出类型为动态库SHARED,为了使得cmake编译中间⽂件不污染源码,特定在该⼯程⽬录下创建⼀个编译⽬录build,cd进⼊该⽬录,输⼊cmake ..后即可在编译⽬录build下⽣成so⽂件
(2)⽣成so动态库并⽣成可执⾏测试程序
按照这个条件,测试程序为⼯程⽬录且假如⼯程⽬录为test,⾥⾯含有测试测试程序main.cpp,我们可以将可以单独编译的动态库放到⼯程⽬录下⾯⼦⽬录math,然后单独编译math⽬录(有⾃⼰的cmake脚本),最后主中动态链接该math⽬录⽣成的动态库,改动如下:
⽬录结构:cmake如何使用
- test
-
main.cpp
-build
-math
-mymath.h
-mymath.cpp
(1) main.cpp包含头⽂件改为:
#include "./math/mymath.h"
(2) ⼦⽬录math中脚本⽂件内容
# 搜索本⽬录搜索源码并赋值给变量
aux_source_directory(. DIR_LIB_SRCS)
# 添加库⽂件
add_library(mymath SHARED ${DIR_LIB_SRCS})
(3)⼯程⽬录脚本内容
# 项⽬信息
project(DynamicLibDemon)
# 搜索本⽬录搜索源码并赋值给变量
aux_source_directory(. DIR_LIB_SRCS)
# 添加库⽂件
add_executable(Demon ${DIR_LIB_SRCS})
# 链接动态库
target_link_libraries(Demon mymath)
最后,进⼊build⽬录,输⼊cmake .. 编译,然后输⼊make即可链接⽣成Demon可执⾏程序,为了能够
使⽤动态库,必须将动态库拷贝到/lib或/usr/lib,然后ldconfig重新载⼊到缓存中即可执⾏Demon,输出结果:
[root@localhost buid]# ldconfig `pwd`
[root@localhost buid]# ./Demon
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10 / 5 = 2
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论