https://blog.csdn.net/zhemingbuhao/article/details/88207566

https://blog.csdn.net/qq_37863891/article/details/90637543

https://blog.csdn.net/zhemingbuhao/article/details/88207566

 

一、Make简介:

工程管理器,顾名思义,是指管理较多的文件,Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件文件的内容来执行大量的编译工作,Make将只编译改动的代码文件,而不用完全编译。

Makefile文件一般和项目的其他源文件放在同一个目录下。在机器上可以同时存在许多不同的makefile文件,如果一个大项目,可以用多个不同的makefile文件来分别管理项目的不同部分。

Make命令和makefile文件的结合提供了有一个在项目管理领域十分强大的工具,不仅可以用于控制源代码的编译,而且还可以用于手册也的编写以及将应用程序安装到目标目录。

一个简单的makefile1的例子:

all:
    gcc main.c -o main
clean: 
    rm -rf main main.o
或者:

main:main.o
    gcc main.o -o main
main.o:main.c
    gcc -c main.c 
clean:
    rm -rf main.o main
在终端运行make –f makefile1的时候,可以看到通过两个步骤将源文件编译生成可执行文件

二、Make程序中有许多选项,其中最常用的3个选项为:

1、-k:作用是在让make命令在发现错误时仍然就执行,而不是在检测到第一个错误时就停止,所以可是使用这个选项在一次操作中发下所有未编译成功的源文件

2、-n:作用是让make命令输出将要执行的操作步骤,而不是真正执行这些操作

3、-f <filename>:作用是告诉make将文件名为filename的我文件作为makefile文件。如果未使用这个选项,标准版的make命令将优先在当前命令下查找名称为makefile的文件,如果不存在名称makefile的文件,则开始查找名为Makefile的文件。

比如新建文件makefile:

all:
   @echo ""
   @echo "This is a makefile test "
   @echo "End test"
   @echo ""
然后在终端运行:

然后再新建Makefile:

all:
   @echo ""
   @echo "This is a Makefile test "
   @echo "End test"
   @echo ""
运行后

然后使用-f选项,

all:
    @echo ""
    @echo "This is a make command test"
    @echo "End test"
    @echo ""
可以看出已经不识别makefile的语法高亮,那使用-f选项指定运行maketest文件,效果如下。

三、Makefile中的宏

可以通过KEY=value在makefile中定义宏。可以使用$(KEY)或者${KEY}引用宏

可以将上述的文件makefile1修改成makefile2:

CC = gcc
CFLAGS = -g -Wall -O 
 
main:main.o
    $(CC) main.o -o main
main.o:main.c
    $(CC) $(CFLAGS) -c main.c 
clean:
    rm -rf main.o main
终端执行命令make -f makefile2,可以看到:

Makefile中的特殊宏定义:

$*:不包括后缀名的当前依赖文件的名称

    $+         所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件

    $<         第一个依赖文件的名称

    $?         所有时间戳比目标文件晚的依赖文件,并以空格分开

    $@        目标文件的完整名称

    $^          所有不重复的目标依赖文件,以空格分开

    -:         告诉make命令忽略所有的错误

    @:       告诉make在执行命令前不要将改命令显示在标准输出上

那么,上面的makefile2可以修改为:

CC = gcc
CFLAGS = -g -Wall -O 
main:main.o
    $(CC) $^ -o $@
%.o:%.c
    $(CC) $(CFLAGS) -c $^
clean:
    rm -rf main.o main
四、如果有多个依赖文件,那么怎么写呢

1、比如如下工程(场景一:下列的文件都在一个目录中,五个文件分别是main.c,add.c,add.h,sub.c,aub.h):

main.c的内容为:

#include <stdio.h>
#include "add.h"
#include "sub.h"
 
int main()
{
    int a = 10, b = 5;
    printf("a + b = %d\r\n", add(a, b));
    printf("a - b = %d\r\n", sub(a, b));
    return 0;
}
add.c的内容为:

#include <stdio.h>
 
int add(int a, int b)
{
    return a + b;
}
add.h的内容为:

#ifndef __ADD_H__
#define __ADD_H__
 
int add(int, int);
 
#endif
sub.c为:

#include <stdio.h>
 
int sub(int a, int b)
{
    return a - b;
}
sub.h为:

#ifndef __SUB_H__
#define __SUB_H__
 
int sub(int, int);
 
#endif
那么makefile可以这样写:

CC = gcc
CFLAGS = -g -O  -Wall
 
main:add.o sub.o main.o 
    $(CC) $^ -o $@
%.o:%.c
    $(CC) $(CFLAGS) -c $^
clean:
    rm -rf main main.o add.o sub.o
在终端运行make命令后:

但是这样的会有一个问题,那就是如果项目中文件比较多的话,在这一个目录下会有好多原文件和头文件,对于项目的维护也不方便,那么可以做如下的更改(以下的目录结构,学过STM32的同学应该比较清楚,这个是个人习惯的问题,其他的结构可能会更好^_^):

在项目文件家下新建文件夹,比如例子中的,可以新建四个文件夹,分别是:

Main add sub obj

将main.c移动到main文件夹中,并且新建makefile,输入内容:

$(OBJDIR)/main.o:main.c
    $(CC) -c $^ -o $@
将add.c和add.h移动到add文件夹中,

$(OBJDIR)/add.o:add.c
    $(CC) -c $^ -o $@
将sub.c和sub.h移动到sub文件夹中

$(OBJDIR)/sub.o:sub.c
    $(CC) -c $^ -o $@
然后在obj文件夹中新建makefile并且写入:

$(BINDIR)/$(BIN):$(OBJ) 
       $(CC) $^ -o $@  $(OBJHEAD) $(OBJLINK)
然后在顶层目录下新建文件makefile,写入内容如下:

CC = gcc
CFLAGS = -g -O -Wall
 
OBJ := add.o sub.o main.o
TOPDIR := $(PWD)
OBJDIR := $(TOPDIR)/obj
BINDIR := $(TOPDIR)/bin
BIN := main
 
SUBDIR :=  add sub main obj
OBJHEAD := $(TOPDIR)/add/add.h $(TOPDIR)/sub/sub.h
OBJLINK := --std=c99
 
export CC TOPDIR OBJDIR BINDIR BIN OBJLINK OBJ
 
all:CHECKDIR $(SUBDIR)
CHECKDIR:
    mkdir -p $(SUBDIR) $(BINDIR)
$(SUBDIR):RUN
    make -C $@
RUN:
    
clean:
    rm -rf $(OBJDIR)/*.o $(BINDIR) 
在这里简单解释一下makefile中的相关命令:

CC = gcc #声明编译器

CFLAGS = -g -O -Wall #声明编译的选项

OBJ := add.o sub.o main.o #声明依赖的文件

TOPDIR := $(PWD) #声明顶级目录

OBJDIR := $(TOPDIR)/obj #定义编译中间文件的存放的目录

BINDIR := $(TOPDIR)/bin #定义可执行文件的存放目录

BIN := main #定义可执行文件的名称

SUBDIR :=  add sub main obj #声明所有的子目录

OBJHEAD := $(TOPDIR)/add/add.h $(TOPDIR)/sub/sub.h #声明所有的头文件

OBJLINK := --std=c99 #声明编译时候需要的链接护着其他的选项

export CC TOPDIR OBJDIR BINDIR BIN OBJLINK OBJ #到处所有的全局变量,给次级目录中的makefile只用

all:CHECKDIR $(SUBDIR) #强大的all

mkdir -p $(SUBDIR) $(BINDIR)

        对于makedir中的的选项:

                -m 对新建目录设置存取权限。也可以用chmod命令设置。

                -p 可以是一个路径名称。此时若路径中的某些目录尚不存在,加上此选项后,系统将自动建立好那些尚不存在的目录,                    即一次可以建立多个目录。

make -C $@

        当make的目标为all时,

                -C $@ 指明跳转到次级目录下读取那里的Makefile;

                M=$(PWD) 表明读取完Makefile(次级目录下Makefile)执行完成后返回到当前目录继续读入、执行当前的Makefile(                      顶级目录下Makefile)。   

clean:

        关于clean的规则,在make clean的时候,并不产生目标文件,且没有依赖文件,所以命令都会执行,但如果目录中存在名                为“clean”的文件或者目录,则规则没有依赖文件,且clean始终是最新的,所以命令不会被执行,为了避免这个问题,可以使            用.PHONY来指明改目标,则将上述的clean部分修改为:

.PHONY:clean
clean:
    rm -rf $(OBJDIR)/*.o $(BINDIR) 
这样在执行"make clean"的时候就不管"clean"文件或者目录是否存在,正常执行makefile中clean的命令。

PHONY 目标并非是由其它文件生成的实际文件,只是在显式请求时执行命令的名字。

rm -rf $(OBJDIR)/*.o $(BINDIR) #删除编译生成的中间文件以及可执行文件的存储的目录(可执行文件同时被删除)

可以使用tree命令查看一下当前的目录的结构:

那么,在编译的时候,直接在顶层目录下make即可完成所有的编译工作:

编译完成后,在看一下目录结构,多了一个目录bin:

2、如果需要跨平台编译和测试的话,可以在makefile中增加条件判断,而且为了让makefile打印出来的信息更加的直观和人性化,可以适当的添加一些提示信息,简单的更改的makefile如下:

ifeq ($(t), 0)
TOOL=
else
TOOL=arm-none-linux-gnueabi-
endif
 
CC = $(TOOL)gcc
CFLAGS = -g -O -Wall
 
OBJ := add.o sub.o main.o
TOPDIR := $(PWD)
OBJDIR := $(TOPDIR)/obj
BINDIR := $(TOPDIR)/bin
BIN := main
 
SUBDIR :=  add sub main obj
OBJHEAD := $(TOPDIR)/add/add.h $(TOPDIR)/sub/sub.h
OBJLINK := --std=c99
 
export CC TOPDIR OBJDIR BINDIR BIN OBJLINK OBJ
 
all:CHECKDIR $(SUBDIR)
    @echo "*****************************************************************************"
    @echo "*                                                                           *"
    @echo "*                 Congratulations! Compile completed!!!                     *"
    @echo "*       Executable file name is : $(BIN)    "
    @echo "*  Executable file in directory : $(BINDIR)"
    @echo "*                                                                           *"
    @echo "*****************************************************************************"
CHECKDIR:
    @echo "*****************************************************************************"
    @echo "*                                                                           *"
    @echo "* Create subfolders:                                                        *"
    mkdir -p $(SUBDIR) 
    mkdir -p $(BINDIR)
    @echo "*                                                                           *"
    @echo "*               Successful Creation of subfolders!                          *"
    @echo "*                                                                           *"
    @echo "*****************************************************************************"
$(SUBDIR):RUN
    make -C $@
    @echo "*****************************************************************************"
RUN:
    @echo "*****************************************************************************"
    @echo "*                                                                           *"
    @echo "* All subdirectories are:                                                   *"
    @echo "*    "$(SUBDIR)
    @echo "* All links are:                                                            *"
    @echo "*    "$(OBJLINK)
    @echo "*                                                                           *"
    @echo "*****************************************************************************"
    @echo "*                                                                           *"
    @echo "*                            begin Compile                                  *"
    @echo "*                                                                           *"
    @echo "*****************************************************************************"
clean:
    rm -rf $(OBJDIR)/*.o $(BINDIR) 
help:
    @echo "*********************************** help ************************************"
    @echo "*                                                                           *"
    @echo "*                            Option Description                             *"
    @echo "*                                                                           *"
    @echo "*********************************** help ************************************"
所以,以我的选项为例,如果需要在电脑上运行,则在make的时候需要make t=0命令,如果需要在arm板子上运行,那么就可以直接make就可以了,以下是两种效果的截图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值