Unix 系列
一、编译过程
GCC :
/*步骤一:编写 .C文件 */
vi hello.c
/*步骤二:预编译头文件扩展*/
gcc -E hello.c -o hello.i
/*步骤三:编译生成汇编代码 */
gcc -S hello.i -o hello.s
/*步骤四:编译获得目标代码 */
gcc -c hello.s -o hello.o
/*步骤五:生成可执行代码*/
gcc hello.o -o hello
文件后缀 | 文件描述 |
---|---|
.h | 头文件 |
.c | 预处理的C语言源代码 |
.s | 汇编语言 |
.o | 目标文件 |
.a | 静态库文件 |
.so | 共享(动态)库文件 |
.out | 可执行文件 |
编译另外可使用:
- gcc -Wall Wall.c // 产生全部警告
- gcc -Werror werror.c -o werror // 将所有警告变成error
- gcc -x c++ cpp.c -lstdc++ -o cpp // 使用c++编译,-lstdc表示链接C++库
二、预编译
#progma
//此文件依赖于相同路径下的 dep.c ,且需要dep.c的修改时间在此文件之前
#progma GCC dependency "dep.c"
//只要出现goto,就视为语法毒药,禁忌
#pragma GCC poison goto
//按字节对齐,可回头看,常用于结构体
#pragma pack()
#if
#if (VER <3)
#error "版本太低"
#elif (VER>3)
#warning "版本太高"
#endif
三、常见宏
void print(void)
{
//当前被编译文件
printf("_BASE_FILE_ : %s\n",_BASE_FILE_);
//输出宏所在文件
printf("_FILE_ : %s\n",_FILE_);
//输出行号
printf("_LINE_ : %s\n",_LINE_);
//输出 此函数位置
printf("_FUNCTION_ : %s\n",_FUNCTION_);
//输出 此函数层数包含关系
printf("_INCLUDE_LEVEL_ : %s\n",_INCLUDE_LEVEL_);
}
四、库文件
1. 静态库
一、说明
概念:将多个目标文件打包成一个文件,链接静态库:将库中被调用的代码复制到调用模块;
特点:
1. 占用较大的空间 ;
2. 若改变库中的.o文件,需要重新链接,否则使用的还是旧的 ;
3. 在运行时无需依赖库,执行效率高;
4. 只是在链接时用到,编译时不使;
二、构建
构建静态库: .c -> .o -> .a
//此命令将x.o y.o z.o 打包 libxxx.a静态库
ar -r libxxx.a x.o y.o z.o
使用方法:
gcc -lxxx // "l"后面跟库名
gcc -L<库路径> //使用库路径
三、制作静态链接文件:
写 cal.c + show.c 文件
//-----------------------------------制作静态库
//calc.h
#ifndef _CALC_H
#define _CALC_H
int add(int,int);
int sub(int,int);
#endif
//calc.c
#include "calc.h"
int add(int a,int b){
return a+b;
}
int sub(int a,int b){
return a-b;
}
———————————————————————————————————————————————————————————
//vi show.h
#ifndef _SHOW_H
#define _SHOW_H
void print(int,char,int,int);
#endif
//vi show.c
#include <stdio.h>
#include "show.h"
void print(int a,char op,int b,int c){
printf("%d%c%d=%d\n",a,op,b,c);
}
由两个O文件生成 .a静态库文件
ar -r libmath.a calc.o show.o
// vi math.h //只需要包括这个头文件,就可以包含所有声明
#ifndef _MATH_H
#define _MATH_H
#include "calc.h"
#include "show.h"
#endif
// vi math.c
#include "math.h"
int main(void)
{
int a=30, b=20;
show(a,'+',b,add(a,b));
show(a,'-',b,sub(a,b));
return 0;
}
方法一:
gcc main.c -o main -lmath -L. //表明静态库的名称为math,路径为当前文件夹
方法二:
export LIBRARY_PATH =. //链接使用的环境变量,找库相对地址
gcc main.c -o main -lmath //在已定义的环境变量找库
2.动态库
一、说明
- 动态库调用时 不拷贝,真正的内存空间只需要一份即可。(shared object,so,DLL);
- 只要保证接口保持不变,无需重新链接编译;
- 代码运行时主要依赖库,执行效率低;
二、构建
库内部的函数调用也用相对地址表示:
//fpic-位置无关码:程序中运行时,库映射的的各进程地址不同,调用时库绝对地址也不同
gcc -c -fpic xxx.c -> xxx.o
//【类似于分配指针】-但相对地址一定一样
gcc -shared -o libxxx.so x.o y.o z.o
动态库使用方法:
方法一:
gcc ... -lxxx -L<库路径> //表明动态库的名称为math,路径为当前文件夹
方法二:
export LIBRARY_PATH =<库路径>
gcc ... -lmath //运行时所调用的动态库必须位于LD_LIBRARY_PATH环境变量所表示的路径中
三、制作动态库文件
制作库文件 xxxx.so
gcc -c -fpic calc.c //生成calc.o
gcc -c -fpic show.c //生成show.o
gcc -shared -o libmath.so calc.o show.o //生成动态库
分别定义链接地址和运行时的库地址,两个都需要声明
export LIBRARY_PATH =. //链接使用的环境变量,找库相对地址
export LD_LIBRARY_PATH =. //运行时拿着相对地址找函数
使用动态库编译:
gcc main.c -o main -lmath //使用环境变量方法
总结
本章节主要回顾静态库、动态库的制作方法与使用;