您的位置:首页 > 移动开发 > Objective-C

g++编写与使用动态链接库so(shared object)(附cmake生成动态库)

2015-11-22 23:08 387 查看
        最近在学习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/ld.so.conf文件内所列的一系列目录,这些目录成为“共享目录”,然后执行ldconfig(ldconfig命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为/etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表. ldconfig通常在系统启动时运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令.)

方法二:将动态链接库所在目录名追加到动态链接库配置文件/etc/ld.so.conf中. 
# pwd >> /etc/ld.so.conf 
# 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文件

          如果仅仅生成动态库文件,创建该库名的工程,并为该工程编写CMakeLists.txt,假定工程目录为math目录这在工程目录下创建CMakeLists.txt脚本文件,因为工程目录,所以脚本中必须指定cmake版本和项目信息,并设置该工程输出目标为动态库即可,如此脚本CMakeLists.txt编写如下:

# cmake最低版本要求

cmake_minimum_required(VERSION 2.8)

# 项目信息

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脚本),最后主CMakeLists.txt中动态链接该math目录生成的动态库,改动如下:

目录结构:

 - 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)工程目录脚本内容

# cmake最低版本要求

cmake_minimum_required(VERSION 2.8)

# 项目信息

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息