编译uCos-ii例子的Makefile

时间:2021-12-16 19:30:47

      帮同学搞毕业设计,需要编译移植到Windows平台的uCos-ii实时操作系统。导师给的代码是2.52版的uCos-ii。首先我需要编译出一个Demo。昨天恶补了Makefile的语法,简单的写法已经会了。这里拿GNUMake 3.81版为例,来写一个Makefile:

##BC4.5编译器路径
BORLAND = C:\BC45
TASM = C:\TASM\BIN\TASM.EXE
LINK = C:\BC45\BIN\TLINK.EXE
##工程名
PROJECT = GetImage
EXECUTABLE = $(PROJECT).exe
LNKFILE = Makefile.LNK
##目标文件
C_OBJECTS = OS_CPU_C.OBJ PC.OBJ UCOS_II.OBJ TEST.OBJ
ASM_OBJECTS = OS_CPU_A.OBJ
##编译参数
$(EXECUTABLE) : BORLAND_OBJ = C0L.OBJ
$(EXECUTABLE) : BORLAND_LIB = EMU.LIB MATHL.LIB CL.LIB
$(EXECUTABLE) : $(C_OBJECTS) $(ASM_OBJECTS)
	@echo $(addprefix $(BORLAND)\LIB\,$(BORLAND_OBJ)) $(C_OBJECTS) $(ASM_OBJECTS),$(EXECUTABLE),,$(addprefix $(BORLAND)\LIB\,$(BORLAND_LIB)) > $(LNKFILE)
	$(LINK) @$(LNKFILE)
	
$(C_OBJECTS) :
	$(BORLAND)\BIN\BCC.EXE -c -ml -1 -G -O -Ogemvlbpi -Z -d -n -k- -v -vi- -wpro -I$(BORLAND)\INCLUDE -L$(BORLAND)\LIB $(subst .OBJ,.C,$@)
$(ASM_OBJECTS) :
	$(TASM) /mx /zn /o $(subst .OBJ,.ASM,$@)
##清理
.PHONY : clean
clean :
	-del $(C_OBJECTS) $(ASM_OBJECTS) $(LNKFILE) *.MAP

      编译uCos-ii需要使用Borland的4.5C编译器,以及其中带的TASM汇编器。我试过其他的支持INTEL汇编格式的汇编器都出现问题,但汇编学太烂了,还是老老实实地用BC4.5吧!刚开始学Makefile,留下一些记录,方便日后查阅。

  • 变量赋值

      看到第一行"BORLAND = C:\BC45"即对变量"BORLAND"赋值为"C:\BC45",设置变量方便后面使用,也方便修改。使用变量用$(BORLAND),这一语法与AUTOIT极像。

  • 变量连接

      由于$(变量)直接代表其值,在第二段中的:

PROJECT = GetImage

EXECUTABLE = $(PROJECT).exe

表示创建一个名为"EXECUTABLE"的变量,其值为"GetImage.exe"。当然也可以使用:

PROJECT = GetImage

EXECUTABLE = $(PROJECT)

EXECUTABLE += .exe

但是使用+=等符号连接变量时要小心递归,如下这种情况是错误的:

PROJECT = GetImage

EXECUTABLE = $(PROJECT)

EXECUTABLE = $(EXECUTABLE) .exe

我们可以通过使用":="立即赋值符替换"="来修正递归错误:

PROJECT = GetImage

EXECUTABLE = $(PROJECT)

EXECUTABLE := $(EXECUTABLE) .exe

  • 为不同目标的同一变量设置不同的值

      假设我们在Makefile开始处设有一变量FLAG,我们要在debug和release两个目标中对其设置不同值。首先,我解释一下“目标”,这里的“目标”正如C语言中"switch…case"中的case,也相当于批处理中的标记。我们举个例子:

PROJECT = GetImage

EXECUTABLE = $(PROJECT).exe

FLAG = –Wall

$(EXECUTABLE):

    gcc –o $(EXECUTABLE) GetImage.c

.PHONY: clean

clean:

    -mkdir $(EXECUTABLE)

      "$(EXECUTABLE):"即为目标表示该目标下的操作能够生成一个目标文件($(EXECUTABLE)文件)。第一个目标为默认目标,在输入make命令时默认执行。"clean:"也是一个目标,在".PHONY:clean"把clean作为".PHONY"的一个依赖,这样"clean:"即为一个伪目标。

伪目标是这样一个目标:
      它不代表一个真正的文件名,在执行make时可以指定这个目标来执行其所在规则定义的命令,有时也可以将一个伪目标称为标签。使用伪目标有两点原因:

1. 避免在我们的 Makefile 中定义的只执行命令的目标(此目标的目的为了执行执一些列命令,而不需要创建这个目标)和工作目录下的实际文件出现名字冲突。

2. 提高执行 make 时的效率,特别是对于一个大型的工程来说,编译的效率也许你同样关心。

      但是,目标指定的变量值只在指定它的目标的上下文中有效,对于其他的目标没有影响。就是说目标指定的变量具有只对此目标上下文有效的“局部性”。

      使用目标指定变量值时,目标指定的变量值不会影响同名的那个全局变量的值就是说目标指定一个变量值时,如果在 Makefile 中之前已经存在此变量的定义(非目标指定的),那么对于其它目标全局变量的值没有变化。变量值的改变只对指定的这些目标可见。

      这就说明,如果我们在debug和clean这两个目标中修改变量FLAG的值,实际上是生成了一个局部的FLAG副本,修改的只是这个副本的值。如果我们在debug和release中不需要使用FLAG原有值时,就不需要设置全局的FLAG变量。如:

.PHONY debug release compile

debug:FLAG = –g

debug:compile

release:FLAG = –o2

release:compile

compile:

      gcc –o GetImage.exe $(FLAG)

  • 注意事项

      1. 在Makefile中,TAB缩进也是一种语法。如果该加缩进的地方没有加缩进或者加成等长的空格,make时将报“缺少分隔符”的错误。

      2. 在定义目标局部变量时,需要把定义变量单独写成一行。否则make错误。本文中的有些代码缩进使用等长的空格,因为其中无法输入TAB -_-!

未完待续……