VPATH target failure - makefile

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/

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)

Evolving a Makefile From Flat Directory Structure to Sub-Directory Structure

SEE UPDATES BELOW
Research Done: I'm finding learning how to evolve Makefiles from one situation to another is difficult. There are a ton of questions and answers out there but few of them actually show how a Makefile can evolve as your project changes. They also all seem to use various different techniques and idioms of Makefiles so translating between one question and another can be tricky when you are learning Makefiles for the first time, as I am.
Problem: My problem is that I have a project that started at as a flat directory structure but then is migrating to a structure with sub-directories. What I can't do is get my Makefile to along for the ride.
First I'll show what I created that works and then I show how I want it to evolve and how that doesn't work.
Flat Directory Structure, Working Makefile
I have project directory that has all my C files and one header file plus my Makefile:
project
Makefile
c8_asm.c
c8_dasm.c
c8_terp.c
chip8.h
Here is my Makefile (which works just fine):
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
# Targets
all: c8_dasm c8_asm c8_terp
c8_dasm: c8_dasm.o
$(CC) $(LDLIBS) c8_dasm.o -o $#
c8_asm: c8_asm.o
$(CC) $(LDLIBS) c8_asm.o -o $#
c8_terp: c8_terp.o
$(CC) $(LDLIBS) c8_terp.o -o $#
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
c8_dasm.o: chip8.h
c8_asm.o: chip8.h
c8_terp.o: chip8.h
.PHONY: clean
clean:
rm c8_dasm c8_asm c8_terp c8_dasm.o c8_asm.o c8_terp.o
I get all my .o files and my executables are created in the project directory.
Evolving The Project
But what I wanted to do is have my sources files (all .c and .h) in a src directory. I wanted to build into an obj directory and have the executables go in a bin directory. So my project would look like this:
project
src
c8_asm.c
c8_dasm.c
c8_terp.c
chip8.h
Makefile
Sub-Directory Structure, Makefile NOT Working
To accommodate the above, I changed my Makefile accordingly:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
MKDIR_P ?= mkdir -p
# Targets
all: $(BIN_DIR)/c8_dasm $(BIN_DIR)/c8_asm $(BIN_DIR)/c8_terp
$(BIN_DIR)/c8_dasm: $(OBJ_DIR)/c8_dasm.o
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_dasm.o -o $#
$(BIN_DIR)/c8_asm: $(OBJ_DIR)/c8_asm.o
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_asm.o -o $#
$(BIN_DIR)/c8_terp: $(OBJ_DIR)/c8_terp.o
$(MKDIR_P) $(dir $#)
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_terp.o -o $#
$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c
$(MKDIR_P) $(dir $#)
$(CC) $< -o $(OBJ_DIR)/$#
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
$(OBJ_DIR)/c8_dasm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_asm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_terp.o: $(SRC_DIR)/chip8.h
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
rm $(OBJECTS)
Upon running this I get the following:
mkdir -p obj/obj/
gcc src/c8_dasm.c -o obj/c8_dasm.o
gcc -lm obj/c8_dasm.o -o bin/c8_dasm
ld: can't link with a main executable file 'obj/c8_dasm.o' for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [bin/c8_dasm] Error 1
I wanted to stop here and get some assistance because I fear I'm making this Makefile for complicated than it need be and I'm trying to avoid getting into bad habits.
I'm hoping to hear opinions about what I'm not conceptualizing correctly here.
FIRST UPDATE
I managed to take it bit by bit and get it mostly working. Here is what I ended up with:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
# Directories.
SRC_DIR = src
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
# Patterns for files.
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(SRC_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
# Targets
all: $(EXECUTABLES)
c8_dasm: $(SRC_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(SRC_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(SRC_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
c8_dasm.o: $(SRC_DIR)/chip8.h
c8_asm.o: $(SRC_DIR)/chip8.h
c8_terp.o: $(SRC_DIR)/chip8.h
.PHONY: clean
clean:
rm $(OBJECTS)
rm -r $(BIN_DIR)
Of course, as I'm finding with Make this leads to other obscure problems. For example doing this:
make
make clean
works fine. Meaning all files are generated and the files are cleaned, including the bin directory.
However, if I do this:
make c8_dasm
make clean
This builds fine. But the clean fails to delete the bin directory (although it does delete the object files). This happens regardless of what individual executable I try to build.
No amount of searching is helping me find out why that is.
SECOND UPDATE
I found that problem was solved as well. It just required using the "-f" for the rm statements in the clean target.
THIRD UPDATE
To get the object file directory part working, I tried (from this: path include and src directory makefile) to construct my Makefile as follows:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
all: $(EXECUTABLES)
c8_dasm: $(SRC_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(SRC_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(SRC_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $(BIN_DIR)/$#
.PHONY: clean
clean:
rm -rf $(BIN_DIR)
rm -f $(OBJECTS)
I was able to condense the original three lines using chip8.h into one target but I have no way to know if that's correct. It compiles at least. I also changed the OBJECTS line to reflect the new OBJ_DIR I created.
However, this doesn't put the object files in the right place. It still puts them in the src directory rather than the obj directory.
This is why it makes sense to not do anything complicated with Makefiles. Just put the actual directory names in your commands. Never rely on wildcards.
People using C and C++ and using Makefiles spend too much time trying to get those to work rather than just actually getting things done. That's why you see so many of the questions that you see and why the answers vary so much.
In your specific case, your targets don't always have to contain the directory and that's part of the problem. The rules getting generated don't have an actual target in your file because of the directories you are prepending to everything. You have to think in terms of what is getting generated by each target: meaning, the output. So if c8_dasm is getting output, that's your target. The directory has nothing to do with that. So you need to remove all of your directory substitutions where they aren't needed.
But before doing that, ask yourself this: if your first solution was working, why change it? It's better to not even do directories when you're using Make. Just have everything in the same directory as you started off with. You can even see that this allows your Makefile to be much cleaner.
I believe I may have figured this out. Below is my Makefile. It seems to do what I want. It does the following:
Compiles all object files into the obj directory.
Compiles and links so that executables are generated in the bin directory.
Recognizes if any .c files are changed and recompiles accordingly.
Recognizes if the .h file is changed and recompiles all C files that reference it.
This seems to satisfy all the criteria but I can't tell if I've painted myself into some corner that I can't see yet.
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
all: $(EXECUTABLES)
c8_dasm: $(OBJ_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(OBJ_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(OBJ_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/chip8.h
$(CC) $(CFLAGS) -c $< -o $#
.PHONY: clean
clean:
rm -rf $(BIN_DIR)
rm -rf $(OBJ_DIR)
Stackoverflow is whining about too many comments, so I'll make this another "answer." After our back-and-forth to my original comment, your last comment is correct. That's what I wanted you to see.
Understand that you can't use Make to do what you want to do exactly.
So here's really the answer: You can't create multiple executables AND with only some of the object files applying to each one AND while using a directory structure. Make is in no way capable of handling that.
Right now you're trying to use Make in a way that it wasn't intended for which is why you're running into so many problems. If you keep playing around you're going to run into is a series of errors that say "duplicate symbol" because you will be compiling each of your files multiple times for each executable, assuming you follow most of the advice you'll find.
Check out this How can I create a Makefile for C projects with SRC, OBJ, and BIN subdirectories? to see what I mean. That one works because all object files are being used to create a single executable. But as you've stated, that's not going to be the case for you. And that's what Make can't handle. That's why you're not finding an answer to that.
And while your chip8.h file is now not going to cause problems in terms of allowing you to compile, your Makefile with that third update would not recognize when the chip8.h file itself has changed. You would have to change a .c file to force a recompile so that changes to your .h were recognized. So you either have to stick with your second update or use something other than Make.

Why this makefile does not build when change a .hpp file

I am having problems with this makefile. I want to each .cpp file get a dependency .hpp eg: a file main.cpp have a dependency main.hpp
The makefile works well, but when I modify main.hpp, Make is not rebuilding.
Can someone give me a hint. Thanks
objetivo=control
objetos=$(shell ls *.cpp | sed 's/cpp/o/')
optimizacion=-O2 -pipe
enlaces=-lncurses -lmenu -lpq -lform -lcdkw
CPP=g++ -std=c++11 -Wall
.PHONY: all clean debug rebuild
all: $(objetivo)
.cpp.o: $*.hpp
$(CPP) $(optimizacion) -c $<
debug: CPP += -g
debug: optimizacion=
debug: $(objetivo)
rebuild: clean all
$(objetivo): $(objetos)
$(CPP) -o $# $(enlaces) $(objetos)
clean:
-rm *.o $(objetivo)
Your solution is not right. Now the .o will be rebuilt whenever the .hpp file changes, but it won't be rebuilt when the .cpp file changes!
If you want to have two different prerequisites, you have to list them both:
%.o: %.cpp %.hpp
$(CPP) $(optimizacion) -c $<
Note that CPP is not the usual variable for a C++ compiler; the standard variable is CXX.
The reason your first attempt didn't work is that old-style suffix rules don't allow any prerequisites. See the manual for details.
I found a solution.
I replaced the rule .ccp.o to:
%.o: %.hpp %.cpp
$(CPP) $(optimizacion) -c $*.cpp
Now every time I modify the related hpp Make rebuild the matched .cpp
Thanks anyway

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 prerequisite variable evaluation

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)
...

Resources