Building .o file using makefile, clarification needed - makefile

My makefile contains the following lines
11 SRC := $(shell echo src/*.cpp)
12 SRC += $(shell echo $(TEST_ROOT)/*.cpp)
13
14 OBJECTS = $(SRC:.cpp=.o)
22 # [debug] target
23 $(TARGET): $(OBJECTS)
24 $(CC) $(OBJECTS) -o $(TARGET)
25
26 # [debug] .o
27 $(OBJECTS): $(SRC)
28 $(CC) $(CFLAGS) $(DEBUG_FLAGS) -c $(SRC) $(OBJECTS)
Which fails because ... well the following evidently is not a way to do it
g++ -pedantic -Wall -Werror -O0 -g -Wno-format -DUSE_MEASURE -c src/Timer.cpp test/TimerTest.cpp src/Timer.o test/TimerTest.o
How should i modify line #28 to produce .o from all my sources please?

This should do the trick:
$(OBJECTS): %.o : %.cpp
$(CC) $(CFLAGS) $(DEBUG_FLAGS) -c $< $#
This rule will build one object file, and Make will call it once for each object that the other rule needs. You can write a rule that will build all object files in one pass, but there's no advantage to that.
EDIT:
Suppose SRC is src/foo.cpp src/bar.cpp testroot/baz.cpp,
so OBJECTS is src/foo.o src/bar.o testroot/baz.o
We could have a separate rule for each:
src/foo.o : src/foo.cpp
...
src/bar.o : src/bar.cpp
...
testroot/baz.o : testroot/baz.cpp
...
But that's redundant (since the commands are very similar) and inconvenient (since we don't want to add/remove rules whenever we add/remove targets). So we use a pattern rule:
%.o : %.cpp
...
Now when Make wants to build src/foo.o, it sees that the target matches the pattern %.o, the stem (corresponding to %) is src/foo, and the corresponding prereq, src/foo.cpp exists, so it uses this rule.
But we have a variable OBJECTS that lists the targets we want to build with this rule, so we can restrict it to a static pattern rule, which looks about the same but has some advantages we need not get into here:
$(OBJECTS) : %.o : %.cpp
...
Now for the ... part. The command tells the compiler to scan the prereq (src/foo.cpp) and build the target (src/foo.o), so we must refer to those things in the command. Automatic variables help with that; $# is the name of the target, and $< is the name of the first (and in this case the only) prerequisite:
$(OBJECTS): %.o : %.cpp
$(CC) $(CFLAGS) $(DEBUG_FLAGS) -c $< $#

Related

Makefile - link input file from folder

I try to compile a project with generated object stored in a sub directory :
myproject:
|
src: .cpp, .cpp ...
|
release: .o, .o ...
Here's a part of Makefile:
SRC ?= src
OBJ_PATH = $(SRC)/Release
vpath %.o $(OBJ_PATH)
...
OBJS := $(addprefix $(OBJ_PATH)/,obj1.o obj2.o )
all: build
obj1.o: $(SRC)/Manager.cpp
$(EXEC) $(CC) $(INCLUDES) $(CCFLAGS) $(GNCD_FLGS) -c $(<) -o $(OBJ_PATH)/$# #-o $# -c $<
obj2.o: $(SRC)/Synth.cpp
$(EXEC) $(CC) $(INCLUDES) $(CCFLAGS) $(GNCD_FLGS) $(DEFS) -c $(<) -o $(OBJ_PATH)/$# #-o $# -c $<
myApp: obj1.o obj2.o
$(EXEC) $(CC) $(LDFLAGS) $(GNCD_FLGS) -o $# $(OBJS) $+ $(LIBS)
$(EXEC) mkdir -p $(OBJ_PATH)/$(TRGT_ARCH)/$(TRGT_OS)/$(BLD_TP)
$(EXEC) cp $# $(OBJ_PATH)/$(TRGT_ARCH)/$(TRGT_OS)/$(BLD_TP)
$(OBJECTS) : Stt.h
build: myApp
run: build
$(EXEC) ./myApp
..but i got an error link:
Could not open input file 'obj1.o'
Makefile:86: recipe for target 'myApp' failed
So it seems couldn't find object in src/Release dir;
any ideas ?
thank's
Your recipe for myApp use $+, which list the prerequisites. It expands in obj1.o obj2.o. But you build obj1.o and obj2.o in $(OBJ_PATH). So the linker try to find the objects in the root directory, but cannot find them, since they are in $(OBJ_PATH).
Since your recipe explicitely lists them (with $(OBJS)), you do not need the automatic variable.
Sidenote
According to Paul's Second rule of Makefiles, it is best that every rule updates a file corresponding exactly to the target name (including the path part) (in other words, always use $# in the recipe), in order to always know which is the exact file updated.
In your case, if you want to build the objects files in OBJ_PATH, you could use a rule of the form $(OBJ_PATH)/obj.o for each.
You could also replace the dependency of myApp by $(OBJS), and use the automatic variable (btw, is there a reason why you prefer $+ over $^ (does the same thing but do not conserv duplicates in the prerequisites list) ?).

Understanding deeply using a specific case how makefiles are interpreted

I'm trying to understand deeply how makefiles work.
For example, I've the following one:
CC = gcc
CFLAGS = -I.
DEPS = int_array.h
OBJS = int_array.o test_int_array.o
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
clean:
rm -rf *.o test_int_array *.dSYM
The part that I really don't understand fully is :
...
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
I know that the option -c basically indicates just to run the preprocessor, compiling and assembling steps (i.e. without producing executables, I guess).
-o means to write the output to the specified file. Which file in this case?
I understood that $# (and $^ for right) is apparently referring to a "left" side, but which one? Is it referring, in the first case, to the left side of :, that is %.o?
What does $< mean?
Could you please explain step by step how the make tool would interpret those two statements?
I think I understood this part more or less:
...
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
which should mean produce an executable called "test_int_array" (which basically is indicated by these options -o $# from the $(OBJS) files on the right (stated using the option $^).
Is $(CFLAGS) needed in both cases? Does the order matter?
In the example:
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
$# is the filename of the target for this rule: test_int_array.
$^ is the names of all prerequisites.
This would be whatever is contained in OBJS, so: int_array.o test_int_array.o
In the example:
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$< is the name of the first prerequisite: %.c
$# is the filename of the target for this rule: %.o
$(CFLAGS) is not needed for linking, since it only includes the flag -I. Also the CFLAGS indicates that the flags are used for compiling only, hence C FLAGS.
In a Makefile, each rule follows this format:
resulting_file : source_files
steps to get resulting_file from source_files
What is called respectively lefthand and righthand in a rule is the resulting_file and the source_files.
%.ext : %.ext2
is a pattern rule. It allows your Makefile to automatically create any .ext file it needs if it can find a file at the same path with .ext2.
%.c : %.o
is a pattern rule to obtain your .o files (int_array.o test_int_array.o) from their equivalent .c files (int_array.c test_int_array.c)
This is invoked when you specify that $(OBJS) is needed to build the test_int_array file.
Pattern rules automatically use certain variables, such as $(CFLAGS) so you do not need to manually add it in that rule. You can find a full list of implicitly used variables in pattern rules here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC96
You can find out about $#, $< and $^ and similar here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC101
$#: the entire lefthand
$<: the first file in the righthand
$^: the entire righthand list of files, space separated.

Is default goal is first rule in makefile

I have simple makefile:
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
gcc -o hellomake hellomake.o hellofunc.o -I.
According to makefile description "first rule in makefile is default goal". According to my understanding the first rule is:
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
But I suppose this is not "default goal" since goal is to create hellomake executable? Where is my mistake?
According to the gnu make manual, By default, make starts with the first target (not targets whose names start with ‘.’).
%.o : ... does not count as an actual target, but rather is a pattern, which is resolved to actual goals when needed.

VPATH not working with Makefile Rule

I have added another rule to a Makefile to attempt to build a C shared library that uses SWIG to wrap the functions for Java using JNI
The additional rule looks like this (basically lifted from one of the SWIG java examples)
java: $(program_C_SRCS)
$(SWIG) -java $(SWIGOPT) $(INTERFACEPATH)
$(CC) -c $(CFLAGS) $(JAVACFLAGS) $(program_C_SRCS) $(ISRCS) $(CPPFLAGS) $(JAVA_INCLUDE)
$(JAVALDSHARED) $(CFLAGS) $(program_C_OBJS) $(IOBJS) $(JAVA_DLNK) $(LDFLAGS) -o $(JAVA_LIBPREFIX)$(TARGET)$(JAVASO)
javac *.java
problem I have is that my VPATH doesn't seem to work with the *.c files anymore
I noticed that this rule causes all the .c files to compiled as one call to gcc rather than a separate call to gcc for the compilation of each .o file
my previous rules for compilation without any JNI stuff look like this:
.PHONY: all clean
all: $(program_DEBUG_NAME) $(program_RELEASE_NAME)
# original rule to build library in src dir (no longer inc. in all)
$(program_NAME): $(program_C_OBJS)
$(LINK.c) -shared -Wl,-soname,$# $^ -o $#
# new rules to build debug/release libraries and place them in relevant build
# dirs
$(program_DEBUG_NAME): $(DEBUG_OBJS)
$(DEBUG_LINK.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/debug/$#
$(program_RELEASE_NAME): $(RELEASE_OBJS)
$(RELEASE_LINK.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/release/$#
# rule to build object files (replaces implicit rule)
$(BUILD_DIR)/debug/%.o: %.c
$(DEBUG_LINK.c) $< -c -o $#
$(BUILD_DIR)/release/%.o: %.c
$(RELEASE_LINK.c) $< -c -o $#
and these work with VPATH no problem
my VPATH statement looks like this:
VPATH = ../../pulse_IO/src ../../../g2/src
Look at your rule:
java: $(program_C_SRCS)
...
$(CC) -c $(CFLAGS) $(JAVACFLAGS) $(program_C_SRCS) ...
...
Suppose program_C_SRCS is foo.c, and the path is somewhere/foo.c. Without VPATH, this rule doesn't run at all because Make can't find foo.c. With VPATH, Make finds it, and knows that the real prereq is somewhere/foo.c. But you have $(program_C_SRCS) in your rule:
java: somewhere/foo.c
...
$(CC) -c $(CFLAGS) $(JAVACFLAGS) foo.c ...
...
This fails because there is no foo.c (locally).
Try this:
java: $(program_C_SRCS)
...
$(CC) -c $(CFLAGS) $(JAVACFLAGS) $^ ...
...
(The use of automatic variables like $^ is the reason your previous rules worked.)

Makefile compiling multiple times the same sources

** Question edited **
Here's a typical Makefile template :
TARGET = my_prog # project name
CC = gcc -o
CFLAGS = -Wall
SOURCES := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS := $(SOURCES:.c=*.o)
rm = rm -f
$(TARGET): $(OBJECTS)
#$(CC) $(TARGET) $(CFLAGS) $(SOURCES)
#echo "Compilation complete!"
clean:
#$(rm) $(TARGET) $(OBJECTS)
#echo "Cleanup complete!"
Question : why is the line 11 (#S(CC) $(TARGET) ...) still echoing when calling make ?
Answer : Because the problem is in the default rule and line 11 is fine.
** UPDATE **
I now have this Makefile
# project name
TARGET = my_prog
CC = gcc -c
CFLAGS = -Wall -I.
LINKER = gcc -o
LFLAGS = -Wall
SOURCES := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS := $(SOURCES:.c=*.o)
rm = rm -f
$(TARGET): $(OBJECTS)
$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
$(OBJECTS): $(SOURCES) $(INCLUDES)
$(CC) $(CFLAGS) $(SOURCES)
clean:
$(rm) $(TARGET) $(OBJECTS)
Question : Why is $(CC) $(CFLAGS) $(SOURCES) being executed n times, where n is the number of source files ?
** UPDATE 2 **
Would this be a good way to solve this (seems to work...) ?
$(TARGET): obj
$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
obj: $(SOURCES) $(INCLUDES)
$(CC) $(CFLAGS) $(SOURCES)
The command $(CC) $(CFLAGS) $(SOURCES) is executed n times, because the rule is executed n times, because there are n objects to be built, because the $(TARGET) rule has that many objects as prerequisites. If you want the command to be run only once, replace all those prerequisites with a single PHONY prerequisite, whose rule executes the command.
But there's no reason to do it that way. You can just make the command more selective, so that it builds only the one object that was the actual target. That way Make doesn't waste time rebuilding the same objects over and over, and if one or two source files have been changed, Make will rebuild only the relevant objects, not all of them:
$(OBJECTS): %.o : %.c $(INCLUDES)
$(CC) $(CFLAGS) $<
This rule is conservative-- it assumes that every object depends on every header, so it will sometimes rebuild things unnecessarily. You can make it better, either by hand if you know the real dependencies or automatically with a more advanced technique.
EDIT:
Your "update 2" is a decent solution, but I would suggest you add the line
.PHONY: obj
to tell Make that there will be no file called "obj". Otherwise Make will run the obj rule every time, trying to build that file.
This still has the problem that if you change one source file, e.g. foo.c, Make will rebuild all the objects.
The $< I used above is an automatic variable. It means "the first prerequisite". So when Make tries to build foo.o, it will evaluate to foo.c.
EDIT:
Jack Kelly (curse him!) has pointed out that I am wrong about how PHONY targets work: the obj rule will always run, and so will the TARGET rule, whether any source files have changed or not. So the "update 2" method is effective, but crude.
I think the output is coming from generating the .o files, not geverating my_prog
Looks like you don't have a rule for creating the .o files, so make is using the default one.
Try putting this:
#echo "starting compilation"
on the line before your line 11 build command
And you can see that "starting compilation" is output after the gcc line.
Perhaps line 10 should read:
$(TARGET): $(SOURCES)
?

Resources