I'm trying to link a Qt program I have cross-compiled for a MacOS target on a Linux host. I followed the instructions found here (https://github.com/Tatsh/xchain) to succesfully build gcc, and I can compile and link both simple test programs as on that page to produce executables which run fine on MacOS.
I have built my own Qt from source using this gcc, and I can compile my Qt program without a hitch. The problem comes at the linking stage, when the object files of my program should be linked to the Qt libs, it almost seems as if the Qt libs can't be found at all, or are ignored because they are somehow incompatible.
The object files of my program and the Qt libs I built both seem to be ok:
$ file MainWindow.o
MainWindow.o: Mach-O object i386
$ file /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4.8.2
/usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4.8.2: Mach-O dynamically linked shared library i386
The g++ invocation goes like this:
$ i686-apple-darwin10-g++ -o myapp.app/Contents/MacOS/myapp
main.o MainWindow.o ...
-L/usr/local/myqt/mac32/Qt-4.8.2/lib -lQtCore -lQtGui ...
Of course there are many more object files and many more Qt libs, I have left them out for brevity.
The errors I get are typical of simply not adding an object or lib to the command line, for example:
...
"QMainWindow::event(QEvent*)", referenced from:
vtable for MainWindowin moc_MainWindow.o
"QDir::~QDir()", referenced from:
_main in main.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
and it seems that basically every Qt lib is not being found.
I have also tried specifying the lib files directly instead of the -L/path and -lQtFoo combo, and I even tried renaming them from .dylib to .so :)
If I run g++ with -v to see the linker call, then also add -v to that, I can see that the paths being checked for libs look ok:
$ i686-apple-darwin10-ld64 -dynamic -arch i386 -headerpad_max_install_names
-macosx_version_min 10.4 -syslibroot /usr/i686-apple-darwin10
-weak_reference_mismatches non-weak -o myapp.app/Contents/MacOS/myapp
-lcrt1.o /usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/bin/../lib/gcc/i686-apple-darwin10/4.2.1/crt3.o
main.o MainWindow.o
...
-L/usr/local/myqt/mac32/Qt-4.8.2/lib -lQtCore -lQtGui ...
-v
#(#)PROGRAM:ld64 PROJECT:odcctools-622.3od16
Library search paths:
/usr/local/myqt/mac32/Qt-4.8.2/lib
/usr/i686-apple-darwin10/usr/X11/lib
/usr/local/myqt/mac32/Qt-4.8.2/lib
/usr/i686-apple-darwin10/usr/lib/i686-apple-darwin10/4.2.1
/usr/i686-apple-darwin10/usr/lib
/usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/lib/gcc/i686-apple-darwin10/4.2.1
/usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/lib/gcc
/usr/i686-apple-darwin10/usr/lib/gcc/i686-apple-darwin10/4.2.1
/usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/i686-apple-darwin10/lib
/usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/i686-apple-darwin10/lib
/usr/i686-apple-darwin10/usr/lib
/usr/local/lib
Framework search paths:
/usr/i686-apple-darwin10/Library/Frameworks/
/usr/i686-apple-darwin10/System/Library/Frameworks/
The lib location and setup looks ok:
$ ls -lh /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib*
lrwxrwxrwx. 1 root root 21 Aug 7 05:22 /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib -> libQtCore.dylib.4.8.2
lrwxrwxrwx. 1 root root 21 Aug 7 05:22 /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4 -> libQtCore.dylib.4.8.2
lrwxrwxrwx. 1 root root 21 Aug 7 05:22 /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4.8 -> libQtCore.dylib.4.8.2
-rwxr-xr-x. 1 root root 2.7M Aug 7 05:22 /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4.8.2
The lib contents also seem to be ok, but I am not too familiar with this part... actually I just discovered 'nm' on another question here just now.
$ i686-apple-darwin10-nm /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtGui.dylib.4.8.2 | grep event
U __ZN16QCoreApplication5eventEP6QEvent
U __ZN16QEventTransition5eventEP6QEvent
U __ZN16QEventTransition9eventTestEP6QEvent
U __ZN17QVariantAnimation5eventEP6QEvent
U __ZN19QAbstractTransition5eventEP6QEvent
U __ZN23QCoreApplicationPrivate15eventDispatcherE
U __ZN7QObject11eventFilterEPS_P6QEvent
U __ZN7QObject5eventEP6QEvent
I am also not too familiar with 'name mangling', but I get the feeling it may have something to do with this.
It has been quite a long journey so far with this whole cross-compiling thing, so it sucks to be this close to the end and hit something that really stumps me this much - any advice would be greatly appreciated!
** EDIT ***
I found that if I take out the -dynamic flag for the ld64 call, different function names are shown as missing. For example the missing reference to "QMainWindow::event(QEvent*)" mentioned above becomes:
"__ZN11QMainWindow5eventEP6QEvent", referenced from:
__ZTV10MainWindow in moc_MainWindow.o
And now I can see that these names are indeed, NOT found in the Qt libs I built (configuration issue...?). This didn't enlighten me much as to what should be done to fix the problem, but perhaps it might give somebody else a clue.
I don't have a full answer for you, but I can tell you that the 'U' in your nm output means the symbol is not defined in that executable (or library in this case) but is expected to be defined in an externally linked library, suggesting that something may actually be wrong with that library.
As a side note, you can use the -C argument to nm to have it demangle your C++ symbols.
I managed to get past this problem, although without totally understanding the details of it. Originally I had these two lines in the mkspecs file and although they did not cause any errors when building Qt, commenting them out fixed the problem:
QMAKE_RANLIB = i686-apple-darwin10-ranlib
QMAKE_STRIP = i686-apple-darwin10-strip
I had set these to the cross-compiler executables like this thinking it was necessary, but it seems that everything in the tool-chain is taken care of simply by specifying the correct gcc and g++.
Related
I'm building a project using a GNU tool chain and everything works fine until I get to linking it, where the linker complains that it is missing/can't find crti.o. This is not one of my object files, it seems to be related to libc but I can't understand why it would need this crti.o, wouldn't it use a library file, e.g. libc.a?
I'm cross compiling for the arm platform. I have the file in the toolchain, but how do I get the linker to include it?
crti.o is on one of the 'libraries' search path, but should it look for .o file on the library path?
Is the search path the same for gcc and ld?
crti.o is the bootstrap library, generally quite small. It's usually statically linked into your binary. It should be found in /usr/lib.
If you're running a binary distribution they tend to put all the developer stuff into -dev packages (e.g. libc6-dev) as it's not needed to run compiled programs, just to build them.
You're not cross-compiling are you?
If you're cross-compiling it's usually a problem with gcc's search path not matching where your crti.o is. It should have been built when the toolchain was. The first thing to check is gcc -print-search-dirs and see if crti.o is in any of those paths.
The linking is actually done by ld but it has its paths passed down to it by gcc. Probably the quickest way to find out what's going on is compile a helloworld.c program and strace it to see what is getting passed to ld and see what's going on.
strace -v -o log -f -e trace=open,fork,execve gcc hello.c -o test
Open the log file and search for crti.o, as you can see my non-cross compiler:
10616 execve("/usr/bin/ld", ["/usr/bin/ld", "--eh-frame-hdr", "-m", "elf_x86_64", "--hash-style=both", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-o"
, "test", "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "-L/usr/lib/gcc/x86_64-linux-g
nu/"..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., "-L/lib/../lib", "-L/usr/lib/../lib", "-L/usr/lib/gcc/x86_64-linux-gnu
/"..., "/tmp/cc4rFJWD.o", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "/usr/lib/gcc/x86_
64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."...], "COLLECT_GCC=gcc", "COLLECT_GCC_OPTIONS=\'-o\' \'test\' "..., "COMPILER_PATH=/usr/lib/gcc/x86_6"..., "LIBRARY_PATH=/usr/lib/gcc/x86_64"..., "CO
LLECT_NO_DEMANGLE="]) = 0
10616 open("/etc/ld.so.cache", O_RDONLY) = 3
10616 open("/usr/lib/libbfd-2.18.0.20080103.so", O_RDONLY) = 3
10616 open("/lib/libc.so.6", O_RDONLY) = 3
10616 open("test", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3
10616 open("/usr/lib/gcc/x86_64-linux-gnu/4.2.3/../../../../lib/crt1.o", O_RDONLY) = 4
10616 open("/usr/lib/gcc/x86_64-linux-gnu/4.2.3/../../../../lib/crti.o", O_RDONLY) = 5
10616 open("/usr/lib/gcc/x86_64-linux-gnu/4.2.3/crtbegin.o", O_RDONLY) = 6
10616 open("/tmp/cc4rFJWD.o", O_RDONLY) = 7
If you see a bunch of attempts to open(...crti.o) = -1 ENOENT, ld is getting confused and you want to see where the path it's opening came from...
I had the same issue while cross-compiling. crti.o was in <sysroot>/usr/lib64 but the linker would not find it.
Turns out that creating an empty directory <sysroot>/usr/lib fixed the issue. It seems that the linker would search for a path <sysroot>/usr/lib first, and only if it exists it would even consider <sysroot>/usr/lib64.
Is this a bug in the linker? Or is this behaviour documented somewhere?
In my case Linux Mint 18.0/Ubuntu 16.04, I have no crti.o at all:
$ find /usr/ -name crti*
I find nothing so I install developer package:
sudo apt-get install libc6-dev
If you find some libs read here
OK I had to reinstall the tool chain, so that the missing files were then included. It seems strange since it should have found it on the gcc path. The main problem I guess was that I had 15 or so different crti.o files on my computer and wasn't point to the correct one. Still doesn't make since but it works now :-) Thanks for your help :-)
I had a similar problem with a badly set-up cross-compiler. I got around it like so:
/home/rob/compiler/usr/bin/arm-linux-gcc --sysroot=/home/rob/compiler hello.c
This assumes /lib, /usr/include and so on exist in the location pointed to by the sysroot option. This is probably not how things are supposed to be done, but it got me out of trouble when I needed to compile a simple C file.
If you are cross-compiling , add sysroot option in LDFLAGS
export LDFLAGS=""--sysroot=${SDKTARGETSYSROOT}" -L${SDKTARGETSYSROOT}/lib -L${SDKTARGETSYSROOT}/usr/lib -L${SDKTARGETSYSROOT}/usr/lib/arm-poky-linux-gnueabi/5.3.0"
I get the same kind of issue on a default Ubuntu 8.04 install. I had to get the libc developer headers/files manually for it to work.
This solved for me (cross compiling pjsip for ARM):
export LDFLAGS='--sysroot=/home/me/<path-to-my-sysroot-parent>/sysroot'
I'm trying to compile a program but it throws the following error:
[cc] /usr/bin/ld: cannot find -ludev
I checked other topics on SO but the responses were to install something while I seem to be having libudev installed.
In /lib/x86_64-linux-gnu I also have:
lrwxrwxrwx 1 root root 16 lut 19 21:30 libudev.so.1 -> libudev.so.1.3.5
-rw-r--r-- 1 root root 67600 lut 19 21:31 libudev.so.1.3.5
I've tried linking libudev.so.0 to libudev.so.1 but it's still not working. What is ld looking for and why is it not working? How can I solve this?
When you use -lfoo the linker will look for a file named libfoo.a or libfoo.so.
So in your case, you need libudev.so without any suffix number.
Some Linux distributions, such as Debian and derivates (Ubuntu?), do not install these symlinks by default. So instead of creating that symlink yourself, try first looking for the *-dev package (libudev-dev).
ld is the command for linker, you need to update your LIBPATH variable to include the library location.
check the value of the env variable LIBPATH and change it to LIBPATH=LIBPATH:<lib location> and compile again.
The problem I faced has been solved here:
Loading shared library in open-mpi/ mpi-run
I know not how, setting LD_LIBRARY_PATH or specifying -x LD_LIBRARY_PATH fixes the problem, when my installation itself specifies the necessary -L arguments. My installation is in ~/mpi/
I have also included my compile-link configs.
$ mpic++ -showme:version
mpic++: Open MPI 1.6.3 (Language: C++)
$ mpic++ -showme
g++ -I/home/vigneshwaren/mpi/include -pthread -L/home/vigneshwaren/mpi/lib
-lmpi_cxx -lmpi -ldl -lm -Wl,--export-dynamic -lrt -lnsl -lutil -lm -ldl
$ mpic++ -showme:libdirs
/home/vigneshwaren/mpi/lib
$ mpic++ -showme:libs
mpi_cxx mpi dl m rt nsl util m dl % Notice mpi_cxx here %
When I compiled with mpic++ <file> and ran with mpirun a.out I got a (shared library) linker error
error while loading shared libraries: libmpi_cxx.so.1:
cannot open shared object file: No such file or directory
The error has been fixed by setting LD_LIBRARY_PATH. The question is how and why? What am i missing? Why is LD_LIBRARY_PATH required when my installation looks just fine.
libdl, libm, librt, libnsl and libutil are all essential system-wide libraries and they come as part of the very basic OS installation. libmpi and libmpi_cxx are part of the Open MPI installation and in your case are located in a non-standard location that must be explicitly included in the linker search path LD_LIBRARY_PATH.
It is possible to modify the configuration of the Open MPI compiler wrappers and make them pass the -rpath option to the linker. -rpath takes a library path and appends its to a list, stored inside the executable file, which tells the runtime link editor (a.k.a. the dynamic linker) where to search for libraries before it consults the LD_LIBRARY_PATH variable. For example, in your case the following option would suffice:
-Wl,-rpath,/home/vigneshwaren/mpi/lib
This would embed the path to the Open MPI libraries inside the executable and it would not matter if that path is part of LD_LIBRARY_PATH at run time or not.
To make the corresponding wrapper add that option to the list of compiler flags, you would have to modify the mpiXX-wrapper-data.txt file (where XX is cc, c++, CC, f90, etc.), located in mpi/share/openmpi/. For example, to make mpicc pass the option, you would have to modify /home/vigneshwaren/mpi/share/openmpi/mpicc-wrapper-data.txt and add the following to the line that starts with linker_flags=:
linker_flags= ... -Wl,-rpath,${prefix}/lib
${prefix} is automatically expanded by the wrapper to the current Open MPI installation path.
In my case, I just simply appends
export LD_LIBRARY_PATH=/PATH_TO_openmpi-version/lib:$LD_LIBRARY_PATH
For example
export LD_LIBRARY_PATH=/usr/local/openmpi-1.8.1/lib:$LD_LIBRARY_PATH
into $HOME/.bashrc file and then source it to active again source $HOME/.bashrc.
I installed mpich 3.2 using the following command on Ubuntu.
sudo apt-get install mpich
When I tried to run the mpi process using mpiexec, I got the same error.
/home/node1/examples/.libs/lt-cpi: error while loading shared libraries: libmpi.so.0: cannot open shared object file: No such file or directory
Configuring LD_LIBRARY_PATH didn't fix my problem.
I did a search for the file 'libmpi.so.0' on my machine but couldn't find it. Took me some time to figure out that 'libmpi.so.0' file is named as 'libmpi.so' on my machine. So I renamed it to 'libmpi.so.0'.
It solved my problem!
If you are having the same problem and you installed the library through apt-get, then do the following.
The file 'libmpi.so' should be in the location '/usr/lib/'. Rename the file to 'libmpi.so.0'
mv /usr/lib/libmpi.so /usr/lib/libmpi.so.0
After that MPI jobs should run without any problem.
If 'libmpi.so' is not found in '/usr/lib', you can get its location using the following command.
whereis libmpi.so
first, run this command
$ sudo apt-get install libcr-dev
if still have this problem then configure LD_LIBRARY_PATH like this:
export LD_LIBRARY_PATH=/usr/local/mpich-3.2.1/lib:$LD_LIBRARY_PATH
then add it to ~/.bashrc before this line:
[ -z "$PS1" ] && return
Simply running
$ ldconfig
appears to me as a better way to solve the problem (taken from a comment on this question). In particular, since it avoids misuse of the LD_LIBRARY_PATH environment variable. See here and here, for why I believe it's misused to solve the problem at hand.
When I run ldd against a shared library such as libphp5.so I see that it has a dependency on libmysqlclient.so.16:
$ ldd ./libphp5.so
libmysqlclient.so.16 => /usr/lib/mysql/libmysqlclient.so.16
[other dependencies snipped out]
Are these dependency filenames and paths (/usr/lib/mysql/libmysqlclient.so.16) baked into the shared library binary? Or is this path determined by some other means such as via /etc/ld.so.conf.d/mysql-i386.conf, which incidentally contains:
/usr/lib/mysql/
One other thing is puzzling me:
There is a shared library I have that I compile from source. This has a dependency on libmysqlclient_r. The gcc compiler switches to produce this this library look like:
gcc -shared -L/usr/lib/mysql -lmysqlclient_r [+various other switches]
When I do ldd mylib.so I see:
libmysqlclient_r.so.16 => /usr/lib/mysql/libmysqlclient_r.so.16 (0x0055c000)
However in the /usr/lib/mysql directory I see:
-rwxr-xr-x. libmysqlclient_r.so -> libmysqlclient_r.so.16.0.0
lrwxrwxrwx. libmysqlclient_r.so.16 -> libmysqlclient_r.so.16.0.0
-rwxr-xr-x. libmysqlclient_r.so.16.0.0
lrwxrwxrwx. libmysqlclient.so -> libmysqlclient.so.16.0.0
lrwxrwxrwx. libmysqlclient.so.16 -> libmysqlclient.so.16.0.0
-rwxr-xr-x. libmysqlclient.so.16.0.0
libmysqlclient_r.so is a symbolic link to libmysqlclient_r.so.16.0.0, so why does ldd show the dependency as libmysqlclient_r.so.16. Is there some magic I'm missing here?
Having been a Windows dev for many years I'm a bit new to gcc and development on Linux.
My Linux distribution is CentOS 6.0 x86-32bit.
You can see which paths are coming from where by running
LD_DEBUG=libs ldd ./libphp5.so
Are these dependency filenames and paths (/usr/lib/mysql/libmysqlclient.so.16) baked into the shared library binary?
The filename almost certainly is. The path usually isn't. You can see what is baked into the binary with
readelf -d ./libphp5.so
Look for (NEEDED) and (RPATH) entries.
Also give man ld.so a read. There are many factors that affect how dynamic loader searches for shared libraries: ld.so.conf, LD_LIBRARY_PATH, whether the executable is suid or not, how glibc was configured, which -rpath settings were given at link time, etc. etc.
Are these dependency filenames and paths (/usr/lib/mysql/libmysqlclient.so.16) baked into the shared library binary?
Yes, they can be and often are. The keyword here is -rpath. However, ld.conf also has its say. The whole system is quite complex, unfortunately.
Everybody out there,
I'm writing a c code which have a strange problem when I compile it .
The source code is OK.
I compile it with following option:
$ gcc above_sample.c -I/home/hadoop/project/hadoop-0.20.2/src/c++/libhdfs -L/home/hadoop/project/hadoop-0.20.2/c++/Linux-amd64-64/lib -lhdfs -o above_sample.
But it show the out put like that:
/usr/bin/ld: warning: libjvm.so, needed by /home/hadoop/project/hadoop-0.20.2/c++/Linux-amd64-64/lib/libhdfs.so, not found (try using -rpath or -rpath-link) /home/hadoop/project/hadoop-0.20.2/c++/Linux-amd64-64/lib/libhdfs.so: undefined reference to `JNI_CreateJavaVM#SUNWprivate_1.1'
/home/hadoop/project/hadoop-0.20.2/c++/Linux-amd64-64/lib/libhdfs.so: undefined reference to `JNI_GetCreatedJavaVMs#SUNWprivate_1.1'
collect2: ld returned 1 exit status
I searched for libjvm.so i found It in my system in /usr/java/lib.
I made a symbolic link of it but did not work.
i copied the library in to several places like usr/lib check the LD_library_Path
but could not manage to compile the program it showing the same error again and again
Can any one tell me what I'm doing wrong ?
how to link .so file to gcc ?
or how .so files are linked in program?
Try adding:
-L/usr/java/lib
To your linker command, since that's the library your linker is not being able to find: I_GetCreatedJavaVMs#SUNWprivate_1.1.
A little piece of advice: it's not a good idea to mess with LD_LIBRARY_PATH. Just fix your linker command.
Linker gives a warning about not found reference to function JNI_CreateJavaVM#SUNWprivate_1.1
/usr/bin/ld: warning: libhdfs.so: undefined reference to
`JNI_CreateJavaVM#SUNWprivate_1.1'
This function name might be specific for library from Sun/Oracle HotSpot JVM. Other JVMs may have another name. For example, mine OpenJDK had only shorter name such as JNI_CreateJavaVM and linker gave me the same warning.
You may get list of the functions from your libjvm.so by running command:
readelf -s libjvm.so | grep JNI_CreateJavaVM # given that you are in catalog containing libjvm.so
If output does not contain required function, then you might want to install another JDK.
That's what worked for me:
CDH=/opt/cloudera/parcels/CDH
OS_ARCH=amd64
gcc hdfs_example.c -I$CDH/include -L$CDH/lib64 \
-L/usr/java/default/jre/lib/${OS_ARCH}/server \
-ljvm -lhdfs -o hdfs_write_test