Undefined reference to как исправить

Your linkage consumes libraries before the object files that refer to them

  • You are trying to compile and link your program with the GCC toolchain.
  • Your linkage specifies all of the necessary libraries and library search paths
  • If libfoo depends on libbar, then your linkage correctly puts libfoo before libbar.
  • Your linkage fails with undefined reference to something errors.
  • But all the undefined somethings are declared in the header files you have
    #included and are in fact defined in the libraries that you are linking.

Examples are in C. They could equally well be C++

A minimal example involving a static library you built yourself

my_lib.c

#include "my_lib.h"
#include <stdio.h>

void hw(void)
{
    puts("Hello World");
}

my_lib.h

#ifndef MY_LIB_H
#define MT_LIB_H

extern void hw(void);

#endif

eg1.c

#include <my_lib.h>

int main()
{
    hw();
    return 0;
}

You build your static library:

$ gcc -c -o my_lib.o my_lib.c
$ ar rcs libmy_lib.a my_lib.o

You compile your program:

$ gcc -I. -c -o eg1.o eg1.c

You try to link it with libmy_lib.a and fail:

$ gcc -o eg1 -L. -lmy_lib eg1.o 
eg1.o: In function `main':
eg1.c:(.text+0x5): undefined reference to `hw'
collect2: error: ld returned 1 exit status

The same result if you compile and link in one step, like:

$ gcc -o eg1 -I. -L. -lmy_lib eg1.c
/tmp/ccQk1tvs.o: In function `main':
eg1.c:(.text+0x5): undefined reference to `hw'
collect2: error: ld returned 1 exit status

A minimal example involving a shared system library, the compression library libz

eg2.c

#include <zlib.h>
#include <stdio.h>

int main()
{
    printf("%sn",zlibVersion());
    return 0;
}

Compile your program:

$ gcc -c -o eg2.o eg2.c

Try to link your program with libz and fail:

$ gcc -o eg2 -lz eg2.o 
eg2.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'
collect2: error: ld returned 1 exit status

Same if you compile and link in one go:

$ gcc -o eg2 -I. -lz eg2.c
/tmp/ccxCiGn7.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'
collect2: error: ld returned 1 exit status

And a variation on example 2 involving pkg-config:

$ gcc -o eg2 $(pkg-config --libs zlib) eg2.o 
eg2.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'

What are you doing wrong?

In the sequence of object files and libraries you want to link to make your
program, you are placing the libraries before the object files that refer to
them. You need to place the libraries after the object files that refer
to them.

Link example 1 correctly:

$ gcc -o eg1 eg1.o -L. -lmy_lib

Success:

$ ./eg1 
Hello World

Link example 2 correctly:

$ gcc -o eg2 eg2.o -lz

Success:

$ ./eg2 
1.2.8

Link the example 2 pkg-config variation correctly:

$ gcc -o eg2 eg2.o $(pkg-config --libs zlib) 
$ ./eg2
1.2.8

The explanation

Reading is optional from here on.

By default, a linkage command generated by GCC, on your distro,
consumes the files in the linkage from left to right in
commandline sequence. When it finds that a file refers to something
and does not contain a definition for it, to will search for a definition
in files further to the right. If it eventually finds a definition, the
reference is resolved. If any references remain unresolved at the end,
the linkage fails: the linker does not search backwards.

First, example 1, with static library my_lib.a

A static library is an indexed archive of object files. When the linker
finds -lmy_lib in the linkage sequence and figures out that this refers
to the static library ./libmy_lib.a, it wants to know whether your program
needs any of the object files in libmy_lib.a.

There is only object file in libmy_lib.a, namely my_lib.o, and there’s only one thing defined
in my_lib.o, namely the function hw.

The linker will decide that your program needs my_lib.o if and only if it already knows that
your program refers to hw, in one or more of the object files it has already
added to the program, and that none of the object files it has already added
contains a definition for hw.

If that is true, then the linker will extract a copy of my_lib.o from the library and
add it to your program. Then, your program contains a definition for hw, so
its references to hw are resolved.

When you try to link the program like:

$ gcc -o eg1 -L. -lmy_lib eg1.o

the linker has not added eg1.o to the program when it sees
-lmy_lib. Because at that point, it has not seen eg1.o.
Your program does not yet make any references to hw: it
does not yet make any references at all, because all the references it makes
are in eg1.o.

So the linker does not add my_lib.o to the program and has no further
use for libmy_lib.a.

Next, it finds eg1.o, and adds it to be program. An object file in the
linkage sequence is always added to the program. Now, the program makes
a reference to hw, and does not contain a definition of hw; but
there is nothing left in the linkage sequence that could provide the missing
definition. The reference to hw ends up unresolved, and the linkage fails.

Second, example 2, with shared library libz

A shared library isn’t an archive of object files or anything like it. It’s
much more like a program that doesn’t have a main function and
instead exposes multiple other symbols that it defines, so that other
programs can use them at runtime.

Many Linux distros today configure their GCC toolchain so that its language drivers (gcc,g++,gfortran etc)
instruct the system linker (ld) to link shared libraries on an as-needed basis.
You have got one of those distros.

This means that when the linker finds -lz in the linkage sequence, and figures out that this refers
to the shared library (say) /usr/lib/x86_64-linux-gnu/libz.so, it wants to know whether any references that it has added to your program that aren’t yet defined have definitions that are exported by libz

If that is true, then the linker will not copy any chunks out of libz and
add them to your program; instead, it will just doctor the code of your program
so that:-

  • At runtime, the system program loader will load a copy of libz into the
    same process as your program whenever it loads a copy of your program, to run it.

  • At runtime, whenever your program refers to something that is defined in
    libz, that reference uses the definition exported by the copy of libz in
    the same process.

Your program wants to refer to just one thing that has a definition exported by libz,
namely the function zlibVersion, which is referred to just once, in eg2.c.
If the linker adds that reference to your program, and then finds the definition
exported by libz, the reference is resolved

But when you try to link the program like:

gcc -o eg2 -lz eg2.o

the order of events is wrong in just the same way as with example 1.
At the point when the linker finds -lz, there are no references to anything
in the program: they are all in eg2.o, which has not yet been seen. So the
linker decides it has no use for libz. When it reaches eg2.o, adds it to the program,
and then has undefined reference to zlibVersion, the linkage sequence is finished;
that reference is unresolved, and the linkage fails.

Lastly, the pkg-config variation of example 2 has a now obvious explanation.
After shell-expansion:

gcc -o eg2 $(pkg-config --libs zlib) eg2.o

becomes:

gcc -o eg2 -lz eg2.o

which is just example 2 again.

I can reproduce the problem in example 1, but not in example 2

The linkage:

gcc -o eg2 -lz eg2.o

works just fine for you!

(Or: That linkage worked fine for you on, say, Fedora 23, but fails on Ubuntu 16.04)

That’s because the distro on which the linkage works is one of the ones that
does not configure its GCC toolchain to link shared libraries as-needed.

Back in the day, it was normal for unix-like systems to link static and shared
libraries by different rules. Static libraries in a linkage sequence were linked
on the as-needed basis explained in example 1, but shared libraries were linked unconditionally.

This behaviour is economical at linktime because the linker doesn’t have to ponder
whether a shared library is needed by the program: if it’s a shared library,
link it. And most libraries in most linkages are shared libraries. But there are disadvantages too:-

  • It is uneconomical at runtime, because it can cause shared libraries to be
    loaded along with a program even if doesn’t need them.

  • The different linkage rules for static and shared libraries can be confusing
    to inexpert programmers, who may not know whether -lfoo in their linkage
    is going to resolve to /some/where/libfoo.a or to /some/where/libfoo.so,
    and might not understand the difference between shared and static libraries
    anyway.

This trade-off has led to the schismatic situation today. Some distros have
changed their GCC linkage rules for shared libraries so that the as-needed
principle applies for all libraries. Some distros have stuck with the old
way.

Why do I still get this problem even if I compile-and-link at the same time?

If I just do:

$ gcc -o eg1 -I. -L. -lmy_lib eg1.c

surely gcc has to compile eg1.c first, and then link the resulting
object file with libmy_lib.a. So how can it not know that object file
is needed when it’s doing the linking?

Because compiling and linking with a single command does not change the
order of the linkage sequence.

When you run the command above, gcc figures out that you want compilation +
linkage. So behind the scenes, it generates a compilation command, and runs
it, then generates a linkage command, and runs it, as if you had run the
two commands:

$ gcc -I. -c -o eg1.o eg1.c
$ gcc -o eg1 -L. -lmy_lib eg1.o

So the linkage fails just as it does if you do run those two commands. The
only difference you notice in the failure is that gcc has generated a
temporary object file in the compile + link case, because you’re not telling it
to use eg1.o. We see:

/tmp/ccQk1tvs.o: In function `main'

instead of:

eg1.o: In function `main':

See also

The order in which interdependent linked libraries are specified is wrong

Putting interdependent libraries in the wrong order is just one way
in which you can get files that need definitions of things coming
later in the linkage than the files that provide the definitions. Putting libraries before the
object files that refer to them is another way of making the same mistake.

После подключения initial.cpp в main к сожалению выдало вот этот перечень ошибок. Спасибо за догадку

Кликните здесь для просмотра всего текста

||=== Build: Debug in fr (compiler: GNU GCC Compiler) ===|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/klass.h|5|error: redefinition of ‘class Book’|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/klass.h|5|error: previous definition of ‘class Book’|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp||In member function ‘void Book::set_name(std::string)’:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|error: no match for ‘operator<=’ (operand types are ‘std::string {aka std::basic_string<char>}’ and ‘int’)|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|note: candidates are:|
/usr/include/c++/4.8/bits/stl_pair.h|239|note: template<class _T1, class _T2> bool std::operator<=(const std:air<_T1, _T2>&, const std:air<_T1, _T2>&)|
/usr/include/c++/4.8/bits/stl_pair.h|239|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const std:air<_T1, _T2>’|
/usr/include/c++/4.8/bits/stl_iterator.h|315|note: template<class _Iterator> bool std::operator<=(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)|
/usr/include/c++/4.8/bits/stl_iterator.h|315|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const std::reverse_iterator<_Iterator>’|
/usr/include/c++/4.8/bits/stl_iterator.h|365|note: template<class _IteratorL, class _IteratorR> bool std::operator<=(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_IteratorR>&)|
/usr/include/c++/4.8/bits/stl_iterator.h|365|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const std::reverse_iterator<_Iterator>’|
/usr/include/c++/4.8/bits/basic_string.h|2643|note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<=(const std::basic_string<_CharT, _Traits, _Alloc>&, const std::basic_string<_CharT, _Traits, _Alloc>&)|
/usr/include/c++/4.8/bits/basic_string.h|2643|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|note: mismatched types ‘const std::basic_string<_CharT, _Traits, _Alloc>’ and ‘int’|
/usr/include/c++/4.8/bits/basic_string.h|2655|note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<=(const std::basic_string<_CharT, _Traits, _Alloc>&, const _CharT*)|
/usr/include/c++/4.8/bits/basic_string.h|2655|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|note: mismatched types ‘const _CharT*’ and ‘int’|
/usr/include/c++/4.8/bits/basic_string.h|2667|note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<=(const _CharT*, const std::basic_string<_CharT, _Traits, _Alloc>&)|
/usr/include/c++/4.8/bits/basic_string.h|2667|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|note: mismatched types ‘const _CharT*’ and ‘std::basic_string<char>’|
/usr/include/c++/4.8/bits/stl_iterator.h|860|note: template<class _Iterator, class _Container> bool __gnu_cxx::operator<=(const __gnu_cxx::__normal_iterator<_Iterator, _Container>&, const __gnu_cxx::__normal_iterator<_Iterator, _Container>&)|
/usr/include/c++/4.8/bits/stl_iterator.h|860|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const __gnu_cxx::__normal_iterator<_Iterator, _Container>’|
/usr/include/c++/4.8/bits/stl_iterator.h|854|note: template<class _IteratorL, class _IteratorR, class _Container> bool __gnu_cxx::operator<=(const __gnu_cxx::__normal_iterator<_IteratorL, _Container>&, const __gnu_cxx::__normal_iterator<_IteratorR, _Container>&)|
/usr/include/c++/4.8/bits/stl_iterator.h|854|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|13|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const __gnu_cxx::__normal_iterator<_IteratorL, _Container>’|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|error: no match for ‘operator>’ (operand types are ‘std::string {aka std::basic_string<char>}’ and ‘int’)|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|note: candidates are:|
/usr/include/c++/4.8/bits/stl_pair.h|233|note: template<class _T1, class _T2> bool std::operator>(const std:air<_T1, _T2>&, const std:air<_T1, _T2>&)|
/usr/include/c++/4.8/bits/stl_pair.h|233|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const std:air<_T1, _T2>’|
/usr/include/c++/4.8/bits/stl_iterator.h|309|note: template<class _Iterator> bool std::operator>(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)|
/usr/include/c++/4.8/bits/stl_iterator.h|309|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const std::reverse_iterator<_Iterator>’|
/usr/include/c++/4.8/bits/stl_iterator.h|359|note: template<class _IteratorL, class _IteratorR> bool std::operator>(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_IteratorR>&)|
/usr/include/c++/4.8/bits/stl_iterator.h|359|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const std::reverse_iterator<_Iterator>’|
/usr/include/c++/4.8/bits/basic_string.h|2606|note: template<class _CharT, class _Traits, class _Alloc> bool std::operator>(const std::basic_string<_CharT, _Traits, _Alloc>&, const std::basic_string<_CharT, _Traits, _Alloc>&)|
/usr/include/c++/4.8/bits/basic_string.h|2606|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|note: mismatched types ‘const std::basic_string<_CharT, _Traits, _Alloc>’ and ‘int’|
/usr/include/c++/4.8/bits/basic_string.h|2618|note: template<class _CharT, class _Traits, class _Alloc> bool std::operator>(const std::basic_string<_CharT, _Traits, _Alloc>&, const _CharT*)|
/usr/include/c++/4.8/bits/basic_string.h|2618|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|note: mismatched types ‘const _CharT*’ and ‘int’|
/usr/include/c++/4.8/bits/basic_string.h|2630|note: template<class _CharT, class _Traits, class _Alloc> bool std::operator>(const _CharT*, const std::basic_string<_CharT, _Traits, _Alloc>&)|
/usr/include/c++/4.8/bits/basic_string.h|2630|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|note: mismatched types ‘const _CharT*’ and ‘std::basic_string<char>’|
/usr/include/c++/4.8/bits/stl_iterator.h|848|note: template<class _Iterator, class _Container> bool __gnu_cxx::operator>(const __gnu_cxx::__normal_iterator<_Iterator, _Container>&, const __gnu_cxx::__normal_iterator<_Iterator, _Container>&)|
/usr/include/c++/4.8/bits/stl_iterator.h|848|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const __gnu_cxx::__normal_iterator<_Iterator, _Container>’|
/usr/include/c++/4.8/bits/stl_iterator.h|842|note: template<class _IteratorL, class _IteratorR, class _Container> bool __gnu_cxx::operator>(const __gnu_cxx::__normal_iterator<_IteratorL, _Container>&, const __gnu_cxx::__normal_iterator<_IteratorR, _Container>&)|
/usr/include/c++/4.8/bits/stl_iterator.h|842|note: template argument deduction/substitution failed:|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|15|note: ‘std::string {aka std::basic_string<char>}’ is not derived from ‘const __gnu_cxx::__normal_iterator<_IteratorL, _Container>’|
/media/skeptik/f0de2eb3-29cd-4397-9bc1-1a03d896461b/skeptik/C++/fr/initial.cpp|17|error: expected ‘;’ before ‘cout’|
||=== Build failed: 5 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Добавлено через 7 минут
MrCold

Да, если в названии не больше 10 символов, сохраняется в переменную.
Если больше 10 символов — записывает в переменную с 0 по 10 символ.



0



Добрый день! Получаю вот такие ошибки компилятора:

/tmp/cc6E8ltA.o: In function `main':
main.cpp:(.text+0x24): undefined reference to `Hero::view(int)'
main.cpp:(.text+0x30): undefined reference to `Hero::show()'
main.cpp:(.text+0x41): undefined reference to `Hero::view(int)'
main.cpp:(.text+0x4d): undefined reference to `Hero::show()'
collect2: error: ld returned 1 exit status

main.cpp

#include <iostream>
#include "classes.h"

int main (void)
{
  Hero n1;
  n1.view (1);
  n1.show ();
  Hero n2;
  n2.view (2);
  n2.show ();
  return 0;
}

classes.h

class Hero{
  private:
    int life_;

    char view_;
  public:
    void view (int); 
    void show (void);
};

methods.cpp

#include "classes.h"
#include <cstring>

void Hero::view (int value)
{
  if (value == 1)
  {
    strcpy (view_, "Hunter");
    life_ = 10000;
  }
  if (value == 2)
  {
    strcpy (view_, "Soldier");
    life_ = 600;
  }
}

void Hero::show ()
{
  std::cout << "View: " << view_ << std::endl
            << "Life: " << life_ << std::endl;
}

Что не так?

C undefined reference errorC++ undefined reference is a linker error that often may come up when the function is declared but not implemented. These errors are usually partly identified by the linker error messages, but a programmer still needs to manually investigate the code, build system or linked libraries.

In the following article, we will mostly focus on the causes that occur in source code rather than in the build process or during library linkage. Find out the details in the upcoming paragraphs.

Contents

  • What Does Undefined Reference Mean in C++?
    • – Code:
    • – Program Output:
  • How To Fix Undefined Reference in C++
    • – Code:
    • – Program Output:
  • Undefined Reference in Programs Without Main Function
    • – Code:
    • – Program Output:
  • Tracking Down Undefined Reference Errors in Derived Classes
    • – Code:
    • – Program Output:
  • Key Takeaways

What Does Undefined Reference Mean in C++?

Undefined reference means that the linker is not able to find a symbol definition in any object file, but it’s still referenced. Undefined reference error is not C++ language-specific but rather a result of the executable program generation process. The latter process roughly works as follows: the compiler translates the human-readable source code into machine instructions and generates objects files. Then, the linker will try to combine all needed object files to generate an executable program or, alternatively, a library.

The linker itself can be considered as standalone software which deals with the object files and symbols defined in them. Symbols represent different entities like global variables, function names, member function names, etc.

In the following example, we have a SampleClass class that declares a constructor member. The only thing missing is that no definition is provided. So, if we try to build this program, the linker will throw an undefined reference error related to SampleClass::SampleClass() symbol.

– Code:

#include <iostream>
using std::string;
class SampleClass {private:
string user;
string name;
int number;public:
SampleClass();
};
int main() {
SampleClass sp1;
return 0;
}

– Program Output:

/usr/bin/ld: /tmp/ccoWSfKj.o: in function `main’:
tmp.cpp:(.text+0x24): undefined reference to `SampleClass::SampleClass()’
/usr/bin/ld: tmp.cpp:(.text+0x35): undefined reference to `SampleClass::~SampleClass()’
collect2: error: ld returned 1 exit status

How To Fix Undefined Reference in C++

You can fix undefined reference in C++ by investigating the linker error messages and then providing the missing definition for the given symbols. Note that not all linker errors are undefined references, and the same programmer error does not cause all undefined reference errors.

However, it’s more likely to be function-related when it’s declared somewhere, but the definition is nowhere to be found. The issue in the previous example code can be very easily traced as the program is very small.

On the other hand, huge codebases can yield undefined reference errors that may be harder to track down. The next code snippet tries to demonstrate a similar scenario which generates quite a large output of errors from the linker. Notice that the error comes from the polymorphic class SampleClass, which declares PrintContents() as a virtual function.

However, it does not even include empty curly braces to denote the body and qualify for the definition, resulting in an undefined reference error.

– Code:

#include <iostream>
#include <utility>
#include <sstream>using std::cout;
using std::endl;
using std::string;
class SampleClass {
private:
string user;
string name;
int number;public:
SampleClass(string  u, string  n, int num) :
user{std::move(u)}, name{std::move(n)}, number{num} {};
SampleClass(string  u, int num) :
user{std::move(u)}, name{“Name”}, number{num} {} ;virtual string PrintContents() const;
string getName() const;
string getUser() const;
int getNumber() const;
};
class DerivedClass : public SampleClass {
string identifier;public:
DerivedClass(string u, string n, int num, std::string id) :
SampleClass(std::move(u), std::move(n), num),
identifier{std::move(id)} {};
string PrintContents() const override;
string getIdentifier() const;
};
string DerivedClass::getIdentifier() const {
return this->identifier;
}
string DerivedClass::PrintContents() const {
std::stringstream ss;
ss << “user: ” << this->getUser()
<< ” name: ” << this->getName()
<< ” number: ” << this->getNumber()
<< ” identifier: ” << this->identifier  << ‘n’;
return ss.str();
}
string SampleClass::getName() const {
return this->name;
}
string SampleClass::getUser() const {
return this->user;
}
int SampleClass::getNumber() const {
return this->number;
}
void print(SampleClass& sp) {
cout << sp.PrintContents();
}
int main() {
auto dc1 = DerivedClass(“it”, “ai”, 5122, “tait”);
print(dc1);
return 0;
}

– Program Output:

/usr/bin/ld: /tmp/cckqLhcA.o: in function `SampleClass::SampleClass(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int)’:

tmp.cpp:(.text._ZN11SampleClassC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_i[_ZN11SampleClassC5ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_i]+0x1f): undefined reference to `vtable for SampleClass’
/usr/bin/ld: /tmp/cckqLhcA.o: in function `SampleClass::~SampleClass()’:
tmp.cpp:(.text._ZN11SampleClassD2Ev[_ZN11SampleClassD5Ev]+0x13): undefined reference to `vtable for SampleClass’
/usr/bin/ld: /tmp/cckqLhcA.o:(.data.rel.ro._ZTI12DerivedClass[_ZTI12DerivedClass]+0x10): undefined reference to `typeinfo for SampleClass’
collect2: error: ld returned 1 exit status

Undefined Reference in Programs Without Main Function

Undefined reference error can occur if you try to compile the source code file that does not have the main() function. To be more precise, these types of source files will yield linker errors if compiled with the usual compiler arguments.

If you intend to compile a given source file without the main() function, you should pass the special argument to not run the linker stage. The latter is usually achieved with a -c argument to the compiler command (e.g., g++ or clang++ ).

– Code:

#include <iostream>
#include <utility>
#include <sstream>using std::cout;
using std::endl;
using std::string;
class SampleClass {private:
string user;
string name;
int number;public:
SampleClass(string  u, string  n, int num) :
user{std::move(u)}, name{std::move(n)}, number{num} {};
SampleClass(string  u, int num) :
user{std::move(u)}, name{“Name”}, number{num} {} ;
virtual string PrintContents() const;string getName() const;
string getUser() const;
int getNumber() const;
};
class DerivedClass : public SampleClass {
string identifier;
public:
DerivedClass(string u, string n, int num, std::string id) :
SampleClass(std::move(u), std::move(n), num),
identifier{std::move(id)} {};
string PrintContents() const override;
string getIdentifier() const;
};
string DerivedClass::getIdentifier() const {
return this->identifier;
}
string DerivedClass::PrintContents() const {
std::stringstream ss;
ss << “user: ” << this->getUser()
<< ” name: ” << this->getName()
<< ” number: ” << this->getNumber()
<< ” identifier: ” << this->identifier  << ‘n’;
return ss.str();
}
string SampleClass::getName() const {
return this->name;
}
string SampleClass::getUser() const {
return this->user;
}
int SampleClass::getNumber() const {
return this->number;
}
void print(SampleClass& sp) {
cout << sp.PrintContents();
}

– Program Output:

/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/Scrt1.o: in function `_start’:
(.text+0x24): undefined reference to `main’
collect2: error: ld returned 1 exit status

Tracking Down Undefined Reference Errors in Derived Classes

Another useful method to easily track down undefined reference errors in large codebases is enabling compiler warnings. Sometimes these may warn that functions are referenced but never defined. In the following example, the derived class explicitly overrides a virtual function but does not provide an implementation. Note that these types of errors may also be caused when the program build script or file does not include the corresponding source file.

– Code:

#include <iostream>
#include <utility>
#include <sstream>
#include “tmp.h”using std::cout;
using std::endl;
using std::cin;
using std::string;class SampleClass {
private:
string user;
string name;
int number;
public:
SampleClass(string  u, string  n, int num) :
user{std::move(u)}, name{std::move(n)}, number{num} {};
SampleClass(string  u, int num) :
user{std::move(u)}, name{“Name”}, number{num} {} ;
virtual string PrintContents() const { return {}; };string getName() const;
string getUser() const;
int getNumber() const;
};
class DerivedClass : public SampleClass {
string identifier;
public:
DerivedClass(string u, string n, int num, std::string id) :
SampleClass(std::move(u), std::move(n), num),
identifier{std::move(id)} {};
string PrintContents() const override;
string getIdentifier() const;
};
string DerivedClass::getIdentifier() const {
return this->identifier;
}
string SampleClass::getName() const {
return this->name;
}
string SampleClass::getUser() const {
return this->user;
}
int SampleClass::getNumber() const {
return this->number;
}
void print(SampleClass& sp) {
cout << sp.PrintContents();
}
int main() {
auto dc1 = DerivedClass(“it”, “ai”, 5122, “tait”);
print(dc1);
return 0;
}

– Program Output:

/usr/bin/ld: /tmp/ccdcAqfb.o: in function `DerivedClass::DerivedClass(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)’:

tmp.cpp:(.text._ZN12DerivedClassC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_iS5_[_ZN12DerivedClassC5ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_iS5_]+0xa6): undefined reference to `vtable for DerivedClass’
/usr/bin/ld: /tmp/ccdcAqfb.o: in function `DerivedClass::~DerivedClass()’:

tmp.cpp:(.text._ZN12DerivedClassD2Ev[_ZN12DerivedClassD5Ev]+0x13): undefined reference to `vtable for DerivedClass’
collect2: error: ld returned 1 exit status

Key Takeaways

In this article, we covered common reasons that yield an undefined reference to C++ function errors and described several ways to identify them. Here are some key points to bear in mind:

  • Undefined reference error is thrown by the linker rather than the compiler
  • It’s usually caused by the reference to the function that has been declared, but a definition can’t be found
  • Investigate linker error messages which can help to pin down the identifiers that are related to the cause of the problem
  • Don’t run the linker stage on programs that don’t include the main function

How to fix undefined reference in cNow you should be able to move on to some practical problems of analyzing linker errors and fixing them. You are definitely ready to try manually building relatively medium programs with multiple files and investigate possible causes for linker errors.

  • Author
  • Recent Posts

Position is Everything

Your Go-To Resource for Learn & Build: CSS,JavaScript,HTML,PHP,C++ and MYSQL. Meet The Team

Position is Everything

Tutorials > Linux > Fixing the ‘Undefined Reference’ Errors for C/C++ Projects

This tutorial shows how to various problems related to missing symbols in C/C++ projects. We will create a basic project calling the png_create_read_struct() function from the libpng library and will go through common missing setup steps, explaining the errors that will arise.

Before you begin, install VisualGDB 5.4 or later.

  1. Start Visual Studio and locate the VisualGDB Linux Project Wizard:
  2. Pick a name and location for your project:
  3. Press “Create” to launch the VisualGDB-specific part of the wizard. On the first page, pick Create a new project -> Application -> MSBuild:
  4. In this tutorial we will use a cross-toolchain that runs on Windows and builds code for a Linux target and will demonstrate points of failure caused by this configuration. However, most of the steps shown below will work for projects built directly on Linux as well:
  5. Press “Finish” to generate the project. Now we will try calling a function from the libpng library and will go through most possible missing steps that could cause a build-time or run-time error. Add the following code to the main() function and try building the project:

    png_create_read_struct(NULL, NULL, NULL, NULL);

  6. The build will now fail with the following error:

    MissingSymbolDemo.cpp: In function ‘int main(int, char**)’:

    MissingSymbolDemo.cpp:7:5: error: ‘png_create_read_struct’ was not declared in this scope

         png_create_read_struct(NULL, NULL, NULL, NULL);

         ^~~~~~~~~~~~~~~~~~~~~~

  7. You can find out the exact output from GCC by right-clicking on the error message and selecting “Go to Build Log”:
  8. The “‘png_create_read_struct’ was not declared in this scope” error means that the C/C++ compiler does not know the png_create_read_struct symbol. It cannot tell whether it is a function, global function pointer or a preprocessor macro. To resolve this error, the png_create_read_struct() function needs to be declared. A declaration for it would look as follows:

    png_structp png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn);

  9. As it is not practical to copy each function declaration into every source file, most C/C++ libraries provide header files that list all the relevant declarations. You can usually find out the header file name in the documentation and include it into your program as shown below:

    This will be equivalent to copying and pasting the header file contents into your source file.

  10. Including a header file will not search the entire build machine for it. Instead, GCC will only search a few common places (e.g. /usr/include) and the header search directories specified in your project’s settings. In our example, the png.h file is located in toolchain’s /usr/include/libpng directory and won’t be found initially, producing the following error:

    MissingSymbolDemo.cpp:2:10: fatal error: png.h: No such file or directory

    #include <png.h>

              ^~~~~~~

  11. VisualGDB’s will normally search for the missing headers in the nearby directories and will suggest fixing the settings automatically. If you are configuring the project manually, simply locate the header file on your build machine and add its directory to the Include Directories field:Note that if you are using a cross-toolchain, the header must be present in its sysroot directory (e.g. /usr/include/libpng/png.h corresponds to E:sysgccraspberryarm-linux-gnueabihfsysrootusrincludelibpngpng.h). If you are using a cross-toolchain that runs on Windows, you would need to specify the path to the file on the Windows machine (i.e. $(ToolchainDir)arm-linux-gnueabihfsysrootusrincludelibpngpng.h). For convenience, GCC automtaically replaces ‘=’ at the beginning of the path with the sysroot directory, so the correct include directory in this example would be =/usr/include/libpng/png.h (note the ‘=’ at the beginning).
  12. If you build the project now, it will fail with another error:

    C:projectstempMissingSymbolDemo/MissingSymbolDemo.cpp:9: undefined reference to `png_create_read_struct

    Build failed: armlinuxgnueabihfg++.exe exited with code 1

    collect2.exe: error: ld returned 1 exit status

  13. This happens because the png.h file only contains a declaration for the png_create_read_struct() function. I.e. it defines its return type and argument types (letting GCC check them at compile time), but it does not provide an implementation for it. The function implementations are typically located in the static libraries (.a files) or shared libraries (.so files). You can find the correct library name by searching for all .a and .so files that contain the png_create_read_struct text. If you have found several libraries, use the objdump -T <.so file> or objdump -t <.a file> command to list all symbols exported by that library:

    0000e8fc g DF .text 00000024 PNG16_0 png_create_read_struct

    If the symbol you are looking for is listed with a non-zero address (first column), you have found the correct library. Otherwise, that library is importing that symbol, not exporting it.

  14. In this example, the library defining png_create_read_struct() is called libpng.so. You can link it into your project by adding its name (without the lib prefix) to the “Library Names” field, as long as it is located in a standard library directory. If not, you would also need to add the library’s directory to the Library Directories field:
  15. Now you can build the project successfully:If the build still fails, you might be missing an extern “C” clause in the headers. See this tutorial for a detailed step-by-step explanation.
  16. Finally, we will demonstrate a runtime error. Deploy the built program to your target and run “ld <Binary Name>”:
  17. The LDD command will show the shared libraries required by that file. In this tutorial we will move all the libpng* libraries to /usr/lib/arm-linux-gnueabihf/png subdirectory and will show what will happen. Once you have moved the library, start debugging the project with VisualGDB and observe the following error message in the Debug Output:

    /tmp/MissingSymbolDemo: error while loading shared libraries: libpng16.so.16: cannot open shared object file: No such file or directory

    VisualGDB will automatically suggest locating the file on the target:

  18. Locate the libpng16.so library in the directory where you moved it and press “OK”:
  19. This will automatically add the directory of the library to the project’s LD_LIBRARY_PATH variable, so now you will be able to launch it successfully:
  20. If you are running the project manually, simply add the directory of the missing .so file to the LD_LIBRARY_PATH variable as shown below and you will be able to launc it as well:As we have passed NULL to png_create_read_struct() instead of the libpng version number, it will show a warning message. You can eliminate it by passing PNG_LIBPNG_VER_STRING as the first argument to png_create_read_struct().

Понравилась статья? Поделить с друзьями:
  • Ошибка 305 как исправить
  • Как найти на смартфоне диспетчер файлов
  • Как найти американский номер в ватсап
  • Как найти среднее пропорциональное для отрезков
  • Как найти маникюр по картинке