在 ModusToolbox v2.x 中管理 Makefile – KBA229177 (ZH)
- RSS フィードを購読する
- 新着としてマーク
- 既読としてマーク
- ブックマーク
- 購読
- 印刷用ページ
- 不適切なコンテンツを報告
Version: **
ModusToolbox™的构建系统使用makefile文件中的信息来创建项目。本文档描述如何操作makefile来完成常见的任务。本文档采用问答的形式撰写。一般而言,问题的答案提供了一个常见的用例,完成任务所需的知识以及示例片段。
本文档使用以下术语:
- makefile目录(directory):包含makefile文件的目录;这可能指代一个代码示例(starter application)或者您自己的项目。
- 项目()目录:在项目创建过程中生成的目录;包含该项目所有的文件,和makefile的副本。
- .lib文件:一个文本文件,包含一个指向GitHub仓库的URL和某次commit的tag或SHA。
- auto-discovery:指代构建系统自动爬取文件的这一过程。
当您使用ModusToolbox的构建系统创建项目时,项目需要的所有文件都会被复制到项目目录内。这包括了包含在代码示例(starter application)中的原始makefile。
1. 什么是makefile,我该如何使用它?
makefile描述了如何生成和编译项目。它包含需要使用的文件、需要引用的库、指定的编译工具链等描述信息。在ModusToolbox中使用的makefile还有专门针对ModusToolbox构建系统的描述条目。若想了解关于ModusToolbox命令行接口的基本背景和相关信息,请参见:Running ModusToolbox from the Command Line.
Cypress在GitHub提供了大量的代码示例,它们可作为starter application使用。每一个代码示例都包含了和项目对应的makefile和源文件。代码示例不是自完整的,它可能存在其它依赖。但当你使用ModusToolbox IDE的New Application向导或独立的Project Creator工具来创建代码示例对应的项目目录时,这会调用构建系统来生成目录,然后代码示例自身和其包含的其它依赖就都会被一并生成在其项目目录中,变成一个自完整的结构。若使用ModusToolbox IDE,项目目录会存在在你的Eclipse Workspace里。若使用Project Creator,则项目目录是你选择的目录。
makefile控制着项目的生成和编译过程。代码示例中的原始makefile和项目目录中的makefile是同样的。
2. 我应该编辑在代码示例中的makefile文件,还是在项目目录中的makefile文件?
一般而言,你通过代码示例创建了项目以后,你修改你项目目录里的makefile即可。对该makefile的改动会仅对你项目生效。
然而,你也可以直接从GitHub上下载代码示例到本地,创建代码示例的本地副本,然后编辑本地副本里面的makefile。这样的修改,会使得所有依赖于该本地副本的项目都会包含你的改动。
在其它的问题和答案中,本文档会使用makefile目录作为统一的指代。所以这里的makefile目录可能指代你的项目目录,或者代码示例的本地副本。
3. 该如何添加文件到项目中,才能使得auto-discovery可以自动索引它们?
项目构建框架会自动索引makefile目录中所有的源文件。这包括.c,.cpp,.h,.hpp,.S,.s, .o和.a文件。
故最简单的办法就是把文件添加到makefile目录中。文件的搜索是递归的,所以你可以把文件添加到makefile目录树下的任意地方,make编译命令都会找到它们。
然而,常见的用例是,要添加的文件通常位于makefile目录以外。比如说,源码合集通常会存放在位于公司的远程服务器上。
在这种情况下,请使用SOURCES和INCLUDES变量来手动添加不能被构建系统自动索引的源文件和头文件到编译过程中。
SOURCES变量包含一组特定的文件列表,文件之间使用空格分隔。文件路径可以是绝对路径,也可以是相对于makefile目录的相对路径。你可在搜索字串中使用通配符来匹配多个文件。
SOURCES=$(wildcard ../MySource1/*.c) $(wildcard ../MySource2/*.c)
使用INCLUDES变量来设置包含头文件的目录。该变量的值是由一组用空格隔开的相对路径组成的。
INCLUDES=../MySource1 ../MySource2
你也可以设置哪些文件或文件夹应被忽略。请参见“我应如何令auto-discovery忽略特定文件”。
4. 如何添加包含空格的路径?
如何识别路径中的空格困扰着很多编译工具,所以应尽可能避免路径中出现空格。如果你必须这样做,请使用$(wildcard)函数来避开对那些包含空格的路径识别问题。
INCLUDES=$(wildcard ../My Source/)
CY_COMPILER_PATH=$(wildcard C:/Program Files (x86)/IAR Systems/Embedded Workbench 7.3/arm/bin)
5. 在要求使用相对路径的情况下,如何在变量中使用绝对路径?
你想要添加的文件可能会保存在比如公司服务器或者你本地的特定位置。这时候使用绝对路径可能会更容易维护。这个情况下,你可以建立一个只接受相对路径的make变量,然后在它的赋值里面再引用一个代表绝对路径的变量,以达到目的。
ABS_PATH=C:/<path_to_source>/ExternalSourceFiles/
SOURCES=$(ABS_PATH)/external_source.c
6. 构建系统是如何处理斜杠号的?
在Windows系统环境下,ModusToolbox在后端调用的是Cygwin的make命令。Cygwin是兼容POSIX的编译环境,而POSIX的路径使用正斜杠“/”作为路径分隔符。所以在makefile里面配置路径的时候必须使用“/”作为分隔符。
而Windows路径规则是采用反斜杠“\”作为路径分隔符的。有些场合下你可能会遇到很长的绝对路径,并且你需要用“/”替换里面的每一个“\”。这时候你可以使用$(subst)函数以方便你进行转换。
WIN_PATH=C:\Users\<some_long_path>\HeaderFiles
HEADER_FILE=$(subst \,/,$(WIN_PATH))
INCLUDES=$(HEADER_FILE)
7. 如何令auto-discovery忽略特定文件?
举个例子,你可能会有一个子文件夹,里面都是用于测试或验证的用例,而你并不希望这些内容会被编译进你的可执行文件当中。
请使用CY_IGNORE变量。这个变量的取值是一组由空格分隔的文件和/或文件组成的列表,包含你想被auto-discovery忽略的内容。请使用相对于makefile目录的相对路径。当然,你可以使用含通配符的搜索字串来忽略多个文件。
CY_IGNORE=./filename.c ./TestFolder
CY_IGNORE+=$(wildcard ./lib/lib1/tests/*.c)
8. 怎么在.lib文本文件里添加对外部库的引用?
ModusToolbox的构建体系里使用了git版本控制系统。.lib文件里面通常是单独的一行文本,其包含了一个git仓库的URL和特定commit的信息。Cypress提供的.lib文件总是指向一个公开的Cypress持有的仓库,并且如无意外都托管在GitHub上。比如说,以下这个.lib文件就意在导入Peripheral Driver Libray的最新版本到项目中。
https://github.com/cypresssemiconductorco/psoc6pdl/#latest-v1.X
要添加你自己的库,请创建类似的指向某一git仓库的.lib文件。然后把该.lib文件放到makefile目录中。比如像下面这样:
https://gitrepos.company.com/mylibrary/#52fac15a7c06ecac951bc67fff94097e9f671efb
make中getlibs命令会查找并处理所有.lib文件,然后使用git命令去clone或pull相应的代码。它会使用.lib文件中指定的hash或tag信息对仓库进行checkout,最终把对应的源文件拷贝到位于项目目录根部的libs文件夹内。ModusToolbox的新建项目工作流程和Library Manager都会自动处理make中getlibs的调用。
9. 如何通过指定文件和目录的方式来添加一个外部库?
请参见“该如何添加文件到项目中,才能使得auto-discovery可以自动索引它们?”。
10. 如何把一个预先编译好的二进制文件添加的我的项目中?
系统会自动索引makefile目录下所有的.o和.a二进制文件。所以一个快捷的办法就是把这些文件直接添加到makefile目录中。
但通常的情况是,这些二进制文件会被保存在makefile目录之外。这时候可以使用LDLIBS变量来指定这些预编译二进制库文件。LDLIBS变量的值是一组由空格隔开的文件组成的列表。并且使用的是相对于makefile目录的相对路径。你也可以使用包含通配符的搜索字串来匹配多个文件。这些文件会在构建的链接阶段中被包含进来。
LDLIBS=../MyBinaryFolder/binary.o
LDLIBS+=$(wildcard ../lib/*.a)
如果你需要的是包含这些二进制文件的头文件,请使用INCLUDES变量。请参见“该如何添加文件到项目中,才能使得auto-discovery可以自动索引它们?”。
11. 如何指定编译的工具集?
makefile默认从ModusToolbox 2.0起就开始集成和使用GCC Arm® 7.2.1。TOOLCHAIN和CY_COMPILER_PATH两个变量一起决定了你使用的是哪个工具集。
其它支持的工具链包括ARM编译器和IAR编译器,但它们需要你另外独立安装。
可供TOOLCHAIN变量使用的选项有:
- TOOLCHAIN=GCC_ARM (Uses GCC 7.2.1 provided with ModusToolbox IDE)
- TOOLCHAIN=ARM (Uses ARM Compiler)
- TOOLCHAIN=IAR (Uses IAR Compiler)
根据你使用的编译器,在CY_COMPILER_PATH变量里使用绝对路径指定你选用的编译器的bin目录。
CY_COMPILER_PATH=$(wildcard C:/Program Files (x86)/IAR Systems/Embedded Workbench 7.3/arm/bin)
CY_COMPILER_PATH=$(wildcard C:/Keil/ARM/ARMCC/bin)
12. 如何使用第三方的工具集?
如需使用不被ModusToolbox直接支持的第三方工具集,请参考以下步骤:
- 进入到你项目目录中的\psoc6make\make\toolchains\。请注意:这些文件在代码示例中不存在,它们是在你创建项目之后由构建系统添加到你的项目目录中的。
- 创建一个新文件<NEW_TOOLCHAIN>.mk,然后添加工具链的配置。
- 在BSP目录下,进入到目录TARGET_<BSP>\linker\,然后新建一个目录,命名为TOOLCHAIN_<NEW_TOOLCHAIN>。接着添加你的第三方工具集的链接器脚本到这个目录当中。请注意,文件夹的前缀“TOOLCHAIN_”非常重要。
- 在BSP目录下,进入到目录TARGET_<BSP>\startup\,然后新建一个目录,命名为TOOLCHAIN_<NEW_TOOLCHAIN>。接着添加你第三方工具集的startup脚本到这个目录当中。
- 根据“如何指定编译的工具集”中的步骤继续操作。
- 构建你的应用程序。
ModusToolbox的BSP里面已经包含其官方支持的工具链的startup脚本和链接器脚本。如果你使用的第三方工具集需要其它文件,你需要手动提供它们。
13. 如何传递编译器的选项?
请使用CFLAGS和CXXFLAGS这两个变量来分别添加额外的C和C++编译器选项。具体的选项请参考相应的工具链文档。
比如:对于GNU ARM工具链,其用到的各种选项可以在这里找到。它们可以如下面这样加入到变量中:
CFLAGS=-Wall -O2
CXXFLAGS=finline-functions
每个变量的取值都是一组由空格隔开的选项组成的列表,选项应被编译器支持。
要观察改动是否生效,请在makefile中将VERBOSE变量设置为‘1’。这会在构建的时候显示完整的命令行。
准确来说,编译器选项展示在哪里取决于工具链和你使用的IDE。你还可以在IDE中设置VERBOSE变量,而不仅仅是在makefile中。比如,在ModusToolbox IDE中,打开项目属性,然后找到C/C++ Build面板。在Build command条目中你可以指定VERBOSE=1,如图1所示。
图1. Build Command
点击Apply and Close来保存你的改动,然后构建你的应用程序。请注意,在IDE中的改动的选项不会影响makefile。
类似地,当使用命令行的时候,你也可以指定“make build VERBOSE=1”来在构建的过程中显示完整的命令行。
14. 如何创建自定义的构建配置?
默认地,ModusToolbox对不同的编译链均提供了Debug和Release两个构建配置。它们被定义在位于libs\psoc6make\make\toolchains的<TOOLCHAIN>.mk文件中。请使用CONFIG变量来创建你自己的构建配置。比如:
CONFIG=MyBuild
构建系统也会使用CONFIG变量的值来生成相应的构建目录,这些目录位于项目目录下的build\<BSP>\中。
故请不要设置这个变量为null或者为空。
15. 如何传递链接器的选项?
请使用LDFLAGS变量来添加自定义的链接器选项。具体的选项请参考相应的工具链文档。
比如:对于GNU ARM 工具链,其用到的各种选项可以在这里找到。它们可以如下面这样加入到变量中:
LDFLAGS=-nodefaultlibs
变量值的各个参数之间使用空格隔开。
16. 如何使用自定义的链接器脚本?
构建框架会自动使用默认的链接器脚本。各个受官方支持的工具链(Arm,GCC,IAR)的默认链接器脚本由开发板支持包(BSP)提供。
要使用自定义的链接器脚本,请在LINKER_SCRIPT变量中指定相应的文件位置。变量取值必须使用从makefile到该链接器脚本的相对路径。
LINKER_SCRIPT=../../MyFiles/myLinkerScript.ld
该脚本应兼容你指定的工具链(.sct,.ld,.icf)。
17. 如何指定预处理任务?
请使用PREBUILD变量来指定预处理命令。命令之间使用英文分号分隔。请使用相对于makefile目录的相对路径来寻址文件。
PREBUILD=../prebuild1.bat; python prebuild2.py
18. 如何指定后处理任务?
请使用POSTBUILD变量来指定后处理命令。命令之间使用英文分号分隔。请使用相对于makefile目录的相对路径来寻址文件。
POSTBUILD=$(CY_COMPILER_PATH)/bin/arm-none-eabi-objcopy.exe -O ihex $(CY_CONFIG_DIR)/$(APPNAME).elf $(CY_CONFIG_DIR)/$(APPNAME).hex; python sample.py
19. 如何构建一个静态链接库?
构建系统支持创建可执行文件或库文件。如果构建的是可执行文件,需要设置APPNAME变量,而LIBNAME变量留空。
如需要创建成库文件,请确保APPNAME留空,然后在LIBNAME中指定库文件名称。
20. 什么是COMPONENT?
COMPONENT是包含一系列文件集合的文件夹。通常,某个COMPONENT会包含一系列实现了应用程序中某特性或功能的文件。比如,在Cypress的BSP中,硬件设计是封装在名为BSP_DESIGN_MODUS的COMPONENT中。它会包含一个名为design.modus的文件,还可能会包含其它的和该BSP相关的硬件配置文件。
你可以添加或者禁用各个COMPONENT。
21. 如何创建自定义的COMPONENT并把它添加到程序中?
新建一个名为COMPONENT_<NAME>的文件夹。它可以被创建在auto-discovery能自动索引的任意位置。把该COMPONENT对应的文件放在该文件夹内。再次提醒该文件夹必须有“COMPONENT_”的前缀。
接着,使用COMPONENTS+=<NAME>来把这个COMPONENT添加到你的程序。请注意,不要输入文件夹的前缀。举个例子,你创建了一个名为COMPONENT_MY_COMPONENT的文件夹,要添加它到程序中你应该在makefile中这样做:
COMPONENTS+=MY_COMPONENT
22. 如何禁用一个COMPONENT?
使用DISABLE_COMPONENTS+=<NAME>来禁用COMPONENT。比如:
DISABLE_COMPONENTS+=MY_COMPONENT
23. 如何覆写BSP中默认的design.modus文件?
你可以会希望为你的项目自定义硬件配置。design.modus文件是BSP_DESIGN_MODUS这个COMPONENT的一部分。要做到这一点,你需要禁用默认的COMPONENT然后添加另一个自定义的COMPONENT。
对于某BSP,你可以在该BSP的User Guide文档中找到如何进行本操作的提示,比如这个例子。请参考名为“Overriding the BSP design.modus File”的这个章节。
当你使用ModusToolbox IDE或者Project Creator工具来创建项目时,你会得到这个文件的一个本地副本。你可以直接修改它,而无需覆写原文件。但是,如果你再次使用makefile重建了项目,那新的项目不会跟进你的修改。并且如果你更新了BSP的版本,那你对旧版本的改动可能会丢失,如果你忽略相应警告的话。为了避免上述风险,你可以覆写BSP中的默认组件。
为了做到这点,你需要创建一个自定义的COMPONENT。举例来说,你可以复制并重命名默认组件,然后在里面做你想做的改动。BSP的文档资料有对应的详情。
然后,在makefile中,你需要编辑相应的代码来禁用默认组件并使用新的自定义组件。比如,如果你的自定义组件名为“CUSTOM_DESIGN_MODUS”,那你应用程序的makefile可以这么修改:
#禁用默认组件
DISABLE_COMPONENTS+=BSP_DESIGN_MODUS
#启用新的自定义组件
COMPONENTS+=CUSTOM_DESIGN_MODUS
24. 我怎么创建我自己的BSP?
你会需要自定义BSP,如果你的项目不是使用Cypress的套件。准确来说,这个议题和makefile没有关系。但是,如果你有了一个自定义的BSP,你必须修改makefile来使用你自定义的BSP。
你可以通过命令行创建BSP。在一个应用或项目目录内,使用命令“make bsp TARGET_GEN=<BoardName>”。
新得到的这个BSP是根据当前使用的BSP来创建的。你可以选择指定不同的设备,或者额外的器件比如射频。例子如下:
make bsp TARGET_GEN=MyBoard DEVICE_GEN=CY8C624ABZI-D44 ADDITIONAL_DEVICES_GEN=CYW4343WKUBG
接下来,你便可以按照你项目的要求修改新的BSP里的任何文件。需要指出的是,新的BSP已默认包含你指定的设备需要的链接器脚本和startup脚本。
关于手动创建自定义BSP的相应信息,包含在BSP的文档中。比如,对于PSoC 6 MCU的BSP,这些提示在每个BSP的User Guide里面都会有提及,比如这个例子。请在文档中查找章节“Creating a BSP for Your Board”。对于Bluetooth SDK中使用的BSP,这些提示会在wiced_btsdk的ReadMe文件的 “Using BSP (platforms)”章节。每个demo例程的提示信息也在ReadMe文件中。
25. 如何在我的应用程序中使用一个自定义的BSP?
你可能会需要创建这样的一个项目,它的目标硬件并不是Cypress套件。这时你需要使用自定义的BSP来支持你的开发板。自定义的BSP文件夹应命名为TARGET_<BSP_NAME>。在makefile中,你需要使用TARGET变量来匹配。
比如,如果你的BSP命名为“MyBoard”,那这个BSP的所有内容必须是放在名为TARGET_MyBoard的文件夹中。然后,你的makefile应该设置成这样:
#目标的开发板/硬件
TARGET=MyBoard
当你执行“make getlibs”命令的时候,BSP包含的文件需要放在名为TARGET_MyBoard的文件夹中。