GCC编译 --- 起步

【国民技术N32项目移植】基于 Windows 的 ARM GCC 开发环境 阅读详情

    本文适用于Linux下开发初学者。本文初步讲解在Linux下如何使用GCC编译程序、简单生成静态库及动态库。

一、关于安装。一般系统默认是安装好编译器的,并且网络上有大量资料介绍不同发行版本下的安装问题,本文不再描述。

二、C编程中的文件后缀名介绍
    .a 静态库(打包文件)
    .c 未经过预处理的C源码
    .h C头文件  
    .i 经过预处理的C源码
    .o 编译之后产生的目标文件
    .s 生成的汇编语言代码
    .so 动态库(动态链接库)
    解释:*.a是我们在编译过后用ar打包生成的静态库;*.c一般使我们自己编辑的代码,使我们劳动的结晶;*.h一般是我们手工生成的接口文件,如果愿意,也可在*.c完成后用GCC的选项-aux-info帮我们生成;*.i是经过预处理后的源码,是由GCC在选项-E编译下自动生成的文件;*.o是编译后产生的目标文件;*.s是GCC在选项-S编译下生成的汇编语言代码,对于性能要求很高的程序可以先生成汇编语言文件并对汇编做优化,然后用优化后的汇编生成目标文件并链接;*.so是动态库,通过GCC的-fpic -shared选项生成。

三、hello.c的编译过程

   
本小节的演示都针对文件 hello.c 进行
  1. /*
  2.  * hello.c
  3.  */

  4.   #include <stdio.h>
  5.   int  main()
  6.   {
  7.     printf("hello, world!/n");
  8.     return 0;
  9.   }
1.直接生成可执行程序
  1. $ gcc -o hello hello.c
  2. $ ./hello
  3. hello, world!

  4. 如下编译方式结果相同:
  5. $ gcc hello.c -o hello
  6. $ ./hello
  7. hello, world!

  8. 如下编译方式有别于以上编译方案(具体查找ELF和a.out文件格式差别的网络资料,对于此处结果是无任何区别的):
  9. $ gcc hello.c 
  10. $ ./a.out 
  11. hello, world!

2.生成预处理后的文件 hello.i
  1. $ gcc -E hello.c -o hello.i
  2. $ ls
  3. a.out  hello  hello.c  hello.i
  4. hello.i 就是新生成的文件

  5. 如下语句结果相同:
  6. $ gcc -E -o hello.i hello.c 

  7. 如果不设定输出文件,则打印到标准终端,此时我们可以用 less 查看:
  8. $ gcc -E hello.c | less
  9. # 1 "hello.c"
  10. # 1 "<built-in>"
  11. # 1 "<command line>"
  12. # 1 "hello.c"
  13. # 1 "/usr/include/stdio.h" 1 3 4
  14. # 28 "/usr/include/stdio.h" 3 4
  15. # 1 "/usr/include/features.h" 1 3 4
  16. # 329 "/usr/include/features.h" 3 4
  17. ..............................

  18. 或者执行:
  19. $ gcc -E hello.c -o hello.i
  20. $ vi hello.i
  21.   1 # 1 "hello.c"
  22.   2 # 1 "<built-in>"
  23.   3 # 1 "<command line>"
  24.   4 # 1 "hello.c"
  25.   5 # 1 "/usr/include/stdio.h" 1 3 4
  26.   6 # 28 "/usr/include/stdio.h" 3 4
  27.   7 # 1 "/usr/include/features.h" 1 3 4
  28.   8 # 329 "/usr/include/features.h" 3 4

  29. .......... <中间部分略> ..................

  30. 929 # 844 "/usr/include/stdio.h" 3 4
  31. 930 
  32. 931 # 2 "hello.c" 2
  33. 932 
  34. 933 int main()
  35. 934 {
  36. 935         printf("hello, world!/n");
  37. 936 
  38. 937         return 0;
  39. 938 }

  40. 可见,将近1000行的代码,我们的只占了最末8行。

3.生成汇编语言文件 hello.s
  1. $ gcc -S hello.c -o hello.s
  2. $ ls
  3. a.out  hello  hello.c  hello.i  hello.s
  4. hello.s就是新生成的文件

  5. 如下语句结果相同:
  6. $ gcc -S -o hello.s hello.c

  7. 如下语句结果相同:
  8. $ gcc -S hello.c

  9. 也可以采用前一步骤产生的中间文件生成汇编文件:
  10. $ gcc -S hello.i -o hello.s
  11. $ gcc -S -o hello.s hello.i
  12. $ gcc -S hello.i


  13. 生成的汇编部分代码如下:
  14. $ vi hello.s 
  15.   1         .file   "hello.c"
  16.   2         .section        .rodata
  17.   3 .LC0:
  18.   4         .string "hello, world!"
  19.   5         .text
  20.   6 .globl main
  21.   7         .type   main, @function
  22.   8 main:
  23.   9         leal    4(%esp), %ecx
  24.  10         andl    $-16, %esp
  25.  11         pushl   -4(%ecx)
  26.  12         pushl   %ebp
  27. // 注释:如果你熟悉,就可以对部分汇编优化以达到更好效果。
4.生成目标文件 hello.o
  1. $ gcc -c hello.c -o hello.o
  2. $ ls
  3. a.out  hello  hello.c  hello.i  hello.o  hello.s
  4. hello.o就是新生成的目标文件:

  5. 如下语句结果相同:
  6. $ gcc -c -o hello.o hello.c 

  7. 如下语句结果相同:
  8. $ gcc -c hello.c

  9. 也可以采用前面步骤产生的中间文件hello.i或hello.s来生成目标文件:
  10. $ gcc -c hello.i
  11. $ gcc -c hello.s

  12. 我们可以用 objdump 查看 hello.o 的二进制码:
  13. $ objdump -s hello.o

  14. hello.o:     file format elf32-i386

  15. Contents of section .text:
  16.  0000 8d4c2404 83e4f0ff 71fc5589 e55183ec  .L$.....q.U..Q..
  17.  0010 04c70424 00000000 e8fcffff ffb80000  ...$............
  18.  0020 000083c4 04595d8d 61fcc3             .....Y].a..     
  19. Contents of section .rodata:
  20.  0000 68656c6c 6f2c2077 6f726c64 2100      hello, world!.  
  21. Contents of section .comment:
  22.  0000 00474343 3a202847 4e552920 342e312e  .GCC: (GNU) 4.1.
  23.  0010 31203230 30373031 30352028 52656420  1 20070105 (Red 
  24.  0020 48617420 342e312e 312d3532 2900      Hat 4.1.1-52).  
5.采用中间级文件生成可执行程序
  1. $ gcc -o hello hello.i
  2. $ ./hello
  3. hello, world!

  4. $ gcc -o hello hello.s
  5. $ ./hello
  6. hello, world!

  7. $ gcc -o hello hello.o
  8. $ ./hello
  9. hello, world!
四、静态库的生成
    linux下静态库的生成比较方便。在生成目标文件后用 ar 打包即可。在中大型项目中一个模块一般会做成一个静态库,以方便管理、提高编译、链接效率。
    本小节的展示针对 main.c、func1.c、func2.c三个文件
  1. /*
  2.  * main.c
  3.  */
  4. #include <stdio.h>

  5. extern int func1();
  6. extern int func2();

  7. int main()
  8. {
  9.         int i;

  10.         i = func1();
  11.         printf("func1 return = %d/n",i);

  12.         i = func2();
  13.         printf("func2 return = %d/n",i);

  14.         return 0;
  15. }

-----------------------------------------------------
  1. /*
  2.  * func1.c
  3.  */
  4. int func1()
  5. {
  6.         return 100;
  7. }
-----------------------------------------------------
  1. /*
  2.  * func2.c
  3.  */
  4. int func2()
  5. {
  6.         return 200;
  7. }
一下是编译指令:
  1. $ gcc -c func1.c
  2. $ gcc -c func2.c
  3. $ ls
  4. func1.c  func1.o  func2.c  func2.o  main.c

  5. func1.o 和 func2.o 是我们生成的目标文件。打包指令如下:
  6. $ ar -r libfunc.a func1.o func2.o

  7. 我们查看 libfunc.a 中的文件:
  8. $ ar -t libfunc.a 
  9. func1.o
  10. func2.o

  11. 现在用静态库和 main.c 共同生成目标程序:
  12. $ gcc -o main main.c libfunc.a
  13. $ ./main 
  14. func1 return = 100
  15. func2 return = 200

  16. 和我们的预期相符合。下面我们进入动态库。


五、动态库的生成
    linux下动态库的生成通过GCC选项实现。案例程序和静态库中的相同。一下是操作指令:
  1. 首先我们生成目标文件,但是需要加编译器选项 -fpic 和链接器选项 -shared
  2. $ gcc -fpic -c func1.c
  3. $ gcc -fpic -c func2.c
  4. $ gcc -shared -o libfunc.so func1.o func2.o
  5. $ ls
  6. func1.c  func1.o  func2.c  func2.o  libfunc.so  main.c
  7. libfunc.so就是我们生成的目标动态库。我们用动态库和 main.c 生成目标程序:
  8. $ gcc -o main main.c -L. -lfunc
  9. 注意,我们用 -L. -lfunc 作为编译选项。-L. 表从当前目录查找需要的动态库,-lfunc 是动态库的调用规则。Linux系统下的动态库命名方式是 lib*.so,而在链接时表示位 -l* , *是自己起的库名。下面我们运行它:
  10. $ ./main 
  11. ./main: error while loading shared libraries: libfunc.so: cannot open shared object file: No such file or directory
  12. 提示一个错误,指示无法找到动态库。在linux下最方便的解决方案是拷贝libfunc.so到绝对目录 /lib 下。但是只有超级用户才有这个权限。另外一个方案是更改环境变量 LD_LIBRARY_PATH。如下:
  13. $ $ export LD_LIBRARY_PATH=`pwd`
  14. $ ./main 
  15. func1 return = 100
  16. func2 return = 200
  17. 运行成功。现在我们更改动态库的函数而不重新链接。如下:
  18. 更改 func1.c 为:
  19. int func1()
  20. {
  21.         return 101;
  22. }
  23. 更改 func2.c 为:
  24. int func2()
  25. {
  26.         return 202;
  27. }
  28. 重新生成库:
  29. $ gcc -fpic -shared func1.c func2.c -o libfunc.so
  30. $ ./main 
  31. func1 return = 101
  32. func2 return = 202
  33. 可以看出,动态库已经更新了。
六、结束语
    本文简单介绍了linux下如何使用gcc进行编译程序、以及简单的静态、动态库的生成。静态库提供了一种打包管理方案,而动态库使程序局部更新成为了可能,更重要的是,当有多份实例存在时,动态库可减小内存的消耗(只占用一份代码空间)。
    对本系列知识感兴趣者可继续跟踪阅读后续文章:库的版本管理、GCC的编译选项、Makefile与自动化编译。


gcc编译过程 一、总体概述 GCC的编译流程分为四个步骤: 1、预处理(Pre-Processing) 2、编译(Compiling) 3、汇编 (Assembliang) 4、链接(Linking) 二、解释步骤 XXX为源文件 YY为生成的文件 1、预处理(Pre-Processing) 预处理用于将所有的#include头文件以及宏定义替换成其真正的内容,预处理之后得到的仍然是文本文件,但文件体积会大很多。 将 .c 文件转换为 .i 文件,使用gcc命令:gcc -E XXX -o YY 对应于预处理命令 cpp 阅读详情

相关推荐

H3C-V7防火墙配置SSL VPN IP资源典型案例(华三)

H3C-V7防火墙配置SSL VPN IP资源典型案例(华三)

m0_68265458的博客 5163

Linux Kernel编译流程 (二)

1 vmlinux 研究vmlinux文件的产生, zImage和Image产生 Linux Kernel 4.18.20 Source Insight 3.5 1.1 find all target 首先当我们执行sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-命令后, 默认的target是all,所以我们首先在顶层Makefile中找到all, 发现如下代码片段 cfg: u-boot.cfg all: $(ALL-y) cfg $(call

Jun's blog 2165

高效 DEM 拼接

通过以上步骤的系统实施,能够实现高效、准确的大型地理信息系统 DEM 数据拼接,满足复杂和大规模项目的应用需求。

llhllq2015的博客 1032

Linux应用编程(二十四)——Linux内核移植(二:内核源码结构及Makefile分析)

文章目录内核源码结构Linux Makfile分析决定编译那些文件obj-y用来定义那些文件被编进(built-in)内核。例1obj-m用来定义那些文件被编译成可加载模块(Loadable module)例2例3lib-y用来定义那些文件被编成库文件obj-y、obj-m还可以用来指定要进入的下一层目录。例4怎样编译这些文件怎样连接这些文件,它们的顺序如何。总结 内核源码结构 Linux内核文件数目将近2万个,除去其他架构CPU的相关文件,支持S3C2410,S3C2440这两款芯片的完整内核文件有1万

m0_56145255的博客 1975

告别Root!用Python脚本一键解密Android微信EnMicroMsg.db数据库(附完整源码)

本文详细介绍了如何在非Root环境下使用Python脚本一键解密Android微信EnMicroMsg.db数据库。通过ADB调试接口和SQLCipher技术,实现自动化提取和解密微信聊天记录数据库,无需Root权限,适合数据分析师和普通用户安全备份数据。

weixin_29266007的博客 329

Spring Boot整合AWS S3文件上传实战:从配置到权限管理全流程解析

本文详细解析了Spring Boot整合AWS S3文件上传的全流程,包括基础配置、核心上传功能实现、高级权限控制及安全最佳实践。通过实战案例展示如何高效处理文件上传、大文件分片及权限管理,帮助开发者构建健壮的文件管理系统。特别强调AWS S3的高可用性和安全性,适用于企业级应用开发。

sam99的博客 283

Linux Makefile built-in.a与built-in.o

较新的kernel使用的是 built-in.a,原来built-in.o没了,但我编译独立模块需要它。关于built-in.a的优点,Kernel Makefile原文这样说的:(不关心的直接跳过)意思是这个文件没有文件符号表或索引,更小巧灵活(生成kernel更快?),所以链接器用不了,也就是 ld 链接不了,要用脚本 scripts/link-vmlinux.sh来构建出带有符号的。(我不是用这个)

bdjsm_hh的博客 2835

上位机介绍:C# 开发者的必知基础

上位机是指在工业控制系统中,位于上层、负责人机交互和数据管理的计算机/软件,与“下位机”(PLC、传感器、变频器、单片机等硬件设备)相对应,核心是“向下通信控制设备,向上展示交互数据”。下位机:一线干活的“工人”(执行采集、控制指令);上位机:指挥管理的“办公室人员”(发指令、看数据、做报表)。C#开发者掌握上位机开发的核心是“通信+UI+稳定性基础层:搞懂WinForms/WPF基础、串口/Modbus通信,能实现核心功能;进阶层:掌握分层设计、异步编程、工业级容错(断线重连、数据校验);

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1558

GCC 编译器的使用&编译过程

视频观看地址:https://www.100ask.net/detail/p_5f338ae3e4b075dc42ad44a1/8 全文下载: 嵌入式Linux系统开发完全手册 第二版 源文件需要经过编译才能生成可执行文件。在 Windows 下进行开发时,只需要点几个按钮即可编译,集成开发环境(比如 Visual studio)已经将各种编译工具的使用封装好了。Linux 下也有很优秀的集成开发工具,但是更多的时候是直接使用编译工具;即使使用集成开发工具,也需要掌握一些编译选项。 PC 机上的编译工具链为

韦东山嵌入式专栏 4293

Android Telephony主要模块及功能

Telephony的代码主要由五个模块组成 1.Telephony Frameworks 代码区域: frameworks/opt/telephony/ 其中主要的文件在如下目录 /frameworks/opt/telephony/src/java/com/android/internal/telephony/ 其中比较常见的有以下几类文件 1.BaseCommands、RIL构成R

泊客 7720

基于ZYNQ的HP总线与DDR交互:实现PL与PS高效数据传输的完整指南

本文将深入探讨如何通过AXI HP总线实现PL与PS的DDR交互,结合代码示例、硬件配置与创新优化,助力开发者掌握这一关键技术。ZYNQ内部通过AXI HP接口直接连接PL与DDR控制器,PL通过AXI协议发送读写请求,绕过PS的CPU直接操作DDR。通过AXI HP总线实现PL与PS的DDR交互,开发者可充分发挥ZYNQ异构架构的优势。在Xilinx ZYNQ系列芯片中,PS(Processing System)与PL(Programmable Logic)的协同设计是其核心优势。

QQ_778132974的博客 1223

VSCode编辑器和GCC编译器的安装配置,C语言的起步,编程学习的起步

本文介绍了C程序开发的快速入门指南,重点推荐使用VS Code作为开发工具。首先对比了Visual Studio、Code::Block、Clion等常见IDE的特点,详细说明了MinGW-w64编译器的安装配置步骤和环境变量设置方法。接着提供了VS Code的下载安装流程,包括中文语言包和C/C++扩展的安装。最后通过输出"hello world!"的示例程序,演示了从创建项目到编写、运行C代码的完整流程。文章强调开发路径中不能包含中文,并提供了图文并茂的操作指引,适合C语言初学者快速

2301_76633821的博客 1395

[QMT量化交易小白入门]-十二、QMT回测龙头打首板和连板的策略

class a():passA = a() #创建空的类的实例 用来保存委托状态field_list定义了需要的市场数据字段,而类a用于保存交易状态。

木头大左的博客 4757

GCC - 一切从这里开始

GCC rules 你能想象使用封闭源代码的私有编译器编译自由软件吗?你怎么知道编译器在你的可执行文件中加入了什么?可能会加入各种后门和木马。Ken Thompson是一个著名的黑客,他编写了一个编译器,当编译器编译自己时,就在login程序中留下后门和永久的木马。请到 这里 阅读他对这个杰作的描述。幸运的是,我们有了gcc。当你进行 configure; make; make insta

好好学习,天天向上! 1753

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

GCC起步

   在为Linux开发应用程序时,绝大多数情况下使用的都是C语言,因此几乎每一位Linux程序员面临的首要问题都是如何灵活运用C编译器.目前Linux下最常用的C语言编译器是GCC(GNU Compiler Collection),它是GNU项目中符合ANSI C标准的编译系统,能够编译用C、C++和Object C等语言编写的程序.GCC不仅功能非常强大,结构也异常灵活.最值得称道的一点就是它

lxu的专栏 1018

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Linux GCC 编译详解

介绍 linux 下 GCC 的使用

weixin_45004203的博客 5450

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【GCC】gcc编译器的使用

gcc编译器的使用

weixin_50964793的博客 7864

GCC编译器——GCC编译器安装教程

以下内容源于网络资源的整理,如有侵权请告知删除。

主要记录嵌入式学习与开发过程。 1万+

Linux下的GCC编译器

GCC是GNU公社的一个项目,它是GNU Compiler Collection的缩写,起初,GCC只是一个C语言编译器(GNU C Collection),随着开发者的加入,GCC已扩展为可以编译C、C++、Java、Objective-C等多种编程语言的编译器集合了。如今的GCC也具有了交叉编译的功能,即在一个平台上编译另一个平台的代码。所谓编译器,可以简单地将其理解为“翻译器”。

asddrsq的博客 3206

【编译器GCC】

GCC(GNU Compiler Collection)是一套由 GNU 开发的编程语言编译器。它支持多种编程语言,包括 C、C++、Objective-C、Fortran、Ada 和 Go 等。

m0_74520482的博客 3665

GCC编译器——GCC编译器的简介

以下内容源于C语言中文网的学习与整理,如有侵权请告知删除。

主要记录嵌入式学习与开发过程。 6502

GCC编译器

在Linux中,使用最多的编译工具无疑是GCC(GNU Compiler Collection,GNU编译器套件)。1. 开源与自由GCC是GNU项目的一部分,遵循GNU通用公共许可证(GPL),这意味着它是完全开源和免费的。这种开放性吸引了大量的开发者和用户,促进了GCC的普及和发展。2. 跨平台支持GCC支持多种操作系统和硬件架构,包括Linux、Windows、macOS等,以及从x86到ARM等多种处理器架构。这种广泛的兼容性使得GCC成为跨平台开发的首选编译器。3. 语言支持丰富。

dcq715的博客 3648

GCC编译过程

目录 GCC编译 方式一:一步完成 方式二:分步编译 一、预处理 二、编译 三、汇编(生成目标文件) 四、链接 gcc安装查看 方式一: 方式二: 快速安装gcc编译器 gcc 和 g++ 的区别 Linux执行文件 GCC编译 方式一:一步完成 打开命令行窗口(Terminal),编写如下 gcc 指令: gcc hello.c 按下 Enter 回车键,由此 GCC 编译器就帮我们在当前目录下生成了对应的可执行文件,该文件的名称为 a.out,可以通过 l..

weixin_38383877的博客 3071

C语言编译器之一,GCC编译器

C语言作为高级语言,用其编写的程序指令机器并不能识别,因此需要有一个编译器将其转换为机器可识别的二进制指令。C语言已经出现50多年的时间,其相关的编译器种类众多,从最早先的turbo c系列编译器,到大名鼎鼎的gcc,还有基于LLVM的clang,各有优劣,而且在多个平台(如windows、Linux、MAC)上都广泛使用。同时由于Windows的强势存在,其自家的Visual C/C++编译器也有不少的应用。 一般C语言程序是在PC上编写,并将其编译成可执行文件,最终放到电脑或设备上去执行。

goodshanzi的博客 7054
上一篇: grub2 1.95 源码分析之一 —— boot.S 分析及注释
下一篇: fedora 安装
cppgp
博客等级 码龄20年 47粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值