flashburn
flashburn

Reputation: 4508

Makefile cannot find rule for objects

My source is distributed across multiple directories which are not under the same root. I'm don't want to go into the reasons why this is the case and at the moment I just want to compile it. I've written a Makefile to compile my code but it is telling me that it can't find a rule to create object (.o) files. The code for Makefile is below. What am I doing wrong?

TARGET=main

ROOT_DIR:=.
BUILD_DIR:=$(ROOT_DIR)/build
OBJ_DIR:=$(BUILD_DIR)/obj
TARGET_DIR:=$(BUILD_DIR)/bin

OBJ:= src/main.o \
    ../src/system.o \
    ../../LTC2947/src/LTC2947.o \
    ../../spi/src/my_spi.o

INC_DIR:=src ../src/ ../../LTC2947/src ../../spi/src/

CFLAGS := -O2 -g -Wall -Wextra -Werror -std=gnu99 -DDEBUG -L$(LIB_DIR)

#====================================================
TARGET_BIN:=$(TARGET_DIR)/$(TARGET)
_INC_DIR:=$(foreach _dir,$(INC_DIR), -I$(_dir))

# absolute paths for object files
_OBJ:=$(foreach _path, $(OBJ), $(abspath $(_path))) 
# prepend $(OBJ_DIR) to the oejct full paths
_OBJ2:=$(patsubst %,$(OBJ_DIR)/%,$(_OBJ))
# Remove double slashes
_OBJ:=$(shell echo $(_OBJ2) | sed 's,//,/,g')
OBJ_DIRS:=$(dir $(_OBJ))

BUILD_DIRS:= $(OBJ_DIRS) $(TARGET_DIR)

_CFLAGS := $(CFLAGS) $(_INC_DIR)

all: create-build-dirs $(TARGET_BIN)

$(TARGET_BIN): $(_OBJ)
    $(CC) -o $@ $^ $(_CFLAGS) $(LIBS)

%.o: %.c
    $(CC) $(_CFLAGS) -c $< -o $@

.PHONY: clean
clean:
    rm -rf $(BUILD_DIR)
    find . -type f \( -name *~ -o -name core \) -exec rm -f {} \;

create-build-dirs:
    mkdir -p $(BUILD_DIRS)

EDIT

This is the error that is generated

No rule to make target /home/user/projects/myproject/spi/src/my_spi.o

Upvotes: 0

Views: 931

Answers (1)

MadScientist
MadScientist

Reputation: 100836

Please provide the exact error messages you're seeing (cut and paste), not an abstract description.

There are many issues here, but fundamentally this rule:

%.o: %.c
        $(CC) $(_CFLAGS) -c $< -o $@

tells make how to build a file PATH.o from a file PATH.c. The values of PATH in both these files must be exactly identical strings. In your environment (if you provided the error message it would be more clear) it appears that you're creating object files in $(OBJ_DIR) for source files that are not there, so there's no way that the these paths are identical. This means that you are asking make to build a target $(OBJ_DIR)/foo/bar.o, and make will try to find a file $(OBJ_DIR)/foo/bar.c and if it can't this rule doesn't match.

A few other notes:

  • you don't need to use foreach with abspath; it takes multiple names. You can just say $(abspath $(OBJ)).
  • you don't need a sed shell command to replace // with /; you can just use $(subst //,/,$(_OBJ2))
  • you won't be able to use parallel builds here reliably because of the way you're creating output directories; they may be created in parallel with compile lines that want to use them.

Upvotes: 1

Related Questions