Why linkage failed even when nm found the symbol? - linux

When I compile a demo main.cpp, it failed because undefined reference to a_mtk_bt_service_init(), but I have found the symbol by
nm -D ./libmtk_bt_service_client.so|grep a_mtk_bt_service_init,
it's output is 0000000000004098 T a_mtk_bt_service_init,
I'm sure the compiler found the correct dynamic library by use command aarch64-poky-linux-g++ -print-file-name=libmtk_bt_service_client.so -o main main.cpp
This is the demo code main.cpp
void a_mtk_bt_service_init();
int main()
{
a_mtk_bt_service_init();
return 0;
}
and my compile command is
aarch64-poky-linux-g++ -mcpu=cortex-a72.cortex-a53+crypto -mtune=cortex-a72.cortex-a53 --sysroot=/home/sundq/code/newT9/T9-Amazon-Sdk/build/tmp/sysroots/aud8516-slc -o build/xx main.cpp -I../../include -lmtk_bt_service_client

The answer is here Call a C function from C++ code, that is, when c++ code call a c function, we also must add extern "C" before the declare of c function,
so my function declare should like this
extern "C" void a_mtk_bt_service_init();

Related

How to compile HSL for IPOPT (after IPOPT)

I use MINGW64 to compile HSL (https://www.hsl.rl.ac.uk/ipopt/) following the redme. However, I end up with an error 2 (Makefile:753). The critical command is
gfortran -shared .libs/libcoinhsl-0.dll.def common/.libs/deps90.o common/.libs/deps.o common/.libs/dump.o mc19/.libs/mc19d.o ma27/.libs/ma27d.o ma28/.libs/ma28d.o ma57/.libs/ma57d.o hsl_ma77/.libs/hsl_ma77d.o hsl_ma77/C/.libs/hsl_ma77d_ciface.o hsl_ma86/.libs/hsl_ma86d.o hsl_ma86/C/.libs/hsl_ma86d_ciface.o hsl_mc68/C/.libs/hsl_mc68i_ciface.o hsl_ma97/.libs/hsl_ma97d.o hsl_ma97/C/.libs/hsl_ma97d_ciface.o loadmetis/.libs/loadmetis.o -L/mingw64/lib/ -lopenblas -lpthread -lgfortran -O2 -Wl,-rpath -Wl,/mingw64/lib -o .libs/libcoinhsl-0.dll -Wl,--enable-auto-image-base -Xlinker --out-implib -Xlinker .libs/libcoinhsl.dll.a
The output is
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: common/.libs/deps90.o:C:\msys64\home\user\hsl_solo\coinhsl/common/deps90.f90:17672: undefined reference to `metis_nodend_'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: common/.libs/deps90.o: in function `__hsl_mc68_integer_MOD_mc68_order_integer':
C:\msys64\home\user\hsl_solo\coinhsl/common/deps90.f90:17454: undefined reference to `metis_nodend_'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ma57/.libs/ma57d.o: in function `ma57ad_':
C:\msys64\home\user\hsl_solo\coinhsl/ma57/ma57d.f:469: undefined reference to `metis_nodend_'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\msys64\home\user\hsl_solo\coinhsl/ma57/ma57d.f:682: undefined reference to `metis_nodend_'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\msys64\home\user\hsl_solo\coinhsl/ma57/ma57d.f:618: undefined reference to `metis_nodend_'
collect2.exe: error: ld returned 1 exit status
As I am not that experienced with compiling software, does anyone have an idea how I can get this error fixed?
Symbol metis_nodend_ belongs to Metis.
The metis_nodend_ symbol needs to be resolved either by linking against a Metis library (you might need to specify where to find that via some flags for configure), by a function of that name that loads the Metis library at runtime (that is what loadmetis tries to do), or by a dummy function of that name that does nothing (thats what older versions of HSL used to do).
The loadmetis of HSL is implemented in C and defines a function METIS_NODEND:
void METIS_NODEND(int *nvtxs, int *xadj, int *adjncy, int *numflag,
int *options, int *perm, int *iperm) {
....
So the problem is probably that the naming conventions do not match, i.e., the functionname in the C object does not match the functionname that the Fortran objects expect.
Try changing METIS_NODEND to metis_nodend or metis_nodend_ in loadmetis.c.
Or try the buildsystem from https://github.com/coin-or-tools/ThirdParty-HSL/

why linking to a static library is generally faster than linking to individual source files?

case 1. gcc -o program main.o file1.o file2.o
case 2. ar crv foo.a file1.o file2.o
then, gcc -o program main.o foo.a
At compile time, linking to a static library (case 2) is generally faster than linking to individual source files.(case 1)
Why and what cases?
Any help is appreciated.
/* Filename :lib.h */
void file2(char *);
void file1(int);
main.c
#include "lib.h"
int main()
{
file1(3);
file2("Hello World");
return 0;
}
file1.c
#include <stdio.h>
#include "lib.h"
void file1(int arg) {
printf("you passed %d\n", arg);
} 
file2.c
#include <stdio.h>
#include "lib.h"
void file2(char* arg) {
printf("you passed %s\n", arg);
}
The only case I can think of is when your object files are rather large.
Linking against a library will only "pull in" referenced items. So your executable can be smaller and the functions closer in memory for shorter jumps. But that is an unlikely thing in a modern platform.

macosx thread explicitly marked deleted

I'm building an application with C++11 threads, but I can't seem to get it to work with clang++ on MacOSX 10.9. Here is the simplest example I can find that causes the issues:
#include <thread>
#include <iostream>
class Functor {
public:
Functor() = default;
Functor (const Functor& ) = delete;
void execute () {
std::cerr << "running in thread\n";
}
};
int main (int argc, char* argv[])
{
Functor functor;
std::thread thread (&Functor::execute, std::ref(functor));
thread.join();
}
This compiles and runs fine on Arch Linux using g++ (version 4.9.2) with the following command-line:
$ g++ -std=c++11 -Wall -pthread test_thread.cpp -o test_thread
It also compiles and runs fine using clang++ (version 3.5.0, also on Arch Linux):
$ clang++ -std=c++11 -Wall -pthread test_thread.cpp -o test_thread
But fails on MacOSX 10.9.5, using XCode 6.1 (regardless of whether I include the -stdlib=libc++ option):
$ clang++ -std=c++11 -Wall -pthread test_thread.cpp -o test_thread
In file included from test_thread.cpp:1:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:332:5: error: attempt to use a deleted function
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:342:5: note: in instantiation of function template specialization
'std::__1::__thread_execute<void (Functor::*)(), std::__1::reference_wrapper<Functor> , 1>' requested here
__thread_execute(*__p, _Index());
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:354:42: note: in instantiation of function template specialization
'std::__1::__thread_proxy<std::__1::tuple<void (Functor::*)(), std::__1::reference_wrapper<Functor> > >' requested here
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get());
^
test_thread.cpp:19:15: note: in instantiation of function template specialization 'std::__1::thread::thread<void (Functor::*)(), std::__1::reference_wrapper<Functor> , void>'
requested here
std::thread thread (&Functor::execute, std::ref(functor));
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/type_traits:1001:5: note: '~__nat' has been explicitly marked deleted
here
~__nat() = delete;
^
1 error generated.
I can't figure out how to get around this, it seems like a compiler bug to me. For reference, the version of clang on that Mac is:
$ clang++ --version
Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
Any ideas what it is I'm doing wrong?
Thanks!
Donald.
The standard does not require the std::thread constructor - or the similar std::async for that matter - to unwrap a reference_wrapper when passed as the first argument with a pointer-to-member-function the way std::bind does. Pass a pointer to Functor instead of a reference_wrapper. (See Library Active Issues list DR2219.)

Why can the value of the symbol returned by dlsym() be null?

In Linux. Per the dlsym(3) Linux man page,
*Since the value of the symbol could actually be NULL
(so that a NULL return from dlsym() need not indicate an error),*
Why is this, when can a symbol (for a function, specifically) be actually NULL? I am reviewing code and found a piece using dlerror to clean first, dlsym next, and dlerror to check for errors. But it does not check the resulting function from being null before calling it:
dlerror();
a_func_name = ...dlsym(...);
if (dlerror()) goto end;
a_func_name(...); // Never checked if a_func_name == NULL;
I am just a reviewer so don't have the option to just add the check. And perhaps the author knows NULL can never be returned. My job is to challenge that but don't know what could make this return a valid NULL so I can then check if such a condition could be met in this code's context. Have not found the right thing to read with Google, a pointer to good documentation would be enough unless you want to explain explicitly which would be great.
I know of one particular case where the symbol value returned by dlsym() can be NULL, which is when using GNU indirection functions (IFUNCs). However, there are presumably other cases, since the text in the dlsym(3) manual page pre-dates the invention of IFUNCs.
Here's an example using IFUNCs. First, a file that will be used to create a shared library:
$ cat foo.c
/* foo.c */
#include <stdio.h>
/* This is a 'GNU indirect function' (IFUNC) that will be called by
dlsym() to resolve the symbol "foo" to an address. Typically, such
a function would return the address of an actual function, but it
can also just return NULL. For some background on IFUNCs, see
https://willnewton.name/uncategorized/using-gnu-indirect-functions/ */
asm (".type foo, #gnu_indirect_function");
void *
foo(void)
{
fprintf(stderr, "foo called\n");
return NULL;
}
Now the main program, which will look up the symbol foo in the shared library:
$ cat main.c
/* main.c */
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
void *handle;
void (*funcp)(void);
handle = dlopen("./foo.so", RTLD_LAZY);
if (handle == NULL) {
fprintf(stderr, "dlopen: %s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any outstanding error */
funcp = dlsym(handle, "foo");
printf("Results after dlsym(): funcp = %p; dlerror = %s\n",
(void *) funcp, dlerror());
exit(EXIT_SUCCESS);
}
Now build and run to see a case where dlsym() returns NULL, while dlerror() also returns NULL:
$ cc -Wall -fPIC -shared -o libfoo.so foo.c
$ cc -Wall -o main main.c libfoo.so -ldl
$ LD_LIBRARY_PATH=. ./main
foo called
Results after dlsym(): funcp = (nil); dlerror = (null)
Well, if it's returned with no errors, then pointer is valid and NULL is about as illegal as any random pointer from the shared object. Like the wrong function, data or whatever.
It can't be if the library/PIE is a product of normal C compilation, as C won't ever put a global object at the NULL address, but you can get a symbol to resolve to NULL using special linker tricks:
null.c:
#include <stdio.h>
extern char null_addressed_char;
int main(void)
{
printf("&null_addressed_char=%p\n", &null_addressed_char);
}
Compile, link, and run:
$ clang null.c -Xlinker --defsym -Xlinker null_addressed_char=0 && ./a.out
&null_addressed_char=(nil)
If you don't allow any such weirdness, you can treat NULL returns from dlsym as errors.
dlerror() returns the last error, not the status of the last call. So if nothing else the code you show may potentially get a valid result from dlsym() and fool itself into thinking there was an error (because there was still one in the queue). The purpose behind dlerror is to provide human-readable error messages. If you aren't printing the result, you are using it wrong.

Compiling/Linking CUDA and CPP Source Files

I am working through a sample program that uses both C++ source code as well as CUDA. This is the essential content from my four source files.
matrixmul.cu (main CUDA source code):
#include <stdlib.h>
#include <cutil.h>
#include "assist.h"
#include "matrixmul.h"
int main (int argc, char ** argv)
{
...
computeGold(reference, hostM, hostN, Mh, Mw, Nw); //reference to .cpp file
...
}
matrixmul_gold.cpp (C++ source code, single function, no main method):
void computeGold(float * P, const float * M, const float * N, int Mh, int Mw, int Nw)
{
...
}
matrixmul.h (header for matrixmul_gold.cpp file)
#ifndef matrixmul_h
#define matrixmul_h
extern "C"
void computeGold(float * P, const float * M, const float * N, int Mh, int Mw, int Nw);
#endif
assist.h (helper functions)
I am trying to compile and link these files so that they, well, work. So far I can get matrixmul_gold.cpp compiled using:
g++ -c matrixmul_gold.cpp
And I can compile the CUDA source code with out errors using:
nvcc -I/home/sbu/NVIDIA_GPU_Computing_SDK/C/common/inc -L/home/sbu/NVIDIA_GPU_Computing_SDK/C/lib matrixmul.cu -c -lcutil_x86_64
But I just end up with two .O files. I've tried a lot of different ways to link the two .O files but so far it's a no-go. What's the proper approach?
UPDATE: As requested, here is the output of:
nm matrixmul_gold.o matrixmul.o | grep computeGold
nm: 'matrixmul.o': No such file
0000000000000000 T _Z11computeGoldPfPKfS1_iii
I think the 'matrixmul.o' missing error is because I am not actually getting a successful compile when running the suggested compile command:
nvcc -I/home/sbu/NVIDIA_GPU_Computing_SDK/C/common/inc -L/home/sbu/NVIDIA_GPU_Computing_SDK/C/lib -o matrixmul matrixmul.cu matrixmul_gold.o -lcutil_x86_64
UPDATE 2: I was missing an extern "C" from the beginning of matrixmul_gold.cpp. I added that and the suggested compilation command works great. Thank you!
Conventionally you would use whichever compiler you are using to compile the code containing the main subroutine to link the application. In this case you have the main in the .cu, so use nvcc to do the linking. Something like this:
$ g++ -c matrixmul_gold.cpp
$ nvcc -I/home/sbu/NVIDIA_GPU_Computing_SDK/C/common/inc \
-L/home/sbu/NVIDIA_GPU_Computing_SDK/C/lib \
-o matrixmul matrixmul.cu matrixmul_gold.o -lcutil_x86_64
This will link an executable binary called matrimul from matrixmul.cu, matrixmul_gold.o and the cutil library (implicitly nvcc will link the CUDA runtime library and CUDA driver library as well).

Resources