Linking libpng with g++ - c++

I'm trying to get libpng working on linux. I couldn't get it to work through netbeans, so I ran g++ directly as g++ -lpng -lz main.cpp -o test and it compiles. When I try to run it it it outputs ./test: error while loading shared libraries: libpng14.so.14: cannot open shared object file: No such file or directory. I assume this means I am linking dynamically and it can't find the .so file
~/Programs/NetBeansProjects/DiamondSquare$ ldd test
linux-gate.so.1 => (0x008a5000)
libpng14.so.14 => not found
libz.so.1 => /usr/local/lib/libz.so.1 (0x00209000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x0094b000)
libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x00e3a000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00927000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00220000)
/lib/ld-linux.so.2 (0x00b85000)
I didn't really want to link dynamically in the first place. How could I resolve this?
I know that libpng14.so.14 is in /usr/local/lib also, if that matters.
Extra points if you can tell me how to do this within netbeans.

It's odd that g++ is able to find the library but test can not (you can tell that g++ can find it because test specifically expect libpn14 even though you only tell g++ '-lpng'). Are you sure you aren't passing any -L or -R flags to g++? Are your LD_PRELOAD or LD_LIBRARY_PATH environment variables set in the shell you're running g++ in but not in the shell you're running test in? You can point LD_PRELOAD at a specific shared library to tell an app or g++ how to find it, and any folders in LD_LIBRARY_PATH are automatically searched.
Also to link libpng statically put "-Wl,-Bstatic" before "-lpng." Beware, any libraries after the -Bstatic will be linked statically. You can switch back to dynamic and list some more libraries by using "-Wl,-Bdynamic -lfoo".

Dynamic linking is the default and should be preferred in general. You say libpng is in /usr/local/lib, are you really positive about this? It finds /usr/local/lib/libz.so.1. If libpng14.so.14 was in /usr/local/lib, too it should find it.

Related

Static linking of an FORTRAN code with MPI

I want to build a standalone bainary (static linking) of my fortran code so that it does not use any shared libaries anymore.
The program uses mpi so I need all connected libaries.
I started with generating my own libary pack:
ar rc my_lib.a /opt/intel/impi/4.1.0.030/intel64/lib/* /opt/intel/composerxe/mpirt/lib/intel64/*
Followed by compiling my files:
ifort -c -I/home/.../Remote/mpif.h -L/home/../Remote/my_lib.a file1.f
ifort -c -I/home/.../Remote/mpif.h -L/home/.../Remote/my_lib.a file1.f
ifort -O3 -o dns zufall.o dnspipe.o my_lib.a
But this returned the following error message:
ld: dns: hidden symbol `stat' in /usr/lib/x86_64-linux-gnu/libc_nonshared.a(stat.oS) is referenced by DSO
ld: final link failed: Bad value
How could I fix that?
Remark 1: #Gilles
I tried that now and it works:
mpiifort -c zufall.f
mpiifort -c dnspipe.f
ifort -o dns zufall.o dnspipe.o -L/opt/intel/impi/4.1.0.030/intel64/lib -Wl,-non_shared,-lmpigf,-lmpi,-lmpigi,-call_shared
The ldd dns output than is:
linux-vdso.so.1 => (0x00007fff6ace6000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f557a6f9000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f557a4dd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f557a151000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5579f3b000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5579d37000)
/lib64/ld-linux-x86-64.so.2 (0x00007f557a993000)
Is this now static?
I don't have the same version of Intel MPI so I can't test for sure my solution here. But still, here is how it goes after a few remarks:
Having a fully static binary might not be such a good idea, especially when it comes to the libc... But on a fully homogeneous cluster, why, not.
Normally, just using mpiifort -static should do the trick. However, experience shows that this is rarely the case because of some random functions missing here and there in the static libs, etc.
If only some of the libraries are the ones you want to have statically linked, then there is a solution. If for example this is the Intel libraries you want static, the -intel-static linking option is supposedly doing the tick. But again, unfortunately, most of the time it doesn't work as advertised, notably for the MPI libraries.
So let's assume that what you want is at least packing the MPI libraries into your binary. So this is how I do it:
> mpiifort -c hello_mpi.f90
> ifort -o hello_mpi hello_mpi.o -L$INTEL_MPI_PATH/intel64/lib -Wl,-non_shared,-lmpigf,-lmpi,-lmpigi,-call_shared
The list of libraries to include will depend on the version of the MPI library you use I guess, but you can easily get it with a mpiifort -show.
This works for me. Does it for you?

Undefined symbol when loading a shared library

In my program I need to load a shared library dynamically with dlopen(). Both the program and the shared library are successfully cross-compiled for an ARM architecture with the cross-compiler installed on my x86. However, whenever the program tries to load the library at run time on ARM, it fails giving this error:
undefined symbol: _dl_hwcap
I cannot find the culprit of this error.
Let me give details on how the shared library (libmyplugin.so) is built on x86 first. I use the g++ cross-compiler as below:
/home/me/arm/gcc-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ -march=armv7-a -mfloat-abi=hard -c -s -fPIC -o build/module1.o module1.cpp
/home/me/arm/gcc-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ -march=armv7-a -mfloat-abi=hard -c -s -fPIC -o build/module2.o module2.cpp
/home/me/arm/gcc-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ -o dist/libmyplugin.so build/module1.o build/module2.o --sysroot /home/me/arm/sysroot/ -Wl,--no-as-needed -ldl -lX11 -lXext /home/me/arm/libstatic.a -shared -s -fPIC
Please pay attention to the following notes:
module1.cpp and module2.cpp are my source code files.
libstatic.a is a big archive of object .o files implementing the stuff directly invoked/referenced by module1.cpp and module2.cpp. These object files have been compiled by others for the same ARM architecture as mine, with the same compiler flags, but using a slightly more updated g++ compiler (v4.9 instead of my v4.8.3). Unfortunately, I have no control on the building of these objects.
--sysroot /home/me/arm/sysroot/ represents the remote filesystem of my ARM OS from which the local g++ cross-compiler can take the native libraries while linking.
-Wl,--no-as-needed -ldl -lX11 -lXext: these flags are required to force the dynamic loader to load the X11 libraries present on the system when my shared library is loaded by the program. In particular, --no-as-needed is required because the X11 libraries are NOT directly referenced by module1.o and module2.o; on the contrary the X11 libraries are referenced by the static library only.
Note that all the above setup works on x86. It's just that I don't understand what is the reason of the _dl_hwcap symbol not resolved when the program tried to load the library on ARM.
Do you have any idea how to investigate this issue?
There are a myriad of things that could be problematic, but here are four avenues of exploration. I am concentrating on the -shared in your link line, but the last item addresses that as well.
(A nice HOWTO on shared libraries is here:
http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
a) Check your environment variable LD_LIBRARY_PATH. Since you aren't using RPATH to the linker (RPATH embeds a full path to the .so so you can find it at runtime), then the only way the linker can find your code is to search the LD_LIBRARY_PATH.
Make sure the .so or .0 you want is in the path.
b) Use the UNIX utility 'nm' to search .so (shared objects) and .a files for that symbol. For example, 'nm -D /usr/lib64/libpython2.6.so' will show all dynamic symbols
in the libpython.so, and you can look for symbols of interest:
For example, Is 'initgc' defined or used in libpython?
% nm -D /usr/lib64/libpython2.6.so | grep initgc
000003404300cf0 T initgc
The 'T' means TEXT or, yes, it is defined there. See if you can find the symbol in the module of interest using grep and nm. (A 'U' means undefined, which means it is defined in another module).
c) Another useful tool is 'ldd'. It shows all dynamic libraries that the library you are looking on depends on. For example:
% ldd /usr/lib64/libpython2.6.so
linux-vdso.so.1 => (0x00007fffa49ff000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00000033f0200000)
libdl.so.2 => /lib64/libdl.so.2 (0x00000033f0600000)
libutil.so.1 => /lib64/libutil.so.1 (0x00000033fea00000)
libm.so.6 => /lib64/libm.so.6 (0x00000033f0a00000)
libc.so.6 => /lib64/libc.so.6 (0x00000033efe00000)
/lib64/ld-linux-x86-64.so.2 (0x00000033efa00000)
If it can't find a library (because it's not on the LD_LIBRARY_PATH or wasn't specified in the RPATH), the library will turn up empty.
d) I am a little worried from your link line of seeing a '.a' file with a -shared option. Some compilers/linkers cannot use a '.a' (archive) file to create a '.so' file. '.so' files usually have to made from other '.so' files or '.o' files that have been compiled with -fPIC.
I would recommend (if you can), recompile /home/me/arm/libstatic.a so that it's a .so. If you can't do, you might have to make your final output a '.a' file as well. (In other words, get rid of the -shared command line option).
In summary: Check your LD_LIBRARY_PATH, use nm and ldd to look around at your .a and .so files, but I think the end result is that you may not be able to combine .so and .a files.
I hope this helps.
I think this symbol may be in the "ld-lsb" library needed by "Xext". On my system the library is a symlink "/lib64/ld-lsb-x86-64.so -> ld-linux-x86-64.so.2", but I am sure that is not the same on the arm. Maybe give it a whirl on your linker line?

Shipping libstdc++.so.6 with application

I want to use gcc 4.8.1 for my application (requires libstdc++.so.6.0.18), however customers only have libstdc++.so.6.0.13. I have been using -static-libgcc -static-stdlibc++ for a while now, but my application consists of several dynamically linked libraries and one main application. This means that when compiling each dynamic library, they must statically compile the standard library, which is redundant and wasteful. I want to just ship the standard library of my choice with my product, however every time I run my application in an environment like theirs, it always loads the wrong standard library. It prefers the /usr/lib64/ version no matter what I seem to do (it seems to take precedence over LD_LIBRARY_PATH).
Constraints:
I'm not allowed to force them to upgrade to a new standard library.
I don't want to make the dynamic libraries static. (I'd be able to statically compile everything into the main app once, but there are some logistical barriers that prevent me from recompiling some libraries into static ones).
-Wl,-rpath=$(path_to_directory) is a bit dangerous, however it is legal because the customers do source some settings that allow me to set path variables. However, setting the rpath of my new stdlibc++ doesn't seem to be overriding the default /usr/lib64 version. I still get GLIBCXX errors because it won't use the right library.
Surely there is an elegant solution for this?
Perhaps there is just an error in my procedure. Here's an example (sorry about the censor, but it's just username stuff):
~/example$ pwd
/home/username/example
~/example$ echo $LD_LIBRARY_PATH
~/example$ ls
Makefile libstdc++.so.6.0.18 test.cpp
~/example$ make
g++ -std=c++11 -Wall -Werror test.cpp -o test
~/example$ ldd test
./test: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by ./test)
linux-vdso.so.1 => (0x00007fffe5919000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x000000390b800000)
libm.so.6 => /lib64/libm.so.6 (0x0000003904800000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000390b400000)
libc.so.6 => /lib64/libc.so.6 (0x0000003904400000)
/lib64/ld-linux-x86-64.so.2 (0x0000003904000000)
~/example$ setenv LD_LIBRARY_PATH /home/username/example
~/example$ echo $LD_LIBRARY_PATH
/home/username/example
~/example$ ldd test
./test: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by ./test)
linux-vdso.so.1 => (0x00007fff2d3ff000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x000000390b800000)
libm.so.6 => /lib64/libm.so.6 (0x0000003904800000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000390b400000)
libc.so.6 => /lib64/libc.so.6 (0x0000003904400000)
/lib64/ld-linux-x86-64.so.2 (0x0000003904000000)
Sorry guys, I made a rather dumb mistake...
~/example$ file libstdc++.so.6.0.18
libstdc++.so.6.0.18: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped
Some dweeb built the wrong version of the library, and another dweeb (namely myself) tried using it on a 64-bit machine. Using LD_LIBRARY_PATH was working all along...
Your problem is that the executable is linked to the soname libstdc++.so.6 not to the full library filename libstdc++.so.6.0.16. The dynamic linker will look for libstdc++.so.6 in the usual places (i.e. LD_LIBRARY_PATH, DT_RPATH, ldconfig dirs etc.) so to ensure the 6.0.18 version is found you need a symlink called libstdc++.so.6 pointing to it.
Instead of using LD_LIBRARY_PATH (which is fragile on machines you don't control, because users might alter their environment) I prefer linking with '-Wl,-rpath,$ORIGIN' (N.B. the quotes are necessary to stop the shell expanding $ORIGIN)
An RPATH of $ORIGIN tells the dynamic linker to start looking for shared libraries in the same directory as the executable, so if you ship libstdc++.so alongside your executable it will be found. If you want to ship the executable in a bin directory and have the library in a lib directory you can use '-Wl,-rpath,$ORIGIN/../lib' or other paths relative to the location of the executable.

Linking 'libstdc++' library is broken in embedded linux

I have been working on a project which will be loaded on an embedded system, has not enough memory/disk space to install a C++ compiler and compile the code, natively.
So, I need to “cross-compile” the code on my development (Host) machine to be used on the target machine (Embedded Linux).
The happening problem related to using strings and iostreams which are a feature of the C++ standard template library (STL). However, because memory is so critical in an embedded system, the standard template library (libstdc++), can not be available on target side.
I need to statistically link the standard libraries on host machine, rather than dynamically link on target side. So, in my Makefile I need to have a slightly complex modification in both compiling and linking steps in order to build my project.
I have used some parameters such as -nodefaultlibs, -static-libstdc++, and -lstdc++ in the linking step and also added -nostdinc++ to the compiler flags. Still, there exist the problem on target side; " can not load library libstdc++.so.6 "
Most of these settings I have tried did not work. Is there any solution?
-lstdc++ overrides -static-libstdc++, try linking with just -static-libstdc++.
See this for example:
$ g++ -o foo foo.cpp -static-libstdc++ -lstdc++
$ ldd foo
linux-gate.so.1 => (0x0056b000)
libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0x007ae000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00110000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0x005dd000)
/lib/ld-linux.so.2 (0x002bc000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0x0095e000)
libstdc++ is linked dynamically!
$ g++ -o foo foo.cpp -static-libstdc++
$ ldd foo
linux-gate.so.1 => (0x0097b000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0x001f9000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x0037f000)
/lib/ld-linux.so.2 (0x00199000)
now it is not.

How to call Matlab from C++ code?

I am trying to call Matlab functions from C++ code.
With Matlab it comes an example of such code at /extern/examples/eng_mat/engdemo.cpp, however I found no way to build that source code.
Here is the makefile I use:
CFLAGS = -Wall -O3
INCLUDES = -I/opt/Matlab-2009a/extern/include
LIBRARIES = -Wl,-R/opt/Matlab-2009a/bin/glnx86 -L/opt/Matlab-2009a/bin/glnx86 -lmx -lmat -leng
out : engdemo.cpp
g++ $(CFLAGS) $(INCLUDES) -static $^ $(LIBRARIES) -o out
clean :
rm -f out
(Here /opt/Matlab-2009a is my Matlab root.) I am getting a linker error like this:
/usr/bin/ld: cannot find -lmx
collect2: ld returned 1 exit status
make: *** [out] Error 1
And the question is: how can I make g++ to compile engdemo.cpp ?
Note, that the shared library exists:
$ locate libmx.so
/opt/Matlab-2009a/bin/glnx86/libmx.so
/opt/Matlab-2009a/bin/glnx86/libmx.so.csf
and
$ ldd /opt/Matlab-2009a/bin/glnx86/libmx.so
linux-gate.so.1 => (0x004b4000)
libut.so => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/libut.so (0x0078f000)
libmwfl.so => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/libmwfl.so (0x00110000)
libicudata.so.38 => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/libicudata.so.38 (0xb7f82000)
libicuuc.so.38 => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/libicuuc.so.38 (0x00bee000)
libicui18n.so.38 => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/libicui18n.so.38 (0x001f7000)
libicuio.so.38 => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/libicuio.so.38 (0x00e1c000)
libz.so.1 => /usr/lib/libz.so.1 (0x0098e000)
libstdc++.so.6 => /opt/Matlab-2009a/bin/glnx86/../../sys/os/glnx86/libstdc++.so.6 (0x00531000)
libm.so.6 => /lib/libm.so.6 (0x00194000)
libgcc_s.so.1 => /opt/Matlab-2009a/bin/glnx86/../../sys/os/glnx86/libgcc_s.so.1 (0x00eaa000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00900000)
libc.so.6 => /lib/libc.so.6 (0x00345000)
librt.so.1 => /lib/librt.so.1 (0x00964000)
libdl.so.2 => /lib/libdl.so.2 (0x0014e000)
libexpat.so.1 => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/../../bin/glnx86/libexpat.so.1 (0x00152000)
libboost_thread-gcc42-mt-1_36.so.1.36.0 => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/../../bin/glnx86/libboost_thread-gcc42-mt-1_36.so.1.36.0 (0x00fc2000)
libboost_signals-gcc42-mt-1_36.so.1.36.0 => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/../../bin/glnx86/libboost_signals-gcc42-mt-1_36.so.1.36.0 (0x0017d000)
libboost_system-gcc42-mt-1_36.so.1.36.0 => /opt/Matlab-2009a/bin/glnx86/../../bin/glnx86/../../bin/glnx86/libboost_system-gcc42-mt-1_36.so.1.36.0 (0x00a06000)
/lib/ld-linux.so.2 (0x001db000)
So, how can I make g++ to compile engdemo.cpp ?
Assuming $MATLABROOT is the path to MATLAB:
$MATLABROOT/bin/mex -f $MATLABROOT/bin/engopts.sh engdemo.cpp
If you add the -v switch, the verbose output will show you what commands are being used to compile the engine application.
Why are you compiling with -static? From "man gcc":
-static
On systems that support dynamic linking, this prevents linking with the shared libraries. On other systems, this option has no effect.
In other words, the -static option forces the linker to only consider static libraries, meaning that it will try to find libmx.a rather than libmx.so. Since Matlab only ships with shared (dynamic) libraries, it fails.
Try removing that option & see what happens.
If that doesn't work, you may need to run libtool to help it find the .so's at runtime.
I thought I'd post something that related that might be of use to someone who stumbles upon this post in the future, on the theme of calling a Matlab function from C++.
In a tutorial posted on the Mathworks site the use of shared libraries is demonstrated for calling Matlab function(s) from a C++ file. Here, the mcc command is used to create a shared library.
Subsequently, the mbuild command is used to build the executable. However, if you have a complicated C++ code, which itself needs its own set of shared libraries for compilation, mbuild won't work. The tutorial doesn't demonstrate what needs to be done in this case. So, the purpose of my reply is to post that solution. The user C++ file is vigenere.cpp, and the shared library to be linked in this case is libvigenere.so, and this is the resultant call to g++:
g++ -o vigenere -L/usr/local/MATLAB/R2013b/runtime/glnxa64 -L. -I/usr/local/MATLAB/R2013b/extern/include/ vigenere.cpp -lmwmclmcrrt -lm -lvigenere
Some prerequisites:
The Matlab Compiler Runtime (MCR) needs to be installed. Either type mcrinstaller at the Matlab prompt, or download the appropriate installer from the Matlab site.
After doing this, make sure to set your LD_LIBRARY_PATH as per the instructions at the end of the installer.
The current working directory needs to be added to the LD_LIBRARY_PATH. In bash, I do this by export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
Note that 1&2 are also described in a readme.txt file generated by the mcc command.