c语言编译步骤,即一个*.c文件是如何一步步成为*.exe的?
参见:C语言真正的编译过程
window下GCC(minGW)的安装
参见:MinGW下载安装
GCC常见命令:
本人理解的c语言编译过程、中间文件、常用命令
本次实验环境:
window7、minGW
实验代码:https://download.csdn.net/download/u010476739/10800828
实验一、编译单个文件
代码 test.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("hello\n");
system("pause");
}
gcc命令:(gcc test.c -o test.exe -save-temps)
编译结果:
双击执行test.exe
实验二、编译多个文件
目录:
sub.h
sub.c
main.c
代码sub.h
#ifndef MY_MATH
#define MY_MATH
int add(int,int);
int sub(int,int);
#endif
代码sub.c
int add(int x,int y)
{
return x+y;
}
int sub(int x,int y)
{
return x-y;
}
代码main.c
#include <stdio.h>
#include <stdlib.h>
#include "sub.h"
int main()
{
int a=5;
int b=2;
printf("add(a,b)=%d\n",add(a,b));
printf("sub(a,b)=%d\n",sub(a,b));
system("pause");
return 0;
}
执行命令:
gcc sub.c main.c -o test.exe
实验三、模块化编程
文件目录结构:
header
m1.h
m2.h
mod1
m1.c
mod2
m2.c
main.c
代码:
m1.h
#ifndef M1
#define M1
int add(int,int);
#endif
m2.h
#ifndef M2
#define M2
int sub(int,int);
#endif
m1.c
int add(int x,int y)
{
return x+y;
}
m2.c
int sub(int x,int y)
{
return x-y;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "header/m1.h"
#include "header/m2.h"
int main()
{
int a=5,b=3;
printf("add(a,b)=%d\n",add(a,b));
printf("sub(a,b)=%d\n",sub(a,b));
system("pause");
}
编译方案一、各自单独编译,最后链接成exe程序
1.编译模块mod1(仅需要m1.c)
cd mod1
gcc -c m1.c -o m1.obj
2.编译模块mod2(仅需要m2.c)
cd mod2
gcc -c m2.c -o m2.obj
3.编译主模块main
cd ..
gcc -c main.c -o main.obj
4.将main.obj,m1.obj,m2.obj链接到一起
gcc main.obj mod1/m1.obj mod2/m2.obj -o test.exe
编译方案二、直接编译
直接将这些文件编译成exe可执行程序
gcc main.c mod1/m1.c mod2/m2.c -o test.exe
实验四、gcc命令选项
文件目录结构:
header
m1.h
m2.h
mod1
m1.c
mod2
m2.c
main.c
代码:
m1.h
#ifndef M1
#define M1
int add(int,int);
#endif
m2.h
#ifndef M2
#define M2
int sub(int,int);
#endif
m1.c
int add(int x,int y)
{
return x+y;
}
m2.c
int sub(int x,int y)
{
return x-y;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "m1.h"
#include "m2.h"
int main()
{
int a=5,b=3;
printf("add(a,b)=%d\n",add(a,b));
printf("sub(a,b)=%d\n",sub(a,b));
system("pause");
}
1.编译主模块main.c 并指定include查找的路径
gcc -I ./header -c main.c -o main.obj
2.编译模块m1.c
gcc -c mod1/m1.c -o mod1.obj
3.编译模块m2.c
gcc -c mod2/m2.c -o mod2.obj
4.将编译的结果链接为一个exe程序
gcc main.obj mod1/m1.obj mod2/m2.obj -o test.exe
实验五、gcc生成动态库dll文件
目录结构:
myfunc
myfunc.h
myfunc.c
main.c
代码:
myfunc.h
#ifndef MYFUNC
#define MYFUNC
int add(int,int);
#endif
myfunc.c
int add(int x,int y)
{
return x+y;
}
main.c
#include <stdio.h>
#include <stdlib.h>
int add(int,int);
int main()
{
int a=10,b=2;
printf("add(a,b)=%d\n",add(a,b));
system("pause");
}
编译思路:
首先将myfunc.c编译为动态库文件myfunc.dll,myfunc.h文件可以供外面调用
然后编译main.c文件并使用myfunc.dll链接为main.exe可执行文件
将myfunc.dll拷贝到main.exe同一个目录下,双击main.exe可查看效果
1.编译myfunc.c文件为动态库myfunc.dll
cd myfunc
gcc myfunc.c -shared -o myfunc.dll
2.编译main.c文件并链接为main.exe可执行程序
cd ..
gcc main.c myfunc/myfunc.dll -o main.exe
3.将myfunc/myfunc.dll文件拷贝至与main.exe同目录后双击运行main.exe
实验六、gcc生成静态库lib文件
目录结构:
staticmod
mod.h
mod.c
main.c
代码:
mod.h
#ifndef MOD
#define MOD
int add(int,int);
#endif
mod.c
int add(int x,int y)
{
return x+y;
}
main.c
#include <stdio.h>
#include <stdlib.h>
int add(int,int);
int main()
{
int a=1,b=6;
printf("add(a,b)=%d\n",add(a,b));
system("pause");
return 0;
}
实现思路:
首先将mod.c编译为静态链接库 mod.lib(仅mod.c就可以了)
然后编译main.c生成main.exe,生成后的main.exe可单独运行
1.将mod.c编译生成静态链接库
cd staticmod
gcc -c mod.c -o mod.obj
使用ar将obj文件打包成.lib文件
ar -crv mod.lib mod.obj
2.编译main.c生成main.exe可执行程序
cd ..
gcc main.c staticmod/mod.lib -o main.exe
双击生成后的main.exe即可运行
实验七、gcc生成的多个动态库相互引用
目录结构:
mod1
m1.c
m1.h
mod2
m2.h
m2.c
mod3
m3.h
m3.c
main.c
代码:
m1.h
#ifndef MOD1
#define MOD1
int func1(x,y);
#endif
m1.c
int func1(int x,int y)
{
return x+y;
}
m2.h
#ifndef MOD2
#define MOD2
int func2(int,int);
#endif
m2.c
int func1(int,int);
int func2(int x,int y)
{
int res=func1(x,y);
res=res+2;
return res;
}
m3.h
#ifdefine MOD3
#define MOD3
int func3(int,int);
#endif
m3.c
int func2(int,int);
int func3(int x,int y)
{
int res=func2(x,y);
res+=3;
return res;
}
main.c
#include <stdio.h>
#include <stdlib.h>
int func3(int,int);
int main()
{
int a=10,b=2;
printf("func3(a,b)=%d\n",func3(a,b));
system("pause");
return 0;
}
实现思路:
首先将m1.c编译为动态库m1.dll,m2.c编译为m2.dll,m3.c编译为m3.dll
然后将main.c编译并链接为main.exe,将m1.dll,m2.dll,m3.dll拷贝到main.exe同目录下,然后双击main.exe运行可以看到效果
1.将m1.c编译为m1.dll
cd mod1
gcc -shared m1.c -o m1.dll
2.将m2.c编译为m2.dll
cd ../mod2
gcc -shared m2.c ../mod1/m1.dll -o m2.dll
3.将m3.c编译为m3.dll
cd ../mod3
gcc -shared m3.c ../mod2/m2.dll -o m3.dll
4.将main.c编译为main.exe
cd ..
gcc main.c mod3/m3.dll -o main.exe
将m1.dll,m2.dll,m3.dll拷贝到main.exe同目录下,双击main.exe即可看到效果
实验八、gcc生成的多个静态库相互引用
mod1是一个静态库,mod2是一个静态库引用了mod1,主模块main引用了mod2
目录结构:
mod1
m1.h
m1.c
mod2
m2.h
m2.c
main.c
代码:
m1.h
#ifndef MOD1
#define MOD1
int func1(int,int);
#endif
m1.c
int func1(int x,int y)
{
return x+y;
}
m2.h
#ifndef MOD2
#define MOD2
int func2(int,int);
#endif
m2.c
int func1(int,int);
int func2(int x,int y)
{
int res=func1(x,y);
res+=3;
return res;
}
main.c
#include <stdio.h>
#include <stdlib.h>
int func2(int,int);
int main()
{
int a=10,b=5;
printf("func2(a,b)=%d\n",func2(a,b));
system("pause");
}
实现思路:
首先将mod1编译成obj文件,可以考虑继续打包成lib文件
然后将mod2编译成obj文件,然后将mod1的obj文件和mod2的obj文件一块打包成m2.lib文件
最后编译main.c引用m2.lib文件即可
1.将mod1编译成obj文件
cd mod1
gcc -c m1.c -o m1.obj
下一条命令可选
ar -crv m1.lib m1.obj
2.将mod2编译成obj文件
cd ../mod2
gcc -c m2.c -o m2.obj
将m1.obj和m2.obj联合打包成m2.lib文件
ar -crv m2.lib ../mod1/m1.obj m2.obj
3.编译main.c
cd ..
gcc main.c mod2/m2.lib -o main.exe
双击运行main.exe即可看到效果
实验九、gcc生成exe同时引用动态库和静态库
主模块同时引用静态库和动态库:
mod1是一个静态库,mod2是一个动态库,主模块main引用了mod1和mod2
目录结构:
mod1
m1.h
m1.c
mod2
m2.h
m2.c
main.c
代码:
m1.h
#ifndef MOD1
#define MOD1
int func1(int,int);
#endif
m1.c
int func1(int x,int y)
{
return x+y;
}
m2.h
#ifndef MOD2
#define MOD2
int func2(int,int);
#endif
m2.c
int func2(int x,int y)
{
return x-y;
}
main.c
#include <stdio.h>
#include <stdlib.h>
int func1(int,int);
int func2(int,int);
int main()
{
int a=10,b=5;
printf("func1(a,b)=%d\n",func1(a,b));
printf("func2(a,b)=%d\n",func2(a,b));
system("pause");
}
实现思路:
首先将mod1编译成obj并继续打包成lib文件,将mod2直接编译为dll文件
然后编译main.c引用m1.lib和m2.dll文件即可,将m2.dll拷贝到main.exe同目录双击运行即可
1.将mod1编译成obj文件并打包成lib文件
cd mod1
gcc -c m1.c -o m1.obj
ar -crv m1.lib m1.obj
2.将mod2编译成dll文件
cd ../mod2
gcc -shared m2.c -o m2.all
3.编译main.c
cd ..
gcc main.c mod1/m1.lib mod2/m2.dll -o main.exe
将m2.dll拷贝到main.exe同目录,双击main.exe运行即可看到效果
实验十、gcc静态库引用动态库
mod1是动态库,mod2是静态库并且引用mod1,,主模块引用mod2
目录结构:
mod1
m1.h
m1.c
mod2
m2.h
m2.c
main.c
代码:
m1.h
#ifndef MOD1
#define MOD1
int func1(int,int);
#endif
m1.c
int func1(int x,int y)
{
return x+y;
}
m2.h
#ifndef MOD2
#define MOD2
int func2(int,int);
#endif
m2.c
int func1(int,int);
int func2(int x,int y)
{
int res=func1(x,y);
return res+3;
}
main.c
#include <stdio.h>
#include <stdlib.h>
int func2(int,int);
int main()
{
int a=15,b=2;
printf("func2(a,b)=%d\n",func2(a,b));
system("pause");
}
实现思路:
首先将mod1编译为m1.dll
然后将mod2编译为m2.obj并将m2.obj打包为m2.lib
最后编译main.c并引用m2.lib和m1.dll生成main.exe
将m1.dll拷贝至main.exe同目录,双击运行即可看到效果
实验十一、gcc动态库引用静态库
mod1是静态库,mod2是动态库并且引用mod1,主模块引用mod2
目录结构:
mod1
m1.h
m1.c
mod2
m2.h
m2.c
main.c
代码:
m1.h
#ifndef MOD1
#define MOD1
int func1(int,int);
#endif
m1.c
int func1(int x,int y)
{
return x+y;
}
m2.h
#ifndef MOD2
#define MOD2
int func2(int,int);
#endif
m2.c
int func1(int,int);
int func2(int x,int y)
{
int res=func1(x,y);
return res+6;
}
main.c
#include <stdio.h>
#include <stdlib.h>
int func2(int,int);
int main()
{
int a=12,b=3;
printf("func2(a,b)=%d\n",func2(a,b));
system("pause");
}
实现思路:
首先将m1.c编译为m1.obj并打包为m1.lib
然后将m2.c编译为m2.dll(gcc -shared m2.c ../mod1/m1.lib -o m2.dll)
最后编译主模块,引用了m2.dll,将m2.dll拷贝至main.exe同目录,双击main.exe即可看到效果
1.将m1.c编译为m1.obj并打包为m1.lib
cd mod1
gcc -c m1.c -o m1.obj
ar -crv m1.lib m1.obj
2.将m2.c编译为m2.dll
cd ../mod2
gcc -shared m2.c ../mod1/m1.lib -o m2.dll
3.编译main.c
cd ..
gcc main.c mod2/m2.dll -o main.exe
然后将m2.dll拷贝至main.exe同目录,双击main.exe即可看到效果