GCC编译过程及使用

GCC

平常我们在编译程序时使用的命令为:gcc ***.c -o ***,实际上这条指令帮我们执行了四个步骤,分别是预处理、编译、汇编、链接。下面对四个步骤分别进行详细介绍。
下面均使用demo1.c为例进行介绍:

#include <stdio.h>

#define MAX 20
#define MIN 10

//#define DEBUG

int main()
{
	printf("1:hello world!\n");
	printf("1:MAX = %d,MIN = %d\n",MAX,MIN);
#ifdef DEBUG
	printf("2:hello world!\n");
	printf("2:MAX = %d,MIN = %d\n",MAX,MIN);
#endif
	return 0;
}

我们在执行gcc demo1.c -o demo时可以加上-v选项来查看细节

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) 
COLLECT_GCC_OPTIONS='-o' 'demo' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/7/cc1 -quiet -v -imultiarch x86_64-linux-gnu demo1.c -quiet -dumpbase demo1.c -mtune=generic -march=x86-64 -auxbase demo1 -version -fstack-protector-strong -Wformat -Wformat-security -o /tmp/cc7WkG9D.s
GNU C11 (Ubuntu 7.5.0-3ubuntu1~18.04) version 7.5.0 (x86_64-linux-gnu)
	compiled by GNU C version 7.5.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.19-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/7/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
GNU C11 (Ubuntu 7.5.0-3ubuntu1~18.04) version 7.5.0 (x86_64-linux-gnu)
	compiled by GNU C version 7.5.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.19-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: b62ed4a2880cd4159476ea8293b72fa8
COLLECT_GCC_OPTIONS='-o' 'demo' '-v' '-mtune=generic' '-march=x86-64'
 as -v --64 -o /tmp/ccXx5K0c.o /tmp/cc7WkG9D.s
GNU assembler version 2.30 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.30
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/7/:/usr/lib/gcc/x86_64-linux-gnu/7/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/7/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/7/:/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/7/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/7/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-o' 'demo' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/7/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/7/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper -plugin-opt=-fresolution=/tmp/ccPSXVVL.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o demo /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/7 -L/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/7/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/7/../../.. /tmp/ccXx5K0c.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-o' 'demo' '-v' '-mtune=generic' '-march=x86-64'

预处理(.c到.i)

命令:gcc -E -o demo1.i demo1.c,指令分析:预处理demo1.c,预处理后的结果放在demo1.i里面
在这里插入图片描述
可以打开demo1.i,找下main函数你会发现雀氏把宏给展开替换了,这里把MAX替换成20.MIN替换成10,还根据DEBUG开关把无效的代码去掉。
在这里插入图片描述
下面显示出在库中去寻找头文件
在这里插入图片描述

编译(.i到.s)

命令:gcc -S -o demo1.s demo1.i 指令分析:对demo1.i进行编译,编译的结果放在demo1.s里面
可以打开demo1.s会发现里面全部都是汇编码,即这一步是将高级语言转换成汇编码
在这里插入图片描述

汇编(.s到.o)

命令:gcc -c -o demo1.o demo1.s 指令分析:对demo1.s进行编译,编译的结果放在demo1.o里面
将汇编码汇编为机器码,机器码是给机器看的,人是看不懂的,如图:
在这里插入图片描述

链接(.o到可执行文件)

命令:gcc -o demo1 demo1.o 指令分析:对demo1.s进行编译,编译的结果放在demo1.o里面
将所有机器码(.o文件)链接成可执行文件(APP)
在这里插入图片描述

面试问题

介绍“编译”的四个步骤:预处理、编译、汇编、链接。如果程序有错误,在哪一个步骤中会报错?
答:在编译过程中会报错
在这里插入图片描述

GCC常用编译选项

在这里插入图片描述
main.c

#include <stdio.h>
#include "sub.h"

int main(int argc, char *argv[])
{
       int i;
       printf("Main fun!\n");
       sub_fun();
       return 0;
}

sub.c

void sub_fun(void)
{
       printf("Sub fun!\n");
}

sub.h

void sub_fun(void);

对于<>的头文件,编译器会去工具链里默认的指定路径中去查找头文件
对于" "的头文件,一般表示用户自己定义使用的头文件,编译器默认会从当前文件夹中寻找,如果找不到,则到系统默认库环境中去寻找。

-I的使用

当我们把main.c里面的#include "sub.h"改为 #include <sub.h>时,编译就会报错误
在这里插入图片描述
错误显示找不到<sub.h>,这是因为<>会去工具链默认的指定路径(/usr/include)去寻找sub.h,但是里面根本没有,这时候就需要我们用-I去指定路径寻找,修改编译指令为:gcc -o demo main.c sub.c -I .即可通过,.代表当前路径
在这里插入图片描述

-L的使用

在库的制作之前我们必须得有.o文件,例如这里的sub.o,main.o文件
在这里插入图片描述

制作使用静态库

制作:ar crs libsub.a sub.o,这里ar可以理解为压缩、打包之内的
使用:gcc -o demo main.o libsub.a
在这里插入图片描述

制作使用动态库

制作: gcc -shared -o libsub.so sub.o
对于动态库,我们链接时要掐头去尾 : gcc -o demo2 main.o -L ./ -lsub
此外需要使用 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./命令修改环境变量才可运行。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
GCC 是 C/C++ 编译器,不支持直接编译 Java 代码。Java 代码需要先被编译成字节码,然后由 Java 虚拟机(JVM)解释执行或者编译成本地代码执行。 Java 编译器通常使用 javac 命令进行编译。下面是一个简单的编译示例: ``` javac HelloWorld.java ``` 这将会编译名为 HelloWorld.java 的 Java 源代码文件,并生成一个名为 HelloWorld.class 的字节码文件。 如果你想使用 GCC 编译 Java 代码,你需要先将 Java 代码编译成字节码,然后再使用 GCC 编译字节码文件所生成的头文件和源文件。 下面是一个基本的步骤: 1. 使用 javac 命令编译 Java 代码文件: ``` javac HelloWorld.java ``` 2. 使用 javah 命令生成头文件: ``` javah HelloWorld ``` 这将生成一个名为 HelloWorld.h 的头文件。 3. 将头文件和字节码文件一起使用 JNI 编写 C 代码。在 C 代码中,你需要包含 Java 的头文件和 JNI 库,这样就可以调用 Java 方法了。 4. 使用 GCC 编译 C 代码: ``` gcc -c -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux HelloWorld.c ``` 其中,-I 选项指定了 Java 和 JNI 的头文件所在的目录。 5. 使用 GCC 链接 C 代码和 Java 库: ``` gcc -shared -o libHelloWorld.so HelloWorld.o -lc -ljvm ``` 这将生成一个名为 libHelloWorld.so 的共享库,可以在 Java 中使用 System.loadLibrary() 方法加载。 需要注意的是,由于 GCC 不是专为编译 Java 代码而设计的,因此使用 GCC 编译 Java 代码可能会比较麻烦,并且可能会出现一些问题。建议还是使用专门的 Java 编译器 javac 来编译 Java 代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值