4

I have a makefile that used http://make.mad-scientist.net as a resource. The build process works but everything is being rebuild each time. If I run make --debug it says that the d dependency file was not found so it is regenerated.

When I look in my output folder, there is only one .d file which no filename, just .d. It looks like this file is appended during the build as the file size increases during a build.

This us using GNU Arm Embedded Toolchain 10 2021.10.

Here is the makefile, stripped down to minimal operation. The "project" has 6 or so c files and 4 or 5 header files across several folders to mimic a real project. The build artifacts are placed in a build folder and the object files + dependency files are in a obj folder under build.

###################### PATH SETUP ############################################### 
## Setup common paths before importing project specific makefile 
PLATFORM := $(PLATFORM_NAME)
FAMILY := PG22
TARGET := EFM32PG22C200F512IM40
################################ PROJECT DEFINES ########################################################
# Let's setup the initial C_DEF variable with any build time defines
#   Let the port specific makefile append anything specific
C_DEF := -DPLATFORM_$(PLATFORM) -DUSE_RTT_FOR_DEBUGGING=1 -D$(TARGET) -DFAMILY_$(FAMILY) -DNO_HFXO -D__STARTUP_CLEAR_BSS -DSL_TRUSTZONE_NONSECURE

BUILD_DIR := build

OBJ_DIR := $(BUILD_DIR)/$(PLATFORM)/obj
BIN_DIR := $(BUILD_DIR)/$(PLATFORM)

SCRIPTS_DIR := .scripts
MODULES_DIR := modules

PROJ_HAL_DIR := Ports/$(PLATFORM)/HAL           

# For organizational purposes, lets capture all of the submodule paths
MODULE_DIRS :=  $(MODULES_DIR)/submod-hal_generic
EFM32PG22_CONFIG_DIR = Ports/$(PLATFORM)/config
$(PLATFORM)_LINKER := $(EFM32PG22_CONFIG_DIR)/linker.ld
################################ SOURCE PATHS ########################################################
# We need to explicably list source directory paths
SOURCE_DIRS := application/src $(MODULE_DIRS) Ports/$(PLATFORM)/config

################################ INCLUDE PATHS ########################################################
# We need to explicably list source directory paths.
#  Just include the general generic paths here and let the port specific makefile add its own paths as needed
#  We already captured the paths above so just use a loop to build the include variable
MODULES_INCLUDES := $(foreach dir,$(MODULE_DIRS),-I$(dir))
INCLUDE_DIRS := -Iapplication/src \
               -IPorts/$(PLATFORM) \
               -IPorts/$(PLATFORM)/config \
               -I$(PROJ_HAL_DIR) \
               $(MODULES_INCLUDES)
                
################################ C FILE LIST GENERATION #######################################################
# Time for more automagical operations. Instead of listing all the filenames manually, let's just use
#   make features to generate the list. 
#   There is no mechanism to ignore files. 
CFILES := $(foreach dir,$(SOURCE_DIRS),$(notdir $(wildcard $(dir)/*.c)))

############################### SOURCE EXCLUSIONS ###############################################################
# C FILE LIST GENERATION will collect all source files in provide paths which won't work for some submodules
# who have test files not meant for normal compilation for the MCU project.
EXCLUSIONS := checksums_unit_tests.c cyclic_fifo_queue_test.c

CFILES := $(filter-out $(EXCLUSIONS), $(CFILES))

CC_$(PLATFORM) := arm-none-eabi-gcc.exe \
                   -std=c99              \
                   -Og                   \
                   -Wall                 \
                   -Wextra               \
                   -pedantic             \
                   -ffunction-sections   \
                   -fdata-sections       \
                   -finline-functions    \
                   -mcpu=cortex-m33      \
                   -mthumb               \
                   -g3                   \
                   -gdwarf-2             \
                   -Wno-format           \
                   -fno-common           \
                   -ffreestanding        \
                   -fno-builtin          \
                   -nostartfiles         \
                   -fstack-usage         \
                   -MD

CC := $(CC_$(PLATFORM))
# This code has multiple intention fall-throughs in switch statements that generate warnings b/c of -Wall option. Let's just supress fallthrough warnings in general.
CC += -Wno-implicit-fallthrough
# These warnings are just plain annoying and serve no purpose. 
CC += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-parameter

################################ OBJECT FILE GENERATION########################################################
# Time for more automagical operations. Instead of relisting all the filenames as objects, let's just use
#   make features to generate the list. Insert $(OBJ_DIR) to each output file name so the output files are generated in the rigth
#   location. 
ALL_OBJECT_FILES := $(patsubst %.c,$(OBJ_DIR)/%.o,$(CFILES))

################################ SECRET SAUCE #################################################################
# Use vpath to tell make to look in these directories for dependencies. 
vpath %.c $(SOURCE_DIRS)           

################################ TARGETS #####################################################################
LINKER := $($(PLATFORM)_LINKER)
LDFLAGS := -Wl,--gc-sections -T"$(LINKER)" -Wl,-L$(OBJ_DIR) -Wl,--start-group $(ALL_OBJECT_FILES) -Wl,--end-group -Wl,-Map,$(BIN_DIR)/$(FILENAME).map -Wl,--print-memory-usage 

all: $(BIN_DIR)/$(FILENAME).srec $(BIN_DIR)/$(FILENAME).bin

createdirs:
    $(info "Creating Directories")
    mkdir -p $(BUILD_DIR)
    mkdir -p $(BIN_DIR)
    mkdir -p $(OBJ_DIR)

$(BIN_DIR)/$(FILENAME).srec: createdirs $(BIN_DIR)/$(FILENAME).elf  
    arm-none-eabi-objcopy -O srec $(BIN_DIR)/$(FILENAME).elf $(BIN_DIR)/$(FILENAME).srec

$(BIN_DIR)/$(FILENAME).bin: $(BIN_DIR)/$(FILENAME).elf  
    arm-none-eabi-objcopy -O binary $(BIN_DIR)/$(FILENAME).elf $(BIN_DIR)/$(FILENAME).bin

$(BIN_DIR)/$(FILENAME).elf: $(ALL_OBJECT_FILES)
    $(CC) $(LDFLAGS)                   \
            --specs=nano.specs            \
            --specs=nosys.specs           \
            -o $(BIN_DIR)/$(FILENAME).elf   
    arm-none-eabi-objdump -S $(BIN_DIR)/$(FILENAME).elf > $(BIN_DIR)/$(FILENAME).lst

.PHONY: clean all

clean:
    rm -rf $(BUILD_DIR)
    rm -f *.o
    rm -f *.su

################################ RECIPES #####################################################################
# Auto-Dependency Generation
# Sources: 
#               http://make.mad-scientist.net/papers/advanced-auto-dependency-generation
#               http://www.math.utah.edu/docs/info/make_4.html
#               https://stackoverflow.com/questions/4036191/sources-from-subdirectories-in-makefile
# The basic idea is that this magical incantation coerces GCC to output a .d
# dependency file for each .c file (therefore this method only works with GCC).
# Those dependency files are then included back into this makefile and magically
# used in the right magical places using magical nonsense line noise syntax.

# Where we want to put the .d dependency files.
DEPDIR := $(OBJ_DIR)
# Linux nerd nonsense that coerces GCC into generating .d dependency files.
#
# -MT $@ sets the name of the target in the generated dependency file.
# -MMD generates dependency information as a side-effect of compilation,
#      not instead of compilation, whatever the heck that means. This version
#      omits system headers from the generated dependencies: if you prefer to
#      preserve system headers as prerequisites, use -MD.
# -MP adds a target for each prerequisite in the list, to avoid errors when deleting files.
# -MF $(DEPDIR)/$*.d writes the generated dependency file $(DEPDIR)/$*.d.
DEPFLAGS := -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d

# This is the main invocation of GCC.  Why this is all stored in a variable that
# looks like the name of a .c file, I have no idea.
COMPILE.c := $(CC) $(C_DEF) $(DEPFLAGS) $(INCLUDE_DIRS) -c

# Create the generic recipe. Note there are two recipes. The first one is blank and deletes anything that is there by default.
#
# $(DEPDIR)/%.d declares the generated dependency file as a prerequisite of the
#               target, so that if it’s missing the target will be rebuilt.
# | $(DEPDIR) declares the dependency directory as an order-only prerequisite of
#             the target (whatever the heck that nonsense means), so that it
#             will be created when needed.  Basically, I have no clue what this does.
$(OBJ_DIR)/%.o: %.c
$(OBJ_DIR)/%.o: %.c $(DEPDIR)/%.d | $(DEPDIR)       
        $(COMPILE.c) $< -o $@

$(DEPDIR): ; @mkdir -p $@

# Some absolute nonsense line noise syntax to generate a list of all the
# dependency files that could exist.
DEPFILES := $(CFILES:%.c=$(DEPDIR)/%.d)
# Mention each dependency file as a target, so that make won’t fail if the file doesn’t exist.
$(DEPFILES):

# Include all dependency files which exist, to include the relevant targets.
# See https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html for wildcard function documentation
include $(wildcard $(DEPFILES))

Here is a snapshot of the build output using -debug. The command line command for make is: make.exe -j16 --debug --makefile=makefile FILENAME=test PLATFORM_NAME=EFM32PG22

C:\Users\xyz\Desktop\TEST>make.exe -j16 --debug --makefile=makefile FILENAME=test PLATFORM_NAME=EFM32PG22
GNU Make 3.82.90
Built for i686-pc-mingw32
Copyright (C) 1988-2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Updating goal targets....
 File 'all' does not exist.
     File 'createdirs' does not exist.
    Must remake target 'createdirs'.
"Creating Directories"
mkdir -p build
         File 'build/EFM32PG22/obj/file1.d' does not exist.
        Must remake target 'build/EFM32PG22/obj/file1.d'.
        Successfully remade target file 'build/EFM32PG22/obj/file1.d'.
       Prerequisite 'build/EFM32PG22/obj/file1.d' of target 'build/EFM32PG22/obj/file1.o' does not exist.
      Must remake target 'build/EFM32PG22/obj/file1.o'.
arm-none-eabi-gcc.exe -std=c99 -Og -Wall -Wextra -pedantic -ffunction-sections -fdata-sections -finline-functions -mcpu=cortex-m33 -mthumb -g3 -gdwarf-2 -Wno-format -fno-common -ffreestanding -fno-builtin -nostartfiles -fstack-usage -MD -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-parameter -DPLATFORM_EFM32PG22 -DUSE_RTT_FOR_DEBUGGING=1 -DEFM32PG22C200F512IM40 -DFAMILY_PG22 -DNO_HFXO -D__STARTUP_CLEAR_BSS -DSL_TRUSTZONE_NONSECURE -MT  -MMD -MP -MF build/EFM32PG22/obj/.d -Iapplication/src -IPorts/EFM32PG22 -IPorts/EFM32PG22/config -IPorts/EFM32PG22/HAL             -Imodules/submod-hal_generic -c application/src/file1.c -o build/EFM32PG22/obj/file1.o
         File 'build/EFM32PG22/obj/main.d' does not exist.
        Must remake target 'build/EFM32PG22/obj/main.d'.
        Successfully remade target file 'build/EFM32PG22/obj/main.d'.
       Prerequisite 'build/EFM32PG22/obj/main.d' of target 'build/EFM32PG22/obj/main.o' does not exist.
      Must remake target 'build/EFM32PG22/obj/main.o'.
mkdir -p build/EFM32PG22
arm-none-eabi-gcc.exe -std=c99 -Og -Wall -Wextra -pedantic -ffunction-sections -fdata-sections -finline-functions -mcpu=cortex-m33 -mthumb -g3 -gdwarf-2 -Wno-format -fno-common -ffreestanding -fno-builtin -nostartfiles -fstack-usage -MD -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-parameter -DPLATFORM_EFM32PG22 -DUSE_RTT_FOR_DEBUGGING=1 -DEFM32PG22C200F512IM40 -DFAMILY_PG22 -DNO_HFXO -D__STARTUP_CLEAR_BSS -DSL_TRUSTZONE_NONSECURE -MT  -MMD -MP -MF build/EFM32PG22/obj/.d -Iapplication/src -IPorts/EFM32PG22 -IPorts/EFM32PG22/config -IPorts/EFM32PG22/HAL             -Imodules/submod-hal_generic -c application/src/main.c -o build/EFM32PG22/obj/main.o
         File 'build/EFM32PG22/obj/file2.d' does not exist.
        Must remake target 'build/EFM32PG22/obj/file2.d'.
        Successfully remade target file 'build/EFM32PG22/obj/file2.d'.
       Prerequisite 'build/EFM32PG22/obj/file2.d' of target 'build/EFM32PG22/obj/file2.o' does not exist.
      Must remake target 'build/EFM32PG22/obj/file2.o'.
mkdir -p build/EFM32PG22/obj
arm-none-eabi-gcc.exe -std=c99 -Og -Wall -Wextra -pedantic -ffunction-sections -fdata-sections -finline-functions -mcpu=cortex-m33 -mthumb -g3 -gdwarf-2 -Wno-format -fno-common -ffreestanding -fno-builtin -nostartfiles -fstack-usage -MD -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-parameter -DPLATFORM_EFM32PG22 -DUSE_RTT_FOR_DEBUGGING=1 -DEFM32PG22C200F512IM40 -DFAMILY_PG22 -DNO_HFXO -D__STARTUP_CLEAR_BSS -DSL_TRUSTZONE_NONSECURE -MT  -MMD -MP -MF build/EFM32PG22/obj/.d -Iapplication/src -IPorts/EFM32PG22 -IPorts/EFM32PG22/config -IPorts/EFM32PG22/HAL             -Imodules/submod-hal_generic -c application/src/file2.c -o build/EFM32PG22/obj/file2.o
         File 'build/EFM32PG22/obj/file4.d' does not exist.
        Must remake target 'build/EFM32PG22/obj/file4.d'.
        Successfully remade target file 'build/EFM32PG22/obj/file4.d'.
       Prerequisite 'build/EFM32PG22/obj/file4.d' of target 'build/EFM32PG22/obj/file4.o' does not exist.
      Must remake target 'build/EFM32PG22/obj/file4.o'.
arm-none-eabi-gcc.exe -std=c99 -Og -Wall -Wextra -pedantic -ffunction-sections -fdata-sections -finline-functions -mcpu=cortex-m33 -mthumb -g3 -gdwarf-2 -Wno-format -fno-common -ffreestanding -fno-builtin -nostartfiles -fstack-usage -MD -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-parameter -DPLATFORM_EFM32PG22 -DUSE_RTT_FOR_DEBUGGING=1 -DEFM32PG22C200F512IM40 -DFAMILY_PG22 -DNO_HFXO -D__STARTUP_CLEAR_BSS -DSL_TRUSTZONE_NONSECURE -MT  -MMD -MP -MF build/EFM32PG22/obj/.d -Iapplication/src -IPorts/EFM32PG22 -IPorts/EFM32PG22/config -IPorts/EFM32PG22/HAL             -Imodules/submod-hal_generic -c modules/submod-hal_generic/file4.c -o build/EFM32PG22/obj/file4.o
         File 'build/EFM32PG22/obj/startup_efm32pg22.d' does not exist.
        Must remake target 'build/EFM32PG22/obj/startup_efm32pg22.d'.
        Successfully remade target file 'build/EFM32PG22/obj/startup_efm32pg22.d'.
       Prerequisite 'build/EFM32PG22/obj/startup_efm32pg22.d' of target 'build/EFM32PG22/obj/startup_efm32pg22.o' does not exist.
      Must remake target 'build/EFM32PG22/obj/startup_efm32pg22.o'.
arm-none-eabi-gcc.exe -std=c99 -Og -Wall -Wextra -pedantic -ffunction-sections -fdata-sections -finline-functions -mcpu=cortex-m33 -mthumb -g3 -gdwarf-2 -Wno-format -fno-common -ffreestanding -fno-builtin -nostartfiles -fstack-usage -MD -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-parameter -DPLATFORM_EFM32PG22 -DUSE_RTT_FOR_DEBUGGING=1 -DEFM32PG22C200F512IM40 -DFAMILY_PG22 -DNO_HFXO -D__STARTUP_CLEAR_BSS -DSL_TRUSTZONE_NONSECURE -MT  -MMD -MP -MF build/EFM32PG22/obj/.d -Iapplication/src -IPorts/EFM32PG22 -IPorts/EFM32PG22/config -IPorts/EFM32PG22/HAL             -Imodules/submod-hal_generic -c Ports/EFM32PG22/config/startup_efm32pg22.c -o build/EFM32PG22/obj/startup_efm32pg22.o
         File 'build/EFM32PG22/obj/file3.d' does not exist.
        Must remake target 'build/EFM32PG22/obj/file3.d'.
        Successfully remade target file 'build/EFM32PG22/obj/file3.d'.
       Prerequisite 'build/EFM32PG22/obj/file3.d' of target 'build/EFM32PG22/obj/file3.o' does not exist.
      Must remake target 'build/EFM32PG22/obj/file3.o'.
arm-none-eabi-gcc.exe -std=c99 -Og -Wall -Wextra -pedantic -ffunction-sections -fdata-sections -finline-functions -mcpu=cortex-m33 -mthumb -g3 -gdwarf-2 -Wno-format -fno-common -ffreestanding -fno-builtin -nostartfiles -fstack-usage -MD -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-parameter -DPLATFORM_EFM32PG22 -DUSE_RTT_FOR_DEBUGGING=1 -DEFM32PG22C200F512IM40 -DFAMILY_PG22 -DNO_HFXO -D__STARTUP_CLEAR_BSS -DSL_TRUSTZONE_NONSECURE -MT  -MMD -MP -MF build/EFM32PG22/obj/.d -Iapplication/src -IPorts/EFM32PG22 -IPorts/EFM32PG22/config -IPorts/EFM32PG22/HAL             -Imodules/submod-hal_generic -c Ports/EFM32PG22/config/file3.c -o build/EFM32PG22/obj/file3.o
 File 'all' does not exist.
 File 'all' does not exist.
 File 'all' does not exist.
 File 'all' does not exist.
     Prerequisite 'build/EFM32PG22/obj/file1.o' is newer than target 'build/EFM32PG22/test.elf'.
     Prerequisite 'build/EFM32PG22/obj/main.o' is newer than target 'build/EFM32PG22/test.elf'.
     Prerequisite 'build/EFM32PG22/obj/file2.o' is newer than target 'build/EFM32PG22/test.elf'.
     Prerequisite 'build/EFM32PG22/obj/file4.o' is newer than target 'build/EFM32PG22/test.elf'.
     Prerequisite 'build/EFM32PG22/obj/startup_efm32pg22.o' is newer than target 'build/EFM32PG22/test.elf'.
     Prerequisite 'build/EFM32PG22/obj/file3.o' is newer than target 'build/EFM32PG22/test.elf'.
    Must remake target 'build/EFM32PG22/test.elf'.
arm-none-eabi-gcc.exe -std=c99 -Og -Wall -Wextra -pedantic -ffunction-sections -fdata-sections -finline-functions -mcpu=cortex-m33 -mthumb -g3 -gdwarf-2 -Wno-format -fno-common -ffreestanding -fno-builtin -nostartfiles -fstack-usage -MD -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-parameter -Wl,--gc-sections -T"Ports/EFM32PG22/config/linker.ld" -Wl,-Lbuild/EFM32PG22/obj -Wl,--start-group build/EFM32PG22/obj/file1.o build/EFM32PG22/obj/main.o build/EFM32PG22/obj/file2.o build/EFM32PG22/obj/file4.o build/EFM32PG22/obj/startup_efm32pg22.o build/EFM32PG22/obj/file3.o -Wl,--end-group -Wl,-Map,build/EFM32PG22/test.map -Wl,--print-memory-usage                    \
                --specs=nano.specs            \
                --specs=nosys.specs           \
                -o build/EFM32PG22/test.elf
Memory region         Used Size  Region Size  %age Used
           FLASH:          96 B       112 KB      0.08%
      NV_STORAGE:          0 GB        16 KB      0.00%
             RAM:         32 KB        32 KB    100.00%
arm-none-eabi-objdump -S build/EFM32PG22/test.elf > build/EFM32PG22/test.lst
 File 'all' does not exist.
   Prerequisite 'createdirs' of target 'build/EFM32PG22/test.srec' does not exist.
   Prerequisite 'build/EFM32PG22/test.elf' is newer than target 'build/EFM32PG22/test.srec'.
  Must remake target 'build/EFM32PG22/test.srec'.
arm-none-eabi-objcopy -O srec build/EFM32PG22/test.elf build/EFM32PG22/test.srec
   Prerequisite 'build/EFM32PG22/test.elf' is newer than target 'build/EFM32PG22/test.bin'.
  Must remake target 'build/EFM32PG22/test.bin'.
arm-none-eabi-objcopy -O binary build/EFM32PG22/test.elf build/EFM32PG22/test.bin
 File 'all' does not exist.
 File 'all' does not exist.
Must remake target 'all'.
Successfully remade target file 'all'.

Output object folder

enter image description here

  • What does `.d` mean? – Neil Jul 04 '23 at 02:01
  • @Neil ".d" means "depends". These file contain the dependencies between files in make syntax. – the busybee Jul 04 '23 at 11:52
  • Welcome to StackOverflow! Please take the [tour] to learn how this site works, and read "[ask]". Then come back and [edit] your question to enhance it. -- Please provide a [mre] showing the behavior. For example, the command to build the ".d" files is not shown. You might even want to add a copy of the output in the terminal (echoes of commands as text, please), when cleaning and rebuilding the project. – the busybee Jul 04 '23 at 12:09
  • The .d file is the dependency file generated during the build process. It should be one per file, like source.c = source.d. In my case, I have maybe 30 source files being compiled but only one dependency (.d) file is generated and it is generated without a file name prepended. @the busybee, I will see what I can add. In general, make is executed with a simple command such as make.exe -j16 --makefile=makefile. – themadmstrmind Jul 04 '23 at 12:54
  • Yeah, sure, make is called by a single line. What I'd like to see are the commands executed by make, of course especially the ones to generate the dependency file(s). If this makefile is not of that brain-dead kind that some IDEs generate, it echoes each command before its execution. This will help to follow the "logic" described by the makefile. -- A missing filename (before the extension) is often a sign of `$<` or similar at a wrong place, or an empty expansion of a macro. That's why I ask kindly for a complete minimized example. – the busybee Jul 04 '23 at 14:15
  • @the busybee, my original post is updated with everything. – themadmstrmind Jul 04 '23 at 23:48
  • Before spending time to write an actual answer: who wrote the comments in the makefile? Some of them are nonsense and show a lack of understanding. – the busybee Jul 05 '23 at 08:13
  • 1
    The basic problem is that you define `DEPFLAGS` with `:=` which makes instant evaluation of `$*` to the empty string, so your compilation command is missing filenames. – raspy Jul 05 '23 at 08:15
  • @the busybee... ouch but you are right! Make is new and foreign to me. The comments are actually a combination of two people and I should have removed them for simplicity sake. raspy... You were on the right road. – themadmstrmind Jul 05 '23 at 13:04

1 Answers1

0

Thanks to @raspy, DEPFLAGS should be = and not := but we need to go one step further as COMPILE.c should also be a = and not :=. The post on https://make.mad-scientist.net/ was right this whole time (I missed those details).

Correct DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d COMPILE.c = $(CC) $(C_DEF) $(DEPFLAGS) $(INCLUDE_DIRS) -c

  • Just a thought: The makefiles I commonly see separate the command to generate the dependency files from the command to compile the sources. I did not think long enough on the necessity of this. Anyway, it helps to simplify and grasp such a makefile. – the busybee Jul 05 '23 at 15:11
  • Try [formatting](https://stackoverflow.com/help/formatting) your code for a better legibility. – Kozmotronik Jul 08 '23 at 17:41