Compiling multiple c++ files doesn't work with certain file names - c++

I am trying to compile multiple .cpp files, using a Makefile with make. I have a .cpp file containing the main function, in the other .cpp file a basic class (for every doubt I'll put all the code i'm using down here).
Example of names used to make it compile or to make it not compile:
-it works by having them named "prova.cpp"(contains the main function) and "pa.cpp"(contains the class) (below the commands done by the Makefile)
gioele#GioPC-U:~/Dev/Cpp/Exercises/666prova$ make
g++ -g -Wall -c src/prova.cpp -o obj/prova.o
g++ -g -Wall -c src/pa.cpp -o obj/pa.o
g++ -g -Wall obj/prova.o -o bin/provaBin
-it doesn't work by having them named "ciao.cpp"(contains the main function) and "pa.cpp"(contains the class)
gioele#GioPC-U:~/Dev/Cpp/Exercises/666prova$ make
g++ -g -Wall -c src/pa.cpp -o obj/pa.o
g++ -g -Wall -c src/ciao.cpp -o obj/ciao.o
g++ -g -Wall obj/pa.o -o bin/provaBin
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [Makefile:15: bin/provaBin] Errore 1
I think the problem is with the order of the files inside the Makefile. When it doesn't work is because is trying to get a binary from the .o without the main function. No idea on how to resolve.
The file with the main method:
#include <iostream>
int main() {
std::cout << "Hello world!" << std::endl;
return 0;
}
The class file:
class Class {
public:
int x;
int y;
};
The Makefile (still learning to work with Makefiles, probably the problem is here, any advice to make a Makefile of this kind better is appreciated, or if I am using something not properly):
CC=g++
CFLAGS=-g -Wall
OBJ=obj
SRC=src
BINDIR=bin
BIN=$(BINDIR)/provaBin
SRCS=$(wildcard $(SRC)/*.cpp)
OBJS=$(patsubst $(SRC)/%.cpp, $(OBJ)/%.o, $(SRCS))
all: $(BIN)
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $< -o $#
$(OBJ)/%.o: $(SRC)/%.cpp
$(CC) $(CFLAGS) -c $< -o $#
clean:
$(RM) $(BINDIR)/* $(OBJ)/*
Thank you in advance.

You can fix this by changing one character.
In this rule:
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $< -o $#
the prerequisite list $(OBJS) expands to a list of object files, such as prova.o pa.o or pa.o ciao.o. You want Make to incorporate that list into the linking command, like this:
g++ -g -Wall prova.o pa.o -o bin/provaBin
But the automatic variable $< expands to only the first item in the prerequisite list. If the first item is an object file that does not contain the main() function, such as pa.o, the linker will complain that main() is missing. (If it is an object file that contains main(), such as prova.o, then you will not get that error, but you may still have problems.)
The solution is to use the automatic variable $^, which expands to the complete list of prerequisites:
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $^ -o $#

Related

My makefile keeps compiling over itself; what am I doing wrong?

I'm not sure if there is some built-in variable or rule that I don't know about, or if something is wrong with make, or if I'm just crazy.
For one of my projects, I have a makefile as follows:
CC=g++
CFLAGS=-O3 `libpng-config --cflags`
LFLAGS=-lm `libpng-config --ldflags`
OBJS=basic_render.o render.o mandel.o
BINS=basic_render
.PHONY: all clean
all: $(BINS)
clean:
rm -f $(BINS) $(OBJS)
%.o: %.cpp
$(CC) $(CFLAGS) -c -o $# $<
%: $(OBJS)
$(CC) $(LFLAGS) -o $# $(OBJS)
When building, I want to simply be able to run
make clean
make
to build everything in the BINS list.
This works all right at first, but for some reason, the behaviour changes after I edit a source file.
Before editing source file:
$ make clean
rm -f basic_render basic_render.o render.o mandel.o
$ make
g++ -O3 `libpng-config --cflags` -c -o basic_render.o basic_render.cpp
g++ -O3 `libpng-config --cflags` -c -o render.o render.cpp
g++ -O3 `libpng-config --cflags` -c -o mandel.o mandel.cpp
g++ -lm `libpng-config --ldflags` -o basic_render basic_render.o render.o mandel.o
rm mandel.o basic_render.o render.o
I can do this over and over again and it works just fine. After I make changes to basic_render.cpp (literally just changing a couple of constants), it suddenly changes to this:
$ make clean
g++ -O3 `libpng-config --cflags` -c -o basic_render.o basic_render.cpp
g++ -O3 `libpng-config --cflags` -c -o render.o render.cpp
g++ -O3 `libpng-config --cflags` -c -o mandel.o mandel.cpp
g++ -lm `libpng-config --ldflags` -o makefile basic_render.o render.o mandel.o
rm mandel.o basic_render.o render.o
makefile:1: warning: NUL character seen; rest of line ignored
makefile:1: *** missing separator. Stop.
not only did make clean just try to compile the program, it compiled basic_render with the output set in Makefile, overwriting the Makefile itself.
After editing basic_render.cpp, I looked in Makefile, and it hadn't changed, so it's not like my editor is changing the makefile or something.
So, what am I doing wrong here?
Here is an MCVE of your problem:
$ ls -R
.:
bar.c main.c Makefile
$ cat main.c
extern int bar(void);
int main(void)
{
bar();
return 0;
}
$ cat bar.c
int bar(void)
{
return 42;
}
$ cat Makefile
OBJS := main.o bar.o
BINS := prog
.PHONY: all clean
all: $(BINS)
%: $(OBJS)
$(CC) -o $# $(OBJS)
clean:
$(RM) $(OBJS) $(BINS)
Make first time:
$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o prog main.o bar.o
rm bar.o main.o
Pause to notice the undesired consequence of 10.4 Chains of Implicit Rules:
rm bar.o main.o
All of the object files are auto-deleted after the program is linked, defeating the purpose
of Make. The implicit rules to blame for that are our own implicit rule:
%: $(OBJS)
$(CC) -o $# $(OBJS)
plus the built-in implicit rule1:
%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
which together make an implicit rule chain that results in all of the object files
becoming intermediate files.
Moving on, let's update a source file:
$ touch main.c
and make a second time:
$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o Makefile main.o bar.o
rm bar.o main.o
Makefile:1: warning: NUL character seen; rest of line ignored
Makefile:1: *** missing separator. Stop.
There is our Makefile clobbered by the linkage:
cc -o Makefile main.o bar.o
This snafu is explained in the manual 3.5 How Makefiles Are Remade:
Sometimes makefiles can be remade from other files, such as RCS or SCCS files.
If a makefile can be remade from other files, you probably want make to get an
up-to-date version of the makefile to read in.
To this end, after reading in all makefiles, make will consider each as a goal
target and attempt to update it. If a makefile has a rule which says how to update it
(found either in that very makefile or in another one) or if an implicit rule applies to it
(see Using Implicit Rules), it will be updated if necessary.
After all makefiles have been checked, if any have actually been changed,
make starts with a clean slate and reads all the makefiles over again.
(It will also attempt to update each of them over again, but normally this will
not change them again, since they are already up to date.)
(Emphasis mine). Is there an implicit rule that is applicable to Makefile considered
as a target? Yes, it is:
%: $(OBJS)
$(CC) -o $# $(OBJS)
since the target pattern % matches any file whatever. If we restore our clobbered
Makefile and try the same experiment thing again, this time with debugging:
make -d >debug.log 2>&1
the output will show us:
...
Reading makefiles...
Reading makefile 'Makefile'...
Updating makefiles....
Considering target file 'Makefile'.
Looking for an implicit rule for 'Makefile'.
...
...
Found an implicit rule for 'Makefile'.
...
...
Finished prerequisites of target file 'Makefile'.
Prerequisite 'main.o' is newer than target 'Makefile'.
Prerequisite 'bar.o' is newer than target 'Makefile'.
Must remake target 'Makefile'.
cc -o Makefile main.o bar.o
...
We can avoid this upshot, and also the self-defeating auto-deletion of
our object files, by not using a match-anything implicit rule to perform our
linkage. The customary thing is to make a program from its object files by
an explicit rule, e.g.
Makefile (2)
OBJS := main.o bar.o
BIN := prog
.PHONY: all clean
all: $(BIN)
$(BIN): $(OBJS)
$(CC) -o $# $(OBJS)
clean:
$(RM) $(OBJS) $(BIN)
It appears that you cherish the option to have BINS be a list of multiple
programs:
I want to simply be able to run
make clean
make
to build everything in the BINS list.
But consider that with:
BINS := prog1 prog2
and the recipe:
%: $(OBJS)
$(CC) $(LFLAGS) -o $# $(OBJS)
as your way of making everything in the BINS list, you will just make the same program
twice, with two different names. And even if you wanted to do this, the way to do
it would be:
Makefile (3)
OBJS := main.o bar.o
BINS := prog1 prog2
.PHONY: all clean
all: $(BINS)
$(BINS): $(OBJS)
$(CC) -o $# $(OBJS)
clean:
$(RM) $(OBJS) $(BIN)
which runs like:
$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o prog1 main.o bar.o
cc -o prog2 main.o bar.o
[1] You can get GNU Make to show you all its builtin-rules, and all the rest
of its rules for a particular build, with make --print-data-base ...
I would suggest that the % target is somehow matching the makefile file and therefore using it as the target(1).
My advice would be to change that line to:
$(BINS): $(OBJS)
and that should hopefully prevent make from thinking it should create a new makefile when the objects change.
(1) Apart from the explicit rules you provide, make also has quite a lot of implicit rules.
If even one of those rules decides that it depends on makefile (this is often configured since a change to the makefile usually means that a full rebuild should be done, as the rules may well have changed), then the % target may then be used for the makefile.
And, since the objects have changed, the makefile that depends on them will be rebuilt.
I personally have never seen a % target since I believe that means the rule may match any target, including source files which you probably don't want overwritten.
If you're interested in seeing all those implicit rules, make -d should give you quite a bit of information such as the rules used and conditions checked for whether files need to be rebuilt - just be prepared to wade through a lot of output.

"make" fails when using pattern matching

I'm trying to create a generic make file so that I can compile my project independently of how many files I add to it and where I decide to put them in the project tree.
In my step by step approach I cam to this makefile which works fine.
CC=g++
OBJECTS=main.o board.o
VPATH=src:\
src/board:\
include/board:\
build:\
bin
boardG : main.o board.o
$(CC) -o bin/boardG build/main.o build/board.o
main.o : main.cpp board.hpp
$(CC) -c -I include $< -o build/$#
board.o : board.cpp board.hpp
$(CC) -c -I include $< -o build/$#
This version will do the job just fine. See output below:
me#01:~/code/projects/boardG$ make
g++ -c -I include src/main.cpp -o build/main.o
g++ -c -I include src/board/board.cpp -o build/board.o
g++ -o bin/boardG build/main.o build/board.o
The problem here is that I will have to create one rule for each .cpp file. Which is precisely what I try to avoid. Hence I tried to adapt the version above using matching patterns like this:
CC=g++
OBJECTS=main.o board.o
VPATH=src:\
src/board:\
include/board:\
build:\
bin
boardG : main.o board.o
$(CC) -o bin/boardG build/main.o build/board.o
%.o : %.cpp %.hpp
$(CC) -c -I include $< -o build/$#
When I run make now I get the follwing output:
me#01:~/code/projects/boardG$ make
g++ -c -o main.o src/main.cpp
src/main.cpp:2:27: fatal error: board/board.hpp: No such file or directory
compilation terminated.
<builtin>: recipe for target 'main.o' failed
make: *** [main.o] Error 1
My project has the follwing structure/files in it.
./bin/
./build/
./include/board/board.hpp
./src/main.cpp
./src/board/board.cpp
./makefile
I'm wondering why make would change the command when using pattern matching? Or, and probably more accurately, what am I doing wrong that makes make fail?
Just avoid using VPATH when it comes to object files. What's happening is that make is actually using the built-in rule for %.o and not using your rule at all.
If you prefix all your objects with the directory, this should work:
CC=g++
OBJDIR = build
OBJECTS = $(OBJDIR)/main.o $(OBJDIR)/board.o
VPATH = src:\
src/board:\
include/board:\
bin/boardG : $(OBJECTS)
$(CC) -o $# $^
$(OBJDIR)/%.o : %.cpp %.hpp
$(CC) -c -I include $< -o $#
Here is a helpful resource, which more or less exactly describes the problem you've run into.

How do I create a makefile for SDL2/C++ on Windows?

As the title states I'm trying to create a makefile for compiling C++ programs using SDL2 on Windows. I have MinGW installed and working. I'm using Sublime 2 as my environment. Here's what I have so far:
CXX = g++
CXXFLAGS = -std=c++0x -g -O3 -w -Wl,-subsystem,windows
INCLFLAGS = -IC:\Libraries\i686-w64-mingw32\include\SDL2
LDFLAGS = -LC:\Libraries\i686-w64-mingw32\lib -lmingw32 -lSDL2main -lSDL2
OBJECTS = main.o
TARGET = 1_hellosdl
$(TARGET) : $(OBJECTS)
$(CXX) $(INCLFLAGS) $(LDFLAGS) $(CXXFLAGS) -o $(TARGET) $(OBJECTS)
main.o :
clean:
rm -rf $(OBJECTS) $(TARGET)
remake:
clean $(TARGET)
Right now when I compile I get the following error:
g++ -std=c++0x -g -O3 -w -Wl,-subsystems,windows -c -o main.o main.cpp
In file included from main.cpp:1:0:
main.hpp:4:17: fatal error: SDL.h: No such file or directory
#include <SDL.h>
So the issue is that g++ can't find the SDL include file when it tries to compile main.cpp. I get that this is because $(INCLFLAGS) isn't being added to the line under main.o :.
Optimally, I'd like to specify INCLFLAGS implicitly similar to CXXFLAGS and LDFLAGS, but based on this it doesn't look like it's possible.
Is there a way to do this using an implicit variable or, failing that, what's the best alternative? Is there anything else I am doing wrong?
I managed to solve this by moving $(INCLFLAGS) into $(CXXFLAGS):
INCLFLAGS = -IC:\Libraries\i686-w64-mingw32\include\SDL2
CXXFLAGS = $(INCLFLAGS) -std=c++0x -g -O3 -w -Wl,-subsystem,windows
Additionally, I had to move $(LDFLAGS) to the end in order for it to link correctly:
$(TARGET) : $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJECTS) $(LDFLAGS)

C++ - Makefile Good Practice

I have a Makefile that works for how I'm using it, but will anyone tell me if what I'm doing is good practice? Or if there is a better, cleaner or more efficient way to achieve the goal I am reaching?
Here is my Makefile Code.
# Object files to either reference or create
OBJECTS = Proj2.o Blackjack.o Deck.o Card.o Hand.o Player.o
# The executable file that will be created
EXEC = Proj2.out
# The c++ flags to use for compilation
CXXFLAGS = -Wall
# The c++ compiler to use for compilation
CXX = g++
# This section is called on 'make'
# Will call compile, and then call clean
all: compile clean
# Perform action on all object files (May or may not exist)
# The makefile will implicitly compile all .o files needed
# Will also compile them into the EXEC file listed
compile: $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $(EXEC) $(OBJECTS)
# This section is called after compilation is completed
# This will clean all existing .o files listed in the directory
clean:
rm -f *.o
Here is the terminal output when I call make.
g++ -Wall -c -o Proj2.o Proj2.cpp
g++ -Wall -c -o Blackjack.o Blackjack.cpp
g++ -Wall -c -o Deck.o Deck.cpp
g++ -Wall -c -o Card.o Card.cpp
g++ -Wall -c -o Hand.o Hand.cpp
g++ -Wall -c -o Player.o Player.cpp
g++ -Wall -o Proj2.out Proj2.o Blackjack.o Deck.o Card.o Hand.o Player.o
rm -f *.o
Is it good practice to use a Makefile like this? Specifically, am I doing the cleaning part of my Makefile correctly?
You should not make all depend on clean at all. By doing this you are ensuring that every time you run make, you have to recompile everything. If you want to do that then using make is itself useless: just write a shell script that compiles and links your code.
The clean target should be a separate target and if you want to clean your workspace you run make clean explicitly.
The other problem with your makefile is that the link rule lists compile as the target, but it builds $(EXE). It's almost never a good idea to have a rule create a file which is not exactly the target you told make it would build. To ensure this, always use $# as the target to generate. Rewrite it like this:
compile: $(EXE)
$(EXE): $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $# $^

g++ consolidation: ld: fatal: file main.o: unknown file type

I'm scanning the web and all my project files for solution but still can't find the answer why my linker won't finish the job. Everything smoothly compiles into .o files, but the last make command fails. And here is the Makefile content:
CXX = g++
CXXFLAGS = -Wall -pedantic -c
OBJS = main.o operacje.o porownaj.o
dzialania: $(OBJS)
$(CXX) $^ -o $#
main.o: main.cpp operacje.h porownaj.h
$(CXX) $(CXXFLAGS) $^ -o $#
operacje.o: operacje.cpp operacje.h porownaj.h
$(CXX) $(CXXFLAGS) $^ -o $#
porownaj.o: porownaj.cpp operacje.h porownaj.h
$(CXX) $(CXXFLAGS) $^ -o $#
clean:
rm -f *o
and again, here is the mistake that pops out:
g++ main.o operacje.o porownaj.o -o dzialania
ld: fatal: file main.o: unknown file type
ld: fatal: file processing errors. No output written to dzialania
*** Error code 1
make: Fatal error: Command failed for target `dzialania'
I'm sure it's some kind of a basic mistake but after staring at the file for a few hours I won't notice it anyway. Maybe some of you folks with notice the bug with a fresh eye.
btw. it's my first post after long-term passive lurking, I hope I did everything right. Thanks in advance!
#edit1 OK, I did all the suggested corrections
#edit2 Seems like the problem is caused by improper module division of my program. I'll rearrange it's structure and let you know if it works then. Thanks for all the support!
#edit3 OK, I changed the structure of my program and everything runs smooth, Thanks again!
Try using $< instead of $^ in your rules to compile main.o, operacje.o, and porownaj.o:
main.o: main.cpp operacje.h porownaj.h
$(CXX) $(CXXFLAGS) $< -o $#
operacje.o: operacje.cpp operacje.h porownaj.h
$(CXX) $(CXXFLAGS) $< -o $#
porownaj.o: porownaj.cpp operacje.h porownaj.h
$(CXX) $(CXXFLAGS) $< -o $#
That will cause make to compile only the corresponding .cpp file. When you use $^ the header files are passed to the g++ command which tells the compiler to create precompiled headers for them - that's what's ending up in main.o instead of the object file for main.cpp.
GNU make variable definitions like CC = g++, or CFLAGS = -Wall -pedantic etc.. should each be on its own line:
CC = g++
CFLAGS = -Wall -pedantic
OBJS = main.o operacje.o porownaj.o
BTW, you probably mean
CXX = g++
CXXFLAGS = -Wall -pedantic
You certainly don't want -c explicitly in your CFLAGS or CXXFLAGS; you really should remove it.
Also, recipes should be after its rule, so you want
dzialania: $(OBJS)
$(LINK.cc) $^ -o $#
operacje.o: operacje.cpp operacje.h porownaj.h
$(CXX) $(CXXFLAGS) -c $< -o $#
The several spaces are actually a single tab character.
Run make -p to understand the rules known by make; see also this answer and that one.
Take time to read GNU make documentation.