0
votes

In this partial Makefile when I execute make with no argument and .PHONY disabled it returns:

make: Nothing to be done for 'debug'.

With .PHONY enabled (or make -r) it go to 'build' without make any object file, so GCC don't can open any object file because there is no object files in target directories yet.

arm-none-eabi-gcc: error: obj/debug/ThirdParty/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_adc.o: No such file or directory

This makefile separate objs into folders obj/debug or obj/release.

File structure:

bin
inc
Src
ThirdParty  // thirdparty source files
obj // mkdir -p should create this directories tree
    debug
        Src
        ThirdParty
    release
        ...

Makefile

.PHONY: build debug release clean $(COBJ) $(SOBJ)

# Main target
debug:  CC_FLAGS += $(DEBUG)  
debug:  ELF = debug.elf 
debug:  OBJPATH = obj/debug
debug:  COBJ = $(patsubst ./%,$(OBJPATH)/%,$(C:.c=.o))  # C contains c code
debug:  SOBJ = $(patsubst ./%,$(OBJPATH)/%,$(S:.s=.o))  # S contains asm code
debug:  build

release: CC_FLAGS += $(RELEASE)
release: OBJPATH = obj/release
release: COBJ = $(patsubst ./%,$(OBJPATH)/%,$(C:.c=.o))
release: SOBJ = $(patsubst ./%,$(OBJPATH)/%,$(S:.s=.o))
release: ELF = release.elf 
release: build


build: $(COBJ) $(SOBJ)      
    $(CC) $(COBJ) $(SOBJ) $(LIBS) $(LD_FLAGS)  -o bin/$(ELF)


%.o: %.c
    echo $@
    @mkdir -p $(OBJPATH)/$(dir $@)  
    $(CC) $(CC_FLAGS) -c   $< -o $(OBJPATH)/$@

%.o: %.s
    @mkdi -p $(OBJPATH)/$(dir $@)
    $(CC) $(CC_FLAGS) -c   $< -o $(OBJPATH)/$@

One sample of $(COBJ):

obj/debug/ThirdParty/FreeRTOS/queue.o

Linux x86-64

GNU Make 4.2.1

Arm-none-eabi-gcc - I think this don't matter

2
Arm-none-eabi-gcc - I think this don't matter? Answer to your question, Well it matters. You need right compiler arch in order to cross-compile. They are two variants arm-unknown-eabi-gcc and arm-none-eabi-gcc to confuse further.danglingpointer
I have no problem about this. This is a problem of make and makefile. If I remove $(CC) and call echo this mistake still continue.user3512397

2 Answers

2
votes

You are missing a critical note from the GNU make manual regarding target-specific variables:

As with automatic variables, these values are only available within the context of a target’s recipe (and in other target-specific assignments).

So, in your makefile:

debug:  COBJ = $(patsubst ./%,$(OBJPATH)/%,$(C:.c=.o))  # C contains c code
debug:  SOBJ = $(patsubst ./%,$(OBJPATH)/%,$(S:.s=.o))  # S contains asm code

build: $(COBJ) $(SOBJ)
        ...

At this point $(COBJ) and $(SOBJ) refer to the globally-set values of the COBJ and SOBJ variables (because as above, target-specific values are available only within the recipe, NOT in the prerequisites list). These variables have no global values, so they expand to the empty string, and your makefile essentially has just:

build:
        ...

with no prerequisites, which is why you're seeing the behavior you are.

There are multiple ways you could manage this. One is to use recursive make: remove the release: build and debug: build lines and add this:

debug release:
        @$(MAKE) COBJ='$(COBJ)' SOBJ='$(SOBJ)' build

Another way is to use secondary expansion (you can't do it the way I originally suggested but you can do it with constructed variable names:

OBJPREFIX := obj
COBJ = $(patsubst ./%,$(OBJPREFIX)/$@/%,$(C:.c=.o))
SOBJ = $(patsubst ./%,$(OBJPREFIX)/$@/%,$(S:.s=.o))

# Main target
debug:  CC_FLAGS += $(DEBUG)
debug:  ELF = debug.elf

release: CC_FLAGS += $(RELEASE)
release: ELF = release.elf 

.SECONDEXPANSION:
release debug: $$(COBJ) $$(SOBJ)      
        $(CC) $(COBJ) $(SOBJ) $(LIBS) $(LD_FLAGS)  -o bin/$(ELF)

This uses the name of the target in the output object name.

Another way is to use generated makefiles.

You might consider reading the series of posts here: http://make.mad-scientist.net/category/metaprogramming/ (starting with the oldest one first).

0
votes

As MadScientist mentioned the limited scope of target-specific variables I put out of makefile a selector and run make with TARGET = 'target' argument like this:

make TARGET = debug
make TARGET = release

No elegant but functional!

Makefile:

O  = $(C:%.c=%.o)
O += $(S:%.s=%.o)

ifeq ($(TARGET), release)
    ELF = bin/release.elf
    CC_FLAGS += -O3
    OBJPATH = obj/release
else
    ELF = bin/debug.elf
    CC_FLAGS += -g3
    OBJPATH = obj/debug
endif

OBJ = $(addprefix $(OBJPATH)/, $(O))


all: makepath build

build: $(OBJ) 
    @echo ---- LINKING ----
    $(CC) $(OBJ) $(LIBS) $(LD_FLAGS)  -o $(ELF) 

makepath: 
    @mkdir -p $(dir $(OBJ)) 


$(OBJPATH)/%.o:%.c
    @echo ---- C ----
    $(CC) $(CC_FLAGS) -c $<  -o $@

$(OBJPATH)/%.o:%.s
    @echo ---- S ----
    $(CC) $(CC_FLAGS) -c $<  -o $@

clean:
    find -name *.o -delete
    find -name *.elf -delete