Undefined symbols for architecture x86_64 when linking multiple files - c++

I'm trying to link three files using g++. The files are simulation.o, lattice.o and thermodynamics.o.
They're a bit long, but the gist of it is. I have a makefile:
main: simulation.o thermodynamics.o lattice.o
g++ simulation.o thermodynamics.o lattice.o
simulation.o: simulation.cpp lattice.o lattice.h thermodynamics.o thermodynamics.h
g++ -std=c++11 simulation.cpp -o simulation.o -c
thermodynamics.o: thermodynamics.cpp
g++ -std=c++11 thermodynamics.cpp -o thermodynamics.o -lgsl -c
lattice.o: lattice.cpp
g++ -std=c++11 lattice.cpp -o lattice.o -c
It passes the compile stage, but never links them. For each method I need from a different file, it simply says that it's undefined, and and refuses to find them.
The classes and methods are all defined in the .h files. But for some reason I can define an external function but not an external class.

It fails to link because your makefile uses linker flags when compiling. Whereas the linker flags must be used when linking.
Corrections:
CXXFLAGS := -std=c++11 -Wall -Wextra
main: simulation.o thermodynamics.o lattice.o
g++ -o main simulation.o thermodynamics.o lattice.o -lgsl
simulation.o: simulation.cpp lattice.h thermodynamics.h
g++ -c ${CXXFLAGS} -o simulation.o simulation.cpp
thermodynamics.o: thermodynamics.cpp thermodynamics.h
g++ -c ${CXXFLAGS} -o thermodynamics.o thermodynamics.cpp
lattice.o: lattice.cpp lattice.h
g++ -c ${CXXFLAGS} -o lattice.o lattice.cpp

I figured out what went wrong. Had to do with the way I've split the classes between files.
I declared the classes in the .h files, and then redeclared them inside .cpp files. Instead I should have filled the cpp files with implementations of the form class::method(params).
Also I didn't #include the .h file inside the .cppfile.
Lastly, I also had the wrong order of linkage: as pointed out by #Maxim Egorushkin, the order of linking matters. I should have linked the files all at once, and not at the final stage.
Thanks for everyone that answered!

Related

problem with including fmt library in several cpp files

Good day!
I installed the fmt library in Ubuntu. Added it in my project
#include "fmt/core.h"
#include "fmt/format.h"
#include "fmt/format-inl.h"
to use fmt::format_int и fmt::format. I added library headers in several cpp files of my project. During linkage I got the mistake "multiple definition":
obj/container.o: In function fmt::v7::format_error::~format_error()': container.cpp:(.text+0x40e): multiple definition of fmt::v7::format_error::~format_error()'
obj/line.o:line.cpp:(.text+0x40e): first defined here
I've read something about this mistake. It is recommended to divide declaration and implementation in h and cpp files, to set some status to objects that causes mistake and so on. But all this recommendations imply editing of library (not my!) code!
What is wrong?
I do the following
compilation of files - one by one
g++ -std=c++11 -Wall -o obj/line.o -c /home/...//line.cpp
g++ -std=c++11 -Wall -o obj/container.o -c /home/...//container.cpp
g++ -std=c++11 -Wall -o obj/geometryObject.o -c /...//geometryObject.cpp
g++ -std=c++11 -Wall -o obj/model.o -c /home/...//model.cpp
g++ -std=c++11 -Wall -o obj/point.o -c /home/...//point.cpp
g++ -std=c++11 -Wall -o obj/main.o -c /home/...//main.cpp
Linking - error here
g++ -std=c++11 -Wall -o myapp obj/line.o obj/container.o obj/geometryObject.o obj/model.o obj/point.o obj/main.o
You shouldn't be including fmt/format-inl.h because it's an internal header. Please see the documentation for the list of public headers and what they provide.

Link To Library with C and C++ Bindings

I am trying to determine if it is possible to link against a linux library with c and c++ bindings. I have an existing c++ project which is broken down into several libraries. I would like to extend these libraries with C bindings so that I can use them with cgo.
I am aware of how to mix c/c++ with extern "c" syntax. The problem that I have is in daisy chaining libraries. I've created a sample project which demonstrates my question:
https://github.com/Shelnutt2/c_cpp_linker_test
In this project we have hello.c, world.cpp both of which are built into a library called libwords . I can link libwords to libhelloworld without an issue. The problem occurs when trying to build main.cpp, which wants to call a c and c++ functions from libhelloworld (and thus the linked libwords)
Due to the linking differences of C++ vs C the main executable can not find the hello function
main.cpp:15: undefined reference to `hello'
Is it possible to link against the same library in this manner or do I need to break c-bindings into their own wrapper library?
In this example project I used shared libraries, but I'm open to static linking if that is possible.
You should link your application with both libraries. The exports are not transitive.
main: main.o libhelloworld.so
$(CXX) $< -L'$(CURDIR)' -lwords -lhelloworld -o $#
> gmake
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -c -o helloworld.o helloworld.cpp
cc -Wall -g -O -fPIC -DC_LINK_TEST=1 -c -o hello.o hello.c
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -c -o world.o world.cpp
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -shared hello.o world.o -o libwords.so
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -L'/usr/home/me/c_cpp_linker_test' -lwords -shared helloworld.o libwords.so -o libhelloworld.so
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -c -o main.o main.cpp
#c++ main.o libhelloworld.so -o main
c++ main.o -L'/usr/home/me/c_cpp_linker_test' -lwords -lhelloworld -o main
> LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd` ./main
c gives us: hello
cpp gives us: hello world
>
Otherwise there is no problem with linking both C and C++ calling conventions, as the name mangling is different.
(never mind the change g++ to c++ - I use clang)

Makefile - Efficient Compiling

Let's say, compiling hello.c requires car.c and water.c.
But main.c requires hello.c.
When I say requires, I mean that the compiled output would differ if the things it requires is modified in any way.
So, if car.c or water.c is changed, then hello.c would need recompiling.
Then, would this be the correct Makefile?
main: main hello.o
gcc main.c hello.c -o main
hello.o: water.c, car.c
gcc water.c car.c -o hello.o
Otherwise, if it's not correct, can someone explain to me why it is wrong and give me an example?
Thank you!
Let's say, compiling hello.c requires car.c and water.c. But main.c requires hello.c.
This statement doesn't make a lot of sense. The only thing it could mean is that either these aren't C or C++ source files, rather some other language that uses these names confusingly, or they contain #include directives that include those other files.
In that latter case (which is rare, and a poor design), there's no need to specify the included files on the command line, since gcc will include them for you. You just need to specify the dependencies in the Makefile:
main: main.c hello.c car.c water.c
gcc -o main main.c
since main.c has #include "hello.c" and hello.c has #include "car.c" and #include "water.c", only the one compile gets everything.
If these are some other language, and you mean something completely different, its likely that gcc can't understand (or compile) them at all...
What you're doing is a little strange, but I guess not incorrect. Don't have a recursive dependency on main and compile hello.o as an object file.
main: main.c hello.o
gcc main.c hello.o -o main
hello.o: hello.c water.c car.c
gcc hello.c water.c car.c -c hello.o
I would re-write it as:
SRC := hello.c main.c water.c
OBJS := $(patsubt %.c,%.o,$(SRC))
main: $(OBJS)
$(CC) -o $# $^
This makefile works because there is an implicit rule for compiling C files. This will mean that when $(OBJS) is expanded to hello.o, main.o, and water.o, each of those .o files will be built by "$(CC) -o hello.o -c hello.c".
Note that if you use the GCC -c flag to only compile the file, but not link it, you will not need to be worried that hello.c relies on car.c and water.c.
EDIT:
Note that in your original makefile, the line "main: main hello.o" is incorrect. A target cannot depend on itself.
In general, with Make, you want to specify dependencies, but not the implementation of making those dependencies, if you can help it. It is much cleaner to say "I need this" versus "do these steps". In a lot of cases, Make is smart enough that if you say "I need this," it will "do the right thing."
In your makefile there are entities of the following type:
final executable program: main
compiled objects (relocatable ELFs linked into the main executable). I can see hello.o, but I cannot find water.o, car.o and main.o (since each *.c compilation unit is generally converted by the compiler to a *.o compiled object).
the source files (compilations units): main.c, hello.c, water.c and car.c. These are used as inputs by the compiler to generate the corresponding *.o files.
So, based on the above, the appropriate Makefile would look like this (tested):
main.o:
gcc -c main.c
hello.o:
gcc -c hello.c
water.o:
gcc -c water.c
car.o:
gcc -c car.c
main: hello.o water.o car.o main.o
gcc hello.o water.o car.o main.o -o main
The shortened versioned, using makefile text functions and automatic variables (tested):
%.o:
gcc -c $(addsuffix .c, $(basename $#))
main: hello.o water.o car.o main.o
gcc $^ -o main
Another approach (tested):
SRC := hello.c water.c car.c main.c
OBJ := $(addsuffix .o, $(basename $(SRC)))
main: $(OBJ)
gcc $^ -o main

C++ - Makefile using g++

I have made a Makefile for my CMSC 202 course project, 'Blackjack'. It does everything I need it to and it works perfectly. You may be asking why I posted here then, this is because I have no idea how it works and I didn't use any other resources but myself to create it.
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 at the end
EXEC = Proj2.out
# The flags to use for compilation
FLAGS = -Wall
# The code compiler to use for compilation
CC = g++
# Perform action on all object files (May or may not exist)
all: $(OBJECTS)
$(CC) $(FLAGS) -o $(EXEC) $(OBJECTS)
Here is the terminal output when I call make in the terminal.
g++ -c -o Proj2.o Proj2.cpp
g++ -c -o Blackjack.o Blackjack.cpp
g++ -c -o Deck.o Deck.cpp
g++ -c -o Card.o Card.cpp
g++ -c -o Hand.o Hand.cpp
g++ -c -o Player.o Player.cpp
g++ -Wall -o Proj2.out Proj2.o Blackjack.o Deck.o Card.o Hand.o Player.o
Can anyone tell me how the .o files are being compiled? It does not look like they are being prompted to be compiled with that g++ -c -o $.o $.cpp command anywhere in the Makefile. Nor did I state to use any .cpp files.
Thank you in advance for your help.
Edit
Thanks to all your great help, this is now the terminal output I receive when using 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
Thank you so much to all of you who have contributed.
Make has a set of implicit rules (see here for a reference). For instance
Compiling C++ programs
`n.o' is made automatically from `n.cc' or `n.C' with a command of the form
`$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)'.
Most make's will also use this rule for .cpp files.
When make sees there's a x.o requirement for one of your targets, it will try to see if it can generate x.o using implicit rules, and in your case find it can do it starting from a .cpp file.
This Makefile uses implicit rules which are a great way to reduce duplication.
By default the first target will be built, here all. It depends on a number
of object files listed in a variable $OBJECTS, e.g. Proj2.o who's
dependencies aren't listed in the Makefile. Now if make sees an input file in the current directory
with a matching name, e.g. Proj2.cpp it will try
to build Proj2.o from it (there are other implicit rules for sources in
other languages). Proj2.o would then be built by default with the command
$(CXX) $(CXXFLAGS) -c -o Proj2.o
where $(CXX) the name of the C++ compiler (g++ in your case).
The explicit build step for all assembles all the object files into the
target executable.
Looking at above build command you'll notice a small problem in your Makefile. Since the flags to the C++ compiler are given in a variable FLAGS and not the standard CXXFLAGS no warnings will be emitted when building the object files. Using the standard name would fix this (you do want warnings, maybe even more than -Wall gives you).

GLEW based program does not compile

I am trying to use GLEW in a program I'm creating, but my compiler will not compile it, instead it throws a ton of errors at this line gcc -g -c glew.c -o glew.o. This is my Makefile:
MY_LIBS =
glewex: glew.o main.o glew.h
g++ main.o glew.o glew.h -o glewex $(MY_LIBS)
glew.o: glew.c
gcc -g -c glew.c -o glew.o
main.o: main.cpp
g++ -g -c main.cpp -o main.o
It simply outputs hundreds of errors that look like this:
__glewActiveTexture redeclared without dllimport attribute: previous import ignored [ -Wattributes ]
Try this:
gcc -g -DGLEW_STATIC -c glew.c -o glew.o
That should prevent DLL import/export decorations from getting added to the declarations.
You don't want to add the library source files to the compiler input of your project. You should add the library to the list of linker inputs; either statically (libglew.a) or dynamic (-lglew).
I.e. either
gcc -o … -lglew
or
gcc -o … libglew.a
When linking GLEW statically you must add -DGLEW_STATIC to the compiler options generating the compilation units (.o files)