undefined reference to function in shared library created directly from static library - c++

I have an old static library that contains a simple simulator. The simulator is initiated by calling a function (sim) also included in the library. Now, I am trying to make this static library into a dynamic library:
g++ -shared -fPIC -o libdynamicSimulator.so -Wl,--whole-archive libstaticSimulator.a -Wl,--no-whole-archive
The object files in ./libstaticSimulator.a are also compiled with the -fPIC flag. This step works fine with no compiler/linker error. I followed a SO post for this step.
However, I encountered linker error when I tried to test the shared library by calling the sim function from a main:
g++ -O2 -g -m64 -Wall -fno-strict-aliasing -c -o main.o main.c
g++ -O2 -g -m64 -Wall -fno-strict-aliasing -L. main.o -o sim_dynlib -ldynamicSimulator -lm -lpthread
main.o: In function `main':
main.c:40: undefined reference to `sim(unsigned long*, unsigned long*, unsigned long*, unsigned long)'
collect2: error: ld returned 1 exit status
make: *** [sim_dynlib] Error 1
I used nm to verify that the symbol is there in the dynamic library:
$ nm ./libdynamicSimulator.so | grep sim
0000000000102e10 T sim
The library is written in C++ but sim's name is not mangled because it is defined within a extern "C" block:
extern "C" {
uint64_t sim(uint64_t *a1, uint64_t *a2, uint64_t *a3, uint64_t len)
{
...
}
}
Here is how the main.c is declaring and using the function:
extern uint64_t sim(uint64_t *a1, uint64_t *a2, uint64_t *a3, uint64_t len);
int main(int argc, char **argv)
{
... // preparing a1, a2, a3, len
uint64_t act_sum = sim(a1, a2, a3, len);
...
}
I have been googling for hours trying to find the problem but all I could find was about reordering the -l's in the g++ command line, which I already did -- -ldynamicSimulator after main.o.
I feel that I am missing something really simple/stupid here but for the life of me, I could not figure out what it is.
Any help or comment is appreciated.

I have figured it out. My feeling was correct -- it is a stupid mistake:
The declaration of the sim() function in main.c needs to be put into a extern "C" block, since I am using g++ as the compiler.
extern "C" {
extern uint64_t sim(uint64_t *a1, uint64_t *a2, uint64_t *a3, uint64_t len);
}
int main(int argc, char **argv)
{
... // preparing a1, a2, a3, len
uint64_t act_sum = sim(a1, a2, a3, len);
...
}
The linker error is gone after this change.
Another shorter declaration that works:
extern "C" uint64_t sim(uint64_t *a1, uint64_t *a2, uint64_t *a3, uint64_t len);

Related

undefined reference to : what's wrong?

Im' trying to port a home made software from AIX to "Red Hat Enterprise Linux 7.8"
I'm facing "undefined reference to" errors at link time and, for now, I can't find where I screwed up.
The goal is to generate an executable from 2 homemade shared librairies (msi and atmi), some object previously compiled (MsiServices.o) and a C program (pingsrv.c).
Below is the command :
gcc -DWall -o bin/pingsrv -DUNIX -I. -g -DUNIX -D_THREAD_SAFE -D_LARGEFILE64_SOURCE -I/home/vgi/git/msi-tools/ping/server/target/msi/include/yaml-cpp -I/home/vgi/git/msi-tools/ping/server/target/msi/include/apr-1 -I/home/vgi/git/msi-tools/ping/server/target/msi/include/activemq-cpp-3.9.4 -I/home/vgi/git/msi-tools/ping/server/target/msi/include /tmp/MsiServices.o ./pingsrv.c -L/home/vgi/git/msi-tools/ping/server/target/msi/lib -lmsi -lactivemq-cpp -llog4cxx -latmi -lapr-1 -laprutil-1 -lexpat -lstdc++ -lyaml-cpp
Errors appears a link time:
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libatmi.so: undefined reference to `Msi_tpreturn'
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libatmi.so: undefined reference to `Msi_tpcall'
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libmsi.so: undefined reference to `msi::service::optarg'
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libatmi.so: undefined reference to `Msi_userlog'
Library atmi is written in C and is able to call some C++ instance methods by using wrappers:
...
typedef struct MsiScheduler MsiScheduler ;
extern void Msi_tpreturn(MsiScheduler *,int, long , char *, long, long);
extern void Msi_userlog(MsiScheduler *,char*) ;
extern int Msi_tpcall(MsiScheduler *,char *svc, char *idata, long ilen, char **odata, long *olen, long flags) ;
...
extern void tpreturn(int rval, long rcode, char * data, long len, long flags)
{
assert(vg_Consumer != NULL) ;
Msi_tpreturn(vg_Consumer,rval,rcode,data,len,flags) ;
}
Wrappers called by this library are defined in another library called msi. Wrappers are defined in a C++ source file (MsiScheduler.cpp):
void Msi_tpreturn(MsiScheduler * c,int ret,long code,char *data,long len,long flags)
{
TypedBuffer* buffer = NULL ;
if (data != NULL)
{
buffer = TypedBuffer::createBuffer(getType(data),data,len) ;
}
MsiReply * reply = MsiReply::createReply(ret,code,buffer) ;
c->tpreturn(reply) ;
if (data != NULL)
{
freebuf(data) ;
}
delete reply ;
}
int Msi_tpcall(MsiScheduler * c,char *svc, char *idata, long ilen, char **odata, long *olen, long flags)
{
...
}
void Msi_userlog(MsiScheduler *c ,char* str)
{
c->userlog(str) ;
}
header file (MsiScheduler.h) contains this fragment :
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__STDC__) || defined(__cplusplus)
extern void Msi_tpreturn(MsiScheduler *,int, long , char *, long, long);
extern void Msi_userlog(MsiScheduler *,char*) ;
extern int Msi_tpcall(MsiScheduler *,char *svc, char *idata, long ilen, char **odata, long *olen, long flags) ;
#else
extern void Msi_tpreturn();
extern void Msi_userlog() ;
extern int Msi_tpcall() ;
#endif
#ifdef __cplusplus
}
#endif
Librairies are constructed like that:
g++ -g -fPIC -Wall -I/home/vgi/git/msi/msi-service/target/ext/include/apr-1 -I/home/vgi/git/msi/msi-service/target/ext/include/activemq-cpp-3.9.4 -I/home/vgi/git/msi/msi-service/target/ext/include/yaml-cpp -I/home/vgi/git/msi/msi-service/target/ext/include -I/home/vgi/git/msi/msi-service/target/ext/include -I../lib/inc -I./ -o MsiScheduler.o -c MsiScheduler.cpp
...
g++ -shared MsiUtil.o MsiConfig.o MsiInstrumentation.o MsiMetric.o MsiService.o MsiExceptions.o MsiCharsetConverter.o MsiTypes.o MsiMessage.o MsiMessageUtil.o MsiScheduler.o MsiServer.o -o libmsi.so
...
gcc -g -fPIC -Wall -I/home/vgi/git/msi/msi-service/target/ext/include/apr-1 -I/home/vgi/git/msi/msi-service/target/ext/include/activemq-cpp-3.9.4 -I/home/vgi/git/msi/msi-service/target/ext/include/yaml-cpp -I/home/vgi/git/msi/msi-service/target/ext/include -I/home/vgi/git/msi/msi-service/target/ext/include -I../lib/inc -I./ -o atmi.o -c atmi.c
gcc -shared atmi.o memmngt.o -o libatmi.so
FYI, everything compile and link well on AIX OS (with xlc,xlC commands).
I also tried to change librairies order for linking command, without success.
I guess there is something specific to linux/gcc but I haven't found it yet.
libmsi.so:0000000000034f20 T _Z10Msi_tpcallPN3msi7service12MsiSchedulerEPcS3_lPS3_Pll
libmsi.so:0000000000035138 T _Z11Msi_userlogPN3msi7service12MsiSchedulerEPc
libmsi.so:0000000000034e55 T _Z12Msi_tpreturnPN3msi7service12MsiSchedulerEilPcll
libatmi.so: U Msi_tpcall
libatmi.so: U Msi_tpreturn
libatmi.so: U Msi_userlog
In your nm output, the T's mean that the symbol on the right is defined in libmsi.so, and the U's mean that the symbol on the right is needed by libatmi.so. But obviously, the names of these symbols don't match up. The names in libmsi.so have the C++ mangling which helps keep overloaded functions separate.
This means the extern "C" did not apply to the function definitions when compiling MsiScheduler.cpp. Make sure it includes MsiScheduler.h, and that part of the header is not skipped by any #if. If that's not the issue, double check that the function parameter types are exactly the same in the MsiScheduler.h declarations and MsiScheduler.cpp definitions, though they seem to be.
When you're compiling pingsrv.c you try to link msi with -l. Have you put libmsi.so in the library path so that -l can find it?

Ebpf:undefined symbol for helpers

I run an up to date debian testing (with kernel 4.19).
Helpers are not found on my system (but they exist in the header, Qt jumps to them)
#include "bpf/bpf.h"
int main (){
int r = bpf_create_map(BPF_MAP_TYPE_ARRAY,1,1,1,0);
return 0;
}
Compilation results in
undefined reference to `bpf_create_map(bpf_map_type, int, int, int, unsigned int)'
compiled with
g++ -c -pipe -g -std=gnu++1z -Wall -W -fPIC -DQT_QML_DEBUG -I. -I../../Qt/5.13.0/gcc_64/mkspecs/linux-g++ -o main.o main.cpp
g++ -lbpf -o server main.o
Same result with
g++ main.cpp -lbpf -o out
I have the libbpf-dev installed as well and i have the associated libraries (a and so).
What is wrong?
Update
even the following code won't work
#include <linux/bpf.h>
int main (){
//int r = bpf_create_map(BPF_MAP_TYPE_ARRAY,1,1,1,0);
bpf_attr attr = {};
attr.map_type = BPF_MAP_TYPE_ARRAY;
attr.key_size = 1;
attr.value_size = 1;
attr.max_entries = 1;
bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
return 0;
}
results in
error: 'bpf' was not declared in this scope
Update2:
BTW, key size is mandated to be 4 and not 1; but it is a point aside, that was unrelated to my problem here.
Namespace issue due to compiling in C++, you probably want:
extern "C" {
#include "bpf/bpf.h"
}
int main()...
Regarding your second error (error: 'bpf' was not declared in this scope), this is not directly related to libbpf, this is because there is no function simply called bpf() to actually perform the syscall. Instead you have to use the syscall number. For example, libbpf defines the following:
static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
unsigned int size)
{
return syscall(__NR_bpf, cmd, attr, size);
}
... and uses sys_bpf() after that, the same way you try to call bpf() in your sample.
For the record, “BPF helpers” often designates BPF functions that you call from within a BPF program, which is not the case here. Hence some confusion in the comments, I believe.

Undefined reference (but nm says the function exists) [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 have a library from a camera manufacturer, and in the demo code provided, a function called metadata_init() works fine, in my code though, I get an undefined reference error.
The make output from the demo code:
/opt/linaro-multilib-2013.09-gcc4.8/bin/arm-linux-gnueabihf-gcc -lm -g -L"/home/aro/Downloads" -o hicore demoS2.c -lpthread -lyuvlib -lrt
and thats it, the build succeeds fine, I will have a working ./hicore application in there.
My project is a little bit more complicated, and I compile using eclipse.
The console output is:
11:33:23 **** Build of configuration Camera-R4-Debug for project Camera ****
make all
Building file: ../src/Camera.cpp
Invoking: Cross G++ Compiler
arm-linux-gnueabihf-g++ -I/opt/Camerasdk/R4/include -I"/cameraBuilds/Wrapper/include" -I"/opt/ExternalLibraries/curl/Camera/R4/include" -I"/opt/ExternalLibraries/libxml2/Camera/R4/include" -I"/opt/ExternalLibraries/OpenCV24/Camera/R4/include" -I"/home/aro/cameraBuilds/Camera" -I/opt/InternalLibraries/include -I/opt/InternalLibraries/include_linux -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/Camera.d" -MT"src/Camera.o" -o "src/Camera.o" "../src/Camera.cpp"
../src/Camera.cpp: In function ‘int metadata_construct_http_message(char*, METADATA_HTTP_MESSAGE_TYPE, void*, int*)’:
../src/Camera.cpp:379:24: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
"</svg>\r\n";
^
../src/Camera.cpp: In function ‘int main()’:
../src/Camera.cpp:426:97: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
(void)metadata_init("stream.cgi", strlen("stream.cgi"), metadata_construct_http_message);
^
Finished building: ../src/Camera.cpp
Building file: ../src/CameraFrameGrabber.cpp
Invoking: Cross G++ Compiler
arm-linux-gnueabihf-g++ -I/opt/Camerasdk/R4/include -I"/cameraBuilds/Wrapper/include" -I"/opt/ExternalLibraries/curl/Camera/R4/include" -I"/opt/ExternalLibraries/libxml2/Camera/R4/include" -I"/opt/ExternalLibraries/OpenCV24/Camera/R4/include" -I"/home/aro/cameraBuilds/Camera" -I/opt/InternalLibraries/include -I/opt/InternalLibraries/include_linux -I/opt/InternalLibraries/ipslib/include -I/opt/InternalLibraries/ipsstream/include -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/CameraFrameGrabber.d" -MT"src/CameraFrameGrabber.o" -o "src/CameraFrameGrabber.o" "../src/CameraFrameGrabber.cpp"
Finished building: ../src/CameraFrameGrabber.cpp
Building file: ../src/CameraLogger.cpp
Invoking: Cross G++ Compiler
arm-linux-gnueabihf-g++ -I/opt/Camerasdk/R4/include -I"/home/aro/cameraBuilds/Wrapper/include" -I"/opt/ExternalLibraries/curl/Camera/R4/include" -I"/opt/ExternalLibraries/libxml2/Camera/R4/include" -I"/opt/ExternalLibraries/OpenCV24/Camera/R4/include" -I"/home/aro/cameraBuilds/Camera" -I/opt/InternalLibraries/include -I/opt/InternalLibraries/include_linux -I/opt/InternalLibraries/ipslib/include -I/opt/InternalLibraries/ipsstream/include -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/CameraLogger.d" -MT"src/CameraLogger.o" -o "src/CameraLogger.o" "../src/CameraLogger.cpp"
Finished building: ../src/CameraLogger.cpp
Building file: ../src/CameraParameter.cpp
Invoking: Cross G++ Compiler
arm-linux-gnueabihf-g++ -I/opt/Camerasdk/R4/include -I"/home/aro/cameraBuilds/Wrapper/include" -I"/opt/ExternalLibraries/curl/Camera/R4/include" -I"/opt/ExternalLibraries/libxml2/Camera/R4/include" -I"/opt/ExternalLibraries/OpenCV24/Camera/R4/include" -I"/home/aro/cameraBuilds/Camera" -I/opt/InternalLibraries/include -I/opt/InternalLibraries/include_linux -I/opt/InternalLibraries/ipslib/include -I/opt/InternalLibraries/ipsstream/include -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/CameraParameter.d" -MT"src/CameraParameter.o" -o "src/CameraParameter.o" "../src/CameraParameter.cpp"
Finished building: ../src/CameraParameter.cpp
Building target: Camera
Invoking: Cross G++ Linker
arm-linux-gnueabihf-g++ -L/opt/Camerasdk/R4/lib -L"/cameraBuilds/Wrapper/Camera-R4-Debug" -L"/opt/ExternalLibraries/curl/Camera/R4/lib" -L"/opt/ExternalLibraries/libxml2/Camera/R4/lib" -L"/opt/ExternalLibraries/OpenCV24/Camera/R4/lib" -L"/opt/DetectionModules/Camera/R4/lib" -L/home/aro/Downloads -o "Camera" ./src/Camera.o ./src/CameraFrameGrabber.o ./src/CameraLogger.o ./src/CameraParameter.o -lWrapper -lxml2 -lopencv_highgui -lopencv_imgproc -lopencv_core -lpthread -lyuvlib -lrt -llibjasper -llibjpeg -llibpng -llibtiff -lzlib -lcurl
./src/Camera.o: In function `main':
/home/aro/cameraBuilds/Camera/Camera-R4-Debug/../src/Camera.cpp:426: undefined reference to `metadata_init(char*, int, int (*)(char*, METADATA_HTTP_MESSAGE_TYPE, void*, int*))'
collect2: error: ld returned 1 exit status
make: *** [Camera] Error 1
11:33:24 Build Finished (took 1s.212ms)
The code itself is the very same thing, I just copied it over.
Metadata.h:
#ifndef _HIK_METADATA_H_
#define _HIK_METADATA_H_
const int max_http_body_len = 100 * 1024;
typedef enum
{
CMD_ADD_TYPE = 1,
CMD_OTHER,
} METADATA_CTRL_TYPE;
typedef struct
{
int length;
int fd;
METADATA_CTRL_TYPE cmd_type;
} METADATA_HEADER;
typedef struct
{
char option[128];
int share_socket;
} METADATA_ADD_CFG;
typedef enum
{
HTTP_HEADER_TYPE = 1,
HTTP_BODY_TYPE,
} METADATA_HTTP_MESSAGE_TYPE;
typedef struct
{
char boundary[64];
char http_content_type[64];
char multipart_content_type[64];
} METADATA_MULTIPART_TYPE;
typedef int (*p_metadata_construct_http_msg_callback_f)(char *p_option, METADATA_HTTP_MESSAGE_TYPE cmd_type, void *p_data, int *p_data_len);
int metadata_init(char *p_metadata_url, int url_len, p_metadata_construct_http_msg_callback_f p_callback_f);
#endif
In Camera.cpp:
#include "Metadata.h"
int metadata_construct_http_message(char *p_option, METADATA_HTTP_MESSAGE_TYPE cmd_type, void *p_data, int *p_data_len)
{
// Removed for SO
return 0;
}
int main()
{
(void)metadata_init("stream.cgi", strlen("stream.cgi"), metadata_construct_http_message);
...
}
What causes this, and how can I debug this issue to narrow down how to fix it?
It think the problem could be that metadata_init is a C function, but you use it from a C++ code.
In case of this, extern "C" must be used in the header file, like this:
#ifdef __cplusplus
extern "C" {
#endif
// embed the whole contents of the header file here, I just put the function here for brevity
int metadata_init(char *p_metadata_url, int url_len, p_metadata_construct_http_msg_callback_f p_callback_f);
#ifdef __cplusplus
}
#endif
It is because of name mangling rules. Names are mangled differently in C and C++. With extern "C", you tell the compiler that the names inside should be used with "C" mangling.
C++ has to do a complex name mangling compared to C, because it has to embed almost all signature information to a name (all parameters type), while in C, the mangled name usually is the same as the function name, or there is a _ prepended.

Why's the linker not finding just a single (present) method in a library?

So I recently started using a library called libgambatte (github), everything was going just fine until the linker started complaining about an undefined reference for a method. What's really strange is that it find every other method for that object! Arguments' types are correct (I've copied them from the working program included with the library).
Here's the code:
Make output:
g++ -Wall -Wextra -g3 -I../libgambatte/include -I../common -c -o test.o test.cpp
g++ test.o -L../libgambatte -lgambatte -lz -o test
test.o: In function `main':
<REDACTED>/src/test.cpp:12: undefined reference to `gambatte::GB::runFor(unsigned long*, long, unsigned long*, unsigned long&)'
collect2: error: ld returned 1 exit status
Makefile:9: recipe for target 'test' failed
make: *** [test] Error 1
Makefile:
CPPFLAGS=-Wall -Wextra -g3 -I../libgambatte/include -I../common
LDFLAGS=-L../libgambatte -lgambatte -lz
.PHONY=all clean
all: test
test: test.o
$(CXX) test.o $(LDFLAGS) -o test
clean:
rm -f test.o test
Output of nm ../libgambatte/libgambatte.a | grep runFor:
0000000000007a20 T _ZN8gambatte3CPU6runForEm
0000000000000190 T _ZN8gambatte2GB6runForEPjlS1_Rm
U _ZN8gambatte3CPU6runForEm
Source for test.cpp:
#include <gambatte.h>
using namespace std;
int main(void){
gambatte::uint_least32_t audiobuf[1234];
gambatte::uint_least32_t framebuf[1234];
size_t samples = 1234;
unsigned gb_width = 160;
gambatte::GB gb;
gb.runFor(framebuf, gb_width, audiobuf, samples);
return 0;
}
runFor method declaration:
std::ptrdiff_t runFor(gambatte::uint_least32_t *videoBuf, std::ptrdiff_t pitch,
gambatte::uint_least32_t *audioBuf, std::size_t &samples);
Definition for gambatte::uint_least32_t:
#ifdef HAVE_CSTDINT
#include <cstdint>
namespace gambatte {
using std::uint_least32_t;
using std::uint_least16_t;
}
#elif defined(HAVE_STDINT_H)
#include <stdint.h>
namespace gambatte {
using ::uint_least32_t;
using ::uint_least16_t;
}
#else
namespace gambatte {
#ifdef CHAR_LEAST_32
typedef unsigned char uint_least32_t;
#elif defined(SHORT_LEAST_32)
typedef unsigned short uint_least32_t;
#elif defined(INT_LEAST_32)
typedef unsigned uint_least32_t;
#else
typedef unsigned long uint_least32_t;
#endif
#ifdef CHAR_LEAST_16
typedef unsigned char uint_least16_t;
#else
typedef unsigned short uint_least16_t;
#endif
}
#endif
Sorry for the long code.
I've found the problem: as you can see in the definition of gambatte::uint_least32_t, the type definition is based on the presence of certain constants. My problem manifested because the library (and the included program) are compiled with -DHAVE_STDINT_H and therefore define gambatte::uint_least32_t as a different type, causing the linker to not find the correct signature; compiling with -DHAVE_STDINT_H solved the problem for me.

Undefined symbol error with inline function Solaris(SunOS 5.9)

I have defined an inline function copy_string in file cpstr.c and created .so file (libtest.so) for cpstr.c file. While trying to link this libtest.so for test.c, I am getting an error as
ild: (undefined symbol) char*copy_string(char*,const char*) -- referenced in the text segment of test.o
When I removed inline from the function copy_string, it works fine.
Below are the commands we tried,
CC -c -xarch=v9 test.c
CC -G -xarch=v9 -o libtest.so -Kpic cpstr.c
CC -xarch=v9 -g -o test test.o /myplace/libtest.so
When we tried to get the contents of libtest.so , I couldn't find copy_string name in libtest.so file . But I can see it in the contents when I removed 'inline' from copy_string function .
Can anyone please suggest me with a solution to get rid of undefined symbol error without removing inline function.
test.c
#include <stdio.h>
extern char *copy_string (char *, const char*);
int main()
{
char str[50];
copy_string(str,"hello");
printf("%s\n", str);
return 0;
}
cpstr.c
#include<string.h>
inline char *copy_string (char *str1, const char *str2)
{
return (str2 ? strcpy (str1, str2) : (char *) 0);
}
CC -c -xarch=v9 test.c
CC -G -xarch=v9 -o libtest.so -Kpic cpstr.c
CC -xarch=v9 -g -o test test.o /space/systpe/devendra/dhsqlroot/libtest.so
ild: (undefined symbol) char*copy_string(char*,const char*) -- referenced in the text segment of test.o
It wants you to implement your inline function in the header file
Functions with the function specifier inline shall be defined in each module where they are used. The compiler need to see their inline definitions that to generate correctly the object code. So usually their definition are placed in a header.