2

after my last post i have fixed several issues with my makefile. currently it looks that way:

RM := rm -rf

OBJSDIR := \
    ./objs

# compiler flags
CFLAGS := \
    -mcpu=cortex-m4           \
    -mthumb -mlittle-endian   \
    -mfloat-abi=softfp        \
    -mfpu=fpv4-sp-d16         \
    -O0                       \
    -fmessage-length=0        \
    -fsigned-char             \
    -ffunction-sections       \
    -fdata-sections           \
    -ffreestanding            \
    -fno-move-loop-invariants \
    -Wall                     \
    -g3                       \
    -std=gnu11                \
    -DSTM32F429xx             \
    -DDEBUG                   \
    -DUSE_FULL_ASSERT         \
    -DTRACE                   \
    -DOS_USE_TRACE_ITM        \
    -DUSE_HAL_DRIVER          \
    -DHSE_VALUE=8000000

# assembler flags
ASMFLAGS := \
    -mcpu=cortex-m4             \
    -mthumb -mlittle-endian     \
    -mfloat-abi=softfp          \
    -mfpu=fpv4-sp-d16           \
    -O0                         \
    -fmessage-length=0          \
    -fsigned-char               \
    -ffunction-sections         \
    -fdata-sections             \
    -ffreestanding              \
    -fno-move-loop-invariants   \
    -Wall                       \
    -g3                         \
    -x assembler                \
    -DSTM32F429xx               \
    -DDEBUG                     \
    -DUSE_FULL_ASSERT           \
    -DTRACE                     \
    -DOS_USE_TRACE_ITM          \
    -DUSE_HAL_DRIVER            \
    -DHSE_VALUE=8000000

# include dirs
INCDIRS := \
    -I"./src/application"                              \
    -I"./src/application/config"                       \
    -I"./src/application/task"                         \
    -I"./src/module/adc"                               \
    -I"./src/module/can"                               \
    -I"./src/module/com"                               \
    -I"./src/module/config"                            \
    -I"./src/module/contactor"                         \
    -I"./src/module/cpuload"                           \
    -I"./src/module/io"                                \
    -I"./src/module/ltc"                               \
    -I"./src/module/spi"                               \
    -I"./src/module/uart"                              \
    -I"./src/engine/config"                            \
    -I"./src/engine/database"                          \
    -I"./src/engine/diag"                              \
    -I"./src/engine/isoguard"                          \
    -I"./src/engine/soc"                               \
    -I"./src/engine/sof"                               \
    -I"./src/engine/sysctrl"                           \
    -I"./src/engine/task"                              \
    -I"./src/general"                                  \
    -I"./src/general/config"                           \
    -I"./src/general/includes"                         \
    -I"./src/hal/CMSIS/Device/ST/STM32F4xx/Include"    \
    -I"./src/hal/CMSIS/Include"                        \
    -I"./src/hal/STM32F4xx_HAL_Driver/Inc"             \
    -I"./src/os"                                       \
    -I"./src/os/FreeRTOS"                              \
    -I"./src/os/FreeRTOS/Source"                       \
    -I"./src/os/FreeRTOS/Source/include"               \
    -I"./src/os/FreeRTOS/Source/CMSIS_RTOS"            \
    -I"./src/os/FreeRTOS/Source/portable/GCC/ARM_CM4F" \
    -I"./src/test"                                     \
    -I"./src/module/cpu"                               \
    -I"./src/module/dma"                               \
    -I"./src/module/irq"                               \
    -I"./src/module/rcc"                               \
    -I"./src/test/usb_cdc_lolevel"

S_UPPER_SRCS := \
    ./src/general/config/startup_stm32f429xx.S

S_UPPER_DEPS := \
    ./src/general/config/startup_stm32f429xx.d

# recursive search subfolders matching pattern
rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))

# All of the sources participating in the build are defined here
C_SRCS := \
    $(call rwildcard, , *.c)
#   $(foreach d,$(SUBDIRS),$(call rwildcard, , *.c)) # bug, needs d passed as param to the wildcard func

# exclude STM templates from build
C_SRCS := $(filter-out src/hal/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c, $(C_SRCS))
C_SRCS := $(filter-out src/hal/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_msp_template.c, $(C_SRCS))
#$(info C_SRCS='$(C_SRCS)')

OBJS := \
    $(patsubst %.c, $(OBJSDIR)/%.o,$(C_SRCS))

# add linker script
OBJS += \
    $(OBJSDIR)/src/general/config/startup_stm32f429xx.o

C_DEPS := \
    $(patsubst %.c,$(OBJSDIR)/%.d,$(C_SRCS))
#$(info C_DEPS='$(C_DEPS)')

# compile src files
$(OBJSDIR)/%.o: %.c
    @echo 'Building file: $<'
    @echo 'Invoking: Cross ARM C Compiler'
    arm-none-eabi-gcc $(CFLAGS) $(INCDIRS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -c -o "$@" "$<"
    @echo 'Finished building: $<'
    @echo ' '

# assemble linker script 
src/general/config/startup_stm32f429xx.o: src/general/config/startup_stm32f429xx.S
    @echo 'Building file: $<'
    @echo 'Invoking: Cross ARM GNU Assembler'
    arm-none-eabi-gcc $(ASMFLAGS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -c -o "$@" "$<"
    @echo 'Finished building: $<'
    @echo ' '


ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(CC_DEPS)),)
-include $(CC_DEPS)
endif
ifneq ($(strip $(C++_DEPS)),)
-include $(C++_DEPS)
endif
ifneq ($(strip $(C_UPPER_DEPS)),)
-include $(C_UPPER_DEPS)
endif
ifneq ($(strip $(CXX_DEPS)),)
-include $(CXX_DEPS)
endif
ifneq ($(strip $(ASM_DEPS)),)
-include $(ASM_DEPS)
endif
ifneq ($(strip $(S_UPPER_DEPS)),)
-include $(S_UPPER_DEPS)
endif
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
ifneq ($(strip $(CPP_DEPS)),)
-include $(CPP_DEPS)
endif
endif

# Add inputs and outputs from these tool invocations to the build variables
SECONDARY_FLASH := \
    foxbms.hex \

SECONDARY_LIST := \
    foxbms.lst \

SECONDARY_SIZE := \
    foxbms.siz \

# All Target
all: foxbms.elf secondary-outputs

# Tool invocations
foxbms.elf: $(OBJS) $(USER_OBJS)
    @echo 'Building target: $@'
    @echo 'Invoking: Cross ARM C++ Linker'
    arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mlittle-endian -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-move-loop-invariants -Wall -g3 -T "src/STM32F429ZIT6_FLASH.ld" -Xlinker --gc-sections -Wl,-Map,"foxbms.map" --specs=nano.specs -o "foxbms.elf" $(OBJS) $(USER_OBJS) $(LIBS)
    @echo 'Finished building target: $@'
    @echo ' '
    $(MAKE) --no-print-directory post-build

foxbms.hex: foxbms.elf
    @echo 'Invoking: Cross ARM GNU Create Flash Image'
    arm-none-eabi-objcopy -O ihex "foxbms.elf" "foxbms.hex"
    @echo 'Finished building: $@'
    @echo ' '

foxbms.lst: foxbms.elf
    @echo 'Invoking: Cross ARM GNU Create Listing'
    arm-none-eabi-objdump --source --all-headers --demangle --line-numbers --wide "foxbms.elf" > "foxbms.lst"
    @echo 'Finished building: $@'
    @echo ' '

foxbms.siz: foxbms.elf
    @echo 'Invoking: Cross ARM GNU Print Size'
    arm-none-eabi-size --format=berkeley $(OBJS) "foxbms.elf"
    @echo 'Finished building: $@'
    @echo ' '

# Other Targets
clean:
    -$(RM) \
        $(CC_DEPS)         \
        $(C++_DEPS)        \
        $(OBJS)            \
        $(C_UPPER_DEPS)    \
        $(CXX_DEPS)        \
        $(SECONDARY_FLASH) \
        $(SECONDARY_LIST)  \
        $(SECONDARY_SIZE)  \
        $(ASM_DEPS)        \
        $(S_UPPER_DEPS)    \
        $(C_DEPS)          \
        $(CPP_DEPS)        \
        foxbms.elf
    -@echo ' '

post-build:
    -@echo 'Create binary'
    -arm-none-eabi-objcopy -O binary "foxbms.elf" "foxbms.bin"
    -@echo ' '

secondary-outputs: $(SECONDARY_FLASH) $(SECONDARY_LIST) $(SECONDARY_SIZE)

.PHONY: all clean dependents x
.SECONDARY: post-build

last thing i want to to do is placing all .o and .d files into a /objs subfolder, outside the /src folder. i have edited the makefile but it gives me following error:

make all 
Building file: src/general/nvic.c
Invoking: Cross ARM C Compiler
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mlittle-endian -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-move-loop-invariants -Wall -g3 -std=gnu11 -DSTM32F429xx -DDEBUG -DUSE_FULL_ASSERT -DTRACE -DOS_USE_TRACE_ITM -DUSE_HAL_DRIVER -DHSE_VALUE=8000000 -I"./src/application" -I"./src/application/config" -I"./src/application/task" -I"./src/module/adc" -I"./src/module/can" -I"./src/module/com" -I"./src/module/config" -I"./src/module/contactor" -I"./src/module/cpuload" -I"./src/module/io" -I"./src/module/ltc" -I"./src/module/spi" -I"./src/module/uart" -I"./src/engine/config" -I"./src/engine/database" -I"./src/engine/diag" -I"./src/engine/isoguard" -I"./src/engine/soc" -I"./src/engine/sof" -I"./src/engine/sysctrl" -I"./src/engine/task" -I"./src/general" -I"./src/general/config" -I"./src/general/includes" -I"./src/hal/CMSIS/Device/ST/STM32F4xx/Include" -I"./src/hal/CMSIS/Include" -I"./src/hal/STM32F4xx_HAL_Driver/Inc" -I"./src/os" -I"./src/os/FreeRTOS" -I"./src/os/FreeRTOS/Source" -I"./src/os/FreeRTOS/Source/include" -I"./src/os/FreeRTOS/Source/CMSIS_RTOS" -I"./src/os/FreeRTOS/Source/portable/GCC/ARM_CM4F" -I"./src/test" -I"./src/module/cpu" -I"./src/module/dma" -I"./src/module/irq" -I"./src/module/rcc" -I"./src/test/usb_cdc_lolevel" -MMD -MP -MF"objs/src/general/nvic.d" -MT"objs/src/general/nvic.o" -c -o "objs/src/general/nvic.o" "src/general/nvic.c"
src/general/nvic.c:108:1: fatal error: opening dependency file objs/src/general/nvic.d: No such file or directory
 }
 ^
compilation terminated.
makefile:131: recipe for target 'objs/src/general/nvic.o' failed
make: *** [objs/src/general/nvic.o] Error 1

any hints what i am doing wrong here?

what do i have to do to generate those folders? in some makefile examples i saw people creating a rule with mkdir, others just didn't do that, what is correct?

  • One fairly strong hint would be `fatal error: opening dependency file objs/src/general/nvic.d: No such file or directory` – Jon Chesterfield Nov 23 '15 at 09:34
  • yes obviously he doesn't find what he's looking for (the folder doesn't exist). my question was how do i need to modify my makefile to get it working? is just the rule wrong? or do i need to create those folders using an extra rule? – whitepanda00 Nov 23 '15 at 09:37
  • It's that the rules are wrong. Makefiles are pretty arcane though, so don't feel too bad about that. Make can't find that file. So first question is does that file actually exist - I suspect the directory is there, but the .d file has not been created. – Jon Chesterfield Nov 23 '15 at 09:51
  • no, the folder doesn't exist, that's why i ask wether it gets generated by make with this rule or do i have to create them myself with an additional rule? – whitepanda00 Nov 23 '15 at 10:01
  • Which folder? objs/src/general? – Jon Chesterfield Nov 23 '15 at 10:04
  • the objs/ folder (+ all subfolders) – whitepanda00 Nov 23 '15 at 10:07
  • Ah, right. Yes, that would be a problem. I can't see anything in your makefile which would create these directories. So make thinks the source code is called src/general/nvic.c etc, and you're telling it to create object files called obj/src/general/nvic.o and it's failing because none of the directories exist. Are you looking for `mkdir -p`? – Jon Chesterfield Nov 23 '15 at 10:10
  • yes something like that. i saw people using it in some makefile examples, however some didnt't use it (at least it wasn't in their) post and it seemed to work magicaly even without it...a litte bit confusing. i will need something which works on windows as well and `mkdir -p` doesn't work there sadly.. – whitepanda00 Nov 23 '15 at 10:15
  • I believe `mkdir -p $(dir $(C_DEPS))` will create the directory tree you need on Linux. I'd have to look up an equivalent command for windows. – Jon Chesterfield Nov 23 '15 at 10:22
  • `mkdir -p `will create 2 subfolders: `-p` and `something` on windows, not want i want :( – whitepanda00 Nov 23 '15 at 10:28
  • That sounds about right. Google tells me that window's mkdir behaves appropriately in this case without a flag. So on windows it's `mkdir $(dir $(C_DEPS))`. Your makefile is going to need `if windows MKDIR=mkdir else MKDIR = "mkdir -p"` or equivalent. The tricky question is how you will detect what platform you're currently using. Cross platform makefiles are bad things. – Jon Chesterfield Nov 23 '15 at 10:33
  • well i think i will leave this up to the user (for the first step) and offer both variants, so he needs to comment/uncomment the one he needs for his platform. how do i embed this correctly into current makefile? – whitepanda00 Nov 23 '15 at 10:37

3 Answers3

0

Current theory...

We seem to be clear that the output directories do not already exist on disk. A possible solution, for platforms which know what mkdir -p means, would then be

# compile src files
$(OBJSDIR)/%.o: %.c
    mkdir -p $(@D) # Make the output directory, even if it already exists
    @echo 'Building file: $<'
    @echo 'Invoking: Cross ARM C Compiler'
    arm-none-eabi-gcc $(CFLAGS) $(INCDIRS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -c -o "$@" "$<"
    @echo 'Finished building: $<'
    @echo ' '

For handling the problem of creating directories under Windows or Linux, I'd suggest using the solution of this question.

First theory...

You need to compare the invocations of gcc with the manual. In particular, since the makefile cannot find the dependency, we are interested in that part that creates said file:

-MF"$(@:%.o=%.d)" -MT"$@"

The -MF specifies where the dependency file will be written. However,

An -MT option will set the target to be exactly the string you specify

I don't think you want that. Deleting -MT"$@" may be sufficient to solve your current problem.

If not, would you be willing to create a reproducible test case? I can read the current makefile, but short of setting up rather a lot of supporting files, I can't test any suggested fixes.

edit: Though I like the above theory, it appears to be incorrect. Removing | inserting the -MT string has no obvious effect on my own makefiles.

Community
  • 1
  • 1
Jon Chesterfield
  • 2,251
  • 1
  • 20
  • 30
  • `# compile src files $(OBJSDIR)/%.o: %.c mkdir -p $(@D) # Make the output directory, even if it already exists @echo 'Building file: $<' @echo 'Invoking: Cross ARM C Compiler' arm-none-eabi-gcc $(CFLAGS) $(INCDIRS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -c -o "$@" "$<" @echo 'Finished building: $<' @echo ' '` doesn't work: `make all mkdir objs/src/general makefile:131: recipe for target 'objs/src/general/nvic.o' failed process_begin: CreateProcess(NULL, mkdir objs/src/general, ...) failed.` – whitepanda00 Nov 23 '15 at 11:09
  • That's not enough information. I really do need a compilable example - a cut down makefile and a minimal source file or two - that reproduce the problem. This doesn't have to be proprietary code, but it does need to reproduce the problem. Otherwise it's just guesswork. – Jon Chesterfield Nov 23 '15 at 11:21
0

I'm afraid i can't share sourcecode in its current stage.

editing following part and everything works (but places .o .d files into same folders as their corresponding .c file what i wanted to change)

OBJS := \
    $(patsubst %.c, %.o,$(C_SRCS))

# add linker script
OBJS += \
    /src/general/config/startup_stm32f429xx.o

C_DEPS := \
    $(patsubst %.c,%.d,$(C_SRCS))
#$(info C_DEPS='$(C_DEPS)')

# compile src files
%.o: %.c
    @echo 'Building file: $<'
    @echo 'Invoking: Cross ARM C Compiler'
    arm-none-eabi-gcc $(CFLAGS) $(INCDIRS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -c -o "$@" "$<"
    @echo 'Finished building: $<'
    @echo ' '
  • Why does C_DEPS claim the .d files are in the C_SRC's directory? – Jon Chesterfield Nov 23 '15 at 10:02
  • that's like it was before (when .o and .d files were put into same folder as their corresponding .c file) – whitepanda00 Nov 23 '15 at 10:06
  • Ah, good. I see your OP contains `$(patsubst .c,$(OBJSDIR)/%.d,$(C_SRCS))`, so that's good. A reproducible doesn't need to contain all of your project, just enough scraps to recreate the problem for other users. Still, I think we're at the bottom of this - none of the output directories exist, and they need to. – Jon Chesterfield Nov 23 '15 at 10:13
0

Have you tried to put another pastsub into the %.o: %.c command:

Something like this:

%.o: %.c
    arm-none-eabi-gcc $(CFLAGS) $(INCDIRS) -MMD -MP -MF"$(patsubst %.c,$(OBJSDIR)/%.d,@)" -MT"$@" -c -o "$@" "$<"
Jonatan Goebel
  • 1,107
  • 9
  • 14