g++ undefined reference to while linking with a custom shared library - c++

I am trying to link my C++ program with a custom shared library. The shared library is written in C, however, I don't think that it should matter. My library is called libfoo.so. Its full path is /home/xyz/customlib/libfoo.so. I've also added /home/xyz/customlib to my LD_LIBRARY_PATH so ld should be able to find it. When I run nm -D libfoo.so, I get:
...
00000000000053a1 T myfunc
000000000000505f T foo
0000000000004ca9 T bar
00000000000051c6 T baz
000000000000527f T myfunc2
...
So I think that my library is correctly compiled. I am trying to link it my c++ file test.cpp by running
g++ -L/home/xyz/customlib -Og -g3 -ggdb -fsanitize=address test.cpp -o test -lfoo
However, I am getting the following errors:
/usr/bin/ld: in function sharedlib_test1()
/home/xyz/test.cpp:11: undefined reference to `myfunc()'
/usr/bin/ld: in function sharedlib_test2()
/home/xyz/test.cpp:33: undefined reference to `foo()'
...
What am I doing wrong? How can I resolve this? Note that I have renamed the files and the shared library as I cannot share the exact file and function names.

As indicated by the comments in the post, it turns out that I was missing the extern "C" in the header file. So in my code, I wrapped my include statement in an extern "C" which solved the issue.
TLDR: The header include in the code should look like:
extern "C" // Import C style functions
{
#include <foo.h>
}

Related

C/C++ linking issue with a very simple setup [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 5 years ago.
I'm getting an "undefined reference" error when trying to compile and link a very simple app that has a dependency on a third-party library.
My main.c looks like this:
#include "ss7cp.h"
/*
extern "C" {
void EINSS7CpMain_CpInit(void);
}
*/
int main() {
EINSS7CpMain_CpInit();
}
The third-party header file has:
#if defined (__cplusplus) || defined (c_plusplus)
extern "C" {
#endif
...
void EINSS7CpMain_CpInit(void);
The definition of this function is in an archive:
$ nm -g /path/to/lib/libsign_64_uthr.a | grep EINSS7CpMain_CpInit
0000000000005ae0 T EINSS7CpMain_CpInit
U EINSS7CpMain_CpInit
U EINSS7CpMain_CpInit
By the "T" above, the function must be defined in the text/code section of one of the libs in the archive.
I'm currently not using a Makefile, but just trying to quickly build this simple app entirely from the command line:
g++ -I/path/to/include -L/path/to/lib -lsign_64_uthr -D__EXTENSIONS__ -DLINUX main.c
(The documentation told me to define both __EXTENSIONS__ and LINUX). The rest of the above is pretty straightforward. What I'm getting is:
/tmp/ccvgmIJ8.o: In function `main':
main.c:(.text+0x5): undefined reference to `EINSS7CpMain_CpInit'
collect2: error: ld returned 1 exit status
I've tried both as a C file (main.c) and C++ file (main.cpp, enabling the extern "C" block), but no difference. (Can I assume g++ decides on C versus C++ just by the file extension?)
I've even just compiled the file (with -c) and took a look at the contents of the resultant main.o object file and saw the text "EINSS7CpMain_CpInit" as it is, unmangled (or maybe that's just a debug symbol?)
What are some diagnostics steps I can take to see what I'm missing? Do I actually need to create a Makefile and split the compile and link steps?
It's been ages since I last did any C/C++ and even back when I did it, I usually wasn't the one who had to create the Makefiles from scratch, so I'm probably missing some very fundamental stuff here...
My best guess would be parameter ordering, the lib should come after the source file:
g++ -I/path/to/include -D__EXTENSIONS__ -DLINUX main.c -L/path/to/lib -lsign_64_uthr

Symbol present in .so, compiled .o references it but link fails

I have a strange problem linking c++ with Leptonica. Normal function invocation works fine, but I need functions from the library which were originally not exposed in the .so library. So I have searched for the two interesting functions in the source, removed the static keyword, so they look similar to exposed ones. I have remade the full library after a make clean. The .so file looks OK:
nm liblept.so.5.0.0
...
000000000009d010 T dewarpGetMeanVerticals
000000000009d160 T dewarpGetTextlineCenters
000000000009d8f0 T dewarpIsLineCoverageValid
Compiling to .o file and observing it:
g++ -c -std=c++11 -I../leptonica/src/src/ preproc.cpp -L../leptonica/src/.libs/ -llept -o preproc
nm preproc
...
U dewarpGetMeanVerticals
U dewarpIsLineCoverageValid
While the same compiling without -c flag results in
/tmp/ccCPqS1R.o: In function `_dewarpGetTextlineCenters(Pix*, int)':
preproc.cpp:(.text+0x3d5): undefined reference to `dewarpGetMeanVerticals'
/tmp/ccCPqS1R.o: In function `_dewarpBuildPageModel(L_Dewarp*, char const*)':
preproc.cpp:(.text+0x81d): undefined reference to `dewarpIsLineCoverageValid'
collect2: error: ld returned 1 exit status
What do I do wrong?
Thank you in advance: Balázs
I think you may need the extern "C" keywords around those functions if you want to expose them in the so. Since the names don't appear to be mangled by the C++ compiler in the .so this is probably not the case.
I notice that you're showing us what's in liblept.so.5.0.0 and linking against liblept.so. Is it possible that you need to update a symbolic link so that you're linking against the correct .so file?

Octave sample code failing to compile in g++?

I'm attempting to get the Octave C++ code here to compile in g++ (Ubuntu/Linaro 4.6.4-1ubuntu1~12.04) 4.6.4).
This trimmed version of the above will compile in g++:
#include <iostream>
#include <octave/oct.h>
using namespace std;
int main() {
// Matrix L=Matrix(2,2);
return 0;
}
but if I unremark out the line Matrix L=Matrix(2,2); then compile with g++ temp.cpp it gives the error message:
/tmp/ccTa3Am5.o: In function `Array2<double>::~Array2()':
temp.cpp:(.text._ZN6Array2IdED2Ev[_ZN6Array2IdED5Ev]+0x1f): undefined reference to `Array<double>::~Array()'
/tmp/ccTa3Am5.o: In function `Array<double>::Array(dim_vector const&)':
temp.cpp:(.text._ZN5ArrayIdEC2ERK10dim_vector[_ZN5ArrayIdEC5ERK10dim_vector]+0x26): undefined reference to `Array<double>::get_size(dim_vector const&)'
/tmp/ccTa3Am5.o:(.rodata._ZTV5ArrayIdE[vtable for Array<double>]+0x10): undefined reference to `Array<double>::~Array()'
/tmp/ccTa3Am5.o:(.rodata._ZTV5ArrayIdE[vtable for Array<double>]+0x18): undefined reference to `Array<double>::~Array()'
collect2: ld returned 1 exit status
I'm unsure why. Perhaps I'm missing an #include, perhaps I don't have an appropriate file installed, perhaps I'm not linking to the appropriate library, or perhaps I'm misusing Octave in some way.
Question: Why is this failing to compile? How can I fix it?
It compiles fine if I use mkoctfile --link-stand-alone temp.cpp as indicated at the above site, however, I'd like to use g++ if possible, since I eventually want to be able to call Octave functions from another program I've written in C++.
As indicated in my comment a simple example can be found in this Howto. So in your case a simple way to achieve compilation will be creating a makefile as follows:
makefile:
all: temp
clean:
-rm temp.o temp
temp: temp.o
mkoctfile --link-stand-alone -o temp temp.o
temp.o: temp.cpp
g++ -c -I$(OCTAVE_INCLUDE)
-I$(OCTAVE_INCLUDE)octave -o temp.o temp.cpp
$(OCTAVE_INCLUDE) is an environment variable that should be set to your octave include path (e.g. /usr/include/octave-x.x.xx). Then you can simply compile and link your test application using the command make all.
You need to link to the octave library. If the library is octave.a:
g++ -loctave temp.cpp
Add the library directories to your link command:
your-local-path\octave-x.x.xx\lib\
your-local-path\octave-x.x.xx\lib\octave\x.x.xx\
mkoctfile -L"\your-path\octave-x.x.xx\lib" -L"\your-path\octave-x.x.x\lib\octave\x.x.xx" --link-stand-alone temp.cpp
For cxx11 linker errors:
Converting std::__cxx11::string to std::string
"If you get linker errors about undefined references to symbols that involve types in the std::__cxx11 namespace or the tag [abi:cxx11] then it probably indicates that you are trying to link together object files that were compiled with different values for the _GLIBCXX_USE_CXX11_ABI macro. This commonly happens when linking to a third-party library that was compiled with an older version of GCC."
Defining the following macro before including any standard library headers should fix your problem:
#define _GLIBCXX_USE_CXX11_ABI 0

Link dynamic shared library in Linux - Undefined reference to function

I know there are many questions related to shared libraries on Linux but maybe because I'm tired of having a hard day trying to create a simple dynamic library on Linux (on Windows it would have taken less than 10 minutes) I can't find what happens in this case.
So, I am trying to create a library to be linked at build-time and used at run-time (not a static library, not a library to be embedded into the executable, in other words). For now it contains a simple function. These are my files:
1.
// gugulibrary.cpp
// This is where my function is doing its job
#include "gugulibrary.h"
namespace GuGu {
void SayHello() {
puts("Hello!");
}
}
2.
// gugulibrary.h
// This is where I declare my shared functions
#include <stdio.h>
namespace Gugu {
void SayHello();
}
3.
// guguapp.cpp
// This is the executable using the library
#include "gugulibrary.h"
int main() {
GuGu::SayHello();
return 0;
}
This is how I try to build my project (and I think this is what is wrong):
gcc -Wall -s -O2 -fPIC -c gugulibrary.cpp -o gugulibrary.o
ld -shared -o bin/libGugu.so gugulibrary.o
gcc -Wall -s -O2 guguapp.cpp -o bin/GuGu -ldl
export LD_LIBRARY_PATH=bin
This is saved as a .sh file which I click and execute in a terminal. The error I get when trying to link the library is this:
/tmp/ccG05CQD.o: In function `main':
guguapp.cpp:(.text.startup+0x7): undefined reference to `SayHello'
collect2: ld returned 1 exit status
And this is where I am lost. I want the library to sit in the same folder as the executable for now and maybe I need some symbols/definitions file or something, which I don't know how to create.
Thanks for your help!
In your C++ file, GuGu::SayHello is declared as a C++ symbol. In your header, you are wrapping it in an extern "C" block. This is actually undefined, as you aren't allowed to use C++ syntax (namespace) in that context. But my guess is that what the compiler is doing is ignoring the namespace and generating a C symbol name of "SayHello". Obviously such a function was never defined by your library. Take out the extern "C" bits, because your API as defined cannot be used from C anyway.
You are inconsistent with your GuGu, there are also Gugu's running around, this needs to be made consistent, then it works (At least on my computer are some Gugu's now)

boost test - 'undefined reference' errors

I have two simple files:
runner.cpp:
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>
and test1.cpp:
#define BOOST_TEST_DYN_LINK
#ifdef STAND_ALONE
# define BOOST_TEST_MODULE Main
#endif
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE( Foo)
BOOST_AUTO_TEST_CASE( TestSomething )
{
BOOST_CHECK( true );
}
BOOST_AUTO_TEST_SUITE_END()
To compile, I'm using:
$ g++ -I/e/code/boost_1_52_0 -o runner -lboost_unit_test_framework runner.cpp test1.cpp
I get the following error:
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0x8c): multiple definition of `main'
c:/pdev/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.2/../../../libboost_unit_test_framework.a(unit_test_main.o):unit_test_main.cpp:(.text.startup+0x0): first defined here
c:/pdev/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.2/../../../libboost_unit_test_framework.a(unit_test_main.o):unit_test_main.cpp:(.text.startup+0x14): undefined reference to `init_unit_test_suite(int, char**)'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0x52): undefined reference to `_imp___ZN5boost9unit_test9framework17master_test_suiteEv'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0xb0): undefined reference to `_imp___ZN5boost9unit_test14unit_test_mainEPFbvEiPPc'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test13test_observerD2Ev[__ZN5boost9unit_test13test_observerD2Ev]+0xe): undefined reference to `_imp___ZTVN5boost9unit_test13test_observerE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test13test_observerC2Ev[__ZN5boost9unit_test13test_observerC2Ev]+0xe): undefined reference to `_imp___ZTVN5boost9unit_test13test_observerE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test15unit_test_log_tC1Ev[__ZN5boost9unit_test15unit_test_log_tC1Ev]+0x22): undefined reference to `_imp___ZTVN5boost9unit_test15unit_test_log_tE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x88): undefined reference to `_imp___ZN5boost9unit_test15unit_test_log_t14set_checkpointENS0_13basic_cstringIKcEEjS4_'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x136): undefined reference to `_imp___ZN5boost10test_tools9tt_detail10check_implERKNS0_16predicate_resultERKNS_9unit_test12lazy_ostreamENS5_13basic_cstringIKcEEjNS1_10tool_levelENS1_10check_typeEjz'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x21d): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1ENS0_13basic_cstringIKcEE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x284): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1EPNS0_9test_caseEm'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x2a4): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1Ei'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text$_ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE[__ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE]+0x1d): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24normalize_test_case_nameENS0_13basic_cstringIKcEE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text$_ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE[__ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE]+0x5b): undefined reference to `_imp___ZN5boost9unit_test9test_caseC1ENS0_13basic_cstringIKcEERKNS0_9callback0INS0_9ut_detail6unusedEEE'
collect2.exe: error: ld returned 1 exit status
I'm using g++ 4.7.2 on MinGW, with boost 1.52.0.
I get the same errors when only trying to compile test1.cpp - except the "multiple main definition" one.
I perused the official documentation for quite a while, but its scarce on details regarding linking options. When I compiled the boost libs, besides unit_test_framework, I also got prg_exec_monitor and test_exec_monitor; perhaps I should link these somehow ? I tried many combinations, but all resulted in some kind of undefined reference linker error.
Complete list of boost generated libraries - I have them all in the project root:
libboost_prg_exec_monitor-mgw47-mt-1_52.a
libboost_prg_exec_monitor-mgw47-mt-1_52.dll
libboost_prg_exec_monitor-mgw47-mt-1_52.dll.a
libboost_prg_exec_monitor-mgw47-mt-d-1_52.a
libboost_prg_exec_monitor-mgw47-mt-d-1_52.dll
libboost_prg_exec_monitor-mgw47-mt-d-1_52.dll.a
libboost_test_exec_monitor-mgw47-mt-1_52.a
libboost_test_exec_monitor-mgw47-mt-d-1_52.a
libboost_unit_test_framework-mgw47-mt-1_52.a
libboost_unit_test_framework-mgw47-mt-1_52.dll
libboost_unit_test_framework-mgw47-mt-1_52.dll.a
libboost_unit_test_framework-mgw47-mt-d-1_52.a
libboost_unit_test_framework-mgw47-mt-d-1_52.dll
libboost_unit_test_framework-mgw47-mt-d-1_52.dll.a
With help from #llonesmiz, a number of issues were identified.
1. Libraries need to be specified after objects and sources which use them.
As described here:
The traditional behavior of linkers is to search for external functions from
left to right in the libraries specified on the command line. This means that a
library containing the definition of a function should appear after any source
files or object files which use it. This includes libraries specified with the
short-cut -l option, as shown in the following command:
$ gcc -Wall calc.c -lm -o calc (correct order)
With some linkers the opposite ordering (placing the -lm option before the file
which uses it) would result in an error,
$ cc -Wall -lm calc.c -o calc (incorrect order)
main.o: In function 'main':
main.o(.text+0xf): undefined reference to 'sqrt'
because there is no library or object file containing sqrt after ‘calc.c’. The
option -lm should appear after the file ‘calc.c’
2. Library paths should be explicitly specified.
If no lib paths are specified, the linker might look for the libs in a series
of default folders, thus loading a different library then intended. This is what
happened in my case - I wanted to link boost_unit_test_framework, but did not
specify a path because I assumed the linker would look in the current folder.
That's what happens at runtime, after all - if the dll is in the same folder
with the exe, it will find it.
I found it a little bit strange the linker would find the lib, since it was
named ibboost_unit_test_framework-mgw47-mt-1_52.dll. When I tried to link to
a non-existing lib, the linker complained though, so I assumed this isn't an
issue, and MinGW 's linker ignores those suffixes.
After some more research, I found this article about MinGW library paths.
The folders MinGW searches for libs can be found in the output of gcc -print-search-dirs.
The article also contains some bash magic to make sense of that output:
gcc -print-search-dirs | sed '/^lib/b 1;d;:1;s,/[^/.][^/]*/\.\./,/,;t 1;s,:[^=]*=,:;,;s,;,; ,g' | tr \; \\012 | grep -v '^ */'
This will print a nice list of those folders. gcc will not, by default,
look in the current directory for libs. I looked in each of them, and found the
lib that was being loaded - libboost_unit_test_framework.a, a static lib.
This brings into light another issue worth mentioning:
3. Static versus dynamic linking
I did not specify whether I want boost_unit_test_framework linked statically or dynamically.
In this case, gcc prefers dynamic linking:
Because of these advantages gcc compiles programs to use shared libraries by
default on most systems, if they are available. Whenever a static library
‘libNAME.a’ would be used for linking with the option -lNAME the compiler
first checks for an alternative shared library with the same name and a ‘.so’
extension.
(so is the extension for dynamic libraries on Unix - on Windows, the equivalent is dll.)
So, what happened is that gcc looked for libboost_unit_test_framework.dll
in all it's default folders, but couldn't find it. Then it looked for
libboost_unit_test_framework.a, and statically linked that. This resulted in
linking errors because the sources have #define BOOST_TEST_DYN_LINK, and
therefore expect to have the lib dynamically linked.
To enforce static or dynamic linking, the -Wl,-Bstatic and -Wl,-Bdynamic
linker options come into play, described here.
If I tell the linker that I want dynamic linking:
$ g++ -I/e/code/boost_1_52_0 runner.cpp test1.cpp -o runner -Wl,Bdynamic -lboost_unit_test_framework
This will fail, because the linker will not be able to find the dll.
4.Summary
The issues were:
libraries where specified before the sources which used them
the lib path wasn't specified
the type of linking wasn't specified
the name of the library was not correct
Final, working command:
$ g++ -I/e/code/boost_1_52_0 -o runner runner.cpp test1.cpp -L. -Wl,-Bdynamic -lboost_unit_test_framework-mgw47-mt-1_52