File inclusion errors (C++): undefined reference to ______ - c++

Whenever I compile something that #includes a user-defined class, I get these compilation errors that always look like: main.cpp: undefined reference to Complex::Complex(double, double)
I've reduced the problem to a set of three extremely bare files: main.cpp, and for example, Complex.h and Complex.cpp. I still get undefined reference errors. I'm developing in Code::Blocks on Windows but I get the same thing using g++ in Ubuntu. Why does this happen? I've tried building Complex.cpp before main.cpp in Code::Blocks, and I've tried g++ main.cpp Complex.cpp as much as I've tried just g++ main.cpp. Same errors every time.
/*======== main.cpp ========*/
#include "Complex.h"
int main()
{
Complex A(1.0, 1.0);
return 0;
}
/*======== Complex.h ========*/
#ifndef _COMPLEX_H
#define _COMPLEX_H
class Complex
{
public:
double x, y;
Complex(double real, double imag);
};
#endif
/*======== Complex.cpp ========*/
#include "Complex.h"
Complex::Complex(double real, double imag)
{
x = real;
y = imag;
}
ed: now I get different errors so I must be doing something completely wrong. Using the same code as above, I get:
main.cpp: in function 'int main()':
main.cpp:5:5: error: 'Complex' was not declared in this scope
main.cpp:5:13: error: expected ';' before 'A'
This is bizarre. Everything worked earlier when I had the class in a .cpp file, but that's "bad practice" so I moved my class definitions into .h files and kept the implementation in .cpp files, and now nothing works.

That's not a compilation error, it's a link error. You need to make sure to link all of your objects together. You can do that in a couple ways:
g++ main.cpp Complex.cpp
Should work fine (and does here when I tried with your example). You can also do it in steps:
g++ -c main.cpp
g++ -c Complex.cpp
g++ main.o Complex.o

While we are left in the dark whether this is the actual code (probably not as it works for several others), let's comment on the code itself a bit... (this won't have any effect on the linker error)
Names starting with an underscore followed by a capital letter, e.g. _COMPLEX_H, are reserved for the implementation of the C++ compiler and the C++ standard library. Don't use them.
Member variables are best made private. There is rarely any need to make actual data member public (sometimes it is reasonable to make non-function members public, e.g. an event class where users can subscribe callbacks, but these typically behave like functions although they are technically objects).
Initialization is best done in the member initializer list. That is, the constructor would look something like this:
Complex::Complex(double real, double image):
x(real),
y(imag)
{
}
Finally, to venture a few guesses what is going wrong with the actual code to cause the linking problem:
The constructor is defined to be inline. Obviously, this won't work unless the definition is visible where the constructor is used.
The declaration of Complex somehow made it into an unnamed namespace and thus the definition happens to define a different class than the one seen by main.cpp.

Related

Multiple includes of same header file in project: C vs C++

Here I have an example project with two source files and a header file, as follows:
main.c:
#include<stdio.h>
#include "personal.h"
int main(){
i = 5;
printf("Value is %d\n",i);
return 0;
}
sub.c:
#include "personal.h"
// do nothing
and finally personal.h:
#pragma once
int i;
Each of the .c file includes the personal.h, which is `guarded'. I compile with gcc, all goes fine:
>gcc sub.c main.c -o out
>./out
Value is 5
But with g++, this happens:
>g++ sub.c main.c -o out
/tmp/cctYwVnO.o:(.bss+0x0): multiple definition of `i'
/tmp/ccPElZ27.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
Is there anything fundamentally different between C++ and C in terms of how files are linked, preprocessor activity etc? I tried the same with other compilers like clang and the same happens. I am perhaps missing something silly here.
In C,
int i;
is a tentative definition. By the virtue of inclusion, you have a tentative definition for i in two compilation units. The C standard allows to have tentative definitions in multiple compilation units, but does not mandate that implementation accept that. The custom behavior for Unix C compilers is to allow it but gcc has an option (-fno-common) to prevent it and generate an error at link time (so that you can check the code for compilers, as I think Microsoft one, which does not allow it or for platforms for which that allow better code -- I know of none but that's a rationale given by GCC documentation).
IIRC, C++ has no such allowance.
Note that you probably want a declaration and not a definition in headers. Thus for the i above it should be
extern int i;
in the header and one
int i;
at global scope in one .c file.
sub.c will include personal.h and will create the variable i in global scope. Similarly, main.c will also include personal.h and create variable i in global scope. Eventually, when you link, there are two definitions of i in the global scope and hence the error.

g++ undefined reference to a free standing function

this must have been answered a million times, yet I cannot find a suitable solution.
I have defined a free function in sensor.cpp:
std::string printTargetGasName(enalu::CombThreshold::TargetGas){}
Then I have declared the prototype of the function
in sensor.hpp
std::string printTargetGasName(enalu::CombThreshold::TargetGas);
Then I include sensor.hpp in core_enose.hpp and try to use the function in core_enose.cpp (enalu is just a namespace).
I get undefined reference linking error
core_enose.cpp:284: undefined reference to `enalu::printTargetGasName(enalu::CombThreshold::TargetGas)'
the linking instructions in the make file seem correct, i.e. the sensor.opp comes after the core_enose.opp:
g++ -g -Wall -Wextra -pedantic -std=c++11 [...] obj_dbg/core_enose.opp [...] obj_dbg/sensor.opp [...]
I also checked to see if the symbol correctly exists in the sensor.opp file:
$> nm obj_dbg/sensor.opp | grep printTarget
$> 000000000000cc9c T _Z18printTargetGasNameN5enalu13CombThreshold9TargetGasE
I have tried desperate late night measures as well, such as extern , or re including the sensor.hpp directly in the core_enose.cpp file. Nothing helps and at this point I am frustrated at the simple answer that eludes me.
Note that I am not providing code because sensor.?pp files are rather big containing a few classes that I have also been using in my program. What I describe above are the exact steps I followed to add this free function to an otherwise working application.
Could you help me?
Because your link error is about enalu::printTargetGasName, I suspect that you declared the function in your header within the enalu namespace, but the corresponding C++ doesn't have the namespace enclosure. This might fix you in the sensor.cpp file.
namespace enalu
{
std::string printTargetGasName(enalu::CombThreshold::TargetGas){}
};

g++ fails to link .o files into an executable

I am doing an example drill in the textbook I am using to learn from. All I need to do is compile, link and run the following 3 files:
//file my.h
extern int foo;
void print_foo();
void print(int);
my.h is a simple header file that declares the two functions and a 'global' int foo, with no initial value.
//file my.cpp
#include "my.h"
#include "std_lib_facilities.h" //not included but not source of error
void print_foo()
{
cout << foo << endl;
}
void print(int i)
{
cout << i << endl;
}
my.cpp contains the implementation of the functions included from my.h. std_lib_facilities.h is a file from the textbook, and is not the source of error (according to g++). I can edit it into the body of the question if needed.
//file use.cpp
#include "my.h"
#include <iostream>
int main() {
foo = 7;
print_foo();
print(99)
char cc; cin >> cc;
return 0;
}
use.cpp serves as the main implementation file in this program, and tries to use all three declared & defined objects.
I took the two step command approach to build using g++. First, I compiled both .cpp files:
g++ -c my.cpp use.cpp
which created two object files, my.o and use.o. I used the following command to link them:
g++ -o myprog my.o use.o
giving me this error:
Undefined symbols for architecture x86_64:
"_foo", referenced from:
print_foo() in my.o
_main in use.o
(maybe you meant: __Z9print_foov)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I have tried putting
int foo;
into my.h instead of
extern int foo;
which gave me the same error.
I have tried using the
-std=c++11
flag as well which resulted in the same error.
I am using a MacBook Pro with the latest macOS (just updated in fact), if that helps with interpreting the error message.
I have tried to initialize foo, which didn't change anything.
In addition, I have tried updating the command line tools, same error.
From what I understand, the error is telling me that, even though my.h is included in both files, neither one can actually implement any function using the foo variable (which it calls _foo), despite it being explicitly declared in my.h. My guess is that the linker is using the wrong names under the hood, which make it impossible to link into an executable. This comes from the fact that the error mentioned a
__Z9print_foov
which exists nowhere in any of the files.
It almost seems like a g++ or macOS/Command Line Tools bug at this point. I don't want to add the declarations each time, because that creates duplicate symbol errors anyway. Putting my.cpp and use.cpp into one file would probably link properly, but I need to make sure that I can actually link multiple cpp files, because I will eventually (hopefully) be working with multiple cpp files that need to be linked. Any help is appreciated!
Here you declare a variable:
extern int foo;
and you use the variable:
cout << foo << endl;
but you did not define the variable anywhere. The linker error says that the linker could not find the variable's definition. To fix this, put int foo; at file scope in one of the .cpp files.
In the question you say that changing extern int foo; to int foo; gives the same error. However if you look more carefully at the error message I think you will find that it gives a different one, about multiple definitions.
I suggest to compile in two commands g++ -Wall -c my.cpp (that gives a my.o) and g++ -Wall -c use.cpp (giving use.o), then link a program with g++ my.o use.o -o myprog. Actually you should write a Makefile (see this for inspiration) and simply run make
Your translation units my.cpp and use.cpp are both declaring some extern int foo; variable which is never defined. So you need to define it in one single file (but not in others!), probably by adding (into my.cpp alone for example)
int foo;
(without the extern) or even with some explicit initial value e.g. int foo = 34;
This comes from the fact that the error mentioned a __Z9print_foov which exists nowhere
It is a mangled name, which is referenced (but not defined) in both object files (see also this).
It almost seems like a g++ or macOS/Command Line Tools bug at this point
You are very unlikely to find bugs in compiler tools (both GCC & Clang/LLVM are extremely well tested; since they are multi-million lines free software, they do have residual bugs, but you have more chances to win at the lottery than to be affected by a compiler bug). I'm coding since 1974, and it happened to me only once in my lifetime. A more realistic attitude is to be more humble, and question your own code (and knowledge) before suspecting the compiler or build chain.
BTW, always compile first with all warnings and debug info (e.g. g++ -Wall -g and perhaps also -Wextra). Use the gdb debugger. When you are convinced that your code has no bugs, you might benchmark it by asking the compiler to optimize (so use g++ -Wall -O2 perhaps also with -g to compile).
Read also the linker wikipage. Dive into your C++ textbook (see also this site and the C++11 standard, e.g. n3337 draft) to understand the difference between declaring and defining some variable or function. You generally declare a global extern variable in some common header (included in several translation units), and define it once somewhere else, but the good practice is to avoid having lots of global variables. See also C++17 new inline variables.

Travis-CI fails on symbol lookup error, works fine elsewhere

I have a library (technically a Ruby extension) called NMatrix which is written in C and C++. It uses C++ templates to manage different types, e.g., Rational128 versus Rational64. It also has RubyObject and Complex64 and Complex128. I force these template versions to be built by creating some inside an object file -- in a function that is called from the library entry point.
It works just fine in GCC 4.7, but when I compile on Travis-CI, it encounters an undefined symbol error at run-time:
exposes cblas rot /home/travis/.rvm/rubies/ruby-2.0.0-p247/bin/ruby: symbol lookup error: /home/travis/build/SciRuby/nmatrix/lib/nmatrix.so: undefined symbol: _ZN2nm7ComplexIfEC1ERKNS_10RubyObjectE
The undefined symbol is nm::Complex::Complex(nm::RubyObject const&), which is explicitly defined and instantiated (see below).
Here's a pared down version of data.cpp:
#include "data.h"
void nm_init_data() { // called from library entry point
// These force the compiler to build these versions of the typedef'd templates.
// I think this is a gross way to do it, but can't find a better idea.
nm::RubyObject obj(INT2FIX(1));
nm::Rational32 x(obj);
nm::Rational64 y(obj);
nm::Rational128 z(obj);
nm::Complex64 a(obj); // Clear instantiation of the undefined symbol
nm::Complex128 b(obj);
}
and data.h like so:
#include "nmatrix.h"
#include "complex.h" // classes are all declared in headers
#include "rational.h"
#include "ruby_object.h"
void nm_init_data();
nmatrix.cpp is where the library entry point is declared. The relevant parts look like this:
void Init_nmatrix() {
// declarations of Ruby-exposed functions here, e.g.,
rb_define_method(cNMatrix, "initialize", (METHOD)nmatrix_constructor, -1);
nm_init_data();
}
So what am I doing wrong? Why does this work on GCC 4.7.1 (all specs pass), but not 4.6.3? Is it a bug? (If it's a bug, is there a work-around?)
If you're curious, the full versions of the relevant files are here.

C++: Switching from MSVC to G++: Global Variables

I recently switched to Linux and wanted to compile my Visual Studio 2010 C++ source code, which uses only the STL, on G++.
My Linux machine currently isn't available but I can try to tell you what is going on, first:
As I try to compile my project, all global variables I use in main and which perfectly work on MSVC result in myGlobalVar is not defined in this scope errors.
My project is built nearly the same as the example below:
// myclass.h
class myClass
{
// ....
};
extern myClass globalInstance;
// myclass.cpp
#include "myclass.h"
// myClass functions located here
myClass globalInstance;
// main.cpp
#include "myclass.h"
int main( )
{
// Accessing globalInstance results in an error: Not defined in this scope
}
What am I doing wrong?
Where are the differences between G++ and MSVC in terms of global variables?
you need to compile as follow:
g++ main.cpp myclass.cpp -o myapp
NOT as follow:
g++ main.cpp -o myapp which will miss global variable declaration in myclass.cpp file.
Your sample code should work just fine on Linux as well as Windows. There shouldn't be any differences between GCC & MSVC with regards to visibility of global variables. I think it's more likely that what you're seeing is a symptom of another problem.
The only thing I can think off off the top of my head that might cause an issue like this would be "screwed up" header files, to use the technical term for it. A common issue in porting code from Windows to Linux is header file case sensitivity. Whereas MSVC won't care if you import MyHeader.h as #include <myheader.h> it will certainly fail on Linux. If you header isn't being included, the compiler would miss the extern declaration and might result in the error you're seeing.