• linux下动态库编译的依赖问题


    这里主要是想试验一下,对一个具有多层嵌套的动态库进行编译时,是否要把最底层的库也包含进来的问题,结论是:只要直接依赖的库名称,不需要最底层库名称。

    一,目录结构
    ZZZ
    ├── add
    │   ├── add.cpp
    │   └── add.h
    ├── calc
    │   ├── calc.cpp
    │   └── calc.h
    ├── main
    ├── main.cpp
    ├── pkg
    │   ├── pkg.cpp
    │   └── pkg.h
    └── sub
        ├── sub.cpp
        └── sub.h

    二,文件内容:
    1, add模块内容:
    [add.cpp ]
    int add(int a, int b)
    {
        return a+b;
    }
    [add.h]
    extern  int add(int a, int b);

    2, sub模块内容:
    [sub.cpp]
    int sub(int a, int b)
    {
        return a-b;
    }
    [sub.h]
    extern int sub(int a, int b);

    3, calc模块内容:
    [calc.cpp]
    #include "calc.h"
    #include "add.h"
    #include "sub.h"
    #include <stdio.h>

    void func(int a, int b)
    {
        int result = add(a,b);
        printf("%d+%d=%d ",a, b, result);

        result = sub(a,b);
        printf("%d-%d=%d ",a, b, result);
    }
    [calc.h]
    extern void func(int a, int b);

    4, pkg模块: 对calc模块进行了简单封装
    [pkg.cpp]
    #include "pkg.h"
    #include "calc.h"

    void pkg_func()
    {
        func(100, 80);
    }
    [pkg.h]
    extern void pkg_func();
    5, main程序:调用pkg模块
    [main.cpp]
    #include "pkg.h"

    int main()
    {
        pkg_func();

        return 0;
    }


    三,编译:
    ZZZ目录下:(单功能模块)
    1,[add模块]
        g++ -g -shared -fPIC add/add.* -o libadd.so
    2, [sub模块]:(单功能模块)
        g++ -g -shared -fPIC sub/sub.* -o libsub.so
    3, [calc模块]: clac模块依赖于add和sub模块,用到了两者的头文件,并调用了接口
        错误:g++ -g -shared -fPIC -Iadd -Isub calc/calc.*  -o libcalc.so
        (编译虽然可以过,但是参数不足,这种遗漏依赖库的问题现在不解决,在编译嵌套它的上层库时就会暴露出来)
        正确:g++ -g -shared -fPIC -Iadd -Isub -ladd -lsub -L. calc/calc.*  -o libcalc.so
    4, [pkg模块]:封装calc模块
        错误:g++ -g -shared -fPIC -Icalc  pkg/pkg.* -o libpkg.so
        正确:g++ -g -shared -fPIC -Icalc -lcalc -L. pkg/pkg.* -o libpkg.so
    5, [main程序]
        g++ -g -Ipkg -lpkg -L. main.cpp -o main

    四,试验

    我们知道各模块的依赖关系:pkg->calc->add+sub,让我们慢慢分析,通过3,4步的编译参数我们可以看出:
    编译链接某个so的时候,系统并不检查接口是否可以导出,而只是检查编译是否通过。所以编译参数只包含依赖库的文件名是可以通过,但并不保证是正确的。(制作动态库的时候,到底有没有链接这个过程?,否则为什么在第一层调用库的时候就不报错呢)
    1)g++ -g -Ipkg main.cpp -o main
    /tmp/ccjKIuei.o: In function `main':
    /home/TEST/ZZZ/main.cpp:5: undefined reference to `pkg_func()'
    A: main.cpp里面没有找到pkg_func接口,没包含库名称怎么可能找得到接口呢?

    2) g++ -g -Ipkg -lpkg main.cpp -o main
    /usr/bin/ld: cannot find -lpkg
    collect2: ld 返回 1
    A: 没有找到库名,需要指定库目录

    3)g++ -g -Ipkg -lpkg -L. main.cpp -o main
    /tmp/cc4JknbM.o: In function `main':
    /home/TEST/ZZZ/main.cpp:5: undefined reference to `pkg_func()'
    ./libpkg.so: undefined reference to `func(int, int)'
    collect2: ld 返回 1
    A: libpkg.so里没有找到func接口,说明libpkg.so库在编译时没有包含依赖库名称,执行第4步的正确编译命令。

    4)g++ -g -Ipkg -lpkg -L. main.cpp -o main
    /tmp/ccGpm3HQ.o: In function `main':
    /home/TEST/ZZZ/main.cpp:5: undefined reference to `pkg_func()'
    libcalc.so: undefined reference to `sub(int, int)'
    libcalc.so: undefined reference to `add(int, int)'
    collect2: ld 返回 1
    A: libcalc.so里没找到add,sub接口,说明libcalc.so时在编译时没有包含依赖库名称,执行第3步正确编译命令。

    5) g++ -g -Ipkg -lpkg -L. main.cpp -o main
    100+80=180
    100-80=20

    五,引申:
    现在要在main.cpp是需跨层调用add模块的add接口,需要做的操作是:
    1)添加代码:main.cpp包含add.h头文件,增加add()函数代码,
    2)添加编译选项:只需要添加-I选项即可,不需要再加-l选项的。

    六,结论:
    因为库具有叠加性,最上层库的接口中已经包含了中间层和最低层的导出接口了,这个可以使用ldd命令来查看。
    所以在编译具有多层依赖的动态库时,你只需要包含当前库直接依赖的库名称即可,不需要再把它所依赖库的依赖库名称包含进来。以上面的例子来说,编译pkg模块库的时候,只需要把calc的库包含进来就行了。

     

  • 相关阅读:
    个人介绍
    对软件工程课程的希望
    对这门课程的的希望和目标
    关于sql server profiler 监控工具的使用
    关于eclipse常用的一些快捷键
    后台页面中发现的一点问题总结
    电脑端手机模拟器软件
    关于.net后台的异步刷新的问题
    Excle中的使用小技巧
    关于.net里面的静态html页面和接口组合使用的网站
  • 原文地址:https://www.cnblogs.com/jacklikedogs/p/3838605.html
Copyright © 2020-2023  润新知