Ubuntu 11.10 linking perftools library - c++

I can't get gcc in Ubuntu 11.10 to properly link in the google perftools -lprofiler.
The problem seems to be that the linker discards libraries which are not directly used in a program.
An example will help.
Let's call this main.cpp:
#include <math.h>
int main()
{
double value;
for (int i=0; i < 1000000; i++)
{
for (int j=0; j < 1000; j++)
value = sqrt(100.9);
}
return 0;
}
Compile using:
g++ -c main.cpp -o main.o
g++ main.o -o main -lm -lprofiler
Check the executable using ldd ./main:
linux-vdso.so.1 => (0x00007fff5a9ff000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f32bc1c9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f32bc593000)
Normally, I would run:
CPUPROFILE=/tmp/profile ./main
to produce profile output. But since the profile library is not linked in no profile output is generated.
I've made sure the profiler library is in my search path, and have tried directly linking against the shared library and static library.
The above test works fine on Ubuntu 10.04, Ubuntu 10.10, Ubuntu 11.04, SUSE 12.1, and Fedora 16.
Also, once I include function calls that use the profiler (such as ProfilerStart() and ProfilerStop()), then the profiler library gets linked into the executable.
Any ideas on how to get gcc to link in the profiler library?
Thanks.

g++ main.o -o main -lm -lprofiler
As another.anon.coward commented, you are likely falling victim of your g++ using --as-needed linker flag. Try this instead:
g++ main.o -Wl,--no-as-needed -lprofiler -Wl,--as-needed
Notes:
g++ already adds -lm, no need to add it again
It is important to turn --as-needed back on. Not doing so will likely cause you to link to additional libraries that you don't really need.

In my case, the problem was that there was only a libprofiler.so.0, and no libprofiler.so in /usr/lib/:
user#compy:/usr/include$ dpkg -L libgoogle-perftools4
/.
/usr
/usr/share
/usr/share/doc
/usr/share/doc/libgoogle-perftools4
/usr/share/doc/libgoogle-perftools4/README.Debian
/usr/share/doc/libgoogle-perftools4/copyright
/usr/lib
/usr/lib/libprofiler.so.0.4.5
/usr/lib/libtcmalloc.so.4.2.6
/usr/lib/libtcmalloc_debug.so.4.2.6
/usr/lib/libtcmalloc_and_profiler.so.4.2.6
/usr/share/doc/libgoogle-perftools4/AUTHORS
/usr/share/doc/libgoogle-perftools4/TODO
/usr/share/doc/libgoogle-perftools4/README.gz
/usr/share/doc/libgoogle-perftools4/NEWS.gz
/usr/share/doc/libgoogle-perftools4/changelog.Debian.gz
/usr/lib/libtcmalloc.so.4
/usr/lib/libtcmalloc_and_profiler.so.4
/usr/lib/libprofiler.so.0
/usr/lib/libtcmalloc_debug.so.4
I don't know what the official fix to this is, but I simply created a symlink in /usr/lib:
user#compy:/usr/lib$ sudo ln -s libprofiler.so.0 libprofiler.so
This will make -lprofiler work.
If you don't mind changing your Makefile you can alternatively specify -l:libprofiler.so.0 instead of -lprofiler (note the extra colon) (source).
EDIT: The official way to get the .so is apparently to install the libgoogle-perftools-dev package as explained here:
user#compy:/usr/lib$ dpkg -S libprofiler.so
libgoogle-perftools-dev: /usr/lib/libprofiler.so
libgoogle-perftools4: /usr/lib/libprofiler.so.0.4.5
libgoogle-perftools4: /usr/lib/libprofiler.so.0
I understand that if you want to link to a certain lib, you should install the libx-dev package, which will contain the /usr/lib/libx.so. This file will only be a symlink to a specific version, such as /usr/lib/libx.so.1.2. When you link against /usr/lib/libx.so by specifying -lx to your linker, you will actually create a link in your program against the specific version linked at the time by recording a SONAME of libx.so.1 (the last version number is stripped as oulined here). So when you run your program at a later point in time the dynamic linker will look only for /usr/lib/libx.so.1, which is symlinked to /usr/lib/libx.so.1.2, and no /usr/lib/libx.so hence no dev package needs to exist.
So the libx-dev packages is for compiling and linking against libx, and the libx package is for running a precompiled program against libx.

Related

Building GDAL with all libraries static

I want to develop a small program that checks which polygons from a shapefile intersect a given rectangle. This program is to be used in a website (with PHP's exec() command). The problem is, my webserver cannot install GDAL, for reasons unknown to me. So I can't link to the shared libraries. Instead, I must link to static libraries, but these aren't given.
I've downloaded the GDAL source code from here (2.3.2 Latest Stable Release - September 2018), and followed the build instructions from here. Since I already have GDAL working on my Debian, and don't want to mess with it, I followed the "Install in non-root directory" instructions, with some adjusts from the last item in the "Some caveats" section:
cd /home/rodrigo/Downloads/gdal232/gdal-2.3.2
mkdir build
./configure --prefix=/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/ --without-ld-shared --disable-shared --enable-static
make
make install
export PATH=/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/bin:$PATH
export LD_LIBRARY_PATH=/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib:$LD_LIBRARY_PATH
export GDAL_DATA=/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/share/gdal
/usr/bin/gdalinfo --version
build/bin/gdalinfo --version
The first /usr/bin/gdalinfo --version gives 2.1.2 (the previous installed version). The second, build/bin/gdalinfo --version, gives 2.3.2 (the version just built).
By now, my program only uses the ogrsf_frmts.h header, which is in /usr/include/gdal/ or /home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/include/ directory, depending on the build. There's no ogrsf_frmts.a file, but only a libgdal.a. Is this the file I should be linking against? If so, how? I've tried so far:
gcc geofragc.cpp -l:libgdal.a
gcc geofragc.cpp -Wl,-Bstatic -l:libgdal.a
gcc geofragc.cpp -Wl,-Bstatic -l:/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
gcc geofragc.cpp -Wl,-Bstatic -l/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
gcc geofragc.cpp /home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
gcc geofragc.cpp -l/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
gcc geofragc.cpp -l:/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
but nothing works. What am I missing?
EDIT
The second trial (gcc geofragc.cpp -Wl,-Bstatic -l:libgdal.a) is giving the following error:
/usr/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-linux-gnu/6/../../../../lib/libgdal.a(gdalclientserver.o): In function `GDALServerSpawnAsync()':
(.text+0x1f5e): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
You can use the gdal-config program to get correct options for compilation and linking. This program is a part of the GDAL library and it has its own options:
hekto#ubuntu:~$ gdal-config --help
Usage: gdal-config [OPTIONS]
Options:
[--prefix[=DIR]]
[--libs]
[--dep-libs]
[--cflags]
[--datadir]
[--version]
[--ogr-enabled]
[--gnm-enabled]
[--formats]
You have to make sure this program is on your search path, or you can create an alias - for example:
alias gdal-config='/home/rodrigo/Downloads/gdal232/gdal-2.3.2/bin/gdal-config'
Now your compilation and linking command becomes the following one:
g++ `gdal-config --cflags` geofragc.cpp `gdal-config --libs` `gdal-config --dep-libs`
You have to use the g++ compiler to link with C++-built libraries.
Another option is to create a Makefile with these lines:
CXXFLAGS += ${shell gdal-config --cflags}
LDLIBS += ${shell gdal-config --libs}
LDLIBS += ${shell gdal-config --dep-libs}
geofragc: geofragc.cpp
and just call make with this Makefile.
I hope, it'll help.

Using c++ library on linux [duplicate]

This question already has answers here:
How to install c++ library on linux
(2 answers)
Closed 4 years ago.
I'm new to c++ and don't understand how to install a library on Linux (Mint). I want to use the GNU GMP library:https://en.wikipedia.org/wiki/GNU_Multiple_Precision_Arithmetic_Library
I downloaded the tar.lz file and installed it with
./configure
make
sudo make install
If I try to compile it, I get the error message that the header file "gmpxx.h" wasn't found. Where can I find this file? How do I compile it with the -lgmpxx -lgmp flags? I tried something like:
g++ test.cpp -o test -lgmpxx -lgmp
If the library is using the Autoconf system (which your does) then the default installation prefix is /usr/local.
That means libraries are installed in /usr/local/lib, and header files in /usr/local/include. Unfortunately few Linux systems have those added for the compiler to search by default, you need to explicitly tell the compiler to do it.
Telling the compiler to add a header-file path is done using the -I (upper-case i) option. For libraries the option is -L.
Like so:
g++ test.cpp -I/usr/local/include -L/usr/local/lib -lgmpxx -lgmp
The above command will allow your program to build, but it's unfortunately not enough as you most likely won't be able to run the program you just built. That's because the run-time linker and program loader doesn't know the path to the (dynamic) libraries either. You need to add another linker-specific flag -rpath telling the build-time linker to embed the path inside your finished program. The front-end program g++ doesn't know this option, so you need to use -Wl,-rpath:
g++ test.cpp -I/usr/local/include -L/usr/local/lib -lgmpxx -lgmp -Wl,-rpath=/usr/local/lib
The options can be found in the GCC documentation (for the -I and -L and -Wl options), and the documentation for ld (the compile-time linker) for the -rpath option.
If you install a lot of custom-build libraries, you might add the path /usr/local/lib to the file /etc/ld.so.conf and then run the ldconfig command (as root). Then you don't need the -rpath option.
Now with all of that said, almost all libraries you would usually use for development will be available in your distributions standard repository. If you use them the libraries will be installed with paths that means you don't have to add flags.
So I recommend you install your distributions development packages for the libraries instead.

Which version of glibc should be used when release my *.so file?

I'm working on a shared library which support SSL connection and transmission. I want to release it as a *.so file. After compiling it in my Ubuntu14.04(64bit Desktop) with g++ 4.8.2, it can not work in the CentOS5.8.
The First Round
I compile the shared library with following command:
g++ -v -shared -Wl,-soname,libmyssl.so.1,-o libmyssl.so.1.0 myssl.o -lz -lssl -lcrypto
I use command objdump -p libmyssl.so.1.0|grep NEEDED to know it depends on following libraries:
NEEDED libz.so.1
NEEDED libssl.so.1.0.0
NEEDED libcrypto.so.1.0.0
NEEDED libstdc++.so.6
NEEDED libc.so.6
Then I write a demo to use libmyssl.so.1.0.
g++ -D UNIX64 -o ssldemo ssldemo.cpp ./libmyssl.so.1.0 -lz -lssl -lcrypto
I compile the demo in Ubuntu14.04(the same version), it works fine.
I compile the demo in CentOS(openssl 0.9.8e), it linked failed because invalid openssl's version
The Second Round
I removed the "-lz lssl -lcrypto", so the command as following
g++ -v -shared -Wl,-soname,libmyssl.so.1,-o libmyssl.so.1.0 myssl.o
I use command objdump -p libmyssl.so.1.0|grep NEEDED to know it depends on following libraries:
NEEDED libstdc++.so.6
NEEDED libc.so.6
I use the libmyssl.so.1.0 in above demo code in the same way:
g++ -D UNIX64 -o ssldemo ssldemo.cpp ./libmyssl.so.1.0 -lz -lssl -lcrypto
I compile the demo in Ubuntu14.04(the same version), it works fine.
I compile the demo in CentOS(openssl 0.9.8e), it didn't report ssl linked errors, but it report glibc linked errors as follows:
undefined reference to `memcpy#GLIBC_2.14'
After updating CertOS's glibc, the demo work fine.
The Third Round
I try to remove the depends to "libc.so.6" and "libstdc++.so.6", so I added option "-nodefaultlibs" to the compile command:
g++ -nodefaultlibs -v -shared -Wl,-soname,libmyssl.so.1,-o libmyssl.so.1.0 myssl.o
I use command objdump -p libmyssl.so.1.0|grep NEEDED only get empty string.
I use command ldd libmyssl.so.1.0 get result "statically linked", no sure why it said "statically linked".
I use the libmyssl.so.1.0 in above demo code in the same way:
g++ -D UNIX64 -o ssldemo ssldemo.cpp ./libmyssl.so.1.0 -lz -lssl -lcrypto
It always report following error both in Ubuntu14.04 and CentOS5.8:
Ubuntu:
hidden symbol `atexit' in /usr/lib/x86_64-linux-gun/libc_nonshared.a(atexit.oS) is referenced by DSO
/usr/bin/ln: final link failed: Bad value
CentOS:
hidden symbol `atexit' in /usr/lib64/libc_nonshared.a(atexit.oS) is referenced by DSO
/usr/bin/ln: final link failed: Nonrepresentable section on output
Questions:
Which version of GLIBC should be linked when I compile my *.so file so that it can work fine in as many as possible Linux?
Do have a way to avoid the dependency to the GLIBC? I tried it in The Third Round but failed.
Any other suggestions ?
Which version of GLIBC should be linked when I compile my *.so file
so that it can work fine in as many as possible Linux?
You should select the oldest distro that you want to target and build on this one. This would ensure that your library would require the minimum possible Glibc version. So simply select the distro with oldest Glibc and build there.
Version of your Glibc is usually encoded in libc.so name (e.g. /lib64/libc-2.12.so) but you can also do
$ strings //lib64/libc-2.12.so | grep GLIBC
GLIBC_2.2.5
GLIBC_2.2.6
...
GLIBC_2.12
GLIBC_PRIVATE
Do have a way to avoid the dependency to the GLIBC? I tried it in The Third Round but failed.
Writing entirely Glibc-independent library sounds like an overkill (you'll need to re-implement IO, memcpy, etc., with lower quality/performance compared to Glibc). Are you sure you want to go down this path?
Any other suggestions ?
For complete applications two common solutions are
static linking
bundling them together with stdlibs they were linked against (they'll of course need to be run with special LD_LIBRARY_PATH or -Wl,-rpath)
But in your case (isolated shared library) targeting the lowest supported Glibc seems to be the only option.

Executing cross-compiled C++ program using Boost on Raspberry Pi

I have built a GCC cross toolchain for the RPi and can cross-compile C++ source and successfully run it after copying the executable to the RPi.
Next I built the Boost libraries targeting ARM, using the cross toolchain. I can successfully build and link C++ source to those Boost libraries using the cross toolchain on my PC.
I then copied the program, dynamically linked to Boost, to the RPi and copied all built libraries into /usr/local/lib on the Pi. However, executing fails:
$ ./my_program
./my_program: error while loading shared libraries: libboost_system.so.1.60.0: cannot open shared object file: No such file or directory
Again, this library, libboost_system.so.1.60.0, exists in /usr/local/lib.
I also tried
export LD_LIBRARY_PATH='/usr/local/lib'
but that doesn't change anything. What am I doing wrong?
EDIT:
I build all source files like this (rpi-g++ is a symlink to my cross-compiler):
rpi-g++ -c -std=c++1y -Wall -Wextra -pedantic -O2 -I /path/to/cross/boost/include *.cpp
rpi-g++ -o myprog *.o -L /path/to/cross/boost/lib/ -lboost_system -pthread
EDIT 2:
When linked with
rpi-g++ -o myprog *.o -L /path/to/cross/boost/lib/ -rdynamic -lboost_system -pthread
the problem remains the same. I have checked and verified everything suggested by Technaton as well. Strangely, ldd insists that the created executable is "not a dynamic executable" (checked that on my PC and on the RPi), which doesn't make sense to me.
There are several things you can check. I've posted a complete check list here, but judging from your linker command line, number 5 is probably the culprit.
Check that your library and your program are correctly build for the target architecture. You can verify that by using file ./myprog and file libboost_system.so.1.60.0.
Make sure that you have copied the actual shared object, and not a link to it.
Ensure that the shared object file's permissions are sane (0755).
Run ldconfig -v and check that your shared object file is picked up. Normally, /usr/local/lib is in the standard library search path, and LD_LIBRARY_PATH is not required.
Make sure that your program is actually dynamically linked by running ldd ./myprog. Judging from your linker command line, that is the problem: You're missing -rdynamic.
Check the paths returned from ldd: If you have linked with rpath, the library search path might be screwed up. Try again without -rpath.

Linking an application to libbz2.so.1 rather than libbz2.so.1.0

Here's the current situation I'm in:
I want to distribute a binary app on Linux that would run on several distros (not all of them, just the main ones matter at the moment, let's focus on Ubuntu and Fedora for the sake of this discussion). The app in question links to libbz2 for some of its work. A simple "Hello World" will illustrate the situation :
/* main.cpp */
#include <iostream>
int main(int argc, char* argv[])
{
std::cout << "Hello World!\n";
return 0;
}
The app is built as such :
g++ -lbz2 -o test.bin main.cpp
My build system is on Ubuntu. When I perform a check with ldd on the resulting binary, it lists libbz2.so.1.0 as a runtime dependency. When I take this app to a Fedora machine, the app doesn't run and ldd reveals that it can't find libbz2.so.1.0. Fedora only has libbz2.so.1 and libbz2.so.1.0.4, but not libbz2.so.1.0.
Red Hat's Bugzilla database reveals that this behavior is not a bug, but a feature. I don't really need libbz2.so.1.0, and I would be satisfied with simply linking to libbz2.so.1, but I have yet to figure out how.
I have seen a similar question asked here previously, but the accepted answer (You can pass the actual .so file instead of -l on the linker command line) doesn't seem to work. I tried building with the following command :
g++ /lib/libbz2.so.1 -o test.bin main.cpp
However, ldd still mentions that the app depends on libbz2.so.1.0, even though I passed the full name to g++.
Now, the question is, is there a way on Ubuntu to build the app to have it depend only on libbz2.so.1 rather than on libbz2.so.1.0?
Thanks.
Here's a bit of background to explain what got linked. On ELF platforms the -L and -l flags you pass only locate the binary at link time. If the linker linker determines that a library is required it generates a reference to the SONAME in that binary, regardless of what it was called. For example:
$ objdump -p /lib64/libbz2.so.1 | grep SONAME
SONAME libbz2.so.1
So regardless of what libbz2 is named, that is what will show up as a dependency. Again by example, doing something totally whacked:
$ ln -s /lib64/libbz2.so.1 libblah.so
$ g++ t.C -L. -l blah
You have the apparency of having linked to libblah but because its the SONAME in that binary that matters, your dependency is still this libbz2.so.1
$ ldd a.out | grep bz2
libbz2.so.1 => /lib64/libbz2.so.1 (0x00002b3d1a000000)
Other than the -static trickery (which can break things in interesting ways), there is not easy way out of the mess (ideally the library would do nice symbol versioning like glibc and never or rarely change its SONAME).
Why don't you just link statically instead?
I have done that in the past for builds on Ubuntu and deployment on RHEL which works just fine using static builds.