So I was practicing with a tutorial series on C++ projects for Linux. In order to create the makefile I did CTR+SHIFT+P to go into Palet, searched for make file, selected the correct option, and selected C++ project. In the tutorial, the person changed src in the make file to a static path ie: pwd. That worked. When he changed back to src and after moving the files into the src folder like he did, doing make clean, and then make, I get this:
[termg#term-ms7c02 HelloWorldnonVR]$ make
g++ -std=c++11 -Wall -o obj/list.o -c src/list.cpp
g++ -std=c++11 -Wall -o obj/main.o -c src/main.cpp
g++ -std=c++11 -Wall -o HelloWorld obj/list.o obj/main.o
/usr/bin/ld: obj/main.o: in function `List::List()':
main.cpp:(.text+0x0): multiple definition of `List::List()'; obj/list.o:list.cpp:(.text+0x0): first defined here
/usr/bin/ld: obj/main.o: in function `List::List()':
main.cpp:(.text+0x0): multiple definition of `List::List()'; obj/list.o:list.cpp:(.text+0x0): first defined here
/usr/bin/ld: obj/main.o: in function `List::~List()':
main.cpp:(.text+0x2c): multiple definition of `List::~List()'; obj/list.o:list.cpp:(.text+0x2c): first defined here
/usr/bin/ld: obj/main.o: in function `List::~List()':
main.cpp:(.text+0x2c): multiple definition of `List::~List()'; obj/list.o:list.cpp:(.text+0x2c): first defined here
collect2: error: ld returned 1 exit status
make: *** [Makefile:37: HelloWorld] Error 1
[termg#term-ms7c02 HelloWorldnonVR]$
There are three files. A class and its header, and then the main. list.h is in the include subfolder for src.
I currently cannot find any information about this problem, so any help would be appreciated. The tutorial had no issues with making or running the files. The VSCode extension is C/C++ Makefile Project. My system is Manjaro. I did do make clean and delete the makefile to start fresh, in case I hit the keyboard or something but same result persists. From what I am seeing, the issue is that there is no HelloWorld executable being created. HelloWorld is the appname in the template.
Narrowed the issue down to the header. Without constructors it works but with them it does not.
#include <iostream>
#include <vector>
using namespace std;
class List
{
private:
/* data */
protected:
public:
void print_menu(); //Prototype
void print_list();
void add_item();
void delete_item();
vector<string> list;
string name;
//constructor
List(/* args */);
//destructor
~List();
};
List::List(/* args */)
{
}
List::~List()
{
}
Any ideas on what is causing this?
The error message tells you exactly what the problem is, if you learn the compiler-ese to interpret it:
main.cpp:...: multiple definition of `List::List()'; obj/list.o:list.cpp:...: first defined here
Here it's saying you have defined the constructor twice: once in main.cpp and once in list.cpp.
And, as is the case 99.99999% of the time, the compiler (well in this case technically the linker) is correct. You have defined the constructor and destructor in the header file, and you've included the header file in both the main.cpp file and in the list.cpp file, so the constructor and destructor are defined in both, just as the error says.
You need to put the constructor and destructor in the list.cpp source file, not in the header file.
Alternatively you can put them inside the class itself, which makes them inline, and then you won't have this issue:
class List
{
private:
/* data */
protected:
public:
List(/* args */) {}
~List() {}
void print_menu(); //Prototype
Of course this only makes sense if they are small and simple enough to inline like this.
Related
Let's say I have 3 files:
Test.hh
#ifndef TEST_HH_
#define TEST_HH_
class Test
{
int test() const;
};
#endif /* TEST_HH_ */
Test.cc:
#include "Test.hh"
int Test::test() const
{
return 0;
}
main.cc:
#include "Test.cc"
int main()
{
return 0;
}
It does not compile (rather does not link), I understand why, I defined Test::test() in multiple translation units (in main.cc that includes Test.cc and in Test.cc):
g++ -Wall -g -std=c++17 -c main.cc -o main.o
g++ -Wall -g -std=c++17 -c Test.cc -o Test.o
g++ -o bin main.o Test.o
Test.o: In function `Test::test()':
Test.cc:12: multiple definition of `Test::test()'
main.o:Test.cc:12: first defined here
collect2: error: ld returned 1 exit status
Edit: This is NOT my issue, my issue is that with a seemingly identical situation, in a bigger project, the previous example produces a binary (i.e. compiles and links) when, as far as I understand it, it shouldn't. I will now describe the real case with a bit more details and how the problem suddenly arised when previously it was working fine (when it shouldn't have).
--
I am currently working on a large project (~2500 files), and while trying to use the "Test" class above, I ended up having a lot of "multiple definitions" errors at link time. To translate it to our example, it's like I had another class doing this:
OtherClass.hh
#include "Test.hh" // including or using forward declaration led to the same results
//class Test; forward declaration
class OtherClass
{
// Some stuff, whatever
};
I ended up finding that Test.cc was included in another source file (main.cc in my very simplified exemple though it was in another "someClass.cc" in my actual project). After including the header instead of the source, it compiled again. What's more surprising is that other classes had been using Test.hh the same way until then without any problems.
Since I was really surprised, I ended up doing a grep on all my files and found that another 2 source files had included other sources files as well.
WhateverClass.cc
#include "Test2.cc"
YetAnotherClass.cc
#include "Test3.cc"
All those files are compiled and contain function definitions yet the linker does not complain. I tried doing a compilation from scratch and it still worked.
So my question is: Why does this compile even though some source files include others and all of them are compiled ? And why did it suddenly stop working even though I just included the header of one of those source files just like other classes had been doing ? Is there a kind of "undefined behavior" for cases like this ?
If it is of any help, my project is using CMake. I tried compiling with ninja or Make with the same results.
I had a similar question before. So, here's what I learned- never include source file. Only include header files. Your error comes from including a source (.cc) file in your main. You should include Test.hh instead. Declare all your classes and functions in header, include that header to all the source files where the definitions and the calls are.
I have this c++ project with classes' definitions inside .hpp files and methods' declarations inside .cpp files.
The project uses a makefile to build and run.
The program ran without errors before but LinkedList didn't work as I wanted so I re-wrote it entirely.
Now LinkedList.hpp includes both the class definition and its methods' declarations.
I adjusted the other classes' methods so that they use LinkedList correctly.
Now when debugging the program I get this multiple definition of, first defined here error.
find: ‘lib’: No such file or directory
g++ -std=c++17 -Wall -Wextra -g -Iinclude -o output/main src/Game.o src/Hero.o src/Title.o src/Level.o src/Menu.o src/Entity.o src/Window.o src/main.o src/Map.o src/Object.o -lncurses
/usr/bin/ld: src/Hero.o:/home/user/projects/project-X-githubClone/projectX/include/Object.hpp:2: multiple definition of `TileTypeStr'; src/Game.o:/home/user/projects/project-X-githubClone/projectX/include/Object.hpp:2: first defined here
/usr/bin/ld: src/Level.o:/home/user/projects/project-X-githubClone/projectX/include/Object.hpp:2: multiple definition of `TileTypeStr'; src/Game.o:/home/user/projects/project-X-githubClone/projectX/include/Object.hpp:2: first defined here
/usr/bin/ld: src/Entity.o:/home/user/projects/project-X-githubClone/projectX/include/Object.hpp:2: multiple definition of `TileTypeStr'; src/Game.o:/home/user/projects/project-X-githubClone/projectX/include/Object.hpp:2: first defined here
/usr/bin/ld: src/Map.o:/home/user/projects/project-X-githubClone/projectX/include/Object.hpp:2: multiple definition of `TileTypeStr'; src/Game.o:/home/user/projects/project-X-githubClone/projectX/include/Object.hpp:2: first defined here
collect2: error: ld returned 1 exit status
make: *** [Makefile:74: main] Error 1
So if I get this correctly, the problem is the multiple definitions of const char* TileTypeStr[].
But why then when I change that array's name to, say, tts the error message still reads "multiple definitions of TileTypeStr"?
and why if I comment out the only 2 references (including its declaration and initialisation) of this array inside the whole project the error message is still the same?
TileTypeStr[] was misplaced after all, moved it inside the toString() method I needed it for, then ran make clean to recompile all of the source files and make to build main.cpp.
By running make and not recompiling the source files I was stuck running the bugged version of the program.
I have a strange problem when compiling a C++ code using a makefile. The code first compiles perfectly. Then I change one function argument to "const". If I then compile, I will receive the error message when the code tries to use the function in which I changed the argument to const. This can be resolved by removing all .o files and then compiling again, but I am curious as to what causes this issue in the first place. My files are:
MyClass.h
class MyClass {
public:
void fun(double*const c);
};
MyClass.cpp
#include "MyClass.h"
void MyClass::fun(double *const c){
};
Main.cpp
#include "MyClass.h"
int main(int argc,char* argv[]) {
MyClass foo;
double *bar=new double[2];
foo.fun(bar);
};
Makefile
all: main
main: Main.o MyClass.o
g++ -o a.out Main.o MyClass.o
Main.o: Main.cpp
g++ -c Main.cpp
MyClass.o: MyClass.cpp
g++ -c MyClass.cpp
If I now first run make, everything works. But then I change the signature of fun to fun(const double *const c), I receive the error message
Main.cpp:(.text+0x3b): undefined reference to `MyClass::fun(double*)'
collect2: error: ld returned 1 exit status
Makefile:6: recipe for target 'main' failed
make: *** [main] Error 1
However, if I remove all the .o files and then run make again, it compiles.
The rule
main.o: Main.cpp
says thay the main.o object file only depend on the Main.cpp source file. But it actually depends on another file: The MyClass.h header file.
There's also an error in the capitalization of the name of the target.
The above two problems means that when you change the header file MyClass.h to update the function signature, the Main.o object file will not be recreated and still reference the old function.
So the rule should be
Main.o: Main.cpp MyClass.h
That addition will cause the Main.o object file to be recompiled when you change the header file.
This change should also be done for the MyClass.o target.
Also note that the main target uses MyClass.o as a dependency, but then you use the MyClass.cpp source file when linking, instead of the object file.
The name of the target should also be the name of the generated file (i.e. a.out in your case).
The problem is, that your Makefile is broken: It ignores the fact that a .o file does not only depend on the corresponding .cpp file, but also on the .h files it includes. A correct Makefile rule must include all dependencies, including the directly, or even indirectly included .h files.
Since you Makefile is incomplete, make did not recompile the calling site of your function when its definition changed, so the stale object still references the non-const function. Due to C++ name-mangling, the linker caught it in the act, the error would have gone unnoticed in C!
To fix this situation for good, I recommend spending an hour or two reading this article on automatic dependency generation, and implementing some of the solutions it offers into your Makefile. Once you have done this, you will likely just copy-cat your existing solution into the Makefiles of future projects, and otherwise forget about the problem.
I've written some C++ code for an embedded system which works like a charm. The current task is to emulate the behaviour of this device on a PC. Some of the code has to be ported: For a first test I'm using mingw (g++) while the Embedded system is an STM32 and uses the KEIL µVision toolchain.
I've run into a problem that is not really related to functional behaviour rather than a compiler specific weirdness. I have 2 classes defined in an anonymous namespace because they are included throughout the whole project. Now on the embedded device this compiles and runs without a problem. g++ complains about an undefined reference!
When I remove the anonymous namespace arround the class it compiles and runs! But why? Here is some example code that reproduces the situation:
main.cpp:
#include "notmain.h"
#include "theclass.h"
A *ourA=NULL;
int main()
{
theA = new A();
theA->dostuff(1024);
sunshine sun;
sun.Init();
}
notmain.cpp:
#include "notmain.h"
#include "theclass.h"
void sunshine::Init()
{
theA->dostuff(127);
}
notmain.h:
#ifndef NOTMAIN_H_
#define NOTMAIN_H_
class sunshine
{
public:
void Init();
};
#endif
theclass.h:
#ifndef THECLASS_H_
#define THECLASS_H_
#include <stdio.h>
#define theA ourA
namespace
{
class A
{
public:
void dostuff(int b)
{
a = b;
printf("Hello: %d\n",a);
}
private:
int a;
};
}
extern A *ourA;
#endif
Compiler/Linker Output:
09:09:57 ** Incremental Build of configuration Debug for project Testo **
Info: Internal Builder is used for build
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o main.o "..\main.cpp"
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o notmain.o "..\notmain.cpp"
g++ -o Testo.exe notmain.o main.o
notmain.o: In function ZN8sunshine4InitEv':
D:\Projekte\Testo\Debug/../notmain.cpp:6: undefined reference toourA'
collect2.exe: error: ld returned 1 exit status
09:09:57 Build Finished (took 702ms)
Removing that namespace fixes the problem but why does it compile, link, work in KEIL? Can anyone explain this to me?
I would suggest that that is an abuse of the anonymous namespace feature. It does exactly the opposite of what you are trying to achieve.
Anonymous namespaces are used to localise a definition to a single translation unit. If you place one in a header file, then include that header in multiple translation units, that will result in multiple independent definitions in your code.
What is happening here VC++ is that a global ourA has been instantiated as a pointer to one local definition of A defined in main.cpp, then later that local definition is no longer visible but is distinct from the currently visible local version in notmain.cpp. The name mangling of ZN8sunshine4InitEv distinguishes between independent definitions, but name mangling is compiler defined, and I guess ARM's RealView compiler (used by uVision) has a different scheme that fails to spot this error.
It is unclear in fact what the result if this error is in RealView, but it cannot be correct or at least well defined.
RealView is in fact rather poor at issuing warnings that other compilers do normally, and is somewhat permissive when it comes to undefined behaviour I have found. It is always worth using another toolchain such as MinGW/GCC with -Werror -Wall or using a static analysis tool to clean up your code.
To solve this problem you should use an explicitly named namespace, or no namespace at all.
I'm trying to solve a compiling problem regarding outside defined constructor.
Here's 2 of the classes that have this problem:
//Username.h
#ifndef USERNAME_H
#define USERNAME_H
#include <string>
using namespace std;
class Username{
private:
string Name;
public:
Username(string = "");
string getName() const;
void setName(string);
};
#endif
...
//Username.cpp
#include "Username.h"
Username::Username(string n):Name(n){}
string Username::getName() const{return Name;}
void Username::setName(string n){Name = n;}
...
//User.h
#ifndef USER_H
#define USER_H
#include <string>
#include "Username.h"
using namespace std;
class User{
protected:
Username* UserUsername;
public:
User(string s);
virtual ~User();
Username* getUsername() const;
void setUsername(Username*);
};
#endif
...
//User.cpp
#include "User.h"
User::User(string s):UserUsername(new Username(s)){}
User::~User(){}
Username* User::getUsername() const{return UserUsername;}
void User::setUsername(Username* u){UserUsername=u;}
int main(){return 0;}
If I compile using "g++ User.cpp" I get this error:
/tmp/ccEmWmfl.o: In function `User::User(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
User.cpp:(.text+0x3e): undefined reference to `Username::Username(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
collect2: ld returned 1 exit status
If I use "g++ User.cpp Username.cpp -o main" or if I use inline constructors/destructors I get no error.
These classes are very easy, but I have tons more to compile that require more than one class.
I'm new at compiling in Ubuntu shell with g++, so please, can someone help me to understand?
g++ User.cpp
This compiles User.cpp and attempts to create an executable from it (ie the linker is invoked). Since User.cpp has a symbol not fully defined in User.cpp (the Username constructor here:
User::User(string s):UserUsername(new Username(s)){}
the symbol is expected to be defined at the link stage. Linking is done by combining all the generated object file output of all the cpps you generated and piecing together the missing symbols. Here you're not telling g++ about where to find the full definition of the Username constructor other than the cpp with main, so its failing.
This, however:
g++ User.cpp Username.cpp -o main
Tells the linker where to find full Username definitions (in the object file generated by compiling Username.cpp). So linking can succeed in filling in the missing pieces by using whats defined in Username.cpp to match up identifiers not defined in User.cpp.
You may think -- "well I've told the compiler about it by including the header file, it should know!". What you've done is declared the symbol. You've made a promise that something will eventually be defined, either during compilation of that one cpp or by later linking it with another object file generated by compiling another cpp. g++ needs to know where you intend to pull all your definitions from so it can build a final executable correctly.
You already answered your question, if you don't add Username.cpp at the compilation process User can't knwo it.
You can use partial compilation, with the -c flag:
g++ -c User.cpp
This produces a User.o file.
You do this partial compilation thing on each of your files
g++ -c Username.cpp
And then you link all the object files (the *.o files) together:
g++ User.o Username.o -o main
Usually, you'd use some build system to automate this process. With that you'd also get other advantages, like not skipping the recompilation of files that didn't change since the last compilation.
This can also happen, if you are trying to call a member function of a template class from the source file other than the implementation file of the template class. For example: you have clas ABC with ABC.h and ABC.cpp (implementation file).
As long as your calls to generic objects lies in ABC.cpp, all works well. However, if you try to include ABC.h in another class say BCD and call any member function of object ABC, you will get the Undefined Reference To Member function error.
Solution: Create a single header file for your template classes including the implementation to avoid this error which is misleading.
User.cpp add:
#include "Username.h"
It's not really a C++ problem, but more a GCC issue. Normally, you'd build a larger program with Make. You then have a makefile rule that builds all .cpp files in a directory and links hem together. An alternative is that your makefile specifically states which .cpp files should be compiled together.
You have to pass all of your implementation files to the g++ executable. The first compilation attempt fails because you're only compiling User.cpp into an object file and linking it into an executable object called main.
In the second attempt you correctly pass both necessary implementation files to the g++ executable. In this case, User.cpp and Username.cpp are compiled into object files and linked together to form the main executable. In this case, the implementation of the Username::Username() constructor is present.