一、gcc命令

在linux开发编程过程中,需要对完成的代码进行编译运行,这时我们便需要用到gcc命令,下面我介绍gcc的安装与使用

1.安装

在ubuntu系统下终端中输入下面的命令

sudo apt-get install build-essential

该命令中,sudo表示使用管理员权限安装,需要输入系统的密码,安装完成后可以通过如下指令查看gcc版本

gcc -v

输出结果如下

可以看到我的gcc版本为7.5.0,出现该界面则安装成功.

2.使用

gcc语法如下gcc(选项)(文件名)gcc (选项) (文件名)gcc(选项)(文件名)具体选项如下表

选项 作用
-o 指定生成的输出文件
-E 仅执行编译预处理
-S 将C代码转为汇编代码
-wall 显示警告信息
-c 仅进行编译操作,不进行链接操作

下面以一个例子介绍gcc使用,首先在ubuntu创建一个test文件夹,并在文件夹下创建test.c文件

mkdir test
cd test
touch test.c

在test文件夹下可以看到test文件创建成功,打开test.c文件,输入如下代码

#include<stdio.h>#define mynum1 12
#define mynum2 15int main()
{int a = mynum1+mynum2;printf("测试结果为:%d",a);return 0;
}

程序编译一般经过这几个步骤:预处理,编译,汇编与链接。在预处理阶段,会处理以#开头的预处理命令,比如#include,#define等命令,处理完成后一般是生成.i文件,利用gcc对test.c进行预处理

gcc -E test.c -o test.i
//命令中test.c为源文件,-o参数指定预处理后的输出文件为test.i

打开test.i,找到文件最后,可以看到如下结果

通过gcc -E命令解释了代码中#include,并且替换了#define的内容。
C语言编译的第二个步骤为编译,这一步是将C语言代码(上一步预处理后的.i文件)转换为汇编语言,具体命令如下

gcc -S test.i -o test.s
//命令中test.i为处理源文件,-o参数指编译后的输出文件为test.s

运行完该命令会产生.s汇编文件
C语言编译的第三个步骤为汇编,在这个阶段,汇编代码会生成二进制代码(二进制代码文件以.o为后缀名)

gcc -c test.s -o test.o

C语言编译的最后一个步骤为链接,在这个阶段,会链接找到依赖的库文件(静态与动态),将二进制文件链接为可执行文件,一般链接命令如下

gcc  [目标文件] -o [可执行文件] -l [动态库名]

由于这个例子没有动态库,可以直接

gcc  test.o -o test

运行过后你会生成可执行文件,./test执行,结果如图

如果利用gcc进行多文件编译,一般有两种编译方法,假设有文件test1.c与test2.c,第一种编译方法为多个文件一起编译

gcc  test1.c test2.c -o test

将test1.c与test2.c编译连接成test可执行文件
第二种编译方法为分别编译各个源文件,之后对编译输出文件进行链接

gcc -c test1.c //将test1.c编译为test1.o
gcc -c test2.c  //将test2.c编译为test2.o
gcc -o test1.o test2.o -o test//链接

一般而言,我们更多的使用第二种编译方式,主要原因如下:在一个很多文件的大型工程中,假如我们修改了其中一个文件,使用第一种编译方法就需要把所有文件都重新编译,而第二种编译方法只需要重新编译这个文件然后链接即可。

二、Makefile文件

在使用gcc命令时,我们往往需要对工程进行操作,一个工程又具有多个文件,如果按照上述编译方法,往往需要输入很多指令,而且修改文件也不方便,因此引入Makefile文件解决该问题。下面以一个例子简单讲解Makefile的编写与使用。首先建立一个文件夹,叫Makefiletest,然后在该文件夹里创建cal.c,cal.h,input.c,input.h,main.c一共5个文件,分别输入以下代码:

//cal.c
#include"cal.h"int caltwonum(int a,int b)
{return a+b;
}
//cal.h
#ifndef _CAL_H
#define _CAL_Hint caltwonum(int a,int b);
#endif//input.c
#include<stdio.h>
#include"input.h"void inputint(int* a,int* b)
{printf("请输入两个整数:");scanf("%d %d",a,b);printf("\r\n");
}//input.h
#ifndef _INPUT_H
#define _INPUT_Hvoid inputint(int* a,int* b);
#endif//main.c
#include<stdio.h>
#include"input.h"
#include"cal.h"int main()
{int a,b,sum;inputint(&a,&b);sum = caltwonum(a,b);printf("%d + %d = %d \r\n",a,b,sum);return 0;
}

同时在Makefiletest文件夹下创建Makefile文件,输入以下内容

#main是需要生成的目标文件,它依赖main.o input.o cal.o
main:main.o input.o cal.o
#gcc命令,通过main.o input.o cal.o生成main,语句前面要用TABgcc -o main main.o input.o cal.o
#main.o是目标文件,依赖main.c文件,通过gcc -c main.c生成main.o文件
main.o:main.cgcc -c main.c
input.o:input.cgcc -c input.c
cal.o:cal.cgcc -c cal.c#增加clean命令
clean:
#删除所有以.o结尾的文件,使用了通配符*rm *.o
#删除可执行文件mainrm main

创建完成后输入make命令就可以编译文件,生成可执行文件main

可以看到,通过Makefile完成了一系列代码编译与链接,假如此时我修改了cal.c,把a+b换成a*b,此时再次make

可以看到,make仅仅重新编译了cal.c文件,不会整个工程全部编译。
其实,在上述Makefile中,我们可以利用一些Makefile语法简化编写。
1.变量,可以通过定义变量替换某些语句,例如对上述Makefile进行修改

#用objects替换main.o input.o cal.o
objects = main.o input.o cal.o
main:$(objects)gcc -o main $(objects)

在Makefile中,变量赋值有四种方式,下面分别讲解
1.简单赋值(:=)常规赋值方式,只对当前语句变量有效
2.递归赋值(=)赋值语句会影响多个变量,所有与目标变量相关的其他变量都会受影响
3.条件赋值(?=)如果变量没有定义,则使用符号中的值定义变量,如果该变量已经被赋值,则此语句无效
4.追加赋值(+=)原变量用空格隔开追加一个新值

下面以一段Makefile代码讲解不同赋值方式

x:=hjl
y:=hjl$(x)
x:=kk
x1=hjl
y1=hjl$(x1)
x1=kk
x2=lop
x2?=56
x3=12
x3+=$(x2)
test1:@echo "x == $(x)"@echo "y == $(y)"@echo "x1 == $(x1)"@echo "y1 == $(y1)"@echo "x2 == $(x2)"@echo "x3 == $(x3)"

编写好以后在终端输入make test1,可以得到如下结果

首先我们来对比y与y1的输出,可以看到x采用简单赋值,后续x的改变并没有影响到y,而x1采用递归赋值,一旦x1改变将影响整个文件中与x1有关的变量
2.Makefile目标文件搜索
一个工程可能存在多个源文件,这些源文件不一定在同一个目录下,如果不在一个目录下,按之前Makefile的写法就会出错,我们需要告诉Makefile文件工程源文件在哪?因此Makefile引入了目标文件搜索的功能。
常见的搜索方式有VPATH与vpath,这两个一看仅仅只有大小写的区别,但实际上功能大不相同。首先是VPATH,你可以把它理解为一个环境变量,它的用法如下

VPATH := 搜索路径
#例子
#如果Makefile在当前文件夹没有找到需要文件,则去src文件夹下寻找
VPATH := src
#多个路径之间需要:或者空格隔开,下面这句话表示先搜索hjl文件夹,再搜索src文件夹
VPATH := hjl src

当Makefile在当前文件下找不到需要的文件时,会访问到VPATH变量中的目录下寻找该文件,相当于VPATH给Makefile提供了更多搜索位置
vpath相当于加了条件的VPATH,使用语法如下

#用法一
vpath 条件 路径
#例子
#从hjl文件夹搜索test.c文件
vpath test.c hjl
#多个搜索路径的情况,路径之间用空格或冒号隔开
vpath test.c hjl:src
#用法二
vpath
#清除所有已设置的文件路径

3.伪目标
在之前的例子中,我们在Makefile使用了clean命令,在终端中输入make clean,它会执行clean语句之下的命令,方便我们进行操作。伪目标在Makefile文件中起到了命令替代的作用,用一个简单语句代替原本复杂的命令,简化书写。此外,伪目标要避免与文件重名,一般在Makefile文件中可以用.PYTHON来指明一个目标为伪目标

.PYTHON : clean
clean:rm *.o

4.函数
Makefile为了方便用户使用,提供了一些函数给用户使用,使用语法如下

$(<function> <arguments>)
or
${<function> <arguments>}

function为函数名,argument为函数参数

三、更多Makefile学习

参考跟我一起写Makefile

gcc与Makefile相关推荐

  1. 小羊手把手教你gcc gdb makefile

    1. vim编辑hello.c 2. 分别查看下面gcc指令的结果 GCC交叉编译器简介: 最早为GNU C Compiler是GNU推出的功能强大.性能优越的多平台编译器,是GNU的代表作之一; 支 ...

  2. 使用gcc以及makefile编译C程序

    文章目录 一. gcc编译C程序 1. ubuntu 18.04下使用gcc编译C程序 2. window10下使用gcc编译C程序 二. win10下使用编译软件编译C程序 三. makefile方 ...

  3. ubuntu系统用gcc和Makefile编写程序

    一.用gcc编写程序 步骤一 命令:gcc -c sub1.c 作用:将sub1.c程序转换为目标文件sub1.o 步骤二 命令:gcc main1.c sub1.o -o main1 作用:编译ma ...

  4. STM32CubeMX GCC工程Makefile内容详解

    STM32CubeMX GCC工程Makefile内容详解 基础介绍 因为项目原因,需要对编译系统进行一些比较复杂的使用,但是我对于编译系统这一块并不是非常精通了解,所以需要进行一下学习.正巧,众所周 ...

  5. c语言项目为什么要build?(gcc、makefile、cmake(qmake)、CMakeLists.txt)(qmake、cmake、qbs区别解析)(qmake还是cmake,mingw作用)

    搞不太懂gcc和cmake(qmake)等的区别 1.gcc是GNU Compiler Collection(就是GNU编译器套件),也可以简单认为是编译器, 它可以编译很多种编程语言(括C.C++. ...

  6. gcc/g++/makefile/easymake/cmake/xmake/nmake ...

    最简单的Makefile,但是还是大程序少不了makefile工具 #CC=arm-linux-gnueabihf- CC= target:     $(CC)gcc -o algo_main alg ...

  7. Linux下make使用gcc编译,Linux下GCC和Makefile实例(从GCC的编译到Makefile的引入)

    一.确认已经装好了GCC和Make的软件包 可以使用whereis命令查看: 如果whereis  gcc和whereis  make命令有结果,说明安装了这两个软件,可以继续往下做. 二.使用GCC ...

  8. Linux命令全家桶以及vim/gcc/gdb/makefile/yum

    基本指令 ls指令:对于目录,列出该目录下的所有子目录与文件:对于文件,列出文件名以及其他信息. ls -l //一行只输出一个文件 pwd指令:显示当前用户所在目录 cd指令:改变工作目录,将当前工 ...

  9. Linux~一些基本开发工具的使用(yum,vim,gcc,gdb,makefile)

    目录 一.yum--安装软件 二.Vim--文本编辑器 (1).命令模式 (2).底行模式 (3).插入模式 tips:给对应用户配置sudo命令 一些注意事项 三.gcc/g++--编译器 (1). ...

  10. Ubuntu下使用gcc和makefile编写c语言程序

    文章目录 前言 一.gcc编写c语言程序 1.hello world的输出 2.简单程序的编译与运行 3.windows环境下的编译运行结果对比 二.makefile编写c语言程序 总结 前言 本文通 ...

最新文章

  1. Python中matplotlib默认绘制的条形图比较胖?如何设置成体型匀称的条形图,达到最佳的可视化效果。
  2. 玩转“网上邻居”之WINS解析(一)
  3. python编程基础怎么学英语_英语不行而且从没碰过编程,如何0基础学python?
  4. Java基础day10
  5. java使用原生语句操作mongo_Java 中 MongoDB 使用指南
  6. SpringMvc三大组件详解
  7. Spring应用上下文 - - context
  8. PCA(Principal Component Analysis)原理简单分析
  9. 输入你的密码来连接到_手机怎样连接WiFi?详细步骤,教你操作
  10. HDOJ 1282 回文数猜想(回文串类)
  11. 音视频学习之 - H264解码
  12. StanfordDB class自学笔记 (5) JSON Data
  13. 代码行数统计工具,java,go,c++,html文件都适用
  14. Unity读取内部、外部资源详解
  15. 大学生搜题软件哪个好用?2020搜题软件排行榜
  16. 如何在Microsoft Word 2010中创建自定义封面
  17. 数学中常见的arg min,arg max是什么意思
  18. 诛仙账号合并服务器,《诛仙3》10/17 服务器数据互通公告
  19. 优麒麟桌面闪烁_UKUI 桌面环境登陆 Arch Linux!
  20. 电巢:继腾讯与联通混改后,又有两家企业官宣,科技巨头与国企混改,意味着什么?

热门文章

  1. zxvf的真正含义,别光会敲了!!
  2. CentOS6与CentOS7的差异对比
  3. 2020上半年已过,疫情下互联网迎来红利期,Android技术下半场在哪?
  4. Python后端学习路线
  5. 信息可视化中的时间线设计,不懂的过来
  6. Ajax实现验证用户登陆
  7. Python使用小教程03——tiff/grib/nc/hdf/txt数据的读写
  8. 逆序对的数量(归并排序模板y神)
  9. 携程如何从海量数据中构建精准用户画像?
  10. 关于ZFPlayer集成播放 rtmp 视频流的总结