makefile文件编写「建议收藏」

makefile文件编写「建议收藏」makefile文件用于管理和组织代码工程的编译和链接,其不是可执行文件,其被make工具解析并完成相关动作,下面笔者将介绍makefile中常用的一些语法说明:1、文件包含:语法:include文件名作用:将其它makefile文件包含进来,组成一个更大的makefile文件,这样有利于makefile模块化编程。通常我们将一些配置选项分开成一个独立的makefile文件,这…

大家好,又见面了,我是你们的朋友全栈君。

makefile文件用于管理和组织代码工程的编译和链接,其不是可执行文件,其被make工具解析并完成相关动作,下面笔者将介绍makefile中常用的一些语法说明:

 

1、文件包含:

语法:include 文件名

作用:将其它makefile文件包含进来,组成一个更大的makefile文件,这样有利于makefile模块化编程。通常我们将一些配置选项分开成一个独立的makefile文件,这样有利于makefile文件的管理,或将模块代码的依赖关系和需要编译的文件信息独自写到一个 makefile文件中,最终通过include命令形成一个顶层makefile文件来完成整个工程代码的编译和链接。

 

2、变量定义:

语法:变量名 := 变量值

在makefile中,经常先定义一个变量,然后往该变量中追加新的值(通过+=符号),比如先定义一个C_SRCS变量(该值可以为空),然后将代码文件test1.c和test2.c添加到C_SRCS中,其代码如下所示:

C_SRCS :=

C_SRCS += test1.c test2.c

 

在makefile中有一类特殊的变量,其名称为 自动变量,自动变量的值会依据规则中的target 和 prerequisites自动计算其值,自动变量一般以开头$为起始,下面将列出一些常见的自动变量:

       $@ 为规则中的target名称。

 

       $< 为规则中第一个prerequisite名称

 

 

3、内置命令:

Makefile中内置了一些常用的命令,有字符串处理函数subst、patsubst、strip、findstring、filter、filter-out、sort、word、wordlist、words、firstword、lastword;文件名处理函数dir、notdir、suffix、basename、addsuffix、addprefix、join、wildcard、realpath、abspath;条件处理函数if;循环处理函数foreach等。下面介绍一些常用的函数:

wildcard 函数:其语法为$(wildcard pattern),pattern为匹配的模式,比如$(wildcard %.c) 为查找当前路径下面文件名以.c结尾的文件。

foreach 函数:其语法为$(foreach var,list,text),每循环一次var从list中按顺序取值一个,然后执行一次text代码并记录结果,最终返回所用text代码运行的结果。比如

dirs := C_DIR S_DIR

file := $(foreach dir,$(dirs),$(wildcard $(dir)/*))

将C_DIR和S_DIR文件夹下面的所有文件添加到file变量中。

 

dir 函数:其语法为$(dir names…),用于获取names中文件夹路径,比如

$(dir src/foo.c hacks)

将获得文件夹路径 src/ ./

 

notdir 函数:其语法为$(notdir names…),用于获取names中除去路径的信息,比如

$(notdir src/foo.c hacks)

将获得文件信息 foo.c hacks

 

basename 函数:其语法为$(basename names…),用于获取names中除去后缀信息,比如

$(basename src/foo.c src-1.0/bar hacks)

将获得信息 src/foo src-1.0/bar hacks

 

addsuffix 函数:其语法为$(addsuffix suffix,names…),用于往names中添加后缀信息suffix,比如

$(addsuffix .c,foo bar)

将获得文件信息 foo.c bar.c

 

addprefix 函数:其语法为$(addprefix prefix,names…),用于往names中添加前缀信息prefix,比如

$(addprefix src/,foo bar)

将获得信息src/foo src/bar

 

patsubst 函数:其语法为$(patsubst pattern,replacement,text),根据 pattern信息将text替换成replacement,比如

objects = foo.o bar.o baz.o

files = $(patsubst %.o,%.c,$( objects))

将获得信息 foo.c bar.c baz.c

其可以简单写成

objects = foo.o bar.o baz.o

files = $(objects:.o=.c)

4、规则定义:

规则是makefile中最重要的概念,其告诉make 目标文件的依赖关系,以及如何生成及更新这些目标文件。在makefile文件规则有2种,一种是显式规则,另一种是隐式规则。

显式规则用于说明 何时及如何重新生成目标,其列出了目标依赖的文件信息,并通过调用命令来创建或更新目标,其语法一般为:

targets : prerequisites

        recipe

        …

targets为要生成或更新的目标,prerequisites为目标依赖的关系,recipe为生成目标的命令,一个规则可以有多条recipe,比如

foo.o : foo.c defs.h

        cc -c -g foo.c

其中foo.o为target,foo.c defs.h 为prerequisites,cc -c -g foo.c为recipe。

 

隐式规则用于说明 何时及如何来重新生成一类目标文件根据其名称,其描述了目标是如何依赖于名称相似的文件(一般来说除去后缀信息,其目标与依赖文件的名称是一样的),并调用命令来创建或更新目标,比如

%.o : %.c

        $(CC) -c $(CFLAGS) $< -o $@

       这个隐式规则说明了.o的目标文件依赖于同名的.c文件,其中$< 及 $@为自动变量,$<为第一个prerequisites条件,也就是 目标名称.c,$@为目标,也就是 目标名称.o。

在makefile中,我们通常要编写3种隐式规则,第1种为代码链接规则,第2种为源代码编译规则,第3种为汇编代码编译规则。

 

 

5、文件搜索路径设置

       Make命令默认会在当前路径中搜索prerequisites中的文件,比如头文件,但我们在写程序时,经常将头文件和源文件隔开放在不同的文件夹下,这种该怎么处理呢?1、我们可以通过VPATH变量来解决,2、我们可以通过vpath指令来解决。

 

VPATH变量

VPATH变量为所有的prerequisites指定文件路径,路径之间可以通过 :或空格隔开,比如

VPATH = src:../headers

 

vpath指令

vpath指令的作用与变量VPATH的作用差不多,但vpath有更多的灵活性,其语法为:

vpath pattern directories

       pattern为需要查找的文件匹配模式信息,directories为要查找的文件路径,比如

       vpath %.h ../headers

       其代表在上一层文件夹headers中查找 .h头文件信息。

6、依赖关系生成

       在编写c文件代码时,我们经常通过#include 语句来包含其它文件信息,比如头文件,该c文件被编译时需要依赖于其#include包含进来的文件,在规则编写中,就需要指出这个依赖关系,这样当头文件信息改变后,make程序就知道如何更新目标文件了,而不是整个进行重编译,但这个操作可以看出是非常消耗时间及傻瓜式的,作为解决方案我们可以通过使用 编译器命令 –M选项来自动完成该工作,比如在main.c中#include “defs.h”,通过 cc –M main.c将产生输出 main.o:main.c defs.h,我们可以将输出结果写到 .d文件中,然后通过include指令包含到makefile文件中。

 

7、编译器常用命令选项

       编译器通常进行预处理、编译、汇编和链接处理,预处理包含了宏定义、文件包含、条件编译,编译则直接将代码翻译成机器码,汇编则将汇编代码翻译成机器码,链接则按照内存地址分配文件将各个文件的机器码统一形成一个可执行文件,对编译命令(比如gcc)而言该如何区别这些操作呢?即通过命令选项。下面将介绍一些常见的命令选项

-o file           输出生成的 file文件

 

-c          编译或汇编程序文件,但不会执行链接操作

 

-T script     使用script脚本来分配内存

 

-W1,option  给链接器发送一个选项,比如生成地址映射表,-Wl,-Map,output.map

 

-mcpu=name 规定目标处理器的型号

 

-Wall       使能所有警告调试信息输出

 

-glevel      要求带调试信息的等级,-g0代表不产生调试信息,-g1代表产生最小的调试信息用来跟踪程序的运行,但不包括本地变量,-g3包含了一些额外的调试信息比如程序的宏定义等。

 

-I dir       增加头文件的搜索路径,比如 –I../header

 

-D name    预先定义一个宏定义,比如 –DMPC564xB 表示定义一个宏 MPC564xB

 

8、makefile举例

       本工程的代码结构如下图所示:

makefile文件编写「建议收藏」

其中Asm_Files里面放置的是.S汇编文件,bin里面放置的是编译后的elf、S19、.map、.o等文件,include里面放置的为头文件,Linker_Files里面放置的是.ld内存分配文件、make里面放置的是bat脚本和makefile文件,src里面放置的是C代码源文件。

       其中makefile文件内容如下所示:

CC := powerpc-eabivle-gcc-4.9.4.exe

OBJCOPY := powerpc-eabivle-objcopy

 

TARGET := MCAL_TEST.elf

PROJECT_ROOT := ..

OUT_DIR := $(PROJECT_ROOT)/bin

C_DIRS += ../src

LD_DIRS += ../Linker_Files

S_DIRS += ../Asm_Files

 

INC_DIR += ../include \

              C:/NXP/S32DS_Power_v2017.R1/S32DS/e200_ewl2/EWL_C/include \

              C:/NXP/S32DS_Power_v2017.R1/S32DS/e200_ewl2/EWL_C/include/pa

 

C_DEFINE += START_FROM_FLASH MPC564xB TURN_ON_CPU1

 

C_SRCS += $(foreach DIR,$(C_DIRS),$(wildcard $(DIR)/*.c))

LD_FILE += $(foreach DIR,$(LD_DIRS),$(wildcard $(DIR)/*.ld))

S_SRCS += $(foreach DIR,$(S_DIRS),$(wildcard $(DIR)/*.S))

 

ALL_SRCS := $(C_SRCS:%.c=%.o)

ALL_SRCS += $(S_SRCS:%.S=%.o)

OBJS  := $(addprefix ../bin/,$(notdir $(ALL_SRCS)))

 

LD_FLAGS += -Wl,-Map,$(OUT_DIR)/$(TARGET).map \

-Xlinker \

–gc-sections \

-mcpu=e200z2 \

-specs=ewl_c9x_noio.specs \

–sysroot=”C:/NXP/S32DS_Power_v2017.R1/S32DS/e200_ewl2″

 

COMPILE_FLAGS +=-O0 \

-g3 \

-Wall \

-c \

-fmessage-length=0 \

-ffunction-sections \

-fdata-sections \

-mcpu=e200z0 \

-specs=ewl_c9x_noio.specs \

-mbig \

-mvle \

-mregnames \

-mhard-float \

–sysroot=”C:/NXP/S32DS_Power_v2017.R1/S32DS/e200_ewl2″ \

 

COMPILE_FLAGS += $(addprefix -D,$(C_DEFINE))

 

vpath %.c $(C_DIRS)

vpath %.S $(S_DIRS)

 

$(OUT_DIR)/%.o:%.c

       $(CC) $(COMPILE_FLAGS) -MMD -MP -MF”$(@:%.o=%.d)” -MT”$(@)” -c $< -o “$(@)” $(addprefix -I,$(INC_DIR))

 

$(OUT_DIR)/%.o:%.S

       $(CC) $(COMPILE_FLAGS) -MMD -MP -MF”$(@:%.o=%.d)” -MT”$(@)” -c $< -o “$(@)” $(addprefix -I,$(INC_DIR))

 

.PHONY:all

all:$(OUT_DIR)/$(TARGET) $(OUT_DIR)/$(TARGET).S19

$(OUT_DIR)/$(TARGET): $(OBJS)

       $(CC) -o “$(@)” $(OBJS) $(addprefix -T,$(LD_FILE)) $(LD_FLAGS)

 

$(OUT_DIR)/$(TARGET).S19:$(OUT_DIR)/$(TARGET)

       $(OBJCOPY) -O srec $(OUT_DIR)/$(TARGET)  $(OUT_DIR)/$(TARGET).S19

 

.PHONY:clean

clean:

       -$(MAKE_PATH)/rm $(OUT_DIR)/*

 

bat脚本内容如下所示:

@echo off

::SET Path=%Path%;C:/NXP/S32DS_Power_v2017.R1/Cross_Tools/powerpc-eabivle-4_9/bin

::SET MAKE_PATH=C:/GnuWin32/bin

SET Path=%Path%;C:/NXP/S32DS_Power_v2017.R1/utils/msys32/usr/bin;C:/NXP/S32DS_Power_v2017.R1/Cross_Tools/powerpc-eabivle-4_9/bin

SET MAKE_PATH=C:/NXP/S32DS_Power_v2017.R1/utils/msys32/usr/bin

CALL %MAKE_PATH%/make.exe clean

CALL %MAKE_PATH%/rm.exe build.log

CALL %MAKE_PATH%/make.exe -j %NUMBER_OF_PROCESSORS% all 2>&1 | tee.exe -a build.log

Pause

 

运行脚本内容后,bin文件夹内容如下所示,可以看出生成了elf、S19文件。

makefile文件编写「建议收藏」

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/134068.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • phpstorm 2021最新激活码[在线序列号]「建议收藏」

    phpstorm 2021最新激活码[在线序列号],https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • c# 非阻塞算法_c# – 了解非阻塞线程同步和Thread.MemoryBarrier

    c# 非阻塞算法_c# – 了解非阻塞线程同步和Thread.MemoryBarrier这是Thread.MemoryBarrier()的一个例子classFoo{int_answer;bool_complete;voidA(){_answer=123;Thread.MemoryBarrier();//Barrier1_complete=true;Thread.MemoryBarrier();//Barrier2}voidB(){Thread…

  • 常用公共数据集[通俗易懂]

    常用公共数据集[通俗易懂]原文链接:http://homepages.inf.ed.ac.uk/rbf/CVonline/Imagedbase.htmCVonline:图像数据库(Google直译的结果,希望对大家有帮助)按主题索引行动数据库属性识别自主驾驶生物/医药相机校准脸和眼/虹膜数据库指纹一般图像一般RGBD和深度数据集一般视频手,掌握,手动和手势数据库图像,视频和形状数据库检索对象数据库人(静),人体姿势人员检测…

  • Android开发入门书籍推荐

    Android开发入门书籍推荐http://liangruijun.blog.51cto.com/3061169/623548/Android开发入门书籍推荐Android编程入门教程andbookandbook是我看到的最简单但最好的Android程序开发入门书籍,内容仅有60多页,图文并茂,如果你从来没有接触过Android开发,也完全可以通过阅读此书了解程序开发过程,甚至对APK程

  • Linux搭建eureka集群,基于dns搭建eureka集群[通俗易懂]

    Linux搭建eureka集群,基于dns搭建eureka集群[通俗易懂]eureka集群方案:1.通常我们部署的eureka节点多于两个,根据实际需求,只需要将相邻节点进行相互注册(eureka节点形成环状),就达到了高可用性集群,任何一个eureka节点挂掉不会受到影响。2.可能会有初学者和我一样,一开始的时候没有完全理解eureka集群的原理,直接把每个eureka节点的url写进配置文件,期望所有的eureka节点进行相互注册。实际上,节点间进行信息同步的时候,…

  • 《将博客搬至CSDN》[通俗易懂]

    《将博客搬至CSDN》[通俗易懂]后续的文章将自动同步到csdn

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号