C/C++ duplicate symbols error - c++

I'm currently trying to compile an existing project which is a mix of cpp and c.
My makefile is as follows;
execute: mgnsvd.o multifit.o cit.o main.o
g++ -Wall -g multifit.o cit.o main.o mgnsvd.o -lgsl -lgslcblas -o execute
main.o: main.cpp cit.cpp
g++ -Wall -g -c main.cpp
cit.o: cit.cpp mgnsvd.c multifit.h
g++ -Wall -g -c cit.cpp
multifit.o: multifit.c mgnsvd.c multifit.h
g++ -Wall -g -c multifit.c
mgnsvd.o: mgnsvd.c
g++ -Wall -g -c mgnsvd.c
And my main is a rather plain
// global libraries
#include <iostream>
// local files
#include "cit.cpp"
// using directives
using std::endl;
using std::cout;
// main
int main(){
cout << "Hello, world" << endl;
return 0;
}
If is comment out #include "cit.cpp" it compiles fine. However, if i include it the following error happens;
ld: duplicate symbol _first_function_in_cit in main.o and cit.o for architecture x86_64
_first_function is always the first function, and is not defined or even declared/used anywhere else. A grep of the object files confirms the function seems to be incorporated into main.o, but why? I've not worked on a C++/C project before, so maybe I'm making some canonical error? I'm also in OSX, if that makes a difference.
For the record, there are no classes - the .h file contains a few structs and some macros.

cit.cpp is being compiled by itself, and is also included in main.cpp so you're getting two copies of all the code in it.

There is no need for
#include "cit.cpp"
cit.cpp is compiled as a separate unit and later linked.
With the above include you get the code twice with results in duplicate symbols

YOu are compiling cit.cpp to yield cit.o, and you are compiling it again with that #include "cit.cpp" attrocity in your main.cpp. So of course you are getting duplicate symbols.

Related

Why am I getting "undefined reference to main"

I am a very new to programming and have a very basic question that may be answered in other threads however I think they are far too advanced for me to understand how. I have actually found many answers so far on this site but this is the first problem that forced me to create an account and ask.
Anyway i am running a very basic example program on linux mint 18.3. Now I have seen this exact code work on a machine with windows 8 I believe so I was wondering if that could be the problem. I have created a class and when i plug in my object then build and run I get:
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o||In function _start':|
(.text+0x20)||undefined reference tomain'|
This is the entire code:
#include <iostream>
#include "Gladius.h"
using namespace std;
int main()
{
Gladius io;
return 0;
}
Thats it very basic. here is the .h
#ifndef GLADIUS_H
#define GLADIUS_H
class Gladius
{
public:
Gladius();
};
#endif // GLADIUS_H
and the .cpp for the class.
#include "Gladius.h"
#include <iostream>
using namespace std;
Gladius::Gladius()
{
cout << "The Gladius is a short sword" << endl;
}
I know this seems extremely simple but I am just learning to code and i have been looking all over for an explanation why this isn't working yet I see it work on another pc exactly as is. Anyway any explanation would be greatly appreciated.
Here is what i found in command line If this answers your questions about what was in the cmd.
g++ -Wall -fexceptions -g -std=c++11 -Wall -I -c /home/gator/Documents/Spartan1/Gladius.cpp -o obj/Debug/Gladius.o
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function _start':
(.text+0x20): undefined reference tomain'
collect2: error: ld returned 1 exit status
Know the compiler options(gcc/g++ compiler):
-c : Compile and assemble, but do not link
-o file : Place the output into file
So when you run
g++ filename.cpp -o executable_name
, you generate an application which can be executed.
The problem is you are compiling, assembling as well as linking when you are trying to compile "Gladius.cpp" and compiler is trying to search for main() definition.
So in your case, the compilation steps would be:
First compile "Gladius.cpp" and generate object file "Gladius.o":
g++ -Wall -fexceptions -g -std=c++11 -c Gladius.cpp
Next compile "main.cpp" and generate object file "main.o":
g++ -Wall -fexceptions -g -std=c++11 -c main.cpp
Generate executable by linking "main.o" and "Gladius.o"
g++ -Wall -fexceptions -g -std=c++11 -o main main.o Gladius.o
Now you can run "main":
./main
Your compiler's command line contains -I -c sequence.
This -I option "swallows" your -c option. -I requires an additional argument, which is an include directory name. You failed to supply that argument, which is why -I assumes that -c that follows it is the directory name. So that -I consumes that -c.
The compiler never sees that -c. Without -c it assumes that you want to compile and link your program. Since Gladius.cpp does not have main in it, you get the error at linking stage.
Here 's a simple demo of the same problem: http://coliru.stacked-crooked.com/a/8a37cd3e90a443e2
You need to figure out why you have an orphaned -I in your command line.
If you are compiling this code using a command line like:
g++ -Wall -Wextra -Werror -O gladius.cpp -o output.exe
then make sure that you include all the .cpp files (not .h files) that contain code that your program needs.
g++ -Wall -Wextra -Werror -O gladius.cpp main.cpp -o output.exe
I explain this to beginners all the time as each .cpp being a bag of Lego's in a kit. You need all the bags that came with the box in order to build the kit. If you omitted main.cpp (or the file that contains main) then you will get the linker error that you are currently getting.
What command are you using to compile, link, and then execute? It should look something like
$ g++ main.cpp gladius.cpp -odemo
$ ./demo
check your command line for linking step.. You may forgot file with main as input, or you had forgot output file name after -o (and masked main.o in result)
I had this very kind of problem myself, and though it may not be the conventional, "proper" solution, I simply renamed the ".c" file to ".cpp", and it all worked.
After all, I was compiling both c and c++ together with a c++ compiler (recommended by the library), and the c code already had the proper c++ #extern flags (see here for more on that).
Also related:
C++ Error: undefined reference to `main'
Including C Code in C++
Why do you need an explicit `-lm` compiler option
Compilation on Linux - In function '_start': (.text+0x20): undefined reference to 'main'

Geany, g++ and SDL errors in compilation

So, I was following a simple C++ with SDL tutorial for linux but i encounter some errors on my way.
First of all I'm using Geany and i downloaded the corresponding SDL2 libs, here is the thing:
in my project folder there is a main.cxx file, which i open with geany as i mentioned before:
I included this libraries:
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_mixer.h>
First i encountered a pelculiar error, compilation performs sucessfully but when it comes to build i got this error:
main.cxx: undefined reference to `SDL_Init'
After searching a bit i found out that i had to add the tag -lSDL to my geany build options so they would end up being somethinf like this:
Compile:
g++ -Wall -c -lSDL "%f"
Build:
g++ -Wall -o -lSDL "%e" "%f"
But there is a problem, now when I execute the build command i get a:
G ++: error: main: There is no such file or directory
Why am i getting this error, am I including a wrong library or g++ has problems with .cxx files?
I already tried converting between .cxx and .cpp.
Thanks in advance.
g++ -Wall -c -lSDL2 "%f"
There is absolutely no need to specify libraries during compilation phase. Remove -lSDL.
g++ -Wall -o -lSDL2 "%e" "%f"
It invokes compiler, implies linking (no -c or other operation-specific flags), and sets output file name to -lSDL2. That is, linker will output resulting binary in a file named -lSDL2 in current working directory. Then, when it comes what files to link, it goes main, which supposed to be -o main, but since you've broken flags order it is now just ordinary file name that linker will try to link into resulting binary. It so happens that this file doesn't exist.
Long story short, make correct linking line - g++ -o "%e" %f -lSDL2 (libraries comes last, library order is also important).

Why one definition rule (ODR) is not honoured by g++ in this case ? .

As you see, there are multiple definitions of testfn symbol while linking, but the linker takes the first occurence (in linking order) and ignores the other occurances in other libraries.
This probably is the way how the linker works.
But Is there any way to enforce linker to flag error on seeing multiple symbols in different linked libraries ? Or any other options to catch such duplicate definitions ?
Content of test1.h:
#ifndef TEST1
#define TEST1
void testfn();
#endif
Content of test1.cpp
#include "test1.h"
#include <iostream>
using namespace std;
void testfn()
{
cout << "file1" << endl;
}
Content of test.h:
#ifndef TEST
#define TEST
void testfn();
#endif
Content of test.cpp:
#include "test.h"
#include <iostream>
using namespace std;
void testfn()
{
cout << "file" << endl;
}
Content of main.cpp:
#include "test.h"
#include "test1.h"
int main()
{
testfn();
return 0;
}
Created a shared libraries.
g++ -fPIC -shared libtest1.so test1.cpp
g++ -fPIC -shared libtest.so test.cpp
Created executable with library order#1
g++ -o main main.cpp -ltest -ltest1
Created executable with library order#2
g++ -o main1 main.cpp -ltest1 -ltest
Ouput of main
./main
file
Ouput of main1
./main1
file1
First of all, it is honoring the ODR, by only taking one of the methods out of the library. And that's just the way shared libraries work.
If you want to see the compiler complain about this, link them all together, without the library step.
g++ -o main1 main.cpp test1.cpp test.cpp
So your question becomes, "How do I tell if I have two libraries which both contain a indentifier with the same name?" Keep in mind that this is often not a problem and sometimes done intentionally. I'd suggest running the library tool (I'm not familiar with the g++ toolset) to get listing of the libraries, and run DIFF of them.
I don't see a way to get GNU ld to complain about multiple symbol definitions across shared libraries. However, if normal static library archives are involved, you might be able to use the --whole-archive/--no-whole-archive set of options to get what you want:
For example, after building libtest.a and libtest1.a instead of the shared library versions, I get no errors with the following link commands:
$ g++ -o main main.cpp -ltest1 -ltest -L.
$ ./main
file1
$ g++ -o main main.cpp -ltest -ltest1 -L.
$ ./main
file
But do get errors for the following:
$ g++ -o main main.cpp -Wl,--whole-archive -ltest1 -ltest -Wl,--no-whole-archive -L.
./libtest.a(test.o): In function `testfn()':
test.cpp:(.text+0x0): multiple definition of `testfn()'
./libtest1.a(test1.o):test1.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status
I'm not sure you would want to use --whole-archive for release builds - maybe only as a sanity check for possibly name conflicts (I think that using --whole-archive normally will increase the size of your binary for no good reason).
Also, as mentioned before, this seems to have no effect on shared libraries.

Error compiling source file and header file together in C++

This is not actual code i am working on but sample code i had written to understand what i am doing wrong. So i have three files main.cpp, favourite.cpp and favourite.h. I am trying to compile main.cpp but get some weird error.
// main.cpp File
#include <iostream>
#include "favourite.h"
using namespace std;
int main()
{
favNum(12);
}
// favourite.cpp File
#include "favourite.h"
#include <iostream>
using namespace std;
void favNum(int num)
{
cout << "My Favourate number is " << num << endl;
}
// favourite.h File
#ifndef FAVOURITE_H
#define FAVOURITE_H
void favNum(int num);
#endif
This all files are in same folder and i am compiling it normally like g++ main.cpp I am not sure if i need to compile it diffrently as i am using custom header files.
If you say g++ main.cpp and this is your whole command line, the error is a linker error that it can't find favNum, right? In that case, try:
g++ main.cpp favourite.cpp
or split compilation and linking:
g++ -c main.cpp -o main.o
g++ -c favourite.cpp -o favourite.o
g++ main.o favourite.o
Where -c means: Compile only, no linking and -ofilename is required because you want to write the output to two different object files to link them with the last command.
You might also add additional flag, the most important ones are:
-Wall -Wextra -O3
Oh I guess I see the error although you should have included it in your question.
When compiling multiple source files you need to list them all on the GCC command line. Or you can use a Makefile.
So you could do this:
g++ favourite.cpp main.cpp
Or you could write a Makefile like this:
all: program
program: main.o favourite.o
And then just type:
make

Create and use a header in C++

I've got three files, add.h, add.cpp and test.cpp
add.h creates a header for a class, and is nothing but skeletons for implementation later.
add.cpp contains the actual code for the class listed in add.h
test.cpp contains the main method and declares an instance of the class in add and uses some of its methods.
However, I'm having trouble compiling it. In add.h, I have #DEFINES to prevent multiple writes of the header, and in add.cpp and test.cpp I have add.h included, but when I attempt to compile using the line
g++ test.cpp -o test
I get an error about undefined references to the class objects and methods in add.h. I've been searching google on how to compile or run this, but so far no help, can StackOverflow help me?
EDIT: Sorry, I should have also included that I did try g++ test.cpp add.cpp -o test and it didn't work either, yielding the same resulting errors.
Compile each file separately, then link:
g++ -Wall -c test.cpp
g++ -Wall -c add.cpp
g++ -o test test.o add.o
Or compile and link all files in one command:
g++ -Wall -o test test.cpp add.cpp
run g++ test.cpp add.cpp -o test
EDIT: copypasted my comment here
You need to understand why your initial approach isn't working. When you reference stuff from add.h header in test.cpp, the compiler looks for definitions, but does not find them, because they are in add.cpp and you did not pass it to the compiler. The compiler can't just guess that it should look for the definitions in the add.cpp file just because you included add.h in test.cpp.
run g++ test.cpp add.cpp -o test
or
g++ -c add.cpp -o add.o
g++ -c test.cpp -o test.o
g++ test.o add.o -o test
the -c flag tells gcc to just compile and not link
the first two steps compile 1 cpp (a compilation unit) in an object file
the last step links those into a single executable
your actual problem comes from the fact that when you compile test.cpp, it refers to some simbols which are undefined.
If you're just compiling (-c flag) that's fine, and the next step is to link with those objects file containing the missing symbols.
You need
g++ test.cpp app.cpp -o myTest
as app.cpp contains code used by test.cpp.