Sven Sven -3 years ago 49
C Question

Chain of Makefiles are a mess: no rule to make target

In a conversion project, I have modified and remodified an existing makefile chain but managed to break it.
The makefiles need to follow a different chain for when I'm compiling for an AVR project without Contiki and one with (and some extensions on top).
The one without works, the one with does not anymore, since it also needs to take into account the makefiles of Contiki.
I'll try to be complete but leave out unneccessary details.

Using the terminal from /CerberOS/uJ/Build/, I execute the following command:

make cerberos CLASSES=Test_NodeToNode Location= OS=PERIPHERAL


and gives the following message at the end:

make[2]: *** No rule to make target 'blank.u'. Stop.
make[2]: Leaving directory '/home/sven/git/uJVM_PhD_Project/CerberOS/uJ/build'
../../UPNP/micropnp-contiki/build/Makefile_cerberos.include:159: recipe for target 'flash' failed
make[1]: *** [flash] Error 2
make[1]: Leaving directory '/home/sven/git/uJVM_PhD_Project/CerberOS/uJ/build'
Makefile:41: recipe for target 'cerberos' failed


My directory structure is like this:

/CerberOS/
-> /uJ/
---> /build/
-------> Makefile
-------> Makefile.target
-> /UPNP/
--->/contiki/
--------> Makefile.include
---> /micropnp/
--------> Makefile_cerberos.local
-------->/build/
-------------->Makefile_cerberos.include
-------->/cpu/
-------------->/avr/
--------------------> Makefile.avr


Makefile.target contains just "TARGET = avr-micropnp
Makefile is as follows:

BUILDENV_JAVA = $(ROOT)/../uJ/buildenv_java/RT/

SRV = $(ROOT)/../uJ/Services/

CCVT ?= $(ROOT)/../classCvt/classCvt
TOBIN ?= $(ROOT)/../classCvt/tobinOTA
CMD = $(TOBIN) -c $(CCVT)


# By default, uJ is assumed to be in the same parent folder as uPnP
ROOT = ../..

ifndef UJ
UJ = $(ROOT)/uJ
endif

# OS possibilities: UPNP (ID=0), PERIPHERAL (ID=1)
ifndef OS
OS = UPNP
endif

ifeq ($(OS), UPNP)
CFLAGS += -DOS_ID=0
else ifeq ($(OS), PERIPHERAL)
CFLAGS += -DOS_ID=1
else
endif

ifeq ($(TARGET),)
-include Makefile.target
ifeq ($(TARGET),)
${info TARGET not defined, using target 'native'}
TARGET=native
else
${info using saved target '$(TARGET)'}
endif
endif


cerberos: clean clean_uj __code.c
make flash

$(info BUILDENV_JAVA is $(BUILDENV_JAVA))
$(info OS is $(OS))


include ../Makefile_uj.include

ifeq ($(OS), UPNP)

$(info Building as uPNP Platform)
include ../../UPNP/micropnp-contiki/build/Makefile_cerberos.include

else ifeq ($(OS), PERIPHERAL)

$(info Building as periperal)
include ../Makefile_peripheral.include

else
$(info Including nothing)
endif


Makefile_cerberos.include is:

$(info XXXXXXXXXXXXXXXXXXXXXXXX Starting Makefile_cerberos.include XXXXXXXXXXXXXXXXXXXXXXXX)

UPNP = $(ROOT)/UPNP/micropnp-contiki
CONTIKI_PROJECT = blank

# Duplicated from Contiki's Makefile. Necessary because we need the
# $TARGET var set earlier, and Contiki's Makefile is only included
# last minute.
ifeq ($(TARGET),)
-include Makefile.target
ifeq ($(TARGET),)
${info TARGET not defined, using target 'native'}
TARGET=native
else
${info using saved target '$(TARGET)'}
endif
endif

# Allow uPnP wide local settings to be defined in a seperate Makefile
include $(UPNP)/Makefile_cerberos.local

# This enables -ffunction-sections and -fdata-sections, and splits each
# .text and .data section in the object-files in subsections for each function.
# Next, the linker is instructed to garbage collect unused variables and
# functions. The result of this is smaller files, but functions not called in
# the core image will not be available for OTA deployed services.
SMALL=1

# Disable netstacks, except for IPv6 which is used for address parsing
CONTIKI_WITH_IPV6=1
CONTIKI_WITH_IPV4=0
CONTIKI_WITH_RPL=0

# Specify project-conf file (for Contiki settings specific to uPnP)
CFLAGS += -DPROJECT_CONF_H=\"upnp-conf.h\" -fshort-enums

######################################################################
# Setting a few defaults, customizable in Makefile.local
######################################################################

# By default, Contiki is assumed to be in the same parent folder as uPnP
ifndef CONTIKI
CONTIKI = $(ROOT)/UPNP/contiki
endif

### UPNP UJ SVEN
APPDIRS += $(UPNP)/apps
APPS += er-coap rest-engine


######################################################################
# Including source files/directories
######################################################################

# uPnP Core sourcefiles/dirs
#PROJECT_SOURCEFILES += upnp.c vector.c twi_master.c rd-client.c controller.c \
hal.c buzzer.c pir-sensor.c temp-sensor.c relay-switch.c\
lamp.c accelerometer.c loudness-sensor.c rfid.c light-sensor.c\
battery_varta.c thermocouple.c
# Reduced set
PROJECT_SOURCEFILES += upnp.c vector.c twi_master.c rd-client.c controller.c \
hal.c buzzer.c pir-sensor.c temp-sensor.c relay-switch.c\
loudness-sensor.c

PROJECTDIRS += $(UPNP) \
$(UPNP)/lib \
$(UPNP)/drivers/

MCU=atmega1284p

### Compiler definitions
CC = avr-gcc
LD = avr-gcc
AS = avr-as
AR = avr-ar
ELF_SIZE = avr-size -C --mcu=$(MCU)
OBJCOPY = avr-objcopy
STRIP = avr-strip
AVRDUDE = avrdude

OPTI = s

CFLAGS += -Wall -mmcu=$(MCU) -gdwarf-2 -fno-strict-aliasing -O$(OPTI)
ASFLAGS += -mmcu=$(MCU)
LDFLAGS += -mmcu=$(MCU) -Wl,-Map=contiki-$(TARGET).map \
-Wl,--section-start=.bootloader=$(BOOTLOADER_START)
MCU=atmega1284p

# Bootsection start address (byte address!) for linker. Fuses are
# set to the second smallest bootsection (1024 bytes) starting on 0xFC00
# (word address) //TODO see if we can bring this down again!
BOOTLOADER_START=0x1F800

# Avrdude settings
AVRDUDE_PROGRAMMER=atmelice_isp
AVRDUDE_MCU=m1284p
AVRDUDE_OPTIONS=-B 1

### These flags help significantly reduce the code size
ifeq ($(SMALL),1)
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
LDFLAGS += -Wl,--gc-sections
endif # SMALL

### Upload image to MCU
#Let avrdude use defaults if options not defined
ifdef AVRDUDE_PORT
AVRDUDE_PORT:=-P $(AVRDUDE_PORT)
endif
ifdef AVRDUDE_PROGRAMMER
AVRDUDE_PROGRAMMER:=-c $(AVRDUDE_PROGRAMMER)
endif
ifdef AVRDUDE_MCU
AVRDUDE_MCU:=-p $(AVRDUDE_MCU)
endif

SOURCES=$(wildcard *.c $(PROJECT_SOURCEFILES)/*.c)
SOURCES=$(wildcard *_avr.S $(PROJECT_SOURCEFILES)/*_avr.S)

OBJECTS=$(PROJECT_SOURCEFILES:.c=.o)
OBJECTS=$(PROJECT_SOURCEFILES:_avr.S=.o)

HEADERS=$(PROJECT_SOURCEFILES:.c=.h)
HEADERS=$(PROJECT_SOURCEFILES:_avr.S=.h)

### Compilation rules
#Use all standard contiki compile rules, except add .elf rule that prints size
%.elf: %.$(TARGET)
cp $< $@
$(ELF_SIZE) $@

#Prepare images from ELF
%.fuses.bin: %.$(TARGET)
$(OBJCOPY) $< -j .fuse -O binary --change-section-lma .fuse=0 $@

%.eep: %.$(TARGET)
$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 -O ihex $^ $@

%.hex: %.$(TARGET)
$(OBJCOPY) $^ -j .text -j .data -j .bootloader -O ihex $@

#Flash targets
%.fu: %.fuses.bin
$(eval LFUSE = $(shell od -A none --format=x1 --read-bytes=1 $<))
$(eval HFUSE = $(shell od -A none --format=x1 --read-bytes=1 -j1 $<))
$(eval EFUSE = $(shell od -A none --format=x1 --read-bytes=1 -j2 $<))
$(AVRDUDE) $(AVRDUDE_MCU) -B 4 $(AVRDUDE_PORT) $(AVRDUDE_PROGRAMMER) \
-U lfuse:w:0x$(LFUSE):m -U hfuse:w:0x$(HFUSE):m -U efuse:w:0x$(EFUSE):m

%.u: %.hex
$(AVRDUDE) $(AVRDUDE_MCU) $(AVRDUDE_OPTIONS) $(AVRDUDE_PORT) $(AVRDUDE_PROGRAMMER) -U flash:w:$<

%.eu: %.eep
$(AVRDUDE) $(AVRDUDE_MCU) ${AVRDUDE_OPTIONS} ${AVRDUDE_PORT} ${AVRDUDE_PROGRAMMER} -U eeprom:w:$<

flash:
make blank.u

# Include uPnP specific platform files
include $(UPNP)/platform/$(TARGET)/Makefile.early.$(TARGET)

# Include Contiki
include $(CONTIKI)/Makefile.include

# Party overrides compilation rules of Contiki with uPnP specific rules for target platform
include $(UPNP)/platform/$(TARGET)/Makefile.$(TARGET)


According to how I understand it, it makes no sense it does not find a rule to make target blank.u.
The other makefiles do stuff as well, but I have added them to pastebin.
For Makefile_cerberos.local see https://pastebin.com/nT4TmwPY

For Makefile.avr (included by the $(UPNP)/platform/ makefiles): https://pastebin.com/SKz2FmjP

And Makefile.include: https://pastebin.com/NACUiv4Q

I am at a loss.
Can anybody help out?

Answer Source

From looking at your makefile:

%.hex: %.$(TARGET)
    $(OBJCOPY) $^ -j .text -j .data -j .bootloader -O ihex $@

%.u: %.hex
    $(AVRDUDE) $(AVRDUDE_MCU) $(AVRDUDE_OPTIONS) $(AVRDUDE_PORT) $(AVRDUDE_PROGRAMMER) -U flash:w:$<

flash:
    make blank.u

So flash depends on blank.u, and blank.u could depend on the static pattern rule %.u: %.hex, which could depend on the static pattern rule %.hex: %.$(TARGET) - but if blank.$(TARGET) doesn't exist, then Make (correctly) decides that it has no rule to make blank.u, and it fails with the error that you mention.

I notice that your top-level Makefile sets TARGET if it isn't defined:

  ifeq ($(TARGET),)
    ${info TARGET not defined, using target 'native'}
    TARGET=native

However, I don't see anywhere that you're exporting TARGET to the sub-make processes. The easiest way to do this is by adding export TARGET to your top-level makefile, after setting TARGET. The GNU Make Manual has more details.

As an aside, whenever you're invoking make from within a makefile, you should do it as

$(MAKE) blank.u

instead of

make blank.u

This ensures that Make is correctly invoked even if you're using a non-standard binary name and adds a bit of extra handling for different command-line arguments. Again, the GNU Make Manual has details.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download