目录

  • LibOpenCM3(一) Linux下命令行开发环境配置
  • LibOpenCM3(二) 项目模板 Makefile分析

LibOpenCM3 项目模板

项目模板地址: https://github.com/libopencm3/libopencm3-template

如果仅仅用IDE开发, 并不需要了解 Makefile 结构. 对于需要实现自动化发布和测试的项目, Makefile 几乎是默认的选项, 了解 Makefile 工作机制对项目长期的开发和维护都是很有帮助的.

文件结构

├── libopencm3                # libopencm3 封装库
│     ├── COPYING.GPL3
│     ├── COPYING.LGPL3
│     ├── doc
│     ├── HACKING
│     ├── HACKING_COMMON_DOC
│     ├── include
│     ├── ld
│     ├── lib                 # 编译后, 链接库 .a 文件的存放目录
│     ├── locm3.sublime-project
│     ├── Makefile            # libopencm3 项目 Makefile
│     ├── mk
│     │     ├── gcc-config.mk
│     │     ├── gcc-rules.mk
│     │     ├── genlink-config.mk # 用于生成ld文件
│     │     ├── genlink-rules.mk  # 用于生成ld文件
│     │     └── README
│     ├── README.md
│     ├── scripts
│     └── tests
├── LICENSE
├── my-common-code           # 用于演示的公用代码部分
│     ├── api-asm.h
│     ├── api-asm.S
│     ├── api.c
│     └── api.h
├── my-project               # 用于演示的用户项目代码部分
│     ├── Makefile           # 用户项目 Makefile
│     └── my-project.c
├── README.md
└── rules.mk                 # 全局规则

其中, libopencm3 的 Makefile 用于将 libopencm3 编译生成链接库, 用户项目的 Makefile 用于引用 libopencm3 以及包含公用代码生成最终的 elf 和 bin, 以及生成 ld 文件.

libopencm3 的 Makefile

libopencm3 的 Makefile 主要用于将 libopencm3 编译为链接库库

# 注: 如果工具链未加入PATH, 可以在这里加上路径
PREFIX      ?= arm-none-eabi-# 注: 这个perl脚本貌似是用来检查代码注释的格式的
STYLECHECK      := scripts/checkpatch.pl
STYLECHECKFLAGS := --no-tree -f --terse --mailback# 注: 这里设置的编译的范围, 默认是编译全部型号, 这会消耗很长的时间, 如果只需要编译某一个型号, 可以在make时直接指定
#     例如 TARGETS=stm32/f1 make
#     这里的名称要和 lib 下的目录名严格一致, 因为下面会用这个拼接完整目录
#
TARGETS ?=  stm32/f0 stm32/f1 stm32/f2 stm32/f3 stm32/f4 stm32/f7 \stm32/l0 stm32/l1 stm32/l4 \stm32/g0 \stm32/h7 \gd32/f1x0 \lpc13xx lpc17xx lpc43xx/m4 lpc43xx/m0 \lm3s lm4f msp432/e4 \efm32/tg efm32/g efm32/lg efm32/gg efm32/hg efm32/wg \efm32/ezr32wg \sam/3a sam/3n sam/3s sam/3u sam/3x sam/4l \sam/d \vf6xx \swm050 \pac55xx# Be silent per default, but 'make V=1' will show all compiler calls.
# 注: 使用V=1输出编译时的完整命令, 例如 TARGETS=stm32/f1 make V=1
ifneq ($(V),1)
Q := @
# Do not print "Entering directory ...".
MAKEFLAGS += --no-print-directory
endif# Avoid the use of shell find, for windows compatibility
IRQ_DEFN_FILES  := $(foreach TARGET,$(TARGETS),$(wildcard include/libopencm3/$(TARGET)/irq.json))
STYLECHECKFILES := $(wildcard include/*/*.h include/*/*/*.h include/*/*/*/*.h)
STYLECHECKFILES += $(wildcard lib/*/*.h lib/*/*/*.h lib/*/*/*/*.h)
STYLECHECKFILES += $(wildcard lib/*/*.c lib/*/*/*.c lib/*/*/*/*.c)# 注: 默认的目标是 all -> build -> lib
all: buildbuild: lib%.genhdr:@printf "  GENHDR  $*\n";# 注: irq2nvic_h 是个 python 脚本, 用JSON定义的中断编号生成 nvic.h 头文件$(Q)./scripts/irq2nvic_h ./$*;%.cleanhdr:@printf "  CLNHDR  $*\n";$(Q)./scripts/irq2nvic_h --remove ./$*# 注: 根据 TARGETS 拼接目录
LIB_DIRS:=$(wildcard $(addprefix lib/,$(TARGETS)))
# 注: $(IRQ_DEFN_FILES:=.genhdr) 这个表达式, 实际上是批量替换, 替换的左边扩展名为空,
#     所以其作用是将 IRQ_DEFN_FILES 中每一个值, 加上了.genhdr, 去执行 %.genhdr 的规则
$(LIB_DIRS): $(IRQ_DEFN_FILES:=.genhdr)$(Q)$(RM) .stamp_failure_$(subst /,_,$@)@printf "  BUILD   $@\n";$(Q)$(MAKE) --directory=$@ PREFIX="$(PREFIX)" || \echo "Failure building: $@: code: $$?" > .stamp_failure_$(subst /,_,$@)lib: $(LIB_DIRS)$(Q)$(RM) .stamp_failure_tld$(Q)for failure in .stamp_failure_*; do \[ -f $$failure ] && cat $$failure >> .stamp_failure_tld || true; \done;$(Q)[ -f .stamp_failure_tld ] && cat .stamp_failure_tld && exit 1 || true;# 注: 执行 doc 目录下的 make
html doc:$(Q)$(MAKE) -C doc html TARGETS="$(TARGETS)"# 注: 清理, 这些$(XXX:=.xxx)也是批量替换用法
clean: $(IRQ_DEFN_FILES:=.cleanhdr) $(LIB_DIRS:=.clean) $(EXAMPLE_DIRS:=.clean) doc.clean styleclean genlinktests.clean%.clean:$(Q)if [ -d $* ]; then \printf "  CLEAN   $*\n"; \$(MAKE) -C $* clean || exit $?; \fi;$(Q)$(RM) .stamp_failure_*;stylecheck: $(STYLECHECKFILES:=.stylecheck)
styleclean: $(STYLECHECKFILES:=.styleclean)# the cat is due to multithreaded nature - we like to have consistent chunks of text on the output
%.stylecheck: %$(Q)if ! grep -q "* It was generated by the irq2nvic_h script." $* ; then \$(STYLECHECK) $(STYLECHECKFLAGS) $* > $*.stylecheck; \if [ -s $*.stylecheck ]; then \cat $*.stylecheck; \else \rm -f $*.stylecheck; \fi; \fi;%.styleclean:$(Q)rm -f $*.stylecheck;LDTESTS      :=$(wildcard ld/tests/*.data)genlinktests: $(LDTESTS:.data=.ldtest)
genlinktests.clean:$(Q)rm -f $(LDTESTS:.data=.out)%.ldtest:@if ./scripts/genlinktest.sh $* >/dev/null; then\printf "  TEST  OK  : $*\n";     \else                       \printf "  TEST FAIL : $*\n";       \fi;.PHONY: build lib $(LIB_DIRS) doc clean generatedheaders cleanheaders stylecheck genlinktests genlinktests.clean

rule.mk 分析

多匹配的优先级选择, 参考 How Patterns Match 模式匹配的工作机制

# This version of rules.mk expects the following to be defined before
# inclusion..
### REQUIRED ###
# OPENCM3_DIR - duh
# PROJECT - will be the basename of the output elf, eg usb-gadget0-stm32f4disco
# CFILES - basenames only, eg main.c blah.c
# CXXFILES - same for C++ files. Must have cxx suffix!
# DEVICE - the full device name, eg stm32f405ret6
#  _or_
# LDSCRIPT - full path, eg ../../examples/stm32/f4/stm32f4-discovery/stm32f4-discovery.ld
# OPENCM3_LIB - the basename, eg: opencm3_stm32f4
# OPENCM3_DEFS - the target define eg: -DSTM32F4
# ARCH_FLAGS - eg, -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16
#    (ie, the full set of cpu arch flags, _none_ are defined in this file)
#
### OPTIONAL ###
# INCLUDES - fully formed -I paths, if you want extra, eg -I../shared
# BUILD_DIR - defaults to bin, should set this if you are building multiarch
# OPT - full -O flag, defaults to -Os
# CSTD - defaults -std=c99
# CXXSTD - no default.
# OOCD_INTERFACE - eg stlink-v2
# OOCD_TARGET - eg stm32f4x
#    both only used if you use the "make flash" target.
# OOCD_FILE - eg my.openocd.cfg
#    This overrides interface/target above, and is used as just -f FILE
### TODO/FIXME/notes ###
# No support for stylecheck.
# No support for BMP/texane/random flash methods, no plans either
# No support for magically finding the library.
# C++ hasn't been actually tested with this..... sorry bout that. ;)
# Second expansion/secondary not set, add this if you need them.# 注: 指定默认的中间文件目录
BUILD_DIR ?= bin
OPT ?= -Os
CSTD ?= -std=c99# Be silent per default, but 'make V=1' will show all compiler calls.
# If you're insane, V=99 will print out all sorts of things.
V?=0
ifeq ($(V),0)
Q   := @
NULL    := 2>/dev/null
endif# Tool paths.
PREFIX  ?= arm-none-eabi-
CC  = $(PREFIX)gcc
CXX = $(PREFIX)g++
LD  = $(PREFIX)gcc
OBJCOPY = $(PREFIX)objcopy
OBJDUMP = $(PREFIX)objdump
OOCD    ?= openocdOPENCM3_INC = $(OPENCM3_DIR)/include# Inclusion of library header files
INCLUDES += $(patsubst %,-I%, . $(OPENCM3_INC) )# 注: 格式 $(SRC:%.c=%.o) 批量替换, 在SRC中找到所有.c 结尾的文件,然后把所有的.c换成.o
# 等价于 $(patsubst %.c, %.o, $(SRC))
OBJS = $(CFILES:%.c=$(BUILD_DIR)/%.o)
OBJS += $(CXXFILES:%.cxx=$(BUILD_DIR)/%.o)
OBJS += $(AFILES:%.S=$(BUILD_DIR)/%.o)
GENERATED_BINS = $(PROJECT).elf $(PROJECT).bin $(PROJECT).map $(PROJECT).list $(PROJECT).lssTGT_CPPFLAGS += -MD
TGT_CPPFLAGS += -Wall -Wundef $(INCLUDES)
TGT_CPPFLAGS += $(INCLUDES) $(OPENCM3_DEFS)TGT_CFLAGS += $(OPT) $(CSTD) -ggdb3
TGT_CFLAGS += $(ARCH_FLAGS)
TGT_CFLAGS += -fno-common
TGT_CFLAGS += -ffunction-sections -fdata-sections
TGT_CFLAGS += -Wextra -Wshadow -Wno-unused-variable -Wimplicit-function-declaration
TGT_CFLAGS += -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypesTGT_CXXFLAGS += $(OPT) $(CXXSTD) -ggdb3
TGT_CXXFLAGS += $(ARCH_FLAGS)
TGT_CXXFLAGS += -fno-common
TGT_CXXFLAGS += -ffunction-sections -fdata-sections
TGT_CXXFLAGS += -Wextra -Wshadow -Wredundant-decls  -Weffc++TGT_ASFLAGS += $(OPT) $(ARCH_FLAGS) -ggdb3TGT_LDFLAGS += -T$(LDSCRIPT) -L$(OPENCM3_DIR)/lib -nostartfiles
TGT_LDFLAGS += $(ARCH_FLAGS)
TGT_LDFLAGS += -specs=nano.specs
TGT_LDFLAGS += -Wl,--gc-sections
# OPTIONAL
#TGT_LDFLAGS += -Wl,-Map=$(PROJECT).map
ifeq ($(V),99)
TGT_LDFLAGS += -Wl,--print-gc-sections
endif# Linker script generator fills this in for us.
# 注: 判断变量是否为空的格式 ifeq ($(TEST),) TEST := $(something else) endif
ifeq (,$(DEVICE))
LDLIBS += -l$(OPENCM3_LIB)
endif
# nosys is only in newer gcc-arm-embedded...
#LDLIBS += -specs=nosys.specs
LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group# Burn in legacy hell fortran modula pascal yacc idontevenwat
.SUFFIXES:
.SUFFIXES: .c .S .h .o .cxx .elf .bin .list .lss# Bad make, never *ever* try to get a file out of source control by yourself.
%: %,v
%: RCS/%,v
%: RCS/%
%: s.%
%: SCCS/s.%# 注: 默认目标, 需要产生项目elf和bin文件
all: $(PROJECT).elf $(PROJECT).bin
# 注: flash目标, 需要 项目.flash, 会定向到 %.flash 任务
flash: $(PROJECT).flash# error if not using linker script generator
ifeq (,$(DEVICE))
$(LDSCRIPT):
ifeq (,$(wildcard $(LDSCRIPT)))$(error Unable to find specified linker script: $(LDSCRIPT))
endif
else
# if linker script generator was used, make sure it's cleaned.
# 将 ld 文件加入二进制文件列表, 用于 clean 的时候清除
GENERATED_BINS += $(LDSCRIPT)
endif# Need a special rule to have a bin dir
# 注: 匹配 BUILD_DIR 目录下的 .o 文件目标, 检查 .c 文件, 并对应的调用 CC 进行编译
# 匹配规则和优先级顺序参考 GNU Make 手册的 10.5.4 How Patterns Match
$(BUILD_DIR)/%.o: %.c@printf "  CC\t$<\n"@mkdir -p $(dir $@)$(Q)$(CC) $(TGT_CFLAGS) $(CFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $@ -c $<$(BUILD_DIR)/%.o: %.cxx@printf "  CXX\t$<\n"@mkdir -p $(dir $@)$(Q)$(CXX) $(TGT_CXXFLAGS) $(CXXFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $@ -c $<$(BUILD_DIR)/%.o: %.S@printf "  AS\t$<\n"@mkdir -p $(dir $@)$(Q)$(CC) $(TGT_ASFLAGS) $(ASFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $@ -c $<# 注: LIBDEPS 定义在 genlink-config.mk, 指向 libopencm3/lib/libopencm3_xxxx.a 文件,
# 根据设置的 DEVICE 不同, 名称不同
$(PROJECT).elf: $(OBJS) $(LDSCRIPT) $(LIBDEPS)@printf "  LD\t$@\n"$(Q)$(LD) $(TGT_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@# 注: 用 .elf 文件生成 .bin 文件
%.bin: %.elf@printf "  OBJCOPY\t$@\n"$(Q)$(OBJCOPY) -O binary  $< $@%.lss: %.elf$(OBJDUMP) -h -S $< > $@%.list: %.elf$(OBJDUMP) -S $< > $@# 注: 烧录
%.flash: %.elf@printf "  FLASH\t$<\n"
ifeq (,$(OOCD_FILE))$(Q)(echo "halt; program $(realpath $(*).elf) verify reset" | nc -4 localhost 4444 2>/dev/null) || \$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \-f target/$(OOCD_TARGET).cfg \-c "program $(realpath $(*).elf) verify reset exit" \$(NULL)
else$(Q)(echo "halt; program $(realpath $(*).elf) verify reset" | nc -4 localhost 4444 2>/dev/null) || \$(OOCD) -f $(OOCD_FILE) \-c "program $(realpath $(*).elf) verify reset exit" \$(NULL)
endifclean:rm -rf $(BUILD_DIR) $(GENERATED_BINS).PHONY: all clean flash
-include $(OBJS:.o=.d)

my-project 的 Makefile

用户项目的 Makefile 主要用于定义一些路径和名称变量, 最后是引用 genlink-config.mk, rules.mk, genlink-rules.mk 这三个文件进行编译

# 注: 设置项目输出的固件文件名
PROJECT = awesomesauce
# 注: 编译中间产物的存放目录
BUILD_DIR = bin# 注: 下面会将这个目录设置为 VPATH, 用于放置共用代码或其它的库
SHARED_DIR = ../my-common-code
# 注: 编译项目时需要添加的C文件
CFILES = my-project.c
CFILES += api.c
# 注: 汇编文件
AFILES += api-asm.S# TODO - you will need to edit these two lines!
# 注: MCU型号, 用于生成ld文件
DEVICE=stm32f103c6t6
# 注: 用于 openocd 下载和调试的配置文件, 如果不用 openocd, 可以不管
OOCD_FILE = board/stm32f4discovery.cfg
# 注: 如果不设置PATH, 这里要把工具链的路径加上
PREFIX  ?= /opt/gcc-arm/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-# You shouldn't have to edit anything below here.
VPATH += $(SHARED_DIR)
# 注: 头文件路径, libopencm3在rules.mk中会包含, 这里不需要写
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../libopencm3include $(OPENCM3_DIR)/mk/genlink-config.mk
include ../rules.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk

LibOpenCM3(二) 项目模板 Makefile分析相关推荐

  1. b2c项目基础架构分析(二)前端框架 以及补漏的第一篇名词解释

    b2c项目基础架构分析(二)前端框架 以及补漏的第一篇名词解释 继续上篇,上篇里忘记了也很重要的前端部分,今天的网站基本上是以一个启示页,然后少量的整页切换,大量的浏览器后台调用web服务局部.动态更 ...

  2. u-boot分析之makefile分析(二)

    目录 u-boot(二)makefile 引入 目录结构(1.1.6) 配置文件 目标 配置具体的单板 编译阶段 过程 链接入口 配置链接地址 附录 附录A:mkconfig解析 附录B 链接脚本 u ...

  3. 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板

    标题:从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11155 ...

  4. flask mysql项目模板渲染_Flask系列(二) 模板 templates

    BEGIN: 在前面,我们简单的实现了第一个简单的flask项目,但是这个项目只是单纯的在网页上显示一句话,没有任何其他的东西,很是单调.这里,我们即将学习Flask的模板.相信了解过django的人 ...

  5. 项目总结25:海康威视SDK-Java二次开发-客流量分析

    项目总结25:海康威视SDK-Java二次开发-客流量分析 前言 本来一个很简单的SDK接口对接,折腾了好久:总结下原因有: 海康的SDK底层使用C++写的,我不熟悉C++: 海康Java源码示例写的 ...

  6. 《信息化项目文档模板二——项目启动会文档模板》

    系列文章目录 <信息化项目文档模板一--项目需求说明书> <信息化项目文档模板二--项目启动会文档模板> <信息化项目文档模板三--会议纪要模板> <信息化项 ...

  7. uboot源码——主Makefile分析

    以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 一.配置编译初体验 1.uboot来源于官方(uboot官网下载),或者SoC官方(研发s5pv210芯片的公司推出的开发板,SMDKV21 ...

  8. asp.net core web 解决方案多项目模板制作打包总结

    一.文件夹\项目结构 1.1.文件夹 net6.0:针对.net 6.0 项目模板 net6.0pack:针对net6.0打包 1.2.项目结构 Web\WebApi多项目.各层项目.单元测试项目 目 ...

  9. 使用RTC正式项目模板进行传统项目管理

    IBM Rational Team Concert (RTC)是Jazz 平台上的一款核心产品,它是团队协作开发工具,帮助团队提升协作能力,并支持项目管理,代码管理,构建管理等过程.由于RTC能提供多 ...

  10. Cookiecutter: 更好的项目模板工具:(1)简介及可用资源汇总

    原文档地址:https://cookiecutter.readthedocs.io/en/latest/ 本系列只介绍cookiecutter的基础使用,而且会删除与功能使用无关的部分.深度使用及了解 ...

最新文章

  1. Android高级第九讲--JVM 与Android Dalvik之间的异同
  2. 限界分支法:01背包问题,优先级队列(包含解的追踪)
  3. 《走遍中国》珍藏版(三)
  4. 阿里敏捷教练何勉:论精益思想及精益产品开发实践体系
  5. 【渝粤教育】国家开放大学2018年秋季 0275-22T内科护理学 参考试题
  6. U-boot第二阶段概述(转)
  7. 35岁 计算机 学 什么好,35岁一事无成, 想重新学习, 应该学习哪方面的技能?
  8. PDF 文件格式 基本结构
  9. 【科研数据处理】[实践]类别变量频数分析图表、数值变量分布图表与正态性检验(包含对数正态)
  10. react-navigation 6.x 学习(3)
  11. 【FPGA学习】Quartus II新建工程流程
  12. OpenCV二值化图像像素操作
  13. 《细说PHP》第二版--读书笔记
  14. c语言教程+school,C语言教程方法用法 _C语言-w3school教程
  15. 解决Linux没有声音的问题
  16. 基于Annoy的语义泛化-代码模块化
  17. UML建模、数据库设计和UI设计工具
  18. Gearbox变速器
  19. 404丨天朝BAT者……牛么?
  20. 总结下自己做过的深度召回模型

热门文章

  1. `canvas`破苍穹
  2. OutLook 2013 添加 USC gmail 邮箱 解决国内USC邮箱打不开
  3. 增长黑客手册——02
  4. 美团外卖前端可视化界面组装平台 —— 乐高
  5. 阿里云服务器租用价格表最新发布,持续更新
  6. VOB文件用什么软件打开,VOB文件如何转换成MP4格式
  7. 7-1 循环-Fibonacci数列的运算 (50 分)
  8. 抛物线模拟合地对空导弹轨迹[python][抛物线][地对空导弹轨迹]
  9. 123457123457#0#-----com.yuming.ZuiNiuChengYu--前拼后广--最牛成语
  10. IMO MSC 307(88)附件1第2部分烟毒性试验