在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 提醒

相关文章
|
1月前
|
存储 自然语言处理 编译器
【C语言】编译与链接:深入理解程序构建过程
【C语言】编译与链接:深入理解程序构建过程
|
1月前
|
自然语言处理 编译器 Linux
【C语言篇】编译和链接以及预处理介绍(上篇)1
【C语言篇】编译和链接以及预处理介绍(上篇)
40 1
|
3月前
|
NoSQL 编译器 程序员
【C语言】揭秘GCC:从平凡到卓越的编译艺术,一场代码与效率的激情碰撞,探索那些不为人知的秘密武器,让你的程序瞬间提速百倍!
【8月更文挑战第20天】GCC,GNU Compiler Collection,是GNU项目中的开源编译器集合,支持C、C++等多种语言。作为C语言程序员的重要工具,GCC具备跨平台性、高度可配置性及丰富的优化选项等特点。通过简单示例,如编译“Hello, GCC!”程序 (`gcc -o hello hello.c`),展示了GCC的基础用法及不同优化级别(`-O0`, `-O1`, `-O3`)对性能的影响。GCC还支持生成调试信息(`-g`),便于使用GDB等工具进行调试。尽管有如Microsoft Visual C++、Clang等竞品,GCC仍因其灵活性和强大的功能被广泛采用。
122 1
|
1月前
|
Ubuntu 应用服务中间件 nginx
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
本文是关于Ubuntu系统中使用ffmpeg 3.2.16源码编译OpenCV 3.4.0的安装笔记,包括安装ffmpeg、编译OpenCV、卸载OpenCV以及常见报错处理。
136 2
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
|
1月前
|
存储 自然语言处理 编译器
|
21天前
|
Ubuntu 编译器 计算机视觉
Ubuntu系统编译OpenCV4.8源码
【10月更文挑战第17天】只要三步即可搞定,第一步是下载指定版本的源码包;第二步是安装OpenCV4.8编译需要的编译器与第三方库支持;第三步就是编译OpenCV源码包生成安装文件并安装。
|
1月前
|
编译器 Linux C语言
【C语言篇】编译和链接以及预处理介绍(下篇)
【C语言篇】编译和链接以及预处理介绍(下篇)
32 1
【C语言篇】编译和链接以及预处理介绍(下篇)
|
1月前
|
自然语言处理 编译器 Linux
C语言中抽象的编译和链接原理
C语言中抽象的编译和链接原理
20 1
|
1月前
|
Ubuntu Shell API
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
|
1月前
|
存储 C语言
【C语言篇】编译和链接以及预处理介绍(上篇)2
【C语言篇】编译和链接以及预处理介绍(上篇)
36 0