Changing one particular shared library in executable binary - linux

Here is written that curlftpfs is terribly slow because of bug in newest libcurl3-gnutls. Downgrading is not recommended due to large reverse dependencies that this package has (can be verified via apt-cache showpkg libcurl3-gnutls:amd64 or apt-cache rdepends libcurl3-gnutls:amd64). So I've decided to downgrade it different way. I've checked available versions in repository:
$ apt-cache policy libcurl3-gnutls:amd64
libcurl3-gnutls:
Installed: 7.43.0-1ubuntu2.1
Candidate: 7.43.0-1ubuntu2.1
Version table:
*** 7.43.0-1ubuntu2.1 0
500 http://sk.archive.ubuntu.com/ubuntu/ wily-updates/main amd64 Packages
500 http://security.ubuntu.com/ubuntu/ wily-security/main amd64 Packages
100 /var/lib/dpkg/status
7.43.0-1ubuntu2 0
500 http://sk.archive.ubuntu.com/ubuntu/ wily/main amd64 Packages
Then I've downloaded and extracted older version than installed one:
$ apt-get install -d libcurl3-gnutls=7.43.0-1ubuntu2
$ sudo mv /var/cache/apt/archives/libcurl3-gnutls_7.43.0-1ubuntu2_amd64.deb .
$ dpkg -x libcurl3-gnutls_7.43.0-1ubuntu2_amd64.deb extracted_deb
Then I've backed up original binary and searched for some common name in shared libraries:
$ cp $(which curlftpfs) .
$ ldd ./curlftpfs | grep curl
libcurl-gnutls.so.4 => /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4 (0x00007fcac4443000)
$ readelf -d ./curlftpfs | grep -i curl
0x0000000000000001 (NEEDED) Shared library: [libcurl-gnutls.so.4]
Following step was just the proof that linked file belongs exactly to libcurl3-gnutls package and that curlftpfs depends on libcurl3-gnutls:
$ dpkg -S /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4
libcurl3-gnutls:amd64: /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4
$ apt-cache depends curlftpfs
curlftpfs
Depends: libc6
Depends: libcurl3-gnutls
Depends: libfuse2
Depends: libglib2.0-0
Depends: fuse
Conflicts: curlftpfs:i386
Also the content of extracted and installed libcurl3-gnutls package seems exactly the same:
$ dpkg -L libcurl3-gnutls:amd64 | sort
/.
/usr
/usr/lib
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.3
/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4
/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4.3.0
/usr/share
/usr/share/doc
/usr/share/doc/libcurl3-gnutls
/usr/share/doc/libcurl3-gnutls/changelog.Debian.gz
/usr/share/doc/libcurl3-gnutls/copyright
/usr/share/doc/libcurl3-gnutls/NEWS.Debian.gz
/usr/share/lintian
/usr/share/lintian/overrides
/usr/share/lintian/overrides/libcurl3-gnutls
$ find extracted_deb/ | sort
extracted/
extracted/usr
extracted/usr/lib
extracted/usr/lib/x86_64-linux-gnu
extracted/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.3
extracted/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4
extracted/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4.3.0
extracted/usr/share
extracted/usr/share/doc
extracted/usr/share/doc/libcurl3-gnutls
extracted/usr/share/doc/libcurl3-gnutls/changelog.Debian.gz
extracted/usr/share/doc/libcurl3-gnutls/copyright
extracted/usr/share/doc/libcurl3-gnutls/NEWS.Debian.gz
extracted/usr/share/lintian
extracted/usr/share/lintian/overrides
extracted/usr/share/lintian/overrides/libcurl3-gnutls
My question is how can I rewrite the path that is contained in ldd output and point it to file that I've extracted? I've read about rpath and patchelf and chrpath here and here but I guess this is not my case because following commands returns nothing useful:
$ readelf -d ./curlftpfs | grep -i rpath
$
$ chrpath -l ./curlftpfs
./curlftpfs: no rpath or runpath tag found.
$
$ patchelf --print-rpath ./curlftpfs
$
So it seems that rpath is not used. I've also read about $LD_LIBRARY_PRELOAD but I guess that it will change path for all shared libraries for given binary not just one particular (in my case /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4) so I would need to have whole tree of libraries. There is also solutions which suggest changing loader (in my example /lib64/ld-linux-x86-64.so.2 I guess):
$ patchelf --print-interpreter ./curlftpfs
/lib64/ld-linux-x86-64.so.2
$
$ ldd ./curlftpfs | grep ld-linux
/lib64/ld-linux-x86-64.so.2 (0x0000564966b64000)
$
$ ls -laL /lib/x86_64-linux-gnu/ld-2.21.so
-rwxr-xr-x 1 root root 154376 Mar 26 2015 /lib/x86_64-linux-gnu/ld-2.21.so
but to be honest I didn't get the point of this. Can you please assists?

My question is how can I rewrite the path that is contained in ldd
output and point it to file that I've extracted?
It seems like what you want is to override the functionality for just the libcurl-gnutls.so library with an older version. As hinted to in the last link you provided, you can use the LD_PRELOAD environment variable to override the standard library functions.
Say your manually installed (downgraded) version of libcurl-gnutls has the dynamic library file /usr/local/lib/libcurl-gnutls.so.4.4.0.
You could then do something like the following:
LD_PRELOAD=/usr/local/lib/libcurl-gnutls.so.4.4.0 curlftpfs [some_arguments...]
Don't forget that /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4 and /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.3 are just symbolic links to the master library file for libcurl-gnutls. Copying these symbolic links may not have the desired effect. You need the long named SO file, like libcurl-gnutls.so.4.4.0 .
Extra Notes
You can test that this override worked by doing something like the following:
LD_PRELOAD=/usr/local/lib/libcurl-gnutls.so.4.4.0 ldd $(which curlftpfs)
For a manual installation, /usr/local/lib may not be a good place to put a dynamic library that you don't want interfering with other binaries. This is because /etc/ld.so.conf.d/libc.conf may point to /usr/local/lib for automatic libraries. (My Debian machine does)
To see the definitions of the LD_ environment variable, check out the ld.so(8) man page (man ld.so).

Related

Forcing a binary to use a specific (newer) version of a shared library (.so)

I have an older binary executable (utserver, closed source) that I'm trying to run on a system running Fedora 22.
utserver wants openssl_1.0.0 - F22 provides openssl_1.0.1k
I made two symlinks:
$ sudo ln -s /usr/lib64/libssl.so.1.0.1k /usr/lib64/libssl.so.1.0.0
$ sudo ln -s /usr/lib64/libcrypto.so.1.0.1k /usr/lib64/libcrypto.so.1.0.0
But trying to run utserver complains about library version:
$ ./utserver
./utserver: /lib64/libcrypto.so.1.0.0: version `OPENSSL_1.0.0' not found (required by ./utserver)
./utserver: /lib64/libssl.so.1.0.0: version `OPENSSL_1.0.0' not found (required by ./utserver)
OK, so it's looking for a version string. I edited the utserver ELF to change the string OPENSSL_1.0.0 to OPENSSL_1.0.1 but I get the same error (`OPENSSL_1.0.1' not found)
objdump and readelf both show OPENSSL_1.0.1 present in version area of libssl.so.1.0.1:
$ objdump -p /lib64/libssl.so.1.0.1 | grep OPENSSL
3 0x00 0x066a2b21 OPENSSL_1.0.1
4 0x00 0x02b21533 OPENSSL_1.0.1_EC
0x02b21533 0x00 07 OPENSSL_1.0.1_EC
so now I'm confused as to what utserver is actually checking for. I suspect it's seeing OPENSSL_1.0.1_EC and failing. If I add the _EC in the ELF I get a seg fault, presumably because now my offsets are all wrong.
$ readelf -d ./utserver
readelf: Error: Unable to seek to 0x15da90000000 for string table
readelf: Error: no .dynamic section in the dynamic segment
Dynamic section at offset 0x154fb8 contains 34 entries:
Is there any way to tell ld-linux to force load OPENSSL_1.0.1_EC and/or a reference to modifying ELF offsets? Would be much appreciated.
Yes, I know I can find a version of openssl_1.0.0 packaged somewhere, but that's one library I'd rather not revert if I don't have to.
Is there any way to tell ld-linux to force load OPENSSL_1.0.1_EC
No.
There is a reason why the symbol versions have been changed: the old and new symbols are not ABI-compatible. You must recompile the executable to use the new symbols, or (easier) you must provide libssl.so.1.0.0 (which can be installed and co-exist with already installed libssl.so.1.0.1k).
that's one library I'd rather not revert if I don't have to.
You don't have to revert anything (and reverting will break all the programs that want the new version).
Simply providing the libssl.so.1.0.0 from an old package will make old programs (that require it) use that file, while new programs (which require libssl.so.1.0.1k) will continue to use libssl.so.1.0.1k.
easy fix in debian:
add oldstable/jessie to your /etc/apt/sources.list:
deb http://mi.mirror.garr.it/mirrors/debian/ oldstable main contrib non-free
deb-src http://mi.mirror.garr.it/mirrors/debian/ oldstable main contrib non-free
update your apt db:
sudo apt update
and then simply:
sudo apt install libssl1.0.0/jessie
The libssl1.0.0 Debian package contains the missing libraries (the libcrypto.so.1.0.0 and libssl.so.1.0.0), and can be downloaded from this page: http://security.ubuntu.com/ubuntu/pool/main/o/openssl1.0/ (e.g. for x86 architecture the link would be http://security.ubuntu.com/ubuntu/pool/main/o/openssl1.0/libssl1.0.0_1.0.2n-1ubuntu5.10_amd64.deb).
On a Debian-based system (e.g. Ubuntu), one can install the downloaded package with
sudo dpkg -i ./libssl1.0.0_1.0.2n-1ubuntu5.10_amd64.deb
On a non-Debian system one can (i) extract the content of the package with
ar x libssl1.0.0_1.0.2n-1ubuntu5.10_amd64.deb
(ii) get the required library files, and (iii) place them in a location where the executable in question can find them.

Build OpenSSL with RPATH?

I have Ubuntu 14.04. It came with openssl 1.0.1f. I want to install another openssl version (1.0.2) and I want to compile it by myself.
I configure it as follows:
LDFLAGS='-Wl,--export-dynamic -L/home/myhome/programs/openssl/i/lib
-L/home/myhome/programs/zlib/i/lib'
CPPFLAGS='-I/home/myhome/programs/openssl/i/include
-I/home/myhome/programs/zlib/i/include'
./config --prefix=/home/myhome/programs/openssl/i \
zlib-dynamic shared --with-zlib-lib=/home/myhome/programs/zlib/i/lib \
--with-zlib-include=/home/myhome/programs/zlib/i/include
make
make install
After install, when i check the binary with ldd openssl, and the result is:
...
libssl.so.1.0.0 => /home/myhome/programs/openssl/i/lib/libssl.so.1.0.0 (0x00007f91138c0000)
libcrypto.so.1.0.0 => /home/myhome/programs/openssl/i/lib/libcrypto.so.1.0.0 (0x00007f9113479000)
...
which looks fine. But when I check ldd libssl.so, the result is:
...
libcrypto.so.1.0.0 => /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (0x00007fac70930000)
...
It still uses the system version of libcrypto. I tried different ways to
build, but result is always stays the same.
My question is how to configure the build in a way, that it can hardcode all binary and library dependencies of shared libraries without using LD_LIBRARY_PATH, or anything like that.
My question is how to configure the build in a way, that it can hardcode all binary and library dependencies of shared libraries without using LD_LIBRARY_PATH, or anything like that.
OpenSSL supports RPATH's out of the box for BSD targets (but not others). From Configure:
# Unlike other OSes (like Solaris, Linux, Tru64, IRIX) BSD run-time
# linkers (tested OpenBSD, NetBSD and FreeBSD) "demand" RPATH set on
# .so objects. Apparently application RPATH is not global and does
# not apply to .so linked with other .so. Problem manifests itself
# when libssl.so fails to load libcrypto.so. One can argue that we
# should engrave this into Makefile.shared rules or into BSD-* config
# lines above. Meanwhile let's try to be cautious and pass -rpath to
# linker only when --prefix is not /usr.
if ($target =~ /^BSD\-/)
{
$shared_ldflag.=" -Wl,-rpath,\$(LIBRPATH)" if ($prefix !~ m|^/usr[/]*$|);
}
The easiest way to do it for OpenSSL 1.0.2 appears to be add it as a CFLAG:
./config -Wl,-rpath=/usr/local/ssl/lib
The next easiest way to do it for OpenSSL 1.0.2 appears to be add a Configure line and hard code the rpath. For example, I am working on Debian x86_64. So I opened the file Configure in an editor, copied linux-x86_64, named it linux-x86_64-rpath, and made the following change to add the -rpath option:
"linux-x86_64-rpath", "gcc:-m64 -DL_ENDIAN -O3 -Wall -Wl,-rpath=/usr/local/ssl/lib::
-D_REENTRANT::-Wl,-rpath=/usr/local/ssl/lib -ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:
${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
Above, fields 2 and 6 were changed. They correspond to $cflag and $ldflag in OpenSSL's builds system.
Then, Configure with the new configuration:
$ ./Configure linux-x86_64-rpath shared no-ssl2 no-ssl3 no-comp \
--openssldir=/usr/local/ssl enable-ec_nistp_64_gcc_128
Finally, after make, verify the settings stuck:
$ readelf -d ./libssl.so | grep -i rpath
0x000000000000000f (RPATH) Library rpath: [/usr/local/ssl/lib]
$ readelf -d ./libcrypto.so | grep -i rpath
0x000000000000000f (RPATH) Library rpath: [/usr/local/ssl/lib]
$ readelf -d ./apps/openssl | grep -i rpath
0x000000000000000f (RPATH) Library rpath: [/usr/local/ssl/lib]
Once you perform make install, then ldd will produce expected results:
$ ldd /usr/local/ssl/lib/libssl.so
linux-vdso.so.1 => (0x00007ffceff6c000)
libcrypto.so.1.0.0 => /usr/local/ssl/lib/libcrypto.so.1.0.0 (0x00007ff5eff96000)
...
$ ldd /usr/local/ssl/bin/openssl
linux-vdso.so.1 => (0x00007ffc30d3a000)
libssl.so.1.0.0 => /usr/local/ssl/lib/libssl.so.1.0.0 (0x00007f9e8372e000)
libcrypto.so.1.0.0 => /usr/local/ssl/lib/libcrypto.so.1.0.0 (0x00007f9e832c0000)
...
OpenSSL has a Compilation and Installation on its wiki. This has now been added to the wiki at Compilation and Installation | Using RPATHs
It's 2019, and OpenSSL might have changed a little, so I'll describe how I solved this, on the odd chance someone else might find it useful (and in case I ever need to figure out this command line argument again for myself).
I wanted to build OpenSSL in a way that would cross-compile (using docker containers, because I'm dealing with freakishly old Linux kernels yet modern compilers), yet provide an install that did not depend upon absolute paths, as would be the case using rpath as I've seen described in jww's answer here.
I found I can run OpenSSL's Configure script in this way to achieve what I want (from a bash prompt):
./Configure linux-x86 zlib shared -Wl,-rpath=\\\$\$ORIGIN/../lib
This causes the generated Makefile to build the executables and the shared objects in a way that makes the loader look for dependencies first in "./../lib" (relative to the location of the executable or the shared object), then in the LD_LIBRARY_PATH, etc. That wacky combination of characters properly gets past the bash command line, the script, and the Makefile combinations to create the -rpath argument according to how the linker requires it ($ORIGIN/../lib).
(Obviously, choose the other options that make sense to you.. the key here is in the -Wl,-rpath=\\\$\$ORIGIN/../lib option).
So, if I called ./Configure with a prefix of '--prefix=/opt/spiffness', and later decided to rename 'spiffness' to 'guttersnipe', everything will still work correctly, since the paths are relative rather than absolute.
I have not tried passing the argument into ./config to see if it works there since my use case was a bit special, but I suspect it would. If I were not attempting to cross-compile with dockerized containers, I would prefer using ./config to ./Configure, as it does a decent enough job of examining the current environment to see what kind of binaries to create.
I hope this is useful.

repackage an rpm from an installed rpm

On linux can we repackage a installed rpm if so how.I remember that the a rpm can be generated from the installed binaries
rpm -??? > my.rpm
Also the later i.e, the newer rpm should work on a different machine
There is also rpmrebuild
http://rpmrebuild.sourceforge.net
Actually there is a simple but "tricky" way; it is just : rpm -e --repackage package-name
It will output the RPM in /var/spool/repackage/.
Example:
# rpm -e --repackage samba3x-client
# file /var/spool/repackage/samba3x-client-3.5.4-0.83.el5_7.2.i386.rpm
/var/spool/repackage/samba3x-client-3.5.4-0.83.el5_7.2.i386.rpm: RPM v3 bin i386 samba3x-client-3.5.4-0.83.el5_7
Why tricky? Because it actually remove the program prior packaging it, just so you know.
This is possible, but not with the rpm command. I wrote a perl script that does this; it crafts a spec file based on the outputs of rpm -q and does a "build" which just copies the installed files from the system.
You can find it here: https://github.com/cormander/rogue-beret-tools/blob/master/scripts/rpm-repack
Usage example, re-packaging the mailx rpm:
Query it:
$ rpm -ql mailx
/bin/mail
/etc/mail.rc
/usr/bin/Mail
/usr/lib/mail.help
/usr/lib/mail.tildehelp
/usr/share/man/man1/Mail.1.gz
/usr/share/man/man1/mail.1.gz
Repack it:
$ ./rpm-repack -p mailx
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.9773
+ umask 022
+ cd /usr/src/redhat/BUILD
+ /usr/lib/rpm/brp-compress
+ /usr/lib/rpm/brp-strip
+ /usr/lib/rpm/brp-strip-static-archive
+ /usr/lib/rpm/brp-strip-comment-note
Processing files: mailx-8.1.1-44.2.2
Provides: mailx
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1) libc.so.6(GLIBC_2.3) libc.so.6(GLIBC_2.3.4) libc.so.6(GLIBC_2.4) rtld(GNU_HASH)
Checking for unpackaged file(s): /usr/lib/rpm/check-files /tmp/tlkN4yrYEi
Wrote: ~/rpmbuild/RPMS/i386/mailx-8.1.1-44.2.2.i386.rpm
Query the newly built package:
$ rpm -qpl ~/rpmbuild/RPMS/i386/mailx-8.1.1-44.2.2.i386.rpm
/bin/mail
/etc/mail.rc
/usr/bin/Mail
/usr/lib/mail.help
/usr/lib/mail.tildehelp
/usr/share/man/man1/Mail.1.gz
/usr/share/man/man1/mail.1.gz
The code isn't at all elegant, but functional. It does copy a lot of the rpm info (everything from rpm -qi and most of the scripts), but it isn't by any means comprehensive. Also, it can't copy the GPG signature, nor will it have the same checksums as the original RPM file.
NOTE: This is not a "proper" way to build and distribute RPM packages, and was mainly written for troubleshooting and educational purposes.
I think that most rpm based distributions how have official package rpmrebuild (or in the almost official 3'rd party repos like epel, rpmfusion ... etc). I think nowadays this would be your best option for repackaging installed packages.

ld cannot find an existing library

I am attempting to link an application with g++ on this Debian lenny system. ld is complaining it cannot find specified libraries. The specific example here is ImageMagick, but I am having similar problems with a few other libraries too.
I am calling the linker with:
g++ -w (..lots of .o files/include directories/etc..) \
-L/usr/lib -lmagic
ld complains:
/usr/bin/ld: cannot find -lmagic
However, libmagic exists:
$ locate libmagic.so
/usr/lib/libmagic.so.1
/usr/lib/libmagic.so.1.0.0
$ ls -all /usr/lib/libmagic.so.1*
lrwxrwxrwx 1 root root 17 2008-12-01 03:52 /usr/lib/libmagic.so.1 -> libmagic.so.1.0.0
-rwxrwxrwx 1 root root 84664 2008-09-09 00:05 /usr/lib/libmagic.so.1.0.0
$ ldd /usr/lib/libmagic.so.1.0.0
linux-gate.so.1 => (0xb7f85000)
libz.so.1 => /usr/lib/libz.so.1 (0xb7f51000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7df6000)
/lib/ld-linux.so.2 (0xb7f86000)
$ sudo ldconfig -v | grep "libmagic"
libmagic.so.1 -> libmagic.so.1.0.0
How do I diagnose this problem further, and what could be wrong? Am I doing something completely stupid?
The problem is the linker is looking for libmagic.so but you only have libmagic.so.1
A quick hack is to symlink libmagic.so.1 to libmagic.so
As just formulated by grepsedawk, the answer lies in the -l option of g++, calling ld. If you look at the man page of this command, you can either do:
g++ -l:libmagic.so.1 [...]
or: g++ -lmagic [...] , if you have a symlink named libmagic.so in your libs path
It is Debian convention to separate shared libraries into their runtime components (libmagic1: /usr/lib/libmagic.so.1 → libmagic.so.1.0.0) and their development components (libmagic-dev: /usr/lib/libmagic.so → …).
Because the library's soname is libmagic.so.1, that's the string that gets embedded into the executable so that's the file that is loaded when the executable is run.
However, because the library is specified as -lmagic to the linker, it looks for libmagic.so, which is why it is needed for development.
See Diego E. Pettenò: Linkers and names for details on how this all works on Linux.
In short, you should apt-get install libmagic-dev. This will not only give you libmagic.so but also other files necessary for compiling like /usr/include/magic.h.
In Ubuntu, you can install libtool which resolves the libraries automatically.
$ sudo apt-get install libtool
This resolved a problem with ltdl for me, which had been installed as libltdl.so.7 and wasn't found as simply -lltdl in the make.
As mentioned above the linker is looking for libmagic.so, but you only have libmagic.so.1.
To solve this problem just perform an update cache.
ldconfig -v
To verify you can run:
$ ldconfig -p | grep libmagic
Unless I'm badly mistaken libmagic or -lmagic is not the same library as ImageMagick. You state that you want ImageMagick.
ImageMagick comes with a utility to supply all appropriate options to the compiler.
Ex:
g++ program.cpp `Magick++-config --cppflags --cxxflags --ldflags --libs` -o "prog"
Installing libgl1-mesa-dev from the Ubuntu repo resolved this problem for me.
I tried all solutions mentioned above but none of them solved my issue but finally I solved it with the following command.
sudo apt-get install libgmp3-dev
This will do the magic.
Another way to solve this problem is to install the -devel package.
If the compiler is looking for libabc.so while you have libabc.so.1, you need to install the -devel package like libabc-devel as libabc.so.1 is a runtime lib but libabc.so is a development lib.

How do you find out which version of GTK+ is installed on Ubuntu?

I need to determine which version of GTK+ is installed on Ubuntu
Man does not seem to help
This suggestion will tell you which minor version of 2.0 is installed. Different major versions will have different package names because they can co-exist on the system (in order to support applications built with older versions).
Even for development files, which normally would only let you have one version on the system, you can have a version of gtk 1.x and a version of gtk 2.0 on the same system (the include files are in directories called gtk-1.2 or gtk-2.0).
So in short there isn't a simple answer to "what version of GTK is on the system". But...
Try something like:
dpkg -l libgtk* | grep -e '^i' | grep -e 'libgtk-*[0-9]'
to list all the libgtk packages, including -dev ones, that are on your system. dpkg -l will list all the packages that dpkg knows about, including ones that aren't currently installed, so I've used grep to list only ones that are installed (line starts with i).
Alternatively, and probably better if it's the version of the headers etc that you're interested in, use pkg-config:
pkg-config --modversion gtk+
will tell you what version of GTK 1.x development files are installed, and
pkg-config --modversion gtk+-2.0
will tell you what version of GTK 2.0. The old 1.x version also has its own gtk-config program that does the same thing. Similarly, for GTK+ 3:
pkg-config --modversion gtk+-3.0
This isn't so difficult.
Just check your gtk+ toolkit utilities version from terminal:
gtk-launch --version
get GTK3 version:
dpkg -s libgtk-3-0|grep '^Version'
or just version number
dpkg -s libgtk-3-0|grep '^Version' | cut -d' ' -f2-
You can use this command:
$ dpkg -s libgtk2.0-0|grep '^Version'
You could also just compile the following program and run it on your machine.
#include <gtk/gtk.h>
#include <glib/gprintf.h>
int main(int argc, char *argv[])
{
/* Initialize GTK */
gtk_init (&argc, &argv);
g_printf("%d.%d.%d\n", gtk_major_version, gtk_minor_version, gtk_micro_version);
return(0);
}
compile with ( assuming above source file is named version.c):
gcc version.c -o version `pkg-config --cflags --libs gtk+-2.0`
When you run this you will get some output. On my old embedded device I get the following:
[root#n00E04B3730DF n2]# ./version
2.10.4
[root#n00E04B3730DF n2]#
Try,
apt-cache policy libgtk2.0-0 libgtk-3-0
or,
dpkg -l libgtk2.0-0 libgtk-3-0
I think a distribution-independent way is:
gtk-config --version
You can also just open synaptic and search for libgtk, it will show you exactly which lib is installed.
Try:
dpkg-query -W libgtk-3-bin
Because apt-cache policy will list all the matches available, even if not installed, I would suggest using this command for a more manageable shortlist of GTK-related packages installed on your system:
apt list --installed libgtk*
This will get the version of the GTK libraries for GTK 2, 3, and 4.
dpkg -l | egrep "libgtk(2.0-0|-3-0|-4)"
As major versions are parallel installable, you may have several of them on your system, which is my case, so the above command returns this on my Ubuntu Trusty system:
ii libgtk-3-0:amd64 3.10.8-0ubuntu1.6 amd64 GTK+ graphical user interface library
ii libgtk2.0-0:amd64 2.24.23-0ubuntu1.4 amd64 GTK+ graphical user interface library
This means I have GTK+ 2.24.23 and 3.10.8 installed.
If what you want is the version of the development files, use:
pkg-config --modversion gtk+-2.0 for GTK 2
pkg-config --modversion gtk+-3.0 for GTK 3
pkg-config --modversion gtk4 for GTK 4
(This changed because the + from GTK+ was dropped a while ago.)
To make the answer more general than Ubuntu (I have Redhat):
gtk is usually installed under /usr, but possibly in other locations. This should be visible in environment variables. Check with
env | grep gtk
Then try to find where your gtk files are stored. For example, use locate and grep.
locate gtk | grep /usr/lib
In this way, I found /usr/lib64/gtk-2.0, which contains the subdirectory 2.10.0, which contains many .so library files. My conclusion is that I have gtk+ version 2.10. This is rather consistent with the rpm command on Redhat: rpm -qa | grep gtk2, so I think my conclusion is right.
To compile and link a GTK program with pkg-config, we need the library name instead of the actual version number. For example, the following command compiles and links a GTK program that uses the GTK4 library:
gcc -o program program.c `pkg-config --cflags --libs gtk`
To obtain the library name for GTK, use the following command:
pkg-config --list-all | grep gtk

Resources