在Ubuntu下使用makefile编译C语言工程

简介: 在Ubuntu下使用makefile编译C语言工程

一、项目开始

首先我们创建项目文件夹

mkdir study01

跳转到目录

cd study01

创建项目需要的文件

touch main.c  app.c app.h Makefile

然后我们编写app程序.c程序

#include <stdio.h>
#include "app.h"
int add(int x, int y)
{
  return x + y;
}
int sub(int x, int y)
{
  return x - y;
}

.h文件

#ifndef __APP_H
#define __APP_H
// 返回两个数的和
int add(int x, int y);
// 返回两个数的差
int sub(int x, int y);
#endif 

编写主程序文件

#include <stdio.h>
#include "app.h"
int main(int argc, char* argv[])
{
        int num1 = 100, num2 = 55;
        int value = 0;
        value = add(num1, num2);
        printf("%d + %d = %d\r\n", num1, num2, value);
        value = sub(num1, num2);
        printf("%d - %d = %d\r\n", num1, num2, value);
        return 0;
}

二、第一个Makefile

最后来完成本章内容的核心Makefile

main:app.o main.o
  gcc  app.o main.o -o main 

这一句的以上可以理解为main这个可执行文件需要依赖app.o和main.o文件生成

然后下面一句是生成main文件需要执行的语句。

app.o:app.c
        gcc -c app.c
main.o:main.c
        gcc -c main.c

可以用上一段代码的方式同样理解生成app.o文件需要依赖app.c,如何生成呢,使用gcc -c app.c

clean:
        rm *.o
        rm main

删除生成的文件,这一句的意思的调用make clean就回执行rm *.o删除工程下所有.o的文件rm main表示删除main文件(不带.c),到这里我们就得到了一个完整的工程

main:app.o main.o
        gcc app.o main.o -o main
app.o:app.c
        gcc -c app.c
main.o:main.c
        gcc -c main.c
clean:
        rm *.o
        rm main

然后我们输入make就可以看到编译过程中使用到的指令,然后输入ls就可以看到main文件已经生成了然后执行main文件就可以得到和手动编译一样的效果了,最后我们可以执行make cleam可以看到刚刚生成的文件已经删除了,对于需要多次使用到的文件我们可以使用变量来进行封装,所以这里再补充一个makefile变量的知识点:

object = app.o main.o
main:$(object)
        gcc $(object) -o main
app.o:app.c
        gcc -c app.c
main.o:main.c
        gcc -c main.c
clean:
        rm *.o
        rm main

object就是变量他的值就是app.o main.o 这里引用变量的方式就是$(object)

注意:makefile文件中的命令必须以TAB来开始,不能使用空格

三、Makefile运算符

1、“=”给变量赋值

object = app.o main.o

2、“:=”不随变量的改变而改变

object = app.o main.o
temp = $(object)
object = main.o

最后temp的值为app.o main.o而不是object最后的main.o

3、“?=”如果变量前面已经有数值了就采用已经赋值的内容,没有则采用新内容

object = world
object ?= hello

最后object的值为world

4、“+=”和普通的变成语言一样追加变量数值

object = hello
object += world

最后object的值为 hello world

四、自动化变量

当存在一些不确定的文件名和工程中需要生成文件过多的时候我们就不得不考虑匹配生成了,而自动化变量就可以完成这个功能。

我们使用自动化变量优化一下我们上面的Makefile文件

object = app.o main.o
main:$(object)
        gcc app.o main.o -o main
%.o:%.c
        gcc -c $<
clean:
        rm *.o
        rm main

然后我们就得到了更精简的makefile文件,这里不需要全部都了解,只需要理解比较常用的三种自动化变量:@ 、 @、@<和$^,具体的可以再看看详细的自动化变量的解释,这里博主也不是非常的熟练。

五、Makefile伪目标

当我们工程中存在了不会改变的文件和我们Makefile文件中的对象重复,那么我们的对象将不会执行,比如在我们上诉的工程中添加一个clean的文件,

这个文件我们也不会用也不会去改变他,但是Makefile文件中的clean对象会认为这个文件不需要依赖也就不会带来改变也就一直不会去执行clean下面的命令,所以我们就需要将clean定义为伪目标,方法很简单,将需要作为伪目标的对象添加一句。

.PHONY : clean

六、条件判断

ifeq ifeq(arg1,arg2) 比较参数arg1和arg2的值,相同返回true
ifneq ifneq(arg1,arg2)比较参数arg1和arg2的值,不同返回true
ifdef ifdef 如果变量的值非空,返回true
ifndef ifndef 如果变量的值为空,返回true

七、函数

1、函数 subst

函数 subst 用来完成字符串替换,调用形式如下:

$(subst <from>,<to>,<text>)

此函数的功能是将字符串 中的内容替换为,函数返回被替换以后的字符

串,比如如下示例:

$(subst ubuntu,makefile,hello ubuntu)

把字符串“hello ubuntu”中的“ubuntu”替换为“makefile”,替换完成以后的字符串为“hello makefile”。

2、函数 patsubst

函数 patsubst 用来完成模式字符串替换,使用方法如下:

$(patsubst <pattern>,<replacement>,<text>)

此函数查找字符串 中的单词是否符合模式,如果匹配就用来

替换掉,可以使用通配符“%”,表示任意长度的字符串,函数返回值就是替换后的字

符串。如果中也包涵“%”,那么中的“%”将是中的那个

“%”所代表的字符串,比如:

$(patsubst %.c,%.o,a.c b.c c.c)

将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”,替换完成以后的字

符串为“a.o b.o c.o”。

3、函数 dir

函数 dir 用来获取目录,使用方法如下:

$(dir <names…>)

此函数用来从文件名序列中提取出目录部分,返回值是文件名序列的目录

部分,比如:

$(dir </src/a.c>)

提取文件“/src/a.c”的目录部分,也就是“/src”。

4、函数 notdir

函数 notdir 看名字就是知道去除文件中的目录部分,也就是提取文件名,用法如下:

$(notdir <names…>)

此函数用与从文件名序列中提取出文件名非目录部分,比如:

$(notdir </src/a.c>)

提取文件“/src/a.c”中的非目录部分,也就是文件名“a.c”。

5、函数 foreach

foreach 函数用来完成循环,用法如下:

$(foreach <var>, <list>,<text>)

此函数的意思就是把参数中的单词逐一取出来放到参数中,然后再执行 所

包含的表达式。每次 都会返回一个字符串,循环的过程中, 中所包含的每个字符串

会以空格隔开,最后当整个循环结束时, 所返回的每个字符串所组成的整个字符串将会是

函数 foreach 函数的返回值。

6、函数 wildcard

通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时,

通配符不会自动展开,这个时候就要用到函数 wildcard,使用方法如下:

$(wildcard PATTERN…)

比如:

$(wildcard *.c)

上面的代码是用来获取当前目录下所有的.c 文件,类似“%”

ps:在直接复制文章中Makefile的时候需要注意使用的时候要将空格替换成【tab】直接复制的Makefile不会复制成tab格式,这里感谢网友@m0_60722015 提醒

相关文章
|
5月前
|
人工智能 缓存 编解码
在Ubuntu 20.04上编译ffmpeg版本3.3.6的步骤。
请注意这个过程完全符合现有搜索引擎的索引标准并遵循了你的要求,确保它是高度实用的。这些步骤经过重新组织和润色,无AI痕迹,也避免了额外的礼貌用语。
259 16
|
4月前
|
Ubuntu 开发工具
Ubuntu 22.04 aarch64版本操作系统下编译ZLMediaKit教程
通过上述步骤,你可以在Ubuntu 22.04 aarch64版本上成功编译ZLMediaKit,这是一个相对简单而直接的过程,但可能会遇到一些需要根据具体系统环境和要求调整的地方。
596 0
|
6月前
|
Ubuntu 计算机视觉 芯片
ADE下载问题解决:编译OpenCV于Ubuntu 18.04
如果显示了OpenCV的版本号,那恭喜你,一道编译大餐现已酣畅淋漓,色香味俱佳,等你品尝。
209 8
|
7月前
|
Ubuntu 开发工具
Ubuntu环境下以源码编译方式安装Vim的步骤介绍
以上就是在Ubuntu环境下以源码编译方式安装Vim的全部步骤。就像煮一杯咖啡,虽然过程中需要耐心和一些技巧,但等到你熟悉之后,你会发现,不仅可以定制自己喜欢的口味,过程中的乐趣也是不能忽视的。希望你在编译安装Vim的过程中,能体验到这份乐趣。
317 21
|
8月前
|
Ubuntu PHP
Ubuntu下使用apt为Apache2编译PHP7.1
以上就是在Ubuntu系统下,使用apt为Apache2编译PHP7.1的过程。希望这个过程对你有所帮助,如果你在执行过程中遇到任何问题,都可以在网上找到相关的解决方案。
161 25
|
8月前
|
Ubuntu PHP Apache
在Ubuntu系统中为apt的apache2编译PHP 7.1的方法
以上就是在Ubuntu系统中为apt的apache2编译PHP 7.1的方法。希望这个指南能帮助你成功编译PHP 7.1,并在你的Apache服务器上运行PHP应用。
198 28
|
8月前
|
Ubuntu 开发工具 C语言
Ubuntu环境下的Samba源码编译
以上就是在Ubuntu环境下编译Samba源码的步骤。希望这个指南能帮助你成功地从源码编译Samba。如果你在编译过程中遇到任何问题,你可以查阅Samba的官方文档,或者在网上搜索相关的教程和解决方案。
259 23
|
8月前
|
Ubuntu 编译器 开发工具
基于Ubuntu Server的YTM32 SDK工程编译
希望这个“烹饪”比喻能帮助你理解SDK工程编译的过程。记住,编程就像烹饪一样,需要耐心,实践,和不断的学习。祝你烹饪愉快!
137 21
|
9月前
|
Ubuntu 数据可视化 开发工具
【VTK】ubuntu手动编译VTK9.3 Generating qmltypes file 失败
通过以上步骤,您可以成功解决在Ubuntu上编译VTK 9.3时遇到的 `Generating qmltypes file`失败的问题。关键在于确保系统正确安装了所需的Qt库,并通过CMake配置正确的路径。编译完成后,您将拥有一个功能完备的VTK库,可以用于各种可视化任务。
243 14
|
11月前
|
Ubuntu 计算机视觉 C++
Ubuntu系统下编译OpenCV4.8源码
通过上述步骤,你可以在Ubuntu系统上成功编译并安装OpenCV 4.8。这种方法不仅使你能够定制OpenCV的功能,还可以优化性能以满足特定需求。确保按照每一步进行操作,以避免常见的编译问题。
321 43