Cannot Get Makefile to Build Each Object from Its Corresponding Source

Makefile: Error referencing source files in src directory

I believe your problem is the $(DEPS) dependency.

You set IDIR to ../include but from the toplevel directory (where make is run from) that path is incorrect.

How to invoke command for each file using make?

Consider changing the '$(bin)' rule:

out/%: %.c
$(CC) -Iincludes/ -Wall $< -o $@

The existing rule indicate that each program depends on ALL source files, and that each program can be built by compiling the ($<) FIRST source file. The revised rule indicate that echh programs depends on the .c with the same name

Performing an action over each source file with make

According to the docs, you must compile the files other than the one containing main() separately, to produce .rel files, then include those in the compilation command for the main file. There are several variations on how you could do that. The following avoids features specific to GNU make:

# We're assuming POSIX conformance
.POSIX:

CC = sdcc

# In case you ever want a different name for the main source file
MAINSRC = $(PMAIN).c

# These are the sources that must be compiled to .rel files:
EXTRASRCS = \
../../src/gpio.c \
../../src/timers.c \
../../src/i2c.c

# The list of .rel files can be derived from the list of their source files
RELS = $(EXTRASRCS:.c=.rel)

INCLUDES = -I../../headers
CFLAGS = -mstm8
LIBS = -lstm8

# This just provides the conventional target name "all"; it is optional
# Note: I assume you set PNAME via some means not exhibited in your original file
all: $(PNAME)

# How to build the overall program
$(PNAME): $(MAINSRC) $(RELS)
$(CC) $(INCLUDES) $(CFLAGS) $(MAINSRC) $(RELS) $(LIBS)

# How to build any .rel file from its corresponding .c file
# GNU would have you use a pattern rule for this, but that's GNU-specific
.c.rel:
$(CC) -c $(INCLUDES) $(CFLAGS) $<

# Suffixes appearing in suffix rules we care about.
# Necessary because .rel is not one of the standard suffixes.
.SUFFIXES: .c .rel

If you look carefully, by the way, you will see that the file does not explicitly perform any looping over the source files, or any such thing. It just describes how to build each target, including intermediate targets. make figures out on its own how to combine those rules to go from sources to final program (or to any other target you specify from among those you've taught it to build).

GNU make uses same source file for each object file when part of dependency list is removed

There are many issues here. First:

SOURCES=$(wildcard *.cpp) $(wildcard **/*.cpp)

GNU make uses simple globbing, which does not understand **. This behaves the same as *. Since you only have one level of subdirectory this works for you but if you add another (sub-subdirectory) level, this won't match it.

Second, this is wrong:

DEPS = $(patsubst %,$(INCDIR)/%,$(INCLUDES))

As you point out this changes the dependency paths from the (correct) ./include/xy/z.h to the (incorrect) ./include/./include/xy/z.h. I'm not sure why you're trying to change anything at all here: why not just use the INCLUDES variable content directly? Using $(patsubst %,%,$(INCLUDES)) is a no-op; it has no effect.

Third, you should be using simple expansion (:=) for these types of assignments, so that they are not rerun every time the variable is used.

Next, this is wrong:

%.o: $(SOURCES) $(DEPS)
$(CXX) -c -o $@ $< $(CXXFLAGS)

This will expand to something like this after SOURCES are resolved:

%.o: test.cpp src/test_w.cpp src/test_x.cpp src2/test_y.cpp src2/test_z.cpp ./include/include/subinc/test_y.h $(DEPS)
$(CXX) -c -o $@ $< $(CXXFLAGS)

What this means is that every object file depends on all source files (and all $(DEPS)). So if any source or header file ever changes ALL the object files will be rebuilt. Clearly that's not what you want.

Also, the reason it always compiles the same file is that the recipe uses $<, which represents the first prerequisite, and the first prerequisite here is test.cpp, so that's what's always compiled.

When you create a pattern rule, (at least) the first source file should (almost always) be a pattern as well, so that it changes along with the target to build each object file (in this case).

So, you want your pattern rule to look like this:

%.o: %.cpp $(INCLUDES)
$(CXX) -c -o $@ $< $(CXXFLAGS)

Of course this does mean that every object file depends on all header files, so if you change any header file all your object files are rebuilt. Maybe that's OK; if not you'll need to do something more advanced.

Lastly, you asked why it your makefile seems to work properly if you create bogus paths in the $(DEPS) variable. Here's why: because those paths don't exist, make decides that your pattern rule doesn't apply (since not all the prerequisites can be created) and so it ignores your pattern rule completely.

Once that happens, make's default pattern rule for how to build an object file takes over, and that default rule builds things for you properly. However, you may notice that if you modify any of the header files, make won't rebuild your object files (because it doesn't know about that prerequisite relationship).

Makefile from one source Directory trying to access a cpp file from other Directory

Adding vpath %.cpp ../hello along with @gaoithe's solution has solved this issue.

vpath %.cpp ../hello
GCC=g++
CPPFLAGS=-c -Wall
LDFLAGS=
OBJDIR=objdir
OBJ=$(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(wildcard *.cpp)))
OBJ+=$(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(notdir $(wildcard ../hello/*.cpp))))
TARGET=HelloWorld

.PHONY: all clean

all: $(OBJDIR) $(TARGET)

$(OBJDIR):
mkdir $(OBJDIR)

$(OBJDIR)/%.o: %.cpp
$(GCC) $(CPPFLAGS) -c $< -o $@
$(TARGET): $(OBJ)
$(GCC) $(LDFLAGS) -o $@ $^
clean:
@rm -f $(TARGET) $(wildcard *.o)
@rm -rf $(OBJDIR)

now

$ ls objdir/
Hello.o main.o World.o

Experts need to evaluate the new makefile and confirm if this is a scale able solution?

Any inputs on optimising/enhancing the current makefile and help in reducing the build time is highly appreciated.

Makefile which can generate all object files in a specific path

You still have the rule:

$(LIB): $(OBJ)
...

and OBJ is still src_dir/add.o src_dir/sub.o, so that's where Make will try to build these objects if your object rule works as intended. So, first step:

SRC = $(SRC_DIR)/add.c \
$(SRC_DIR)/sub.c

OBJ = $(SRC:.c=.o)

OBJ = $(patsubst $(SRC_DIR)/%.c,$(BIN_DIR)/%.o,$(SRC))

Now you'll find that your object rule,

.c.o:
...

doesn't work, because it expects to find the source file in the same place where the object file should go (i.e. $(OBJ_DIR)). So replace this rule with:

$(BIN_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(INCLUDES) -c $< -o $@

I notice that you have no provision for building $(BIN_DIR)/t.o and $(BIN_DIR)/test.o, but the app needs them. You should look into that.

Further refinements are possible, but this is a start.



Related Topics



Leave a reply



Submit