背景
起因
在学习《深入理解计算机系统》一书中讲解链接一章中,突然想试一下多文件进行链接,结果阻力不断,遇到了各种怪问题。
环境
mac版本:MacOs Big Sur 11.3
gcc版本:Apple clang version 12.0.5 (clang-1205.0.22.11)
过程
理想过程
#include <stdio.h>
#include "swap.c"
// main.c
void swaap();
int buf[2] = {1, 2};
int main() {
printf("%d %d\n", buf[0], buf[1]);
swap();
printf("%d %d\n", buf[0], buf[1]);
}
// swap.c
extern int buf[];
int *bufp0 = &buf[0];
int *bufp1;
void swap()
{
int temp;
bufp1 = &buf[1];
temp = *bufpp0;
*bufp0 = *bufp1;
*bufp1 = temp;
}
# shell中执行
gcc -o2 -g -o p main.c swap.c
# 等价于
cpp main.c main.i
cc1 main.i main.c -o2 -o main.s
as -o main.o main.s
cpp swap.c swap.i
cc1 swap.i swap.c -o2 -o swap.s
as -o swap.o swap.s
ld -o p main.o swap.o
./p
如果顺利的话应该一路直行下来没有什么问题,然而问题就是并不顺利。
真实过程
重复引用问题
当执行第一条gcc语句时,提醒我swap中的变量被重复引用两次。
费了很多力气也没查到问题,最后我才意识到是因为我在main中include了swap,这个时候不需要进行多文件编译,将该语句注释掉后可顺利进行后续步骤。(或者直接改成单文件编译直接完成,从链接变成了包含)
.i生成问题
由于include了stdio.h导致无法正常生产.i文件,原因未知,取消掉之后能顺利生产.i文件
cc1无法使用问题
在mac中是没有cc1这个命令的,至于具体原因我也不太清楚,但是当前采取的方法是
# 将这部分代码
cpp main.c main.i
cc1 main.i main.c -o2 -o main.s
as -o main.o main.s
cpp swap.c swap.i
cc1 swap.i swap.c -o2 -o swap.s
as -o swap.o swap.s
# 化简为
gcc -c main.c
gcc -c swap.c
且此时可正常include stdio.h。
参考文章:
C语言(GCC)如何编译多个文件?
gcc参数中的-I, -L和-l
(其实最开始走了个弯路尝试把swap做成库,后来发现其实生产.o就可以进行链接了)
链接问题
执行最后的ld命令又出现了新的问题
一开始认为和之前一样,是因为include了stdio的问题,尝试注释掉
又出现了新的问题。
经过查找是因为mac系统必须链接动态库,
#将连接命令改成
ld -macosx_version_min 11.0.1 -o b.out main.o swap.o -lSystem
# 但Big Sur系统有一个坑,必须进行修改成如下
ld -o b.out main.o swap.o -macosx_version_min 11.0.1 -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lSystem
链接完成,且此时可以正常对stdio.h进行include。
参考文献:
MacOS Big Sur下使用nasm编写汇编程序
总结
对我当前的环境,最适合的命令方式为:
gcc -c main.c
gcc -c swap.c
ld -o b.out main.o swap.o -macosx_version_min 11.0.1 -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lSystem
完成。