我试图编写一个Makefile,它应该根据需要将所有源代码编译到对象中,然后构建输出二进制文件。
我尝试了几个例子,找到了解决方案,但前提是我将所有源放在同一个文件夹中。
但在这个项目中,文件分布在多个目录和子目录中。
我修改后的Makefile如下
TARGET=analyser
CC=arm-none-eabi-gcc
OBJCPY=arm-none-eabi-objcopy
CFLAGS= -DNDEBUG -DCPU_MK64FN1M0VLL12 -DUSE_RTOS=1 -DPRINTF_ADVANCED_ENABLE=1
-DFRDM_K64F -DFREEDOM -DFSL_RTOS_FREE_RTOS -Os -Wall -fno-common
-ffunction-sections -fdata-sections -ffreestanding -fno-builtin
-mthumb -mapcs -std=gnu99 -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -MMD -MP
--specs=nano.specs --specs=nosys.specs -Wall -fno-common -ffunction-sections
-fdata-sections -ffreestanding -fno-builtin -mthumb -mapcs -Xlinker --gc-sections
-Xlinker -static -Xlinker -z -Xlinker muldefs -Xlinker -Map=output.map -mcpu=cortex-m4
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -Xlinker --defsym=__stack_size__=2048 -Xlinker
--defsym=__heap_size__=25600 -Wall
LDSCRIPT=linker/MK64FN1M0xxx12_flash.ld
ASM_SOURCES := $(shell find . -name "*.S")
GCC_SOURCES := $(shell find . -name "*.c")
ASM_DIRNAME := $(shell dirname $(ASM_SOURCES))
GCC_DIRNAME := $(shell dirname $(GCC_SOURCES))
ASM_OBJECTS := $(patsubst $(ASM_DIRNAME)/%.S, $(ASM_DIRNAME)/%.o, $(ASM_SOURCES))
GCC_OBJECTS := $(patsubst $(GCC_DIRNAME)/%.c, $(GCC_DIRNAME)/%.o, $(GCC_SOURCES))
INCLUDES=
-Iapp/include
-ICMSIS
-Ifsl
-IFreeRTOS/include
-IFreeRTOS/include/private
-IFreeRTOS/src/portable/GCC/ARM_CM4F
-Iinclude
-Idrivers/uart
-Idrivers/serial_manager
-Idrivers/lists
-Ilwip/port
-Ilwip/src
-Ilwip/src/include
all:
$(CC) $(INCLUDES) $(GCC_SOURCES) $(ASM_SOURCES) $(CFLAGS) -T $(LDSCRIPT) -o $(TARGET).elf
$(OBJCPY) $(TARGET).elf $(TARGET).bin -O binary
bad: $(GCC_OBJECTS) $(ASM_OBJECTS)
$(GCC) $(CFLAGS) -T $(LDSCRIPT) $^ -o $(TARGET)
$(ASM_DIRNAME)/%.o:$(ASM_DIRNAME)/%.S
$(GCC) $(INCLUDES) $(CFLAGS) -c $< -o $@
$(GCC_DIRNAME)/%.o:$(GCC_DIRNAME)/%.c
$(GCC) $(INCLUDES) $(CFLAGS) -c $< -o $@
clean:
rm $(TARGET).elf $(TARGET).bin $(TARGET).d output.map
当我执行";制造";命令通过进行编译
但当我执行";制造坏的";我收到错误
对于经验丰富的编码专家来说,这可能很简单,但我对Makefile世界还很陌生。
有人能帮我弄清楚吗?
修改前的原始Makefile如下所示:
TARGET=analyser
CC=arm-none-eabi-gcc
OBJCPY=arm-none-eabi-objcopy
CFLAGS= -DNDEBUG -DCPU_MK64FN1M0VLL12 -DUSE_RTOS=1 -DPRINTF_ADVANCED_ENABLE=1
-DFRDM_K64F -DFREEDOM -DFSL_RTOS_FREE_RTOS -Os -Wall -fno-common
-ffunction-sections -fdata-sections -ffreestanding -fno-builtin
-mthumb -mapcs -std=gnu99 -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -MMD -MP
--specs=nano.specs --specs=nosys.specs -Wall -fno-common -ffunction-sections
-fdata-sections -ffreestanding -fno-builtin -mthumb -mapcs -Xlinker --gc-sections
-Xlinker -static -Xlinker -z -Xlinker muldefs -Xlinker -Map=output.map -mcpu=cortex-m4
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -Xlinker --defsym=__stack_size__=2048 -Xlinker
--defsym=__heap_size__=25600 -Wall
LDSCRIPT=linker/MK64FN1M0xxx12_flash.ld
SRCS=
startup/startup_MK64F12.S
startup/startup_MK64F12.c
app/network_analyser.c
app/config/pin_mux.c
app/config/board.c
app/config/clock_config.c
fsl/fsl_sim.c
fsl/fsl_clock.c
fsl/fsl_enet.c
fsl/fsl_ftfx_cache.c
fsl/fsl_ftfx_controller.c
fsl/fsl_ftfx_flash.c
fsl/fsl_ftfx_flexnvm.c
fsl/fsl_gpio.c
fsl/fsl_debug_console.c
fsl/fsl_str.c
fsl/fsl_uart.c
fsl/fsl_smc.c
fsl/fsl_common.c
fsl/fsl_assert.c
fsl/fsl_sbrk.c
fsl/fsl_phy.c
fsl/fsl_dspi.c
fsl/fsl_dspi_freertos.c
fsl/fsl_uart_freertos.c
FreeRTOS/src/portable/MemMang/heap_3.c
FreeRTOS/src/event_groups.c
FreeRTOS/src/list.c
FreeRTOS/src/portable/GCC/ARM_CM4F/port.c
FreeRTOS/src/queue.c
FreeRTOS/src/stream_buffer.c
FreeRTOS/src/tasks.c
FreeRTOS/src/timers.c
drivers/uart/uart_adapter.c
drivers/serial_manager/serial_manager.c
drivers/serial_manager/serial_port_uart.c
drivers/lists/generic_list.c
lwip/port/enet_ethernetif_kinetis.c
lwip/port/enet_ethernetif.c
lwip/port/sys_arch.c
lwip/src/api/api_lib.c
lwip/src/api/api_msg.c
lwip/src/api/err.c
lwip/src/api/if_api.c
lwip/src/api/netbuf.c
lwip/src/api/netdb.c
lwip/src/api/netifapi.c
lwip/src/api/sockets.c
lwip/src/api/tcpip.c
lwip/src/core/altcp.c
lwip/src/core/altcp_alloc.c
lwip/src/core/altcp_tcp.c
lwip/src/core/def.c
lwip/src/core/dns.c
lwip/src/core/inet_chksum.c
lwip/src/core/init.c
lwip/src/core/ip.c
lwip/src/core/ipv4/autoip.c
lwip/src/core/ipv4/dhcp.c
lwip/src/core/ipv4/etharp.c
lwip/src/core/ipv4/icmp.c
lwip/src/core/ipv4/igmp.c
lwip/src/core/ipv4/ip4.c
lwip/src/core/ipv4/ip4_addr.c
lwip/src/core/ipv4/ip4_frag.c
lwip/src/core/ipv6/dhcp6.c
lwip/src/core/ipv6/ethip6.c
lwip/src/core/ipv6/icmp6.c
lwip/src/core/ipv6/inet6.c
lwip/src/core/ipv6/ip6.c
lwip/src/core/ipv6/ip6_addr.c
lwip/src/core/ipv6/ip6_frag.c
lwip/src/core/ipv6/mld6.c
lwip/src/core/ipv6/nd6.c
lwip/src/core/mem.c
lwip/src/core/memp.c
lwip/src/core/netif.c
lwip/src/core/pbuf.c
lwip/src/core/raw.c
lwip/src/core/stats.c
lwip/src/core/sys.c
lwip/src/core/tcp.c
lwip/src/core/tcp_in.c
lwip/src/core/tcp_out.c
lwip/src/core/timeouts.c
lwip/src/core/udp.c
lwip/src/netif/bridgeif.c
lwip/src/netif/bridgeif_fdb.c
lwip/src/netif/ethernet.c
lwip/src/netif/lowpan6.c
lwip/src/netif/lowpan6_ble.c
lwip/src/netif/lowpan6_common.c
lwip/src/netif/ppp/auth.c
lwip/src/netif/ppp/ccp.c
lwip/src/netif/ppp/chap-md5.c
lwip/src/netif/ppp/chap-new.c
lwip/src/netif/ppp/chap_ms.c
lwip/src/netif/ppp/demand.c
lwip/src/netif/ppp/eap.c
lwip/src/netif/ppp/eui64.c
lwip/src/netif/ppp/fsm.c
lwip/src/netif/ppp/ipcp.c
lwip/src/netif/ppp/ipv6cp.c
lwip/src/netif/ppp/lcp.c
lwip/src/netif/ppp/lwip_ecp.c
lwip/src/netif/ppp/magic.c
lwip/src/netif/ppp/mppe.c
lwip/src/netif/ppp/multilink.c
lwip/src/netif/ppp/ppp.c
lwip/src/netif/ppp/pppapi.c
lwip/src/netif/ppp/pppcrypt.c
lwip/src/netif/ppp/pppoe.c
lwip/src/netif/ppp/pppol2tp.c
lwip/src/netif/ppp/pppos.c
lwip/src/netif/ppp/upap.c
lwip/src/netif/ppp/utils.c
lwip/src/netif/ppp/vj.c
lwip/src/netif/slipif.c
lwip/src/netif/zepif.c
INCLUDES=
-Iapp/include
-ICMSIS
-Ifsl
-IFreeRTOS/include
-IFreeRTOS/include/private
-IFreeRTOS/src/portable/GCC/ARM_CM4F
-Iinclude
-Idrivers/uart
-Idrivers/serial_manager
-Idrivers/lists
-Ilwip/port
-Ilwip/src
-Ilwip/src/include
all:
$(CC) $(INCLUDES) $(SRCS) $(CFLAGS) -T $(LDSCRIPT) -o $(TARGET).elf
$(OBJCPY) $(TARGET).elf $(TARGET).bin -O binary
clean:
rm $(TARGET).elf $(TARGET).bin $(TARGET).d output.map
为什么要用find
替换那个漂亮的显式源列表?把名单拿回来!
特别是为什么的find
恰好是一个程序集源?当然,从C源文件中分离它可能是一个不错的举措,但我认为find
使用它没有任何好处
这个。。。
ASM_DIRNAME := $(shell dirname $(ASM_SOURCES))
。。。没有用处(见下文)。
这个。。。
GCC_DIRNAME := $(shell dirname $(GCC_SOURCES))
。。。不仅没有用处,而且确实存在问题。因为您有多个C源,所以这个变量将获得一个完整的目录名列表,而不仅仅是一个。还有一堆重复的,尽管这部分在实践中不会给你带来问题。
这些。。。
ASM_OBJECTS := $(patsubst $(ASM_DIRNAME)/%.S, $(ASM_DIRNAME)/%.o, $(ASM_SOURCES)) GCC_OBJECTS := $(patsubst $(GCC_DIRNAME)/%.c, $(GCC_DIRNAME)/%.o, $(GCC_SOURCES))
。。。对CCD_ 4使用不当。稍有错误,因为逗号后面的空格是数据,而不是分隔符。不方便,因为普通的替换引用更清晰、更短、更传统,并且更便于移植,只需将一个文件扩展名转换为另一个。显式地表达目录名而不是仅仅将它们包含在%
中也有一些轻浮之处。推荐:
ASM_OBJECTS := $(ASM_SOURCES:.S=.o)
GCC_OBJECTS := $(GCC_SOURCES:.c=.o)
你的all
目标没有任何先决条件,它的配方构建了一切。我知道你从最初的makefile中继承了这一点,但显然你没有意识到这是为了实现你的目标而需要修改的第一件事。如果您想使用all
目标(这是一种常见的约定,但不是必需的),那么它应该将所有顶级构建输出作为先决条件,而不是配方。在您的情况下,这似乎只是$(TARGET).bin
。
每个食谱都应该尽可能地建立食谱的目标,而不是其他重要的东西。根据这个原则,您应该有单独的规则来构建$(TARGET).bin
和$(TARGET).elf
。
每个规则都应该表达其目标的所有先决条件,因此$(TARGET).bin
的规则应该以$(TARGET).elf
为先决条件;$(TARGET).elf
的规则应该将所有对象文件以及链接器脚本作为先决条件。
但是当我执行";制造坏的";我收到错误
这是因为该规则中的尾部反斜杠使其无效。可以通过在最后一个先决条件和第一个反斜杠之间放置分号(;
)来解决这个问题,但应该通过删除反斜杠并确保配方缩进文本制表符(而不是空格)来解决它。
您也应该对您的两个模式规则应用相同的修复,因为如果您正确地进行了前面描述的一些更改,那么这些更改将实际使用。但你也用$(GCC_DIRNAME)
和(稍微)$(ASM_DIRNAME)
变量射中了自己的脚。您不需要这些,因为模式词干可以很好地匹配目录。你不想要前者,因为它使你的规则沿着以下几条线:
dir1 dir1 dir2 dir3/%.o: dir1 dir1 dir2 dir3/%.c
# ... recipe ...
这里面有很多问题,尤其是它只匹配您想要构建的一些.o
文件。更简单的规则会做得更好,比如:
%.o: %.S
$(GCC) $(INCLUDES) $(CFLAGS) -c $< -o $@
%.o: %.c
$(GCC) $(INCLUDES) $(CFLAGS) -c $< -o $@
如果您将INCLUDES
重命名为CPPFLAGS
,那么您甚至可以完全转储后一条规则,以支持编译.c文件的内置规则。
此外,您的clean
目标不会清理对象文件,如果目标的规则实际上没有使用目标名称构建文件,那么您应该声明目标是假的。
总的来说,那么,我的推荐将采用以下形式:
TARGET = analyser
CC = arm-none-eabi-gcc
OBJCPY = arm-none-eabi-objcopy
CFLAGS = # flags ...
LDSCRIPT = linker/MK64FN1M0xxx12_flash.ld
ASM_SOURCES = startup/startup_MK64F12.S
GCC_SOURCES =
# long/list/of/sources.c ...
# last/source.c
ASM_OBJECTS = $(ASM_SOURCES:.S=.o)
GCC_OBJECTS = $(GCC_SOURCES:.c=.o)
CPPFLAGS =
# -Ithe/includes ...
# -Ilast/include
all: $(TARGET).bin
$(TARGET).bin: $(TARGET).elf
$(OBJCPY) $< $@ -O binary
$(TARGET).elf: $(GCC_OBJECTS) $(ASM_OBJECTS)
$(CC) -o $@ $(CFLAGS) -T $(LDSCRIPT) $^
%.o: %.S
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(TARGET).elf $(TARGET).bin $(TARGET).d output.map $(GCC_OBJECTS) $(ASM_OBJECTS)
.PHONY: all clean
您的all:
规则说"每次编译所有内容":
all:
$(CC) $(INCLUDES) $(GCC_SOURCES) $(ASM_SOURCES) $(CFLAGS) -T $(LDSCRIPT) -o $(TARGET).elf
$(OBJCPY) $(TARGET).elf $(TARGET).bin -O binary
如果文件all
不存在,则在所有源上运行C编译器并创建可执行文件(但不创建文件all
)。如果文件all
存在,则不会发生任何事情——all
不依赖于任何内容。
如果您不想编译所有内容,则需要告诉make
可执行文件依赖于对象文件并链接对象文件。
我想你需要更像的东西
PROGRAM = $(TARGET).elf
all: $(PROGRAM)
$(PROGRAM): $(GCC_OBJECTS) $(ASM_OBJECTS)
$(CC) $(INCLUDES) $(GCC_OBJECTS) $(ASM_OBJECTS) $(CFLAGS) -T $(LDSCRIPT) -o $(PROGRAM)
$(OBJCPY) $(PROGRAM) $(TARGET).bin -O binary
你可能需要做一些工作来构建对象文件,但这意味着";all
依赖于程序,程序依赖于对象文件,当对象文件都是最新的时,您可以像这样构建程序"。您可能希望指定.PHONY: all
,因为它不是"真正的"目标——它不是您创建的文件。
您应该使用宏来重复PROGRAM = $(TARGET).elf
(可能还有$(TARGET).bin
)这样的元素。如果你必须把它写出来不止一次,它可能应该是一个宏。
感谢大家参与的任务
主要的问题不仅是语法,而且是由";Sublime 3〃;软件
我已经将我的工作空间更改为";vscode";现在我对不需要的TAB 没有任何问题
Makefile正在中工作
TARGET=analyser
CC=arm-none-eabi-gcc
OBJCPY=arm-none-eabi-objcopy
CFLAGS= -DNDEBUG -DCPU_MK64FN1M0VLL12 -DUSE_RTOS=1 -DPRINTF_ADVANCED_ENABLE=1
-DFRDM_K64F -DFREEDOM -DFSL_RTOS_FREE_RTOS -Os -Wall -fno-common
-ffunction-sections -fdata-sections -ffreestanding -fno-builtin
-mthumb -mapcs -std=gnu99 -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -MMD -MP
--specs=nano.specs --specs=nosys.specs -Wall -fno-common -ffunction-sections
-fdata-sections -ffreestanding -fno-builtin -mthumb -mapcs -Xlinker --gc-sections
-Xlinker -static -Xlinker -z -Xlinker muldefs -Xlinker -Map=output.map -mcpu=cortex-m4
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -Xlinker --defsym=__stack_size__=2048 -Xlinker
--defsym=__heap_size__=25600 -Wall
LDSCRIPT=linker/MK64FN1M0xxx12_flash.ld
ASM_SOURCES = startup/startup_MK64F12.S
GCC_SOURCES = $(shell find . -name "*.c")
INCLUDES=
-Iapp
-ICMSIS
-Ifsl
-IFreeRTOS/include
-IFreeRTOS/include/private
-IFreeRTOS/src/portable/GCC/ARM_CM4F
-Iinclude
-Idrivers/uart
-Idrivers/serial_manager
-Idrivers/lists
-Ilwip/port
-Ilwip/src
-Ilwip/src/include
GCC_OBJECTS = $(GCC_SOURCES:.c=.o)
DEP_OBJECTS = $(GCC_SOURCES:.c=.d)
all: $(TARGET).bin
$(TARGET).bin: $(TARGET).elf
$(OBJCPY) $< $@ -O binary
$(TARGET).elf: $(GCC_OBJECTS)
$(CC) -o $@ $(CFLAGS) $(ASM_SOURCES) -T $(LDSCRIPT) $^
%.o: %.c
$(CC) -I $(INCLUDES) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(TARGET).elf $(TARGET).bin $(TARGET).d output.map $(GCC_OBJECTS) $(DEP_OBJECTS)
.PHONY: all clean
非常感谢你的帮助!