undefined reference in linking against C++ library - c++

I write a C++ library and when linking against the library the symbols in it cannot be found. Here's what I've got:
a.cpp:
void zak()
{
}
test.cpp:
extern void zak();
int main(int argc, const char ** argv)
{
zak();
}
Makefile:
all:
g++ -c -o a.o a.cpp
ar r libzak.a a.o
g++ -L. -lzak test.cpp -o test
Here is what make says on my (Linux Mint 13) box:
g++ -c -o a.o a.cpp
ar r libzak.a a.o
g++ -L. -lzak test.cpp -o test
/tmp/ccC4cnLV.o: In function `main':
test.cpp:(.text+0x7): undefined reference to `zak()'
collect2: error: ld returned 1 exit status
make: *** [all] Error 1
I am sure I am missing something obvious, but what is it?

Link order matters. Put -lzak after test.cpp on the link line.

I think that -l is for shared libraries (.so). Try this: g++ libzak.a test.cpp -o test

Related

Makefile for linking an extern global

I'm trying to use the g_struct variable that's defined in struct.cpp and declared in struct.hpp inside the test.cpp, but the linking fails. Why is that?
// test.cpp
#include "struct.hpp"
int main(void)
{
g_struct.a = 1;
return 0;
}
// struct.cpp
#include "struct.hpp"
Struct g_struct;
// struct.hpp
#pragma once
struct Struct {
int a;
};
extern Struct g_struct;
# Makefile
CC = g++
all: struct.o test
test: test.cpp
$(CC) -o test test.cpp
struct.o: struct.cpp
$(CC) -c -o struct.o struct.cpp
.PHONY: clean
clean:
rm -f *.o test
Linking error:
$ make
g++ -c -o struct.o struct.cpp
g++ -o test test.cpp
/tmp/ccgSoJhd.o: In function `main':
test.cpp:(.text+0xd): undefined reference to `g_struct'
collect2: error: ld returned 1 exit status
Makefile:6: recipe for target 'test' failed
make: *** [test] Error 1
If I link without the -c flag, I get:
$ make
g++ -o struct.o struct.cpp
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:9: recipe for target 'struct.o' failed
make: *** [struct.o] Error 1
You have to link struct.o, which has Struct g_struct;.
test: test.cpp
$(CC) -o test test.cpp struct.o

makefile error lib/Scrt1.o undefined reference to `main'

I glanced tons of similar topic, but I couldn't recognize solution
I tried mine and many variations. Even below the simplest code compiling doesn't work. I think skipping little thing...
Could you help me?
# Make file for test.c file dependencies external C libraries
CC = g++
C = gcc
FLAGS = -Wextra -g
INCLUDES = -lm
test: randomArray.o test.o
$(CC) $(FLAGS) $(INCLUDES) randomArray.o -o test
test.o: randomArray.o
$(C) $(FLAGS) $(INCLUDES) -c test.cpp
randomArray.o: randomArray.c
$(C) $(FLAGS) $(INCLUDES) -c randomArray.c
Error message
make
g++ -Wextra -g -lm randomArray.o -o test
/usr/bin/ld: /usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../lib/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [makefile:9: test] Error 1
#include <iostream>
#include "randomArray.h"
using namespace std;
int main(int argc, char const *argv[])
{
int *bit=randomArray(64);
for (int i = 0; i < 64; i++)
{
cout<<bit[i]<< "\n";
}
return 0;
}
You forgot to link in test.o:
test: randomArray.o test.o
$(CC) $(FLAGS) $(INCLUDES) randomArray.o test.o -o test
Also note that test.o: randomArray.o is probably wrong. It says test.o depends on randomArray.o, which it doesn't. It depends on test.cpp.
test.o: test.cpp
$(CC) $(FLAGS) $(INCLUDES) -c test.cpp

Can't link a C shared object to a C++ program

I am trying to write a makefile for a project. The project involves a test program that defines a main function written in C++11 that is supposed to call a shared object library written in c99 and run some tests.
My makefile successfully compiles the c99 library and produces "libhanoi.so".
When I try to link the C99 library to the C++11 part, I get the following error:
g++ -std=gnu++11 -L. -lhanoi -o main tests/testing.cpp tests/main.cpp
/tmp/cctHQTcW.o: In function `binarion_constructor(unsigned long*)':
main.cpp:(.text+0x28): undefined reference to `binarion64_t'
collect2: error: ld returned 1 exit status
Makefile:29: recipe for target 'tests' failed
make: *** [tests] Error 1
However, the output of "nm -C libhanoi.so" shows that the binarion64_t function is being exported by libhanoi.so:
0000000000000610 T binarion64_t(long long, long long)
When I introduce a typo into the name of libhanoi.so, it introduces an error saying it can't find libhanoi.so.
So it must be able to find libhanoi.so and libhanoi.so is exporting the unimplemented function in main.cpp, yet it still is giving an undefined reference. What's going on?
Minimal example:
hanoi.h:
#ifndef HANOI_H
#define HANOI_H
#include <inttypes.h>
// binarion (base -1+i) constructor
uint64_t binarion64_t(long long A, long long B);
#endif // HANOI_H
binarion.c:
#include "hanoi.h"
uint64_t binarion64_t(long long A,long long B){
return 0;
}
main.cpp:
#include <stdio.h>
extern "C" {
#include "hanoi.h"
};
uint64_t binarion_constructor(uint64_t * args){
return binarion64_t(args[0], args[1]);
}
int main(void){
return 0;
}
Compile:
g++ -std=c99 -c binarion.c
g++ -std=c99 -shared -o libhanoi.so binarion.o -lm
g++ -std=gnu++11 -L. -lhanoi -o main main.cpp
output:
/tmp/ccjoRmCg.o: In function `binarion_constructor(unsigned long*)':
main.cpp:(.text+0x28): undefined reference to `binarion64_t'
collect2: error: ld returned 1 exit status
EDIT:
The commands I'm running are:
gcc -std=c99 -c binarion.c
gcc -std=c99 -shared -o libhanoi.so binarion.o -lm
g++ -std=gnu++11 -L. -lhanoi -o main main.cpp
The files are exactly the ones in the question. The output of "readelf -s libhanoi.so | grep binarion" is:
12: 0000000000000660 19 FUNC GLOBAL DEFAULT 11 binarion64_t
33: 0000000000000000 0 FILE LOCAL DEFAULT ABS binarion.c
46: 0000000000000660 19 FUNC GLOBAL DEFAULT 11 binarion64_t
and the output of "g++ -std=gnu++11 -L. -lhanoi -o main main.cpp" is:
/tmp/cczfgY8M.o: In function `binarion_constructor(unsigned long*)':
main.cpp:(.text+0x28): undefined reference to `binarion64_t'
collect2: error: ld returned 1 exit status
TL; DR:
Use:
gcc -std=c99 -c binarion.c
gcc -std=c99 -shared -o libhanoi.so binarion.o -lm
g++ -std=gnu++11 -L. -lhanoi -o main main.cpp
Explanation:
You should be using gcc to compile a C file, g++ is for C++. When you do g++ -std=c99 -c binarion.c the compiler gives you a hint with:
cc1plus: warning: command line option ‘-std=c99’ is valid for C/ObjC but not for C++
This means that you end up compiling your library as a C++ library. You can verify that by calling readelf -s libhanoi.so | grep binarion:
9: 00000000000005da 19 FUNC GLOBAL DEFAULT 9 _Z12binarion64_txx
29: 0000000000000000 0 FILE LOCAL DEFAULT ABS binarion.c
44: 00000000000005da 19 FUNC GLOBAL DEFAULT 9 _Z12binarion64_txx
As you can see, the function has been name-mangled, which is something C++ does, and C doesn't.
However, when compiling main.cpp you tell the compiler that binarion_t has C linkage:
extern "C" {
#include "hanoi.h"
};
So it is searching for unmangled binarion_t (instead of _Z12binarion64_txx).

Symbol not loaded into templated function

I created a shared library "A" that use an other shared library "B".
I have a problem when I link my program with the shared library "A".
When I use some function from the other shared library ("B") inside cpp file of the shared library "A", all is fine.
But when I use these functions inside .h file (inside a templated method or an inlined method) of the shared library "A", the symbol is not loaded and I get an error "undefined reference to symbol".
I used g++ 7.2.
I think the option -l forget to load the symbols used in header file.
Do you have an idea to avoid this?
Update 2:
Here a full reproducible example:
A.cpp
#include "A.h"
A.h
#ifndef A_H
# define A_H
#include <type_traits>
#include "B.h"
class A
{
public:
template <typename Type>
std::enable_if_t<std::is_arithmetic<Type>::value,void> funcA(Type value);
};
template <typename Type>
std::enable_if_t<std::is_arithmetic<Type>::value,void> A::funcA(Type value)
{
B tmp;
tmp.funcB(value);
}
#endif
B.cpp
#include "B.h"
#include <iostream>
void B::example()
{
std::cout << "works" << std::endl;
}
B.h
#ifndef B_H
# define B_H
class B
{
public:
void funcB(int value);
private:
void example();
};
inline void B::funcB(int value)
{
value += 1;
example();
}
#endif
main.cpp
#include "A.h"
int main()
{
A tmp;
tmp.funcA(5);
return 1;
}
Compile
g++ -std=c++17 -m64 -O2 -DNDEBUG -Wall -Wextra -Werror -fPIC -o A.o -c A.cpp
g++ -std=c++17 -m64 -O2 -DNDEBUG -Wall -Wextra -Werror -fPIC -o B.o -c B.cpp
g++ -std=c++17 -m64 -O2 -DNDEBUG -Wall -Wextra -Werror -fPIC -o main.o -c main.cpp
g++ -o libB.so B.o -shared
g++ -o libA.so A.o -shared -L. -lB
g++ -o application main.o -L . -lA
Error
main.o: In function `main':
main.cpp:(.text.startup+0x1a): undefined reference to `B::example()'
collect2: error: ld returned 1 exit status
Thank you,
SOLVED:
Finally, I solved my problem with this thread:
GCC 4.5 vs 4.4 linking with dependencies
Thank you!

Static Libraries which depend on other static libraries

I have a question about making static libraries that use other static libraries.
I set up an example with 3 files - main.cpp, slib1.cpp and slib2.cpp. slib1.cpp and slib2.cpp are both compiled as individual static libraries (e.g. I end up with slib1.a and slib2.a) main.cpp is compiled into a standard ELF executable linked against both libraries.
There also exists a header file named main.h which prototypes the functions in slib1 and slib2.
main.cpp calls a function called lib2func() from slib2. This function in turn calls lib1func() from slib1.
If I compile the code as is, g++ will return with a linker error stating that it could not find lib1func() in slib1. However, if I make a call to lib1func() BEFORE any calls to any functions in slib2, the code compiles and works correctly.
My question is simply as follows: is it possible to create a static library that depends on another static library? It would seem like a very severe limitation if this were not possible.
The source code for this problem is attached below:
main.h:
#ifndef MAIN_H
#define MAIN_H
int lib1func();
int lib2func();
#endif
slib1.cpp:
#include "main.h"
int lib1func() {
return 1;
}
slib2.cpp:
#include "main.h"
int lib2func() {
return lib1func();
}
main.cpp:
#include <iostream>
#include "main.h"
int main(int argc, char **argv) {
//lib1func(); // Uncomment and compile will succeed. WHY??
cout << "Ans: " << lib2func() << endl;
return 0;
}
gcc output (with line commented out):
g++ -o src/slib1.o -c src/slib1.cpp
ar rc libslib1.a src/slib1.o
ranlib libslib1.a
g++ -o src/slib2.o -c src/slib2.cpp
ar rc libslib2.a src/slib2.o
ranlib libslib2.a
g++ -o src/main.o -c src/main.cpp
g++ -o main src/main.o -L. -lslib1 -lslib2
./libslib2.a(slib2.o): In function `lib2func()':
slib2.cpp:(.text+0x5): undefined reference to `lib1func()'
collect2: ld returned 1 exit status
gcc output (with line uncommented)
g++ -o src/slib1.o -c src/slib1.cpp
ar rc libslib1.a src/slib1.o
ranlib libslib1.a
g++ -o src/slib2.o -c src/slib2.cpp
ar rc libslib2.a src/slib2.o
ranlib libslib2.a
g++ -o src/main.o -c src/main.cpp
g++ -o main src/main.o -L. -lslib1 -lslib2
$ ./main
Ans: 1
Please, try g++ -o main src/main.o -L. -Wl,--start-group -lslib1 -lslib2 -Wl,--end-group.
Group defined with --start-group, --end-group helps to resolve circular dependencies between libraries.
See also: GCC: what are the --start-group and --end-group command line options?
The order make the difference. Here's from gcc(1) manual page:
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.