转载请注明出处,谢谢 https://www.cnblogs.com/tianknight/p/10648021.html

前言

关于gcc这三个参数,参考了诸多文档后,仍然理解上有偏差,仿照下面博客中的方法,自己调试了一波,总算是理解了。还是建议大家动手实践一下。

参考资料如下:

源码准备

新建三个文件:test.c hello.c world.c ,其源码依赖关系为:test.c 依赖 hello.c;hello.c 依赖 world.c

源码内容

test.c

#include <stdio.h>
void world(void);
void hello(void)
{
printf("hello ");
world();
}

hello.c

#include<stdio.h>
void hello(void);
void main(void)
{
hello();
}

world.c

#include<stdio.h>
void world(void)
{
printf("world.\n");
}

尝试编译,保证源码没有问题

# -o 指定输出文件
[root@localhost testc]# ls
hello.c test.c world.c
[root@localhost testc]# gcc -o hehe *.c
[root@localhost testc]# ls
hehe hello.c test.c world.c
[root@localhost testc]# ./hehe
hello world.

编译

首先编译world.c

# -shared 编译链接库
# -fPIC 我的理解是编译链接库时给代码动态分配内存
[root@localhost testc]# gcc -shared -fPIC -o libworld.so world.c
[root@localhost testc]# ls
hello.c libworld.so test.c world.c
[root@localhost testc]# ldd libworld.so
linux-vdso.so.1 => (0x00007ffd7498f000)
libc.so.6 => /lib64/libc.so.6 (0x00007fcb49815000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcb49dea000) #上述命令和下面的等价,建议选取单条命令即可:gcc -shared -fPIC -o libworld.so world.c
# -c 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件
[root@localhost testc]# gcc -c -fPIC world.c
[root@localhost testc]# ls
hello.c test.c world.c world.o
[root@localhost testc]# gcc -shared -fPIC -o libworld.so world.o
[root@localhost testc]# ls
hello.c libworld.so test.c world.c world.o
[root@localhost testc]# ldd libworld.so
linux-vdso.so.1 => (0x00007ffd0dfa9000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4357dcb000)
/lib64/ld-linux-x86-64.so.2 (0x00007f43583a0000)

编译并链接hello.c

# -lxxx 指定需要动态链接的库文件
# -L 指定动态连接库文件的位置(编译时)
# . 指当前路径
# 下面编译出的libhello.so文件已经显式依赖libworld.so文件,但是没有找到libworld.so的位置
[root@localhost testc]# gcc -shared -fPIC -o libhello.so hello.c -lworld -L.
[root@localhost testc]# ls
hello.c libhello.so libworld.so test.c world.c
[root@localhost testc]# ldd libhello.so
linux-vdso.so.1 => (0x00007ffe61b89000)
libworld.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007ff73cc1e000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff73d1f4000)

调试编译test.c

[root@localhost testc]# ls
hello.c libhello.so libworld.so test.c world.c # 编译出错,提示找不到hello
[root@localhost testc]# gcc -o haha test.c
/tmp/ccQCWcSW.o: In function 'main':
test.c:(.text+0x5): undefined reference to 'hello'
collect2: error: ld returned 1 exit status # 添加libhello.so的链接索引,并指定库的搜索路径为'.'(当前路径)
# 依然编译失败,提示找不到libworld.so,该库被libhello.so依赖,并提示建议使用-rpath 或 -rpath-link解决
[root@localhost testc]# gcc -o haha test.c -lhello -L.
/usr/bin/ld: warning: libworld.so, needed by ./libhello.so, not found (try using -rpath or -rpath-link)
./libhello.so: undefined reference to 'world'
collect2: error: ld returned 1 exit status # 手动添加libworld.so的依赖,编译通过,查看haha的链接库,已经显式指出依赖,但是没有找到其位置
[root@localhost testc]# gcc -o haha test.c -lhello -L. -lworld
[root@localhost testc]# ldd haha
linux-vdso.so.1 => (0x00007fff556ea000)
libhello.so => not found
libworld.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007f1ff0c97000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1ff106b000) # 执行编译出的haha,执行报错,提示找不到依赖库
[root@localhost testc]# ./haha
./haha: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory #修改系统环境变量'LD_LIBRARY_PATH',增加索引库的位置,查看依赖OK,执行haha, 结果OK, 清空'LD_LIBRARY_PATH'
[root@localhost testc]# export LD_LIBRARY_PATH=/home/testc/ && echo $LD_LIBRARY_PATH
/home/testc/
[root@localhost testc]# ldd haha
linux-vdso.so.1 => (0x00007ffd647d2000)
libhello.so => /home/testc/libhello.so (0x00007fb7aa063000)
libworld.so => /home/testc/libworld.so (0x00007fb7a9e60000)
libc.so.6 => /lib64/libc.so.6 (0x00007fb7a9a8e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb7aa266000)
[root@localhost testc]# ./haha
hello world.
[root@localhost testc]# export LD_LIBRARY_PATH= && echo $LD_LIBRARY_PATH # 将-lworld 替换为 -Wl,-rpath-link=. ,编译OK,依然找不到索引库,添加LD_LIBRARY_PATH后,执行OK
[root@localhost testc]# gcc -o haha test.c -lhello -L. -Wl,-rpath-link=.
[root@localhost testc]# ldd haha
linux-vdso.so.1 => (0x00007ffdf67c0000)
libhello.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007fbdbb94b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fbdbbd1f000)
[root@localhost testc]# ./haha
./haha: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
[root@localhost testc]# export LD_LIBRARY_PATH=/home/testc && echo $LD_LIBRARY_PATH
/home/testc
[root@localhost testc]# ldd haha
linux-vdso.so.1 => (0x00007fff89504000)
libhello.so => /home/testc/libhello.so (0x00007fc9e75c6000)
libc.so.6 => /lib64/libc.so.6 (0x00007fc9e71f3000)
libworld.so => /home/testc/libworld.so (0x00007fc9e6ff1000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc9e77c9000)
[root@localhost testc]# ./haha
hello world.
[root@localhost testc]# export LD_LIBRARY_PATH= && echo $LD_LIBRARY_PATH # 将-Wl,-rpath-link=. 换成 -Wl,-rpath=. 编译OK, 查看链接库OK,执行OK
# 修改LD_LIBRARY_PATH后,链接库的位置没有变化
[root@localhost testc]# gcc -o haha test.c -lhello -L. -Wl,-rpath=.
[root@localhost testc]# ls
haha hello.c libhello.so libworld.so test.c world.c
[root@localhost testc]# ldd haha
linux-vdso.so.1 => (0x00007fff86195000)
libhello.so => ./libhello.so (0x00007f4c11254000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4c10e81000)
libworld.so => ./libworld.so (0x00007f4c10c7f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4c11457000)
[root@localhost testc]# ./haha
hello world.
[root@localhost testc]# export LD_LIBRARY_PATH=/home/testc/ && echo $LD_LIBRARY_PATH
/home/testc/
[root@localhost testc]# ldd haha
linux-vdso.so.1 => (0x00007ffc9f36c000)
libhello.so => ./libhello.so (0x00007f35cf07c000)
libc.so.6 => /lib64/libc.so.6 (0x00007f35ceca9000)
libworld.so => ./libworld.so (0x00007f35ceaa7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f35cf27f000)
[root@localhost testc]# export LD_LIBRARY_PATH= && echo $LD_LIBRARY_PATH

结论

  • 编译时链接库需要分为两类: 直接引用 间接引用
  • 直接引用 被源码中直接调用的库
  • 间接引用 被调用库的依赖库
  • -lxxx 指定具体的库名称,编译时需要显式指定直接引用的库名称
  • -L 指定链接库的位置,编译时需要显式指定直接引用的库位置
  • -Wl,-rpath-link ,用于编译时指定间接引用的库位置

    如果知道所有间接引用的库文件名称,并且不嫌麻烦,也可以用-lxxx显式指定每一个库(不推荐-lxxx)
  • -Wl,-rpath ,有两个作用:

    1. 用于编译时指定间接引用的库位置,作用同-Wl,-rpath-link

    2. 用于运行时指定所有引用库的位置,作用同修改环境变量(LD_LIBRARY_PATH),并且库路径引用优先级高于LD_LIBRARY_PATH
  • 使用建议

    1. 编译命令中使用-Wl,-rpath-link 指定间接引用库位置(编译时),使用-Wl,-rpath 指定引用库位置(运行时)

    2. -Wl,-rpath-link 在 -Wl,-rpath 前

-L -Wl,-rpath-link -Wl,-rpath区别精讲的更多相关文章

  1. GCC 中 -L、-rpath和-rpath-link的区别

    GCC 中 -L.-rpath和-rpath-link的区别 来源 http://blog.csdn.net/q1302182594/article/details/42102961 关于这3个参数的 ...

  2. -L、-rpath和-rpath-link的区别

    链接器ld的选项有 -L,-rpath 和 -rpath-link,看了下 man ld,大致是这个意思: -L::  “链接”的时候去找的目录,也就是所有的 -lFOO 选项里的库,都会先从 -L ...

  3. css link和@import区别

    1.link语法结构 <link href="CSSurl路径" rel="stylesheet" type="text/css" / ...

  4. css link和@import区别用法

    这里link与@import介绍的是html引入css的语法单词.两者均是引入css到html的单词. 1.link语法结构<link rel="stylesheet" ty ...

  5. css学习--inline-block详解及dispaly:inline inline-block block 三者区别精要概括

    *知识储备: 内联元素:是不可以控制宽和高.margin等:并且在同一行显示,不换行. 块级元素:是可以控制宽和高.margin等,并且会换行. 1.inline-block 详解 (1)一句话就是在 ...

  6. 第三百四十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—craw母版l创建自动爬虫文件—以及 scrapy item loader机制

    第三百四十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—craw母版l创建自动爬虫文件—以及 scrapy item loader机制 用命令创建自动爬虫文件 创建爬虫文件是根据scrap ...

  7. 引入css文件时,css link和@import区别

    这里link与@import介绍的是html引入css的语法单词.两者均是引入css到html的单词. 一.了解基本 1.link语法结构 <link href="CSSurl路径&q ...

  8. Linux实战教学笔记12:linux三剑客之sed命令精讲

    第十二节 linux三剑客之sed命令精讲 标签(空格分隔): Linux实战教学笔记-陈思齐 ---更多资料点我查看 1,前言 我们都知道,在Linux中一切皆文件,比如配置文件,日志文件,启动文件 ...

  9. (转)不看绝对后悔的Linux三剑客之grep实战精讲

    不看绝对后悔的Linux三剑客之grep实战精讲 原文:http://blog.51cto.com/hujiangtao/1923675 https://www.cnblogs.com/peida/a ...

随机推荐

  1. Idea 快捷键大全【转】

    IntelliJ Idea 常用快捷键列表 Ctrl+Shift + Enter,语句完成“!”,否定完成,输入表达式时按 “!”键Ctrl+E,最近的文件Ctrl+Shift+E,最近更改的文件Sh ...

  2. 实验吧Crypto题目Writeup

    这大概是一篇不怎么更新的没什么用的网上已经有了很多差不多的东西的博客. 变异凯撒 忘记了2333 传统知识+古典密码 先查百度百科,把年份变成数字,然后猜测+甲子的意思,一开始以为是加1,后来意识到是 ...

  3. 理解android中ListFragment和Loader

    一直以来不知Android中Loader怎么用,今天晚上特意花了时间来研究,算是基本上搞明白了,现在把相关的注释和代码发出来,以便笔记和给网友一个参考,错误之处还望大家给我留言,共同进步,这个例子采用 ...

  4. try catch 一点小记录

    这两天做了新的需求,做完之后 在测试环境下 完美通关.之后部署到了预发布环境,然而怎么尝试都不通过.刚开始看到 预发布的一个配置文件错了.发邮件改了下,但是依然流程跑不通.之后 一步步在测试环境看代码 ...

  5. hibernate简单入门教程(一)---------基本配置

    应用级别所以很粗浅 首先介绍一下hibernate框架: 1.优秀的持久化(通俗讲把内存上的短时间运行信息存储在持久化硬盘上)框架. 2.作用于持久层,因为没什么侵入性,所以同样适用于其他层面上的存储 ...

  6. Android开发精彩博文收藏——UI界面类

    本文收集整理Android开发中关于UI界面的相关精华博文,共大家参考!本文不定期更新! 1. Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各 ...

  7. django导入/导出原始数据

    1.使用dumpdata命令导出指定app对应数据库中的数据: python manage.py dumpdata your_app --indent 4  > your_app/fixture ...

  8. Effective C++(1-2) 编译器替换预处理器

    1 C++最主要的四部分: C Object-Oriented C++: 面向对象 Template C++:泛型编程 STL C++高效编程守则视状况而变化,取决于你使用C++的哪一部分. 2 尽量 ...

  9. python面向对象编程(1)——基本概念,术语,self,构造器

    1  python面向对象命名规范 类名通常由大写字母打头.这是惯例标准. 数据值应该使用名词作为名字,方法使用动词加对象的方式,若使用混合记法,则方法名的第一个字母首字母小写,后面的单词的首字母大写 ...

  10. 【解决方案】[XCUITest] WDA is not listening at 'http://localhost:8100/'

    1. 使用Xcode 编译 WebDriver 发现端口为:serverurlhere->http://手机ip:0 <-serverurlhere 2. 解决方案: xcodebuild ...