GCC 动态与静态链接的编译

合集下载

静态库和动态库编译

静态库和动态库编译

静态库和动态库编译静态库和动态库是编程中常用的两种库文件形式,本文将介绍它们的编译过程和使用方法。

1. 静态库编译静态库是一种在编译时被链接到程序中的库文件,它包含了程序所依赖的所有函数和数据结构,因此程序在运行时不需要再加载库文件。

静态库的编译过程包括以下步骤:(1)创建一个或多个源文件,使用编译器将它们编译成目标文件(.o 或 .obj)。

(2)将多个目标文件打包成一个静态库文件,通常使用 ar 工具完成此操作。

例如,在 Linux 系统下,可以使用以下命令创建名为 libfoo.a 的静态库文件:$ ar rcs libfoo.a foo1.o foo2.o ...其中,rcs 参数分别表示创建、向库文件中添加目标文件和生成索引表。

(3)在编译器中使用静态库,需要将其链接到目标程序中。

在Linux 系统下,可以使用以下命令编译名为 main.c 的源文件和名为libfoo.a 的静态库文件:$ gcc -o main main.c -L. -lfoo其中,-L 参数指定库文件搜索路径,. 表示当前目录;-l 参数指定链接库文件,实际上是将其前缀 lib 和后缀 .a 去掉,即 foo。

2. 动态库编译动态库是一种在程序运行时动态加载的库文件,它只包含程序所需要的部分函数和数据结构,因此可以减小程序的尺寸和加载时间。

动态库的编译过程包括以下步骤:(1)创建一个或多个源文件,使用编译器将它们编译成目标文件。

(2)将多个目标文件打包成一个共享库文件,通常使用 ld 或链接器完成此操作。

例如,在 Linux 系统下,可以使用以下命令创建名为 libfoo.so 的动态库文件:$ gcc -shared -o libfoo.so foo1.o foo2.o ...其中,-shared 参数表示生成共享库文件。

(3)在编译器中使用动态库,需要将其链接到目标程序中。

在Linux 系统下,可以使用以下命令编译名为 main.c 的源文件和名为libfoo.so 的动态库文件:$ gcc -o main main.c -L. -lfoo其中,-L 和 -l 参数的含义同静态库。

gccstatic静态编译选项提示错误:usrlibld:cannotfind-lc

gccstatic静态编译选项提示错误:usrlibld:cannotfind-lc

gccstatic静态编译选项提⽰错误:usrlibld:cannotfind-lc 在学习gcc静态库动态库编译的时候选⽤静态库编译时出错显⽰:/usr/lib/ld:cannot find -lc百度:/usr/lib/ld:cannot find -lc多处给的解决⽅案为:然⽽并不能解决问题,最终定位发现是静态编译的问题。

⽽且不⽌会出现这种情况:/usr/lib/ld:cannot find -lc/usr/lib/ld:cannot find -lgcc_s/usr/lib/ld:cannot find -lm等的错误,主要原因在静态编译时需要链接静调库。

如上命令:[xiaohexiansheng@centos6 app]$ gcc -static -I./libs main.c -o app -L./libs -lcrypto -lfunc如果在编译时去掉-static选项选⽤动态库编译则不会出现此种情况[xiaohexiansheng@centos6 app]$ gcc -I./libs main.c -o app -L./libs -lcrypto -lfunc[xiaohexiansheng@centos6 app]$ lsapp libs main.c⾮静态编译时ldd filename,显⽰如下,这是可执⾏程序所需的动态库,运⾏可执⾏程序时需要的动态库。

[xiaohexiansheng@centos6 app]$ ldd applinux-gate.so.1 => (0x004ad000)libcrypto.so => /usr/lib/libcrypto.so (0x03ad9000)libfunc.so => not foundlibc.so.6 => /lib/libc.so.6 (0x0052a000)libdl.so.2 => /lib/libdl.so.2 (0x0070c000)libz.so.1 => /lib/libz.so.1 (0x00713000)/lib/ld-linux.so.2 (0x00508000)静态编译时需要将所有的.a库链接到可执⾏⽂件中,所以需要libc静态库⽂件,在系统找查找glibc-static提⽰没有库⽂件。

c语言中库的定义等相关概念 -回复

c语言中库的定义等相关概念 -回复

c语言中库的定义等相关概念-回复C语言中的库(Library)是指一组预先编写好的可重用的代码,这些代码包含了各种功能,如输入输出、字符串处理、数学运算等。

库可以被其他程序调用,以提高开发效率和代码复用性。

本文将逐步解释库的定义,库的类型,库的使用和实现等相关概念。

定义:库是一种软件资源,其中包含了预先编写好的可重用的代码。

这些代码经过测试和优化,以提供特定功能或解决特定问题。

库可以作为单个文件或多个文件的集合提供。

C语言中的库分为两种类型:静态库和动态库。

库的类型:1. 静态库(Static Library):静态库也称为静态链接库,它在编译时被链接到可执行文件中。

静态库包含了预编译好的目标代码,这些代码可以直接在编译阶段与程序的其他模块进行链接。

静态库的优点是可移植性强,不依赖于特定的运行环境。

然而,静态库的缺点是占用磁盘空间较大,每个可执行文件都会包含一份完整的库代码。

2. 动态库(Dynamic Library):动态库也称为共享库或动态链接库,它在程序运行时被加载到内存中。

动态库的代码可以被多个程序共享,从而节省了系统资源。

动态库的优点是占用磁盘空间较小,可以在运行时动态加载和卸载。

然而,动态库的缺点是可能会导致版本兼容性问题和依赖关系管理较为复杂。

库的使用:使用库的步骤如下:1. 引入头文件(Include Header File):在需要使用库中函数或变量的源代码文件中,通过#include指令包含库的头文件。

头文件包含了库中函数和变量的声明。

示例代码如下:c#include <stdio.h>2. 链接库文件(Link Library File):在编译可执行文件时,需要将库的目标代码与程序的其他模块进行链接。

对于静态库,可以使用编译器提供的静态链接选项进行链接。

对于动态库,可以使用编译器提供的动态链接选项进行链接。

示例代码如下:gcc main.c -lmath 链接静态库gcc main.c -lmath 链接动态库3. 调用库中的函数(Call Functions):在源代码文件中,可以通过函数名直接调用库中的函数,并传递参数。

gcc编译lib

gcc编译lib

GCC编译lib简介GCC(GNU Compiler Collection)是一个开源的编程语言编译器集合,它支持多种编程语言,包括C、C++、Java、Fortran等。

在开发过程中,我们经常会使用GCC 来编译源代码,生成可执行文件。

除了编译应用程序,GCC还可以用于编译库文件(lib),供其他程序调用和链接。

本文将介绍如何使用GCC编译lib,包括编译选项的设置、库文件的生成和使用方法等。

编译选项编译lib时,我们可以根据需求设置不同的编译选项,以控制编译过程和生成的库文件的属性。

常用的编译选项有:•-c:仅编译源文件,生成目标文件(.o文件),不进行链接操作。

•-o:指定生成的目标文件名或库文件名。

•-g:生成调试信息,方便调试程序。

•-Wall:显示所有警告信息。

•-O:优化选项,可选取值为0、1、2、3,数字越大优化级别越高。

•-shared:生成共享库文件(动态链接库)。

•-static:生成静态库文件。

可以根据实际需要选择适合的编译选项。

编译库文件编译库文件需要分为静态库和动态库两种情况进行说明。

静态库静态库是在链接时被完整地复制到可执行文件中的库文件。

使用静态库的优点是可执行文件独立于系统环境,可以在没有安装库文件的系统上运行,但可执行文件的体积较大。

编译静态库的步骤如下:1.编写源代码文件(例如example.c):#include <stdio.h>void hello() {printf("Hello, World!\n");}2.使用GCC编译源代码文件,生成目标文件(.o文件):gcc -c example.c -o example.o3.使用GCC将目标文件打包成静态库文件(.a文件):ar rcs libexample.a example.o其中,ar命令用于创建、修改和提取静态库文件,rcs选项分别表示创建库文件、添加目标文件和生成索引。

gcc编译c文件的几个过程

gcc编译c文件的几个过程

gcc编译c⽂件的⼏个过程https:///zhangpengshou/p/3587751.html/article/663750.htmlhttps:///LiuYanYGZ/p/5548855.htmlhttps:///qq_33160790/article/details/78887349c语⾔编译分为4个过程:1:预编译:预编译做的事情为:把伪指令转换为实际指令 命令 gcc -E a:#define a b b:#条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等 c:#include 头⽂件加⼊到编译的⽂件中 d:⼀些符号处理如file local 等等;# 1"/usr/lib/gcc/x86_64-redhat-linux/4.4.7/include/stddef.h"134# 211"/usr/lib/gcc/x86_64-redhat-linux/4.4.7/include/stddef.h"34typedef long unsigned int size_t;# 35"/usr/include/stdio.h"234# 1"/usr/include/bits/types.h"134# 28"/usr/include/bits/types.h"34# 1"/usr/include/bits/wordsize.h"134# 29"/usr/include/bits/types.h"234typedef unsigned char __u_char;typedef unsigned short int __u_short;typedef unsigned int __u_int;typedef unsigned long int __u_long;typedef signed char __int8_t;typedef unsigned char __uint8_t;typedef signed short int __int16_t;typedef unsigned short int __uint16_t;typedef signed int __int32_t;typedef unsigned int __uint32_t;typedef signed long int __int64_t;typedef unsigned long int __uint64_t;可以看出⼀个很⼩的程序经过编译以后把所有的头⽂件包含进来都是很⼤的2:编译 命令是 gcc -S 把预编译好的⽂件逐条转化为汇编语⾔ 优化阶段,经过预编译得到的输出⽂件中,只有常量;如数字、字符串、变量的定义, 以及c语⾔的关键字,如main,if,else,for,while,{,}, +,-,*,\等等。

gcc 编译指令

gcc 编译指令

gcc 编译指令
GCC(GNU Compiler Collection)是一个开源的编译器套件,用于编译和生成可执行文件。

它支持多种编程语言,如C、C++、Objective-C、Fortran等。

下面是一些常用的GCC编译指令:编译C源文件并生成可执行文件:
gcc source.c -o output
编译C++源文件并生成可执行文件:
g++ source.cpp -o output
指定编译优化级别(例如-O2):
gcc source.c -o output -O2
生成调试信息(用于调试程序):
gcc source.c -o output -g
链接其他库文件:
gcc source.c -o output -l library
指定包含头文件的目录:
gcc source.c -o output -I include_directory
生成位置无关代码(用于动态链接):
gcc source.c -o output -fPIC
生成静态库文件:
gcc -c source.c
ar rcs libname.a source.o
这些只是一些常用的GCC编译指令示例,GCC还支持更多的编译选项和功能。

你可以查阅GCC的官方文档或使用gcc --help命令获取更多的信息和使用方法。

gcc编译的详细步骤

gcc编译的详细步骤

gcc编译的详细步骤⼀:GCC⼀般编译建⽴hello.c# vi hello.c#include <stdlib.h>#include <stdio.h>void main(void){printf("hello world!\r\n");}⽤gcc编译成执⾏程序。

#gcc -o hello hello.c该命令将hello.c直接⽣成最终⼆进制可执⾏程序a.out这条命令隐含执⾏了(1)预处理、(2)汇编、(3)编译并(4)链接形成最终的⼆进制可执⾏程序。

这⾥未指定输出⽂件,默认输出为a.out。

如何要指定最终⼆进制可执⾏程序名,那么⽤-o选项来指定名称。

⽐如需要⽣成执⾏程序hello.exe那么#gcc hello.c -o hello.exe⼆:GCC编译详细步骤,分为四步:从上⾯我们知道GCC编译源代码⽣成最终可执⾏的⼆进制程序,GCC后台隐含执⾏了四个阶段步骤。

GCC编译C源码有四个步骤:预处理-----> 编译 ----> 汇编 ----> 链接现在我们就⽤GCC的命令选项来逐个剖析GCC过程。

1)预处理(Pre-processing)在该阶段,编译器将C源代码中的包含的头⽂件如stdio.h编译进来,⽤户可以使⽤gcc的选项”-E”进⾏查看。

⽤法:#gcc -E hello.c -o hello.i作⽤:将hello.c预处理输出hello.i⽂件。

[root]# gcc -E hello.c -o hello.i[root]# lshello.c hello.i[root]# vi hello.i# 1 "hello.c"# 1 "<built-in>"# 1 "<command line>"# 1 "hello.c"# 1 "/usr/include/stdlib.h" 1 3# 25 "/usr/include/stdlib.h" 3# 1 "/usr/include/features.h" 1 3# 291 "/usr/include/features.h" 3# 1 "/usr/include/sys/cdefs.h" 1 3# 292 "/usr/include/features.h" 2 3# 314 "/usr/include/features.h" 3# 1 "/usr/include/gnu/stubs.h" 1 3# 315 "/usr/include/features.h" 2 3# 26 "/usr/include/stdlib.h" 2 3# 3 "hello.c" 2void main(void){printf("hello world!\r\n");}2)编译阶段(Compiling)第⼆步进⾏的是编译阶段,在这个阶段中,Gcc⾸先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的⼯作,在检查⽆误后,Gcc把代码翻译成汇编语⾔。

gcc常用参数(静动态链接 优化 调试)

gcc常用参数(静动态链接 优化 调试)

一、编译过程概览gcc编译器对程序的编译过程有四个阶段:预处理(preprocessing)、编译(com- pilation proper)、汇编(assembly)和链接(linking)。

预处理:对源文件(source file)进行预处理,进行宏定义的替换等。

编译:将进行完预处理的源文件编译成汇编文件(assembly file)。

将C源代码编译成汇编语言。

汇编:将汇编文件汇编成目标文件(object file)。

链接:将一个或多个目标文件链接成一个可执行的二进制文件(execute file)。

链接的目标文件中有且只有一个main函数,作为可执行文件的开始。

-E在预处理阶段之后停止,不进行编译。

输出是预处理之后的源码,默认发送到标准输出(standard output)。

输入文件格式为.c等,默认输出为标准输出。

-S在编译阶段之后停止,不进行汇编。

输出为每一个指定的未编译的输入文件的汇编代码文件。

输入文件格式为.c、.i等,输出文件格式为.s。

-c编译或者汇编源文件,不进行链接。

输出为每一个源文件的目标文件。

输入文件格式为.c、.i、.s,输出文件格式为.o。

-o filename-o指定输出文件的文件名,如果没有指定-o,则默认输出的可执行文件名是a.out,默认输出的source.suffix的汇编文件名为source.s、目标文件名位source.o。

默认的预处理后的源文件输出到标准输出。

main.cgcc –E main.c –o main.itali main.igcc –S main.i –o main.stail main.sps:gcc –S main.c –o main.s也是可以的。

gcc –c main.s –o main.ogcc main.o –o test./testps:gcc –c main.i(main.c) –o main.ogcc main.c(main.i main.s) –o test都是可以的二、预处理预处理阶段可以用到的一些选项。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

GCC 动态链接与静态连接的编译
根据链接时期的不同,库又有静态库和动态库之分,有别于静态库,动态库的链接是在程序执行的时候被链接的。

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

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

有别于静态库,动态库的链接是在程序执行的时候被链接的。

所以,即使程序编译完,库仍须保留在系统上,以供程序运行时调用。

(TODO:链接动态库时链接阶段到底做了什么)
2 静态库和动态库的比较
链接静态库其实从某种意义上来说也是一种粘贴复制,只不过它操作的对象是目标代码而不是源码而已。

因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题。

首先就是系统空间被浪费了。

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

再者,人非圣贤,即使是精心调试的库,也难免会有错。

一旦发现了
库中有bug,挽救起来就比较麻烦了。

必须一一把链接该库的程序找出来,然后重新编译。

而动态库的出现正弥补了静态库的以上弊端。

因为动态库是在程序运行时被链接的,所以磁盘上只须保留一份副本,因此节约了磁盘空间。

如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。

那么,是不是静态库就一无是处了呢?
答曰:非也非也。

不是有句话么:存在即是合理。

静态库既然没有湮没在滔滔的历史长河中,就必然有它的用武之地。

想象一下这样的情况:如果你用libpcap库编了一个程序,要给被人运行,而他的系统上没有装pcap库,该怎么解决呢?最简单的办法就是编译该程序时把所有要链接的库都链接它们的静态库,这样,就可以在别人的系统上直接运行该程序了。

所谓有得必有失,正因为动态库在程序运行时被链接,故程序的运行速度和链接静态库的版本相比必然会打折扣。

然而瑕不掩瑜,动态库的不足相对于它带来的好处在现今硬件下简直是微不足道的,所以链接程序在链接时一般是优先链接动态库的,除非用-static参数指定链接静态库。

动态链接库
1. 创建动态链接库
代码如下:
#include<stdio.h>
void hello()
{
printf("hello world/n");
}
用命令gcc -shared hello.c -o libhello.so编译为动态库。

可以看到,当前目录下多了一个文件libhello.so。

2. 再编辑一个测试文件test.c,内容如下
代码如下:
#include<stdio.h>
int main()
{
printf("call hello()");
hello();
}
编译gcc test.c -lhello
-l 选项告诉编译器要使用hello这个库。

奇怪的地方是动态库的名字是libhello.so,这里却使用hello.
但这样还不行,编译会出错。

In function `main':
test.c:(.text+0x1d): undefined reference to `hello'
collect2: ld returned 1 exit status
这是因为hello这个库在我们自己的路径中,编译器找不到。

需要使用-L选项,告诉hello库的位置
gcc test.c -lhello -L. -o test
-L .告诉编译器在当前目录中查找库文件
3. 编译成功后执行./test, 仍然出错
说找不到库
有两种方法:
一、可以把当前路径加入/etc/ld.so.conf中然后运行ldconfig,或者以当前路径为参数运行ldconfig(要有root权限才行)。

二、把当前路径加入环境变量LD_LIBRARY_PATH中
当然,如果你觉得不会引起混乱的话,可以直接把该库拷入/lib,/usr/lib/等位置(无可避免,这样做也要有权限),这样链接器和加载器就都可以准确的找到该库了。

我们采用第二种方法:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
这样,再执行就成功了。

下面再讲讲静态链接库
仍使用刚才的hello.c和test.c。

1. gcc -c hello.c 注意这里没有使用-shared选项
2. 把目标文件归档ar -r libhello.a hello.o
程序ar 配合参数-r 创建一个新库libhello.a 并将命令行中列出的对象文件插入。

采用这种方法,如果库不存在的话,参数-r 将创建一个新的库,而如果库存在的话,将用新的模块替换原来的模块。

3. 在程序中链接静态库
gcc test.c -lhello -L. -static -o hello.static
或者gcc test.c libhello.a -L. -o hello.static
生成的hello.static就不再依赖libhello.a了
两个有用的命令
file程序是用来判断文件类型的,在file命令下,所有文件都会原形毕露的。

顺便说一个技巧。

有时在windows下用浏览器下载tar.gz或tar.bz2文件,后缀名会变成奇怪的tar.tar,到Linux有些新手就不知怎么解压了。

但Linux下的文件类型并不受文件后缀名的影响,所以我们可以先用命令file xxx.tar.tar看一下文件类型,然后用tar加适当的参数解压。

另外,还可以借助程序ldd实用程序来判断。

ldd是用来打印目标程序(由命令行参数指定)所链接的所有动态库的信息的,如果目标程序没有链接动态库,则打印“not a dynamic executable”,ldd的用法请参考manpage。

相关文档
最新文档