1.库的分类

根据链接时期的不同,库又有静态库和动态库之分。

静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行。

有别于静态库,动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序运行时调用。(TODO:链接动态库时链接阶段到底做了什么)

2 静态库和动态库的比较

链接静态库其实从某种意义上来说也是一种粘贴复制,只不过它操作的对象是目标代码而不是源码而已。因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题。

首先就是系统空间被浪费了。这是显而易见的,想象一下,如果多个程序链接了同一个库,则每一个生成的可执行文件就都会有一个库的副本,必然会浪费系统空间。

再者,人非圣贤,即使是精心调试的库,也难免会有错。一旦发现了库中有bug,挽救起来就比较麻烦了。必须一一把链接该库的程序找出来,然后重新编译。

而动态库的出现正弥补了静态库的以上弊端。因为动态库是在程序运行时被链接的,所以磁盘上只须保留一份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。

那么,是不是静态库就一无是处了呢?

答曰:非也非也。不是有句话么:存在即是合理。静态库既然没有湮没在滔滔的历史长河中,就必然有它的用武之地。想象一下这样的情况:如果你用libpcap库编了一个程序,要给被人运行,而他的系统上没有装pcap库,该怎么解决呢?最简单的办法就是编译该程序时把所有要链接的库都链接它们的静态库,这样,就可以在别人的系统上直接运行该程序了。

所谓有得必有失,正因为动态库在程序运行时被链接,故程序的运行速度和链接静态库的版本相比必然会打折扣。然而瑕不掩瑜,动态库的不足相对于它带来的好处在现今硬件下简直是微不足道的,所以链接程序在链接时一般是优先链接动态库的,除非用-static参数指定链接静态库。

gcc作为编译工具,用在Linux操作系统中,可以编译C、C++、Object-C、JAVA等语言。编译过程中可以带编译选项,选择编译过程。
 
一、GCC编译流程
1)预处理 Pre-Processing
2)编译 Compiling
3)汇编 Assembling
4)链接 Linking
 
 
二、GCC编译选项

1、gcc总体选项列表

1) -c :指编译,不链接,生成目标文件“.o”。
2) -S :只编译,不汇编,生成汇编代码“.S”。
3) -E :只进行预编译/预处理,不做其他处理。
4) -o file:把输出文件输出到file里。
5) -g :在可执行程序中包含标准调试信息。
6) -v :打印出编译器内部编译各过程的命令行信息和编译器的版本。
7) -I dir :在头文件的搜索路径列表中添加dir目录
8) -L dir :在库文件的搜索路径列表中添加dir目录
9) -static :连接静态库(静态库也可以用动态库链接方式链接)
10) -llibrary :连接名为library的库文件(显示指定需要链接的动态库文件)

2、gcc告警和出错选项
1) -ansi :支持符合ANSI标准的C程序
2) -pedantic :允许发出ANSI C标准所列出的全部警告信息
3) -pedantic-error :允许发出ANSI C标准所列出的全部错误信息
4) -w :关闭所有警告
5) -Wall :允许发出gcc提供的所有有用的报警信息
6) -werror :把所有的告警信息转化为错误信息,并在告警发生时终止编译过程

3、gcc优化选项
gcc可以对代码进行优化,它通过编译选项“-On”来控制优化代码的生成,其中n是一个代表优化级别的整数。对于不同版本的gcc,
n的取值范围不一致,比较典型的范围为0变化到2或者3。
虽然优化选项可以加速代码的运行速度,但对于调试而言将是一个很大的挑战。因为代码在经过优化之后,原先在源程序中声明和使用
的变量很可能不再使用,控制流也可能会突然跳转到意外的地方,循环语句也可能因为循环展开而变得到处都有。

 
三、GCC生成动态库和静态库
 
1)动态库生成
1.单个源文件/目标直接生成动态库

a.
gcc -fPIC -shared xxx.c -o libxxx.so
b.
gcc -fPIC -shared xxx.o -o libxxx.so

2.多个源文件/目标生成动态库

a.
gcc -fPIC -shared xxx1.c xxx2.c xxx3.c -o libxxx.so
b.
gcc -fPIC -shared xxx1.o xxx2.o xxx3.o -o libxxx.so

2)静态库生成
1.单个源文件/目标直接生成静态库

a.
ar -rc libxxx.a xxx.o(正确方法)
b. ar -rc libxxx.a xxx.c (静态库可以生成;当运行连接了该静态库的可执行程序会报错:could not read symbols:Archive has no index;run ranlib
to add one)

2.多个源文件/目标生成静态库

a.
ar -rc libxxx.a xxx1.o xxx2.o xxx3.o (正确方法)
b.
ar -rc libxxx.a xxx1.c xxx2.c xxx3.c (静态库可以生成;当运行连接了该静态库的可执行程序会报错:could not read symbols:Archive has no index;run ranlib to add one)

四、多个源文件生成一个可执行文件

gcc xxx1.c xxx2.c xxx3.c xxx4.c main.c -o main

实例

一、动态链接库

1.创建hello.so动态库

  1. #include <stdio.h>
  2. void hello(){
  3. printf("hello world\n");
  4. }
  5. 编译:gcc -fPIC -shared hello.c -o libhello.so

2.hello.h头文件

  1. void hello();

3.链接动态库

  1. #include <stdio.h>
  2. #include "hello.h"
  3. int main(){
  4. printf("call hello()");
  5. hello();
  6. }
  7. 编译:gcc main.c -L. -lhello -o main

这里-L的选项是指定编译器在搜索动态库时搜索的路径,告诉编译器hello库的位置。"."意思是当前路径.

3.编译成够后执行./main,会提示:

  1. In function `main':
  2. main.c:(.text+0x1d): undefined reference to `hello'
  3. collect2: ld returned 1 exit status

这是因为在链接hello动态库时,编译器没有找到。
解决方法:

  1. sudo cp libhello.so /usr/lib/

这样,再次执行就成功输入:
call hello()

二、静态库

文件有:main.c、hello.c、hello.h
1.编译静态库hello.o:

  1. gcc hello.c -o hello.o  #这里没有使用-shared

2.把目标文档归档

  1. ar -r libhello.a hello.o  #这里的ar相当于tar的作用,将多个目标打包。

程序ar配合参数-r创建一个新库libhello.a,并将命令行中列出的文件打包入其中。这种方法,如果libhello.a已经存在,将会覆盖现在文件,否则将新创建。

3.链接静态库

  1. gcc main.c -lhello -L. -static -o main

这里的-static选项是告诉编译器,hello是静态库。
或者:

  1. gcc main.c libhello.a -L. -o main

这样就可以不用加-static

4.执行./main

输出:call hello()

makefile实例

 

1. 静态库的生成

makefile命令的简介可参考:跟我一起写 Makefile。使用ar命令生成.a文件,可参考:Linux下动态库(.so)和静态库(.a)

# 1、准备工作,编译方式、目标文件名、依赖库路径的定义。
CC = g++
CFLAGS := -Wall -O3 -std=c++0x # opencv 头文件和lib路径
OPENCV_INC_ROOT = /usr/local/include/opencv
OPENCV_LIB_ROOT = /usr/local/lib OBJS = GenDll.o #.o文件与.cpp文件同名
LIB = libgendll.a # 目标文件名 OPENCV_INC= -I $(OPENCV_INC_ROOT) INCLUDE_PATH = $(OPENCV_INC) LIB_PATH = -L $(OPENCV_LIB_ROOT) # 依赖的lib名称
OPENCV_LIB = -lopencv_objdetect -lopencv_core -lopencv_highgui -lopencv_imgproc all : $(LIB) # 2. 生成.o文件
%.o : %.cpp
$(CC) $(CFLAGS) -c $< -o $@ $(INCLUDE_PATH) $(LIB_PATH) $(OPENCV_LIB) # 3. 生成静态库文件
$(LIB) : $(OBJS)
rm -f $@
ar cr $@ $(OBJS)
rm -f $(OBJS) tags :
ctags -R * # 4. 删除中间过程生成的文件
clean:
rm -f $(OBJS) $(TARGET) $(LIB)

2. 动态库的生成

第1、4步准备和收尾工作与静态库的保持一致,第2步和第3步所使用的命令稍有不同。

# 1、准备工作,编译方式、目标文件名、依赖库路径的定义。
CC = g++
CFLAGS := -Wall -O3 -std=c++0x # opencv 头文件和lib路径
OPENCV_INC_ROOT = /usr/local/include/opencv
OPENCV_LIB_ROOT = /usr/local/lib OBJS = GenDll.o #.o文件与.cpp文件同名
LIB = libgendll.so # 目标文件名 OPENCV_INC= -I $(OPENCV_INC_ROOT) INCLUDE_PATH = $(OPENCV_INC) LIB_PATH = -L $(OPENCV_LIB_ROOT) # 依赖的lib名称
OPENCV_LIB = -lopencv_objdetect -lopencv_core -lopencv_highgui -lopencv_imgproc all : $(LIB) # 2. 生成.o文件
%.o : %.cpp
$(CC) $(CFLAGS) -fpic -c $< -o $@ $(INCLUDE_PATH) $(LIB_PATH) $(OPENCV_LIB) # 3. 生成动态库文件
$(LIB) : $(OBJS)
rm -f $@
g++ -shared -o $@ $(OBJS)
rm -f $(OBJS) tags :
ctags -R * # 4. 删除中间过程生成的文件
clean:
rm -f $(OBJS) $(TARGET) $(LIB)

-fpic 和 -shared 命令可参考:Linux下动态库(.so)和静态库(.a)【注】这篇文章说可以使用ld命令生成.so文件,但我在测试时发会报错。

3. 动态库和静态库的调用

, 这两个的使用方法几乎没有区别。动态库的引用有显式和隐式两种,这里只说隐式调用。我使用main.cpp来测试生成的库文件, makefile如下:

CC = g++
CFLAGS := -Wall -O3 -std=c++0x OPENCV_INC_ROOT = /usr/local/include/opencv
OPENCV_LIB_ROOT = /usr/local/lib
MY_ROOT = ../ OPENCV_INC= -I $(OPENCV_INC_ROOT)
MY_INC = -I $(MY_ROOT) EXT_INC = $(OPENCV_INC) $(MY_INC) OPENCV_LIB_PATH = -L $(OPENCV_LIB_ROOT)
MY_LIB_PATH = -L $(MY_ROOT) EXT_LIB = $(OPENCV_LIB_PATH) $(MY_LIB_PATH) OPENCV_LIB_NAME = -lopencv_objdetect -lopencv_highgui -lopencv_imgproc -lopencv_core
MY_LIB_NAME = -lgendll all:test test:main.cpp
$(CC) $(CFLAGS) main.cpp $(EXT_INC) $(EXT_LIB) $(MY_LIB_NAME) $(OPENCV_LIB_NAME) -o test

4. 注意事项:

1、在测试过程中,经常会报错:找不到.so文件。一种简单的解决方法如下: 
在linux终端输入如下命令:

export LD_LIBRARY_PATH=/home/shaoxiaohu/lib:LD_LIBRARY_PATH:

gcc编译工具生成动态库和静态库之一----介绍的更多相关文章

  1. gcc编译工具生成动态库和静态库

    一. 库的分类 1.1. 静态库(.a) 1.1.1. 静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大.所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 1. ...

  2. GCC 指令详解及动态库、静态库的使用

    GCC 指令详解及动态库.静态库的使用 一.GCC 1.1 GCC 介绍 GCC 是 Linux 下的编译工具集,是「GNU Compiler Collection」的缩写,包含 gcc.g++ 等编 ...

  3. 如何使用GCC生成动态库和静态库

    根据链接时期的不同,库又有静态库和动态库之分.静态库是在链接阶段被链接的,所以生成的可执行文件就不受库的影响,即使库被删除,程序依然可以成功运行.而动态库是在程序执行的时候被链接的.程序执行完,库仍需 ...

  4. gcc 编译动态库和静态库

    Linux C 编程入门之一:gcc 编译动态库和静态库 cheungmine 2012 参考: C程序编译过程浅析 http://blog.csdn.net/koudaidai/article/de ...

  5. 【C++】如何使用GCC生成动态库和静态库

    一.静态库和动态库的定义及区别 程序编译的四个过程: 1.预处理  展开头文件/宏替换/去掉注释/条件编译(.i后缀) 2.编译    检查语法,生成汇编(.s后缀) 3.汇编    汇编代码转换成机 ...

  6. 动态库与静态库的学习 博主写的很好 静态库 编译的时候 需要加上 static 动态库编译ok运行不成功就按照文章中的方法修改

    来源连接   http://www.cnblogs.com/skynet/p/3372855.html C++静态库与动态库 这次分享的宗旨是--让大家学会创建与使用静态库.动态库,知道静态库与动态库 ...

  7. Linux下动态库和静态库的生成和使用

    1.准备头文件和源文件 hello.h #ifndef HELLO_H #define HELLO_H void hello(const char *name): #endif hello.c #in ...

  8. Linux环境编译动态库和静态库总结

    对Linux环境动态库和静态库的一些基础知识做一些总结, 首先总结静态库的编译步骤. 1 先基于.cpp或者.c文件生成对应的.o文件 2将几个.o文件 使用ar -cr命令 生成libname.a文 ...

  9. 自己在linux上编译、链接、动态库和静态库的学习笔记

    在平常的项目中,我们都是使用公司要求的makefile.makedebug一类的文件,因此,在编译.链接.生成和链接动态库与静态库的时候,我们只是简单的使用一些已经设置的变量,只是简单的修改.添加一些 ...

随机推荐

  1. 20155208徐子涵 2016-2017-2 《Java程序设计》第8周学习总结

    20155208徐子涵 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 第14章 NIO与NIO2 14.1 认识NIO NIO概述 NIO使用频道(Chan ...

  2. (11)模板语言-if判断

    views.py from django.shortcuts import render,HttpResponse # Create your views here. def index(reques ...

  3. Spring Cloud 微服务实战

    Eureka 服务治理 Maven dependency 与spring boot的版本的对应 Finchley兼容Spring Boot 2.0.x,不兼容Spring Boot 1.5.x Dal ...

  4. js framework comparation

    starting a new project:(finance project for p2p -- like lending club, or prosper ) ,we considering a ...

  5. prufer数列

    涨姿势---prufer数列 一. 简介 Prufer数列是无根树的一种数列.在组合数学中,Prufer数列由有一个对于顶点标过号的树转化来的数列,点数为n的树转化来的Prufer数列长度为n-2.它 ...

  6. PyMongo 常见问题

    PyMongo是线程安全的吗PyMongo是线程安全的,并且为多线程应用提供了内置的连接池 PyMongo是进程安全的吗PyMongo不是进程安全的,如果你在fork()中使用MongoClient实 ...

  7. curl常用传参方式

    1.传header参数curl --header 'Token:40d7c342c110414888cc2a0e1284c636' "127.0.0.1/api/user/baseInfo& ...

  8. linux下PHP手动添加扩展库

    1.进入php源程序目录中的ext目录中,这里存放着各个扩展模块的源代码,选择你需要的模块,比如curl模块: cd curl 执行phpize生成编译文件,phpize在PHP安装目录的bin目录下 ...

  9. 你不知道的JavaScript(中卷) (Kyle Simpson 著)

    第一部分 类型和语法 第1章 类型 1.1 类型 1.2 内置类型 1.3 值和类型 1.3.1 undefined和undeclared 1.3.2 typeof Undeclared 1.4 小结 ...

  10. SWF 文件不能本地访问 只有仅限于文件系统的 SWF 文件

    http://blog.163.com/vituk93@126/blog/static/1709580342012512112757505/ SWF 文件不能被本地访问 不能访问本地 只有仅限于文件系 ...