如何编写一个工程文件夹下通用的Makefile
新建工程文件夹,在里面新建 bsp、imx6ul、obj 和project 这 3 个文件夹,完成以后如图所示:
新建的工程根目录文件夹
其中 bsp 用来存放驱动文件;imx6ul 用来存放跟芯片有关的文件,比如 NXP 官方的 SDK库文件;obj 用来存放编译生成的.o 文件;project 存放 start.S 和 main.c 文件,也就是应用文件;将十二章实验中的 cc.h、fsl_common.h、fsl_iomuxc.h 和 MCIMX6Y2.h 这四个文件拷贝到文件夹 imx6ul 中;将 start.S 和 main.c 这两个文件拷贝到文件夹 project 中。我们前面的实验中所有的驱动相关的函数都写到了 main.c 文件中,比如函数 clk_enable、led_init 和 delay,这三个函数可以分为三类:时钟驱动、LED 驱动和延时驱动。因此我们可以在 bsp 文件夹下创建三个子文件夹:clk、delay 和 led,分别用来存放时钟驱动文件、延时驱动文件和 LED 驱动文件,这样main.c 函数就会清爽很多,程序功能模块清晰。工程文件夹都创建好了,接下来就是编写代码了,其实就是将时钟驱动、LED 驱动和延时驱动相关的函数从 main.c 中提取出来做成一个独立的驱动文件 。
使用VScode 新建工程,工程名字为“ledc_bsp”。新建文件 imx6ul.h,然后保存到文件夹 imx6ul 中,新建 bsp_led.h 和 bsp_led.c 两个文件,将这两个文件存放到 bsp/led 中,bsp_led.c 里面就两个函数 led_init 和 led_switch,led_init 函数用来初始化LED 所使用的IO,led_switch 函数是控制 LED 灯的打开和关闭,这两个函数都很简单。
新建 bsp_clk.h 和 bsp_clk.c 两个文件,将这两个文件存放到 bsp/clk 中,bsp_delay.c 里面就两个函数,delay_short 和 delay。在 main.c 中我们仅仅留下了 main 函数,至此,本例程跟程序相关的内容就全部编写好了。
在工程根目录下新建 Makefile 和 imx6ul.lds 这两个文件,创建完成以后的工程如图所示:
最终的工程目录
在文件 Makefile 中输入如下所示内容:
1 CROSS_COMPILE ?= arm-linux-gnueabihf-
2 TARGET ?= bsp
3
4 CC := $(CROSS_COMPILE)gcc
5 LD := $(CROSS_COMPILE)ld
6 OBJCOPY := $(CROSS_COMPILE)objcopy
7 OBJDUMP := $(CROSS_COMPILE)objdump
8
9 INCDIRS := imx6ul \
10 bsp/clk \
11 bsp/led \
12 bsp/delay
13
14 SRCDIRS := project \
15 bsp/clk \
16 bsp/led \
17 bsp/delay
18
19 INCLUDE := $(patsubst %, -I %, $(INCDIRS))
20
21 SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
22 CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
23
24 SFILENDIR := $(notdir $(SFILES))
25 CFILENDIR := $(notdir $(CFILES)) 26
27 SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
28 COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
29 OBJS := $(SOBJS) $(COBJS) 30
31 VPATH := $(SRCDIRS)
32
33 .PHONY: clean
34
35 $(TARGET).bin : $(OBJS)
36 $(LD) -Timx6ul.lds -o $(TARGET).elf $^
37 $(OBJCOPY) -O binary -S $(TARGET).elf $@
38 $(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
39
40 $(SOBJS) : obj/%.o : %.S
41 $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ {#content}lt;
42
43 $(COBJS) : obj/%.o : %.c
44 $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ {#content}lt;
45
46 clean:
47 rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)
可以看出本验的 Makefile 文件要比前面的实验复杂很多,因为代码 中的 Makefile 代码是一个通用 Makefile,我们以后所有的裸机例程都使用这个 Makefile。使用时候只要将所需要编译的源文件所在的目录添加到Makefile 中即可,我们接下来详细分析一下 Makefile 源码:
第 1~7 行定义了一些变量,除了第 2 行以外其它的都是跟编译器有关的,如果使用其它编译器的话只需要修改第 1 行即可。第 2 行的变量 TARGET 目标名字,不同的例程肯定名字不一一样。
第 9 行的变量 INCDIRS 包含整个工程的.h 头文件目录,文件中的所有头文件目录都要添加到变量INCDIRS 中。比如本例程中包含.h 头文件的目录有imx6ul、bsp/clk、bsp/delay 和bsp/led,所以就需要在变量INCDIRS 中添加这些目录,即:
INCDIRS := imx6ul bsp/clk bsp/led bsp/delay
仔细观察的话会发现第 9~11 行后面都会有一个符号“\”,这个相当于“换行符”,表示本行和下一行属于同一行,一般一行写不下的时候就用符号“\”来换行。在后面的裸机例程中我们会根据实际情况来在变量 INCDIRS 中添加头文件目录。
第 14 行是变量 SRCDIRS,和变量 INCDIRS 一样,只是 SRCDIRS 包含的是整个工程的所有.c 和.S 文件目录。比如本例程包含有.c 和.S 的目录有 bsp/clk、bsp/delay、bsp/led 和 project,即:
SRCDIRS := project bsp/clk bsp/led bsp/delay
同样的,后面的裸机例程中我们也要根据实际情况在变量 SRCDIRS 中添加相应的文件目录。
第 19 行的变量 INCLUDE 是用到了函数 patsubst,通过函数 patsubst 给变量 INCDIRS 添加一个“-I”,即:
INCLUDE := -I imx6ul -I bsp/clk -I bsp/led -I bsp/delay
加“-I”的目的是因为 Makefile 语法要求指明头文件目录的时候需要加上“-I”。
第 21 行变量 SFILES 保存工程中所有的.s 汇编文件(包含绝对路径),变量 SRCDIRS 已经存放了工程中所有的.c 和.S 文件,所以我们只需要从里面挑出所有的.S 汇编文件即可,这里借助了函数 foreach 和函数 wildcard,最终 SFILES 如下:
SFILES := project/start.S
第 22 行变量 CFILES 和变量 SFILES 一样,只是 CFILES 保存工程中所有的.c 文件(包含绝对路径),最终CFILES 如下:
CFILES = project/main.c bsp/clk/bsp_clk.c bsp/led/bsp_led.c bsp/delay/bsp_delay.c
第 24 和 25 行的变量 SFILENDIR 和CFILENDIR 包含所有的.S 汇编文件和.c 文件,相比变量 SFILES 和 CFILES,SFILENDIR 和 CFILNDIR 只是文件名,不包含文件的绝对路径。使用函数 notdir 将 SFILES 和 CFILES 中的路径去掉即可,SFILENDIR 和CFILENDIR 如下:
SFILENDIR = start.SCFILENDIR = main.c bsp_clk.c bsp_led.c bsp_delay.c
第 27 和 28 行的变量 SOBJS 和 COBJS 是.S 和.c 文件编译以后对应的.o 文件目录,默认所有的文件编译出来的.o 文件和源文件在同一个目录中,这里我们将所有的.o 文件都放到 obj 文件夹下,SOBJS 和 COBJS 内容如下:
SOBJS = obj/start.o
COBJS = obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o
第 29 行变量OBJS 是变量SOBJS 和 COBJS 的集合,如下:
OBJS = obj/start.o obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o
编译完成以后所有的.o 文件就全部存放到了 obj 目录下,如图所示:
编译完成后的obj 文件夹
第 31 行的 VPATH 是指定搜索目录的,这里指定的搜素目录就是变量 SRCDIRS 所保存的目录,这样当编译的时候所需的.S 和.c 文件就会在SRCDIRS 中指定的目录中查找。
第 34 行指定了一个伪目标 clean,伪目标前面文章 Makefile 的时候已经讲解过了。
Makefile 文件内容重点工作是找到要编译哪些文件?编译的.o文件存放到哪里?使用到的编译命令和前面实验使用的一样,其实 Makefile 的重点工作就是解决“从哪里来到哪里去的”问题,也就是找到要编译的源文件、编译结果存放到哪里?真正的编译命令很简洁。
链接脚本 imx6ul.lds 的内容和上一篇文章《通过结构体的方式来定义和使用寄存器地址》一样,可以直接使用上一的链接脚本文件。
本文转自小平头电子技术社区:https://www.xiaopingtou.cn/article-104184.html
如何编写一个工程文件夹下通用的Makefile的更多相关文章
- 将java的class文件放到一个指定文件夹下
用javac执行java文件时,要把java文件的class文件放到指定文件夹下,注意文件夹要创建好,执行javac -d 文件夹 ***.java 如图: 在class文件夹下就出现了L的class ...
- C++ 一个统计文件夹下所有代码文件行数的小工具
// CodeLines.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <Commdlg.h> #inclu ...
- 单文件夹下的C程序如何编写Makefile文件
通过学习已经学会了GCC的一些基础的命令,以及如何将C语言源代码编译成可执行文件. 我们已经知道在linux环境下编译源码时,常会有以下三个步骤: ./configure make make clea ...
- webform工程中aspx页面为何不能调用appcode文件夹下的类(ASP.NET特殊文件夹的用法)
App_code 只有website类型的工程才有效. App_Code 下创建的.cs文件仅仅是“内容”不是代码.你设置那个文件为“编译”就行了. 其他特殊文件夹 1. Bin文件夹 Bin文件夹包 ...
- Python遍历一个文件夹下有几个Excel文件及每个Excel文件有几个Sheet
一. 解决问题: 工作中常会遇到合并Excel文件的需求,Excel文件数量不确定,里面的Sheet 数量是可变的,Sheet Name是可变的,所以,需要用到遍历一个文件夹下有几个Excel文件,判 ...
- 为多个文件夹下的C源代码编写Makefile文件
上一篇文章写了如何为在同一个文件夹下的C源代码,本篇文章为多个文件夹下的C源代码编写Makefile文件. 建立两个文件夹,分别为abs与src.其最终目录结构如下: 1 $ ls * 2 jun.c ...
- 如何将Debug文件夹下的资源打包成一个EXE文件直接执行
前言:前段时间写了个小程序,想分享给好友看看,可所以资源都放在Debug文件夹下,整个文件夹发给人家这也太……,为了显得稍微专业一点,想把它们打包一个EXE文件执行,因为我见到到这样的程序,直接一个E ...
- Linux 将文件夹下的所有文件复制到另一个文件里
如何将文件夹/home/work下的文件复制到/home/temp里面? 使用命令: cp -R /home/work/* /home/temp *表示所有文件 但是/home/work 下的隐藏文件 ...
- 【文件】读取一个文件夹下所有的jpg图片
今天做视频处理的时候,发现给的视频是用jpg图片的形式给出的,名字的命名规律性不是很强.就想找一种通用的遍历文件夹下图片的方法. 开始在网上找到了下面这份代码,发现只能读取所有的文件夹,文件都被跳过了 ...
随机推荐
- 使用python删除N天前的文件
python版本为:2.7 import os import sys import time # Sets how many days old files are deleted DAYS_N = 7 ...
- python json序列化与反序列化操作
python json序列化与反序列化操作 # dumps() dict-->str 序列化 # loads() str---dict 反序列化 result1 = json.dumps({'a ...
- xshell使用xftp传输文件、使用pure-ftpd搭建ftp服务
6月25日任务 15.4 xshell使用xftp传输文件15.5 使用pure-ftpd搭建ftp服务扩展vsftp使用mysql存放虚拟用户并验证 http://www.aminglinux.co ...
- python check excel 文件
Use pip install openpyxl first Every simple example import openpyxl # 打开excel文件,获取工作簿对象 wb = openpyx ...
- python_网络编程
网络ISO(国际标准化组织)--->网络体系结构标准(OSI模型)OSI: 网络信息传输比较复杂需要很多功能协同-->将功能分开,降低耦合度,让每个模块完成一定的功能-->将这些模块 ...
- ViewGroup dispatchTouchEvent方法中 mFirstTouchTarget标志是否为空的含义
在ViewGroup dispatchTouchEvent方法中首次出现mFirstTouchTarget的语句为: if (actionMasked == MotionEvent.ACTION_DO ...
- 【nodejs原理&源码赏析(2)】KOA中间件的基本运作原理
[摘要] KOA中间件的基本运作原理 示例代码托管在:http://www.github.com/dashnowords/blogs 在中间件系统的实现上,KOA中间件通过async/await来在不 ...
- DevOps on DevCloud|如何实现应用接口的混合驱动测试
引言:在"DevOps能力之屋(Capabilities House of DevOps)"中,华为云DevCloud提出(工程方法+最佳实践+生态)×工具平台=DevOps能力. ...
- JNI用法小例子
一.准备包含本地方法的.java文件(ContentVideo.java),包括set()和get()两个方法. public class ContentVideo { public native s ...
- luogu P4981 父子
题目背景 上演在各大学男生寝室的日常 :: A :A: "我没带纸,快来厕所救我!" B :B: "叫爸爸." A :A: "爸爸!" .. ...