C++ "undefined reference to" function error - c++

I've been having some problems compiling this code for mergesort on an array of custom data types. The undefined reference is in response to
mergesort(hw1type*, int)
Here are the relevant code snips leaving out the includes, and what not, which I know all work:
Main (Where the error is propagating to):
hw1type * unsorted_array2 = new hw1type[SIZE];
unsorted_array2 = create_random_hw1type(SIZE);
mergesort(unsorted_array2, SIZE);
mergesort.h:
hw1type* mergesort(hw1type*, int);
hw1type* merge(hw1type*, int, hw1type*, int);
mergesort.cc:
hw1type mergesort(hw1type* unsorted_array, int n)
I can't see anything wrong with the way the functions are declared, or the way I'm passing the variables in main. But, it's been a while since I've used c++ so I could use a second or third pair of eyes!
Edit: Turns out it was the make file, I forgot to change. It's always something simple.
Ah, right, I was using the standard make file that came with the other classes.Anyway, here's that code:
I should probably throw mergesort.o into the list of OBJs, but anything else? The make file looks like this:
CC=gcc
CXX=c++
CFLAGS=-ggdb -O3 -I.
LDFLAGS=-L. -lcs600
OBJ=timer.o random_generator.o sort.o
cs600: libcs600.a main.o
$(CXX) $(CFLAGS) main.o -o hw1 $(LDFLAGS)
libcs600.a: $(OBJ)
ar ru libcs600.a $(OBJ)
ranlib libcs600.a
.cc.o:
$(CXX) -c $(CFLAGS) $<
clean:
#rm -f *.o
#rm -f libcs600.a
#rm -f hw1
I need to add mergesort.o to the OBJ field, but anything other than that? Considering it's been a while for C++, it's really been a while since I've messed around with make files.

"Undefined reference" is a link-time error. Make sure the object file that contains the missing function is part of your link command line. In your case, probably something like:
clang++ -o app main.o mergesort.o
Or simply:
clang++ -o app main.cc mergesort.cc
If you didn't compile each file separately first.

You're not compiling mergesort.cc into object code, and/or you're not linking in that object code.
If you're using an IDE, make sure you've added mergesort.cc to your project configuration; if you're using Makefiles or compiling on the command line, make sure you include that in the list of source files you're compiling.

Related

How to avoid forgetting dependencies in make/CMake?

I am new to C++ and am trying to get the hang of build systems like make/CMake. Coming from Go, it seems that there is a constant risk that if you forget to do a little thing, your binaries will become stale. In particular, I can't find a best practice for remembering to keep dependencies/prerequisites updated in make/CMake. I'm hoping I am missing something obvious.
For example, suppose I have a basic makefile that just compiles main.cpp:
CFLAGS = -stdlib=libc++ -std=c++17
main: main.o
clang++ $(CFLAGS) main.o -o main
main.o: main.cpp
clang++ $(CFLAGS) -c main.cpp -o main.o
main.cpp:
#include <iostream>
int main() {
std::cout << "Hello, world\n";
}
So far so good; make works as expected. But suppose I have some other header-only library called cow.cpp:
#include <iostream>
namespace cow {
void moo() {
std::cout << "Moo!\n";
}
}
And I decide to call moo() from within main.cpp via `include "cow.cpp":
#include <iostream>
#include "cow.cpp"
int main() {
std::cout << "Hello, world\n";
cow::moo();
}
However, I forget to update the dependencies for main.o in makefile. This mistake is not revealed during the obvious testing period of running make and rerunning the binary ./main, because the whole cow.cpp library is directly included in main.cpp. So everything seems fine, and Moo! is printed out as expected.
But when I change cow.cpp to print Bark! instead of Moo!, then running make doesn't do anything and now my ./main binary is out of date, and Moo! is still printed from ./main.
I'm very curious to hear how experienced C++ devs avoid this problem with much more complicated codebases. Perhaps if you force yourself to split every file into a header and an implementation file, you'll at least be able to quickly correct all such errors? This doesn't seem bulletproof either; since header files sometimes contain some inline implementations.
My example uses make instead of CMake, but it looks like CMake has the same dependency listing problem in target_link_libraries (though transitivity helps a bit).
As a related question: it seems like the obvious solution is for the build system to just look at the source files and infer dependencies (it can just go one level in and rely on CMake to handle transitivity). Is there a reason this doesn't work? Is there a build system that actually does this, or should I write my own?
Thanks!
First of all you will need to reference the dependencies file in your Makefile.
This can be done with the function
SOURCES := $(wildcard *.cpp)
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))
wich will take the name of all *.cpp files and substitute and append the extension *.d to name your dependency.
Then in your code
-include $(DEPENDS)
- tells the Makefile to not complain if the files do not exist. If they exist they will be included and recompile your sources properly according to the dependencies.
Finally the dependencies can be created automatically with the options: -MMD -MP for the rules to create the objects file. Here you can find a complete explanation. What generates the dependencies is MMD; MP is to avoid some errors. If you want to recompile when system libraries are updated use MD instead of MMD.
In your case you can try:
main.o: main.cpp
clang++ $(CFLAGS) -MMD -MP -c main.cpp -o main.o
If you have more files it is better to have a single rule to create object files. Something like:
%.o: %.cpp Makefile
clang++ $(CFLAGS) -MMD -MP -c $< -o $#
You can take a look also at this 2 great answers:
one
two
In your case a more suitable Makefile should look like the following (there might be some errors but let me know):
CXX = clang++
CXXFLAGS = -stdlib=libc++ -std=c++17
WARNING := -Wall -Wextra
PROJDIR := .
SOURCEDIR := $(PROJDIR)/
SOURCES := $(wildcard $(SOURCEDIR)/*.cpp)
OBJDIR := $(PROJDIR)/
OBJECTS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.o,$(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES))
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
all: main
clean:
$(RM) $(OBJECTS) $(DEPENDS) main
# Linking the executable from the object files
main: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
#include your dependencies
-include $(DEPENDS)
#create OBJDIR if not existin (you should not need this)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile | $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
EDIT to answer comments
As another question, is there any problem with rewriting the DEPENDS definition as just DEPENDS := $(wildcard $(OBJDIR)/*.d)?
Nice question, it took me a while to see your point
From here
$(wildcard pattern…) This string, used anywhere in a makefile, is
replaced by a space-separated list of names of existing files that
match one of the given file name patterns. If no existing file name
matches a pattern, then that pattern is omitted from the output of the
wildcard function.
So wildcard return a list of the file names matching the pattern. patsubst acts on strings, it does not care about what are those strings: it is used as a way to create the file names of the dependencies, not the files themselves. In the Makefile example that I posted DEPENDS is actually use in two cases: when cleaning with make clean and with include so in this case they both work because you are not using DEPENDS in any rule. There are some differences (I tried to run and you should too to confirm). With DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES)) if you run make clean dependencies *.d that do not have a correspondent *.cpp file will not be removed while they will with your change. On the contrary you might include dependencies not relevant to your *.cpp file.
I asked this questions: let's see the answers.
If the .d files get deleted from carelessness but the .o files remain, then we are in trouble. In the original example, if main.d is deleted and then cow.cpp is subsequently changed, make won't realize it needs to recompile main.o and thus it will never recreate the dependency file. Is there a way to cheaply create the .d files without recompiling the object files? If so then we could probably recreate all the /.d files on every make command?
Nice question again.
Yes, you are right. Actually it was an error of mine. This happens because of the rule
main: main.o
$(CXX) $(WARNING) $(CFLAGS) main.o -o main
actually should have been:
main: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
so that it got relinked (the executable is updated) whenever one of the objects change and they will change whenever one their cpp file change.
One problem remains: if you delete your dependencies but not the objects, and change only one or more header files (but not the sources) then your program is not updated.
I corrected also the previous part of the answer.
EDIT 2
To create the dependencies you can also add a new rule to your Makefile:
here is an example.

compiling h file doesn't always show errors

If I have an error on line 1, and I comment out the entirety of the H file, it doesn't always.. update?
It seems to be compiling a past version of the .h file, but if i intentionally put an error in the main.cpp file, then it realizes there are errors in the h file. Also it DOES sometimes show the errors that are just in the h file, but idk if it is after a certain period of time has elapsed
I would just try to put my code in a cpp file attached to the header, but the issue with that is the ugliest error i've ever seen and I'd rather it all stay in the header anyways since it'll only be like 15 lines of code.
Here's the makefile i'm using in case there is some weird thing in this causing the delay.. but I've had this issue just using raw "g++ *.h *.cpp" commands before, so that is probably not the issue. I've struggled with this issue for a long time now and had to put my last HW assignment all in one file because of it
MAINPROG=assignment01
CC=gcc
CXX=g++
CPPFLAGS=-g -std=c++11
LFLAGS=
CFLAGS=-g
TARGET=$(MAINPROG)
CPPS=$(wildcard *.cpp)
LINK=g++ $(CPPFLAGS)
OBJS=$(CPPS:%.cpp=%.o)
%.o: %.cpp
$(CXX) $(CPPFLAGS) -MMD -o $# -c $*.cpp
all: $(TARGET)
$(TARGET): $(OBJS)
$(LINK) $(FLAGS) -o $(TARGET) $^ $(LFLAGS)
clean:
-/bin/rm -rf *.d *.o $(TARGET)
As πάντα ῥεῖ says, it's not normal to compile header files directly. They are incorporated into the compile when they are included into the cpp source.
Your makefile also does not link with the library stdc++ (libstdc++.a). I don't know if this is a problem when linking with g++, but it always is for me with gcc.
Oh, and rm -rf to cleanup! That's fairly aggressive, maybe just rm -f would be better, just in case someone accidentally puts / or .. as the target.
I think you should compile on the command line first, and then sort out the problems with your makefile. It might be worth posting copies of your code.
Generally I will compile simple code with:
gcc -g -Wall -o assignment01 assignment01.cpp -lstdc++
This gives: an exe named "assignment01", with debug info, all warnings, and links with c++ std libs.

"Optional" object file target in Makefile?

I have some code that is "optional": the rest of the program can be linked without it.
How do I properly create a Makefile that excludes it as a dependency if there is an error when creating the object file?
So far I have something like this:
OUT=my_program
OBJS=$(subst .cc,.o,$(wildcard *.cc))
all: $(OUT)
$(OUT): $(OBJS)
my_optional_file.o: other_target
.IGNORE: my_optional_file.o
The good: When processing the rule my_optional_file.o, this correctly ignores all errors.
The bad: When linking the output, my_optional_file.o is specified as an argument to the linker despite the fact that it was not built, making the linker fail because it was given a nonexistent file as input!
How do I exclude my_optional_file.o when there is an error in building it?
Use $(shell find . -maxdepth 1 -iname "*.o") with an explicit call to the linker.
Like :
$(OUT): $(OBJS)
$(CXX) $(LDFLAGS) $(shell find . -maxdepth 1 -iname "*.o") $(LDLIBS) -o $#
The reason is that when implicitly called, the linker command is called like this :
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $#
With $^ expanding to the content of $(OBJS). You need an explicit call to use specific files instead.
The $(wildcard *.o) function cannot be used because it is executed before the files are created so it is always empty.
Assuming your make is GNU make, here is one way of doing this.
Say my program prog has three source files main.c, necessary.c, optional.c
such that I want to link prog from all three .o files, if they get
built ( = a maximal build), but I will settle for main.o and necessary.o ( = a minimal build). (I waive the rationale for this).
A makefile to the purpose is:
.phony: all clean make_prog
max_objs=$(subst .c,.o,$(wildcard *.c))
all: make_prog
make_prog: $(max_objs)
$(MAKE) prog
prog: $(wildcard *.o)
gcc -o $# $^
clean:
rm -f prog *.o
.IGNORE: optional.o
To make prog I first make the phony target, make_prog, whose
prerequisites are all three .o files, but I ignore failure to make
optional.o. Then I make prog for real, and to do that I just
link whatever .o files I've got at this point. If optional.o
isn't there, it doesn't matter.
To be clear about the behaviour of this:-
If, initially, I have a maximal build of prog, then make a change that breaks
optional.c and re-make, no .o is re-made, so prog is not re-made. It
stays maximal.
If, initially, I have a minimal build of prog, then make a change that fixes
optional.c and re-make, optional.o is re-made, so prog is re-made. It
becomes maximal.
Failure to make optional.o excludes prog's dependency on it and introduces
no new ones. So if all other dependencies are satisfied, there's no need to
remake prog.
Now it might be the case that you actually want failure to make optional.o to
introduce a dependency on the failure to make optional.o, in the
sense that it would force prog to be rebuilt minimally.
A simple way to achieve that is by adding the line:
.INTERMEDIATE: optional.o
to the makefile, which will force optional.o always to be deleted at the end of a make.
This has the cost that optional.c will always be compiled, and consequently a maximal build will always be re-linked.
Lastly, someone might wonder why the makefile couldn't more simply be:
.phony: all clean
objs=$(subst .c,.o,$(wildcard *.c))
all: prog
prog: $(objs)
gcc -o $# $(wildcard *.o)
clean:
rm -f prog *.o
.IGNORE: optional.o
Well if we do a make from clean with that, the output is:
cc -c -o main.o main.c
cc -c -o necessary.o necessary.c
cc -c -o optional.o optional.c
gcc -o prog
gcc: fatal error: no input files
compilation terminated.
make: *** [prog] Error 4
That's because $(wildcard *.o) is expanded when the makefile is
parsed, and at that point no .o files exist. We need to be parsing
the makefile again when we expand this, having already made all
the .o files we can.
GNU make does not have optional dependencies. You can simulate that by not returning failure when it fails to build and filtering out non-existent objects when linking.

How to construct a makefile that support multiple targets with main()

I have a makefile that's been working pretty great for the past couple weeks. However, now that I've added another target to my project with "main", it starts to flip out a bit.
CC=g++
CCOPTS=-g -w
OBJS = $(BINDIR)/manager.o $(BINDIR)/rtngnode.o
TARGETS = $(BINDIR)/manager $(BINDIR)/rtngnode
BINDIR = build
all: $(TARGETS) $(OBJS)
clean:
rm -f $(TARGETS) $(OBJS)
.PHONY: all clean
$(TARGETS): $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
$(BINDIR)/%.o: %.cpp
$(CC) -c $(CCOPTS) -o $# $<
I don't quite understand makefiles still... so I'm not sure what's going on. I get these two errors:
build/rtngnode.o: In function `__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, Node> > >::new_allocator()':
/home/caleb/Documents/dev/tote2/mp2/rtngnode.cpp:5: multiple definition of `main'
build/manager.o:/home/caleb/Documents/dev/tote2/mp2/manager.cpp:161: first defined here
build/manager.o: In function `main':
manager.cpp:(.text+0xefb): undefined reference to `NetworkConnection::NetworkConnection(char const*, char const*)'
In my rtngnode target, I have dependancies on the tcpcon class... and my manager target also has a main() reference. I'm pretty confused... so not even sure if I'm asking the right question.
I guess my question is:
For OBJS and TARGETS, what goes there? All of my .cpp files? All of my executables?
How do I like the two together?
The other answers are all accurate, but I think the key thing to understand is this rule:
$(TARGETS): $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
doesn't do what you seem to think that it does. This expands to:
$(BINDIR)/manager $(BINDIR)/rtngnode : $(BINDIR)/manager.o $(BINDIR)/rtngnode.o
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
Make doesn't try to infer some magical matching up of targets to prerequisites here; instead make repeats the entire rule again for each target, but with all the prerequisites. The rule above is identical to writing this:
$(BINDIR)/manager : $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
$(BINDIR)/rtngnode : $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
Given this you can see what the problem is: you're trying to link ALL the objects into EACH executable.
Since your programs are built from a single object file with the same prefix as the program name, you actually don't need to write a rule for them at all; you can rely on make's built-in rule for building the programs. Just take the above rule out completely and it should work.
You should bind your executable with exactly one source file containing the "main" function.
As linker tells you, both manager.cpp and rtngnode.cpp have the definition of main function there. You probably do not want to combine them together. I advice you to start from manually building your code using the gcc commands (using gcc -c to produce object files and gcc -o to produce the executable). Once you understand the logic there - proceed writing makefiles.
By the way, if you can choose your build environment - start with cmake which is less cryptic than makefiles.
The most important thing here has nothing to do with your Makefile (which looks reasonably good except for the somewhat lacking use of compiler warnings):
You may have only one main() in your project, across all source files.
So basically, TARGETS should contain your source files (.cpp) which are then compiled to create object files, which should be in the OBJS variable so they are then passed to the linker to create the executable file.
As of right now your Makefile seems correct, the error tells you that you have 2 main() functions declared, one in the rtngnode.cpp file and again in the manager.cpp, this cannot happen or else the machine would not know which one to call when the program is executed.
Also undefined reference errors are most of the time due to a linker error, happening most of the time when you include a library to the compiler with #include but not to the linker usually using the LIBS variable in your makefile.
HERE is a small tutorial on Makefiles, which could also be a good read.

beginner GNU Makefile Error

This is my first, attempt at a, Makefile after necessity from a previous post.
Anyway here's the code
SortLab.exe : SelectionSort.o Main.o
g++ -o $# $^
SelectionSort.o : SelectionSort.cpp SelectionSort.h
Main.o : Main.cpp
#-------------------------------------------------------------
run: SortLab.exe
./SortLab.exe
clean:
rm -f *.o
rm -f *.exe
build: clean SortLab.exe
%.o: %.cpp
g++ -c $<
I intend to have SelectionSort.cpp & SelectionSort.h form an object file, and Main.cpp to form its own object file. Then finally create an executable. Main.cpp depends on SelectionSort.cpp, where do I go wrong?
Also where can I find what the different GNU commands mean, -o -c and such
You shouldn't need to define the %.o: %.cpp rule yourself, Make knows how to compile C++.
Indent with tabs, not spaces; Make is sensitive to the difference.
Every object file should depend on the headers included in the source files it depends on. You probably need Main.o : Main.cpp SelectionSort.h.
build shouldn't depend on clean, it defeats one of Make's main features (selectively recompilation when files have changed).
If you make build the first target, you can run Make without a target to get a full compile. It's customary to call the main target all.