当前位置: 首页 > news >正文

理清gcc、libc、libstdc++的关系

当你在linux下写C/C++代码的时候,是不是会遇到许多编译链接的问题? 时不时报个glibc,gcc,g++等相关的错误? 很多时候都无从下手,而且比较混乱。 这也是编译链接过程中经常出现的问题。

这篇文章不是去介绍如何编译链接,而是理清编译链接过程中碰到的一些概念和出现的问题。尤其是,libc,glib,glibc,eglibc,libc++,libstdc++,gcc,g++。

从libc说起。
libc是Linux下原来的标准C库,也就是当初写hello world时包含的头文件#include < stdio.h> 定义的地方。

后来逐渐被glibc取代,也就是传说中的GNU C Library,在此之前除了有libc,还有klibc,uclibc。现在只要知道用的最多的是glibc就行了,主流的一些linux操作系统如 Debian, Ubuntu,Redhat等用的都是glibc(或者其变种,下面会说到).

那glibc都做了些什么呢? glibc是Linux系统中最底层的API,几乎其它任何的运行库都要依赖glibc。 glibc最主要的功能就是对系统调用的封装,你想想看,你怎么能在C代码中直接用fopen函数就能打开文件? 打开文件最终还是要触发系统中的sys_open系统调用,而这中间的处理过程都是glibc来完成的。这篇文章详细介绍了glibc是如何与上层应用程序和系统调用交互的。除了封装系统调用,glibc自身也提供了一些上层应用函数必要的功能,如string,malloc,stdlib,linuxthreads,locale,signal等等。

好了,那eglibc又是什么? 这里的e是Embedded的意思,也就是前面说到的变种glibc。eglibc的主要特性是为了更好的支持嵌入式架构,可以支持不同的shell(包括嵌入式),但它是二进制兼容glibc的,就是说如果你的代码之前依赖eglibc库,那么换成glibc后也不需要重新编译。ubuntu系统用的就是eglibc(而不是glibc),不信,你执行 ldd –version 或者 /lib/i386-linux-gnu/libc.so.6
(64位系统运行/lib/x86_64-linux-gnu)看看,便会显示你系统中eglibc/glibc的版本信息。 这里提到了libc.so.6,这个文件就是eglibc/glibc编译后的生成库文件。

还有一个glib看起来也很相似,那它又是什么呢?glib也是个c程序库,不过比较轻量级glib将C语言中的数据类型统一封装成自己的数据类型,提供了C语言常用的数据结构的定义以及处理函数,有趣的宏以及可移植的封装等(注:glib是可移植的,说明你可以在linux下,也可以在windows下使用它)。那它跟glibc有什么关系吗?其实并没有,除非你的程序代码会用到glib库中的数据结构或者函数,glib库在ubuntu系统中并不会默认安装(可以通过apt-get install libglib2.0-dev手动安装),著名的GTK+和Gnome底层用的都是glib库。想更详细了解glib? 可以参考这里

看到这里,你应该知道这些库有多重要了吧? 你写的C代码在编译的过程中有可能出现明明是这些库里面定义的变,却量还会出现’Undefined’, ‘Unreference’等错误,这时候你可能会怀疑是不是这些库出问题了? 是不是该动手换个gilbc/eglibc了? 这里强调一点,在你准备更换/升级这些库之前,你应该好好思考一下,你真的要更换/升级吗?你要知道你自己在做什么!你要时刻知道glibc/eglibc的影响有多大,不管你之前部署的什么程序,linux系统的ls,cd,mv,ps等等全都得依赖它,很多人在更换/升级都有过惨痛的教训,甚至让整个系统奔溃无法启动。所以,强烈不建议更换/升级这些库!

当然如果你写的是C++代码,还有两个库也要非常重视了,libc++/libstdc++,这两个库有关系吗?有。两个都是C++标准库libc++库是针对clang编译器特别重写的C++标准库,那libstdc++库自然就是gcc编译器的事儿了。libstdc++与gcc的关系就像clang与libc++. 其中的区别这里不作详细介绍了。

再说说libstdc++,glibc的关系。 libstdc++与gcc是捆绑在一起的,也就是说安装gcc的时候会把libstdc++装上。 那为什么glibc和gcc没有捆绑在一起呢?
相比glibc,libstdc++虽然提供了c++程序的标准库,但它并不与内核打交道。对于系统级别的事件,libstdc++首先是会与glibc交互,才能和内核通信。相比glibc来说,libstdc++就显得没那么基础了。

说完了这些库,这些库最终都是拿来干嘛的?当然是要将它们与你的程序链接在一起! 这时候就不得不说说gcc了(当然还有前文提到的clang以及llvm等编译器,本文就不细说它们的区别了)。

你写的C代码.c文件通过gcc首先转化为汇编.S文件,之后汇编器as将.S文件转化为机器代码.o文件,生成的.o文件再与其它.o文件,或者之前提到的libc.so.6库文件通过ld链接器链接在一块生成可执行文件。当然,在你编译代码使用gcc的时候,gcc命令已经帮你把这些细节全部做好了。

那g++是做什么的? 慢慢说来,不要以为gcc只能编译C代码,g++只能编译c++代码。 后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序;后缀为.cpp的,两者都会认为是c++程序,注意,虽然c++是c的超集,但是两者对语法的要求是有区别的。在编译阶段,g++会调用gcc,对于c++代码,两者是等价的,但是因为gcc命令不能自动和C++程序使用的库联接,需要这样,gcc -lstdc++, 所以如果你的Makefile文件并没有手动加上libstdc++库,一般就会提示错误,要求你安装g++编译器了。

好了,就说到这,理清这些库与编译器之间的关系,相信会对你解决编译链接过程中遇到的错误起到一点帮助。

如果你的编译器不支持一些新的C/C++特性,想升级gcc/g++, 这里也给出一个基于ubuntu系统的参考方法。

添加ppa

sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update

添加ppa,是因为你所用的ubuntu版本的更新源中可能并没有你想要的gcc/g++版本。

安装新版gcc/g++

sudo apt-get install gcc-4.8
sudo apt-get install g++-4.8

可以到/usr/bin/gcc查看新安装的gcc,g++

配置系统gcc/g++

使用update-alternatives,统一更新gcc/g++

sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.6
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 80 --slave /usr/bin/g++ g++ /usr/bin/g++-4.8
sudo update-alternatives --config gcc

数字优先级(如60,80)高的会被系统选择为默认的编译器,也可以执行第三条命令就是来手动配置系统的gcc,此处按照提示,选择4.8版本的即可。

相关文章:

  • gcc/g++/clang/cl编译器
  • 深入浅出让你理解什么是LLVM
  • Ninja - chromium核心构建工具
  • depot_tools
  • 智能指针 unique_ptr 详解
  • C++11中“= delete;“的使用
  • C++Error2208:...尝试引用已删除的函数
  • Ninja 构建系统
  • ICU
  • 交叉编译详解
  • GYP,GN和Ninja
  • Visual C++ 新增功能(2003 - 2015)
  • v8引擎编译全记录2021-2-23
  • c++ mutex
  • windows标准控件的介绍与使用
  • 【Leetcode】101. 对称二叉树
  • ES6简单总结(搭配简单的讲解和小案例)
  • es6要点
  • isset在php5.6-和php7.0+的一些差异
  • JavaScript新鲜事·第5期
  • Java新版本的开发已正式进入轨道,版本号18.3
  • js继承的实现方法
  • JS学习笔记——闭包
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • LeetCode刷题——29. Divide Two Integers(Part 1靠自己)
  • spring学习第二天
  • Vue ES6 Jade Scss Webpack Gulp
  • 编写高质量JavaScript代码之并发
  • 好的网址,关于.net 4.0 ,vs 2010
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 解析 Webpack中import、require、按需加载的执行过程
  • 聚簇索引和非聚簇索引
  • 前嗅ForeSpider教程:创建模板
  • 让你的分享飞起来——极光推出社会化分享组件
  • 深度学习在携程攻略社区的应用
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 源码安装memcached和php memcache扩展
  • Spring Batch JSON 支持
  • # 达梦数据库知识点
  • #QT(串口助手-界面)
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (1)(1.13) SiK无线电高级配置(六)
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (done) 两个矩阵 “相似” 是什么意思?
  • (MATLAB)第五章-矩阵运算
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .mysql secret在哪_MySQL如何使用索引
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .NET Core引入性能分析引导优化
  • .NET Remoting学习笔记(三)信道