Makefile prerequisite variable evaluation - makefile

I have a large project with multiple Makefiles, and I need to modify the order in which projects are built. However, I cannot seem to understand when variables that are prerequisites get evaluated. Everything that I've read seems to indicate that the entire Makefile is parsed before the dependency graph is built, so I don't understand why this sample is not working:
OBJECTS=main.o
EXE_NAME=test.exe
$(EXE_NAME): $(OBJECTS)
#echo PREREQUISITES: $^
#echo OBJECTS: $(OBJECTS)
$(CXX) $(CXXFLAGS) $(OBJECTS) -o $#
#include shape.mk
#----VV---Contents of shape.mk---VV----
OBJECTS+=Shape.o
OBJECTS+=Square.o
Shape.o: Shape.hpp
Square.o: Shape.hpp Square.hpp
#----^^----End of shape.mk-------^^----
main.o: Square.hpp
.PHONY: clean
clean:
-rm -fr $(OBJECTS) $(EXE_NAME)
When I run this Makefile, however, I get:
PREREQUISITES: main.o
OBJECTS: main.o Shape.o Square.o
g++ main.o Shape.o Square.o -o test.exe
g++: Shape.o: No such file or directory
g++: Square.o: No such file or directory
make: *** [test.exe] Error 1
Why does OBJECT not have the proper value when the dependency graph is built?

Yes, the entire Makefile is parsed before the dependency graph is built, but the the rules and definitions are read in order. You define the test.exe rule as
test.exe: main.o
...
You then go on to redefine OBJECTS, but you've already committed to that rule, so that's what Make will use to build the graph.
Try this:
$(EXE_NAME): # This will be first, the default target.
include shape.mk
$(EXE_NAME): $(OBJECTS)
...

Related

Why is my Makefile rule not deleting .o files?

My Makefile works but I'm still getting the main.o file created when calling make.
I've been looking through Stack Overflow for topics like mine but I haven't been able to understand the reason.
Here's the Makefile's content:
EXEC=program
SOURCES=main.c
OBJECTS=$(SOURCES:.c=.o)
CC=gcc -pthread -lpthread
CFLAGS=-std=gnu99 -g
.PHONY: clean
default: $(EXEC)
main.o: main.c
clean:
-rm *.o $(objects) program
%.o: %.c
$(CC) -o $# -c $< $(CFLAGS)
$(EXEC): $(OBJECTS)
$(CC) -o $# $^
If you want your object files removed after the build step just append the rm -f *.o command to the $(EXEC) target.
Also, a few notes pointed out in the comments:
Makefile variable names are case-sensitive. Use either objects or OBJECTS, not both.
Instead of hard-coding program in your clean target, you should instead use $(EXEC). That way you won't have to change it every time you change your program's name.
You usually want .o files to be left after compiling so you don't have to recompile everything after a small change.
You can have Make delete your object files automatically -- and not rebuild them needlessly when the sources have not been changed -- by making them intermediate files by means of the .INTERMEDIATE special target. Just add this line:
.INTERMEDIATE: $(OBJECTS)

VPATH target failure

I have no idea how to express this little problem other than by "VPATH Failure", and searching for that brought me nowhere, so now I'm giving it a go, throwing my issue into the pool.
I'm working on a simple makefile here and I ran into a problem, that I am completely stumped by.
I made a first original version, that I got working all fine and dandy:
// Variable pre-processing stuff up here
VPATH = ./src/ ./include/
// Usual phony targets in here
$(OBJF)Utilities$(R).o: Utilities.cpp Utilities.hpp
#echo Building $#
#echo $<
#$(CXX) $(FLAGS) -Iinclude -c $< -o $#
$(OBJF)Settings$(R).o: Settings.cpp Settings.hpp
#echo Building $#
#echo $<
#$(CXX) $(FLAGS) -Iinclude -c $< -o $#
// More file targets down here
As proven by the make output
lex#Lex-Laptop:~/Dev/LHArch$ make RELEASE=STATIC rebuild
Removing object files and outputs...
Cleaning done.
Building objs/Release/Static/Utilities.o
./src/Utilities.cpp
Building objs/Release/Static/Settings.o
./src/Settings.cpp
That's nice.
For the sake of removing some redundancy with the dependencies, I thought it to be a good idea to put the code into their own targets, in this manner:
$(OBJF)Utilities$(R).o: Utilities.cpp
#echo Building $#
#echo $<
#$(CXX) $(FLAGS) -Iinclude -c $< -o $#
Utilities.cpp: Utilities.hpp
$(OBJF)Settings$(R).o: Settings.cpp
#echo Building $#
#echo $<
#$(CXX) $(FLAGS) -Iinclude -c $< -o $#
Settings.cpp: Settings.hpp
That is all I changed. I expected it to work as perfectly as it did before, but it only partially did:
lex#Lex-Laptop:~/Dev/LHArch$ make RELEASE=STATIC rebuild
Removing object files and outputs...
Cleaning done.
Building objs/Release/Static/Utilities.o
./src/Utilities.cpp
Building objs/Release/Static/Settings.o
Settings.cpp
g++: error: Settings.cpp: No such file or directory
g++: fatal error: no input files
compilation terminated.
Makefile:101: recipe for target 'objs/Release/Static/Settings.o' failed
make: *** [objs/Release/Static/Settings.o] Error 1
It found and replaced the path of Utilities, but not for Settings apparently. They are in the same folder, the commands are the same for the both of them. I honestly have no clue what is wrong and it sort of ruins my plan.
Have you guys for any wise words on this?
Did I stumble upon something genuine here, or am I just a dumbbutt who hasn't read up on his homework?
There's this rule (link provided by Etan Reisner) that VPATH and vpath should only be used for prerequisites, not for targets.
In your case, VPATH behaves "unpredictably" as soon as you put your .cpp files both as targets and prerequisites. The good news is that there's no redundancy in your first version. You do want the .o to be rebuilt if either of the .cpp and .hpp is updated. In fact, you don't want
Utilities.cpp: Utilities.hpp
since this will try to rebuild the .cpp if you update the .hpp, for which there's no recipe.
I would therefore stick with your first version and, instead, consider using vpath for ease of maintenance
vpath %.cpp ./src/
vpath %.hpp ./include/

Make a static library instead of dynamic

I want to make static XGBoost library, but I'm failing at this easy task.
Firstly, I simply tried to take all .o files and via ar rcs wrapper/libxgboostwrapper.a ./* make static library, but I failed. In fact, when I'm making other stuff which depends on XGBoost it fails with errors: undefined reference to XGBoosterFree.
This function is defined in wrapper part and there is no file wrapper/libxgboostwrapper.o. So in order to make a static library firstly we have to create wrapper/libxgboostwrapper.o, secondly, run ar rcs on all needed .o files.
How I modified Makefile.
Firstly, I slightly changed names of some variables.
ifeq ($(OS), Windows_NT)
LIBRABIT = subtree/rabit/lib/librabit_empty.a
DLIB = wrapper/xgboost_wrapper.dll
SLIB = wrapper/xgboost_wrapper.lib
else
LIBRABIT = subtree/rabit/lib/librabit.a
DLIB = wrapper/libxgboostwrapper.so
SLIB = wrapper/libxgboostwrapper.a
endif
Added new variable.
WRAP = wrapper/libxgboostwrapper.o
Modified target.
TARGET = $(BIN) $(OBJ) $(DLIB) $(SLIB) $(WRAP)
Added dependencies for wrapper/libxgboostwrapper.o exactly the same as for wrapper/libxgboostwrapper.so.
wrapper/libxgboostwrapper.o: wrapper/xgboost_wrapper.cpp src/utils/*.h src/*.h src/learner/*.hpp src/learner/*.h updater.o gbm.o io.o $(LIBRABIT) $(LIBDMLC)
After everything is done for $(BIN), $(MOCKBIN), $(DLIB), I'm trying to compile (or make?) my $(WRAP).
$(WRAP) :
$(CXX) $(CFLAGS) -fPIC -o $# $(filter %.cpp %.o %.c %.a %.cc, $^) $(LDFLAGS) $(DLLFLAGS)
After all this stuff finally I'm making wrapper/libxgboostwrapper.a.
$(SLIB) : updater.o gbm.o io.o $(WRAP) $(LIBRABIT) $(LIBDMLC)
ar rcs $# $^
It fails at step 5 with errors like:
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 10
What am I doing wrong? For me it seems like compilation .so and .o files shuld be the same except flag -shared is not used.
This may take a few iterations, since you seem to have a few misconceptions about how these files work.
STEP 1: First, let's compile a source file to produce an object file:
g++ -o wrapper/xgboostwrapper.o -c wrapper/xgboost_wrapper.cpp
(Don't call the object file "libxgboostwrapper.o". The "lib" prefix is for a library, the ".o" suffix is for an object file, when you use them both it's just confusing.)
Do not proceed until that works.
STEP 2: Write a rule in your makefile to do it:
wrapper/xgboostwrapper.o: wrapper/xgboost_wrapper.cpp
$(CXX) $(CFLAGS) -o $# $<
Do not proceed until that works.
STEP 3: Figure out which header files it actually needs, and add those as prerequisites. (It's a bad idea to use wildcards to add all existing headers as prerequisites.):
wrapper/xgboostwrapper.o: wrapper/xgboost_wrapper.cpp src/utils/foo.h src/xgboost.h
$(CXX) $(CFLAGS) -o $# $<
Try that much and tell us how it went, then we can proceed.

GNU make Pattern Rule Fails with 'Main.cpp"

I've got a general-purpose makefile that I've successfully used for small (personal) projects before, as below:
#Makefile to compile a folder's contents into a program.
PROGNAME := MyProgram
LIBRARIES :=
CXX := g++ --std=c++11
INCLUDES := -Isrc -Ihdr
VPATH := src:hdr
CPP_FILES := $(wildcard src/*.cpp)
OBJ_FILES := $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES))
$(PROGNAME): $(OBJ_FILES)
$(CXX) $(INCLUDES) $(LIBRARIES) $^ -o $# $(ROOTFLAGS)
#Automatically generate dependencies (-MM), change the target to be the
# object file (-MT) and output it to the dependency file (-MF).
%.d: src/%.cpp
$(CXX) $(INCLUDES) -MM -MT '$(patsubst src/%.cpp,obj/%.o,$<)' $< -MF $#
obj/%.o: src/%.cpp %.d hdr/%.h
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
.PHONY: clean
clean:
rm obj/*.o $(PROGNAME)
This is designed for the following directory structure:
ParentFolder/
Makefile
hdr/
file1.h
...
src/
file1.cpp
...
obj/
I gave the makefile to a colleague and they found it didn't work - after some investigation, the cause of the problem seems to be that they had a source file called main.cpp in src/, which when running make would give the following error:
make: *** No rule to make target `obj/main.o', needed by `MyProgram'. Stop.
If I rename main.cpp to something else (e.g. test.cpp) then the makefile works as expected.
What is the cause of this behaviour? I've looked through the GNU Make Manual but did not find anything regarding special treatment of files called main.* (in fact, some of the examples use it).
While trying to fix the problem, I found that defining an explicit rule for main.o meant that it would be found - therefore, I presume it's an interaction with the main name and pattern-based rules, but I have not been able to find what that may be.
The trouble is that this rule:
obj/%.o: src/%.cpp %.d hdr/%.h
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
requires a corresponding header file. I suspect that there is no hdr/main.h, and Make has no way to build one, so when it is searching for a way to build obj/main.o it considers this rule, rejects it, and finds no other.
I suggest you add another pattern rule (after this one) to handle source files without matching header files:
obj/%.o: src/%.cpp %.d
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
(P.S. Your dependency handling is a little odd and appears to be vestigial -- you generate dependency files and never use them. We can help you with that, once you're building main.o correctly.)

Makefile runs over C file twice

I have two files: assign1.c and ports.h.
FYI: I am using avr-gcc.
I built the following makefile, which I also use for another project (and other TARGET) where it works fine.
TARGET = assign2
LIB=
INCLUDE=ports.h
CFLAGS =-mmcu=atmega32 -Wall
CC = avr-gcc
SRC= $(TARGET).c
OBJ= $(SRC:.c=.o)
OBJCOPY = avr-objcopy
FORMAT = ihex
MSG_COMPILING = Compiling:
MSG_LINKING = Linking:
MSG_FLASH = Creating load file for flash:
all:elf hex
elf: $(TARGET).elf
hex: $(TARGET).hex
%.hex: %.elf
#echo $(MSG_FLASH) $#
#echo
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $#
$(RM) *.elf $(TARGET)
#echo
%.elf: $(OBJ) $(LIB)
#echo $(MSG_LINKING) $#
#echo
$(CC) $(CFLAGS) $^ -o $#
#echo
%.o: $(SRC) $(INCLUDE)
#echo $(MSG_COMPILING) $<
#echo
$(CC) $(CFLAGS) -c $<
#echo
.PHONY : clean
clean:
$(RM) *.o *.hex *.elf $(TARGET)
The terminal prints the following output.
C:\Project>make
Compiling: assign2.c
avr-gcc -mmcu=atmega32 -Wall -c assign2.c
In file included from assign2.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"
Linking: assign2.elf
avr-gcc -mmcu=atmega32 -Wall assign2.o -o assign2.elf
Compiling: assign2.c
avr-gcc -mmcu=atmega32 -Wall -c assign2.c
In file included from assign.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"
avr-gcc elf.o assign2.elf -o elf
avr-gcc: elf.o: No such file or directory
make: *** [elf] Error 1
rm assign2.o
C:\Project>
For some reason it seems to compile the first file, a second time and doing so crashes.
Can anyone correct me on my errors?
The problem is your pattern rules. You are writing pattern rules like this (after make expands the variables):
%.o: assign2.c ports.h
What this rule tells make is that ANY target it wants to build that matches the %.o pattern, can be built by compiling assign2.c. That's obviously not true: this rule build exactly one target: assign2.o.
So make reads your makefile and wants to build a file named elf. It sees that elf depends on $(TARGET).elf, so it builds that (that's the first compile and link, that works). Then make wants to build elf itself. You haven't declared it to be .PHONY, so make assumes it might be a real target.
Make looks through its built-in rules to find one that will let it build elf, and it finds a built-in rule: % : %.o which it can use to compile a program from a .o file with the same prefix. So now for target elf make wants to try to build a file elf.o. Oho! It sees there's a pattern rule that lets it build any .o file based on the assign2.c source file, so it runs that rule (that's the second compile) expecting it to build elf.o... which it doesn't, obviously.
Then make runs the built-in link recipe, using elf.o which doesn't exist, and fails.
The solution to your problem is two things:
First, you should always declare all your makefile targets that you don't actually want to build as .PHONY so make won't try to build them:
.PHONY: all elf hex
Second, you should never use pattern rules where the prerequisite is not also a pattern (this can be useful in certain very specific situations, but not in general). You should either change those pattern rules to explicit rules:
assign2.elf: $(OBJ) $(LIB)
...
$(OBJ): $(SRC) $(INCLUDE)
...
Or make them into full pattern rules by using the pattern in the prerequisites list as well:
%.elf : %.obj $(LIB)
...
%.o: %.c $(INCLUDE)
...

Resources