pkg-config: print Requires.private without being recursive - linker

I have a problem which I think I can solve if I manage to get from pkg-config the list in Requires.private without being recursive. First I'll post the problem, and then my try to workaround it.
Problem:
I had a static-only library (let's call it libfoo.a) with no pkg-config files, which I just included as a submodule of my programs. I had to take into account in the program makefile all the dependencies that my library might have, because as a static library, it didn't carry the information of which shared library it depended on. That meant that I had to dinamically link with a lot of libraries in my programs' makefiles, but that worked.
Example:
$(CC) $(OBJS) -o $# -L path/foo/ -l foo `pkg-config --libs opencv gsl ncurses`
It worked, because it could only find a static version of libfoo, and after that it had a list of what libfoo needed (instead of what the program actually needed dinamically).
Now I have improved that library so that it is installed in /usr/local/, provide pkg-config files, and both .a and .so files.
When I link dinamically to my library, everything is fine.
When I try to link statically, if the program doesn't use opencv at all, it is fine (I don't know if it's opencv that is broken when trying to link statically, or that I broke it installing some updates from the testing repo; if I had a clean installation I would know, but I don't). The problem comes when I try to link statically, and some opencv is used. There are some libraries not found, so what I thought as a solution is to replicate what happened before I installed my library.
But now I don't want to hardcode my library's dependencies in my program's makefile, so I use pkg-config.
My try:
Assuming that my program only depends directly on libfoo, and libfoo depends on opencv, gsl and ncurses directly (which my program ignores), this is what I would do:
$(CC) $(OBJS) -o $# -Wl,-Bstatic `pkg-config --libs foo` -Wl,-Bdynamic `pkg-config --static --libs foo`
the first pkg-config is to expose only libfoo to be linked statically, and the second one is to expose libfoo's dependencies to be linked dinamically. But the problem is that I'm exposing, not only libfoo's direct dependencies, but also all the recursive dependencies, which I don't want to.
Is there any way to expose only the direct dependencies? Or is there any other workaround to this situation?
In this case, it is needed to the problem with a broken openCV, and someone could say: hey, just solve that problem with openCV, and forget about that.
But this is also useful for someone who wants to link statically to a library which performance is critical, but still link dinamically to other heavier libraries which aren't as critical.
System:
Debian 10
GCC 8
OpenCV might have some packages or dependencies installed from testing.

I just bumped into this, and I think I'm going to have to write a bit of Python to just repeatedly call pkg-config.

Related

Makefile for C code

I inherited a code which has a makefile, but so far I was unable to run it on a linux server. The main complain of the compiler is that it is unable to load libgmp.so.3 : error while loading shared libraries: libgmp.so.3. I know that libgmp.so.10 exists on this server, but I was wondering which part of the makefile needs to be changed so the compiler looks for libgmp.so.10 rather than libgmp.so.3.
OPTFLAG = -O2 -Wall -fPIC -fexceptions -DNDEBUG
LDFLAGS = -O2 -Wl,-no_compact_unwind -DNDEBUG -lm -pthread
COMPILER = gcc ${OPTFLAG}
LINKER = gcc ${LDFLAGS}
# CPLEX directory
CPLEX_HOME = /opt/ibm/ILOG/CPLEX_Studio1263/cplex
CPLEX_INC = ${CPLEX_HOME}/include/
CPLEX_LIB = ${CPLEX_HOME}/lib/x86-64_linux/static_pic/ -lcplex
# Compile the main file
code: code.c
${COMPILER} -c code.c -o code.o -I${CPLEX_INC}
${LINKER} -o code code.o -L${CPLEX_LIB}
clean::
rm -f *.o
rm -f ${LIB}/*.o
rm -f *~
rm -f ${SRC}/*~ ${INCLUDE}/*~
You need to rebuild whatever program or library uses libgmp.so.3 from source code. Could you provide the exact command run by make and the error message it produces?
EDIT The problem here is that the system has installed a version of the IBM CPLEX software which comes with its own GCC binary, and that GCC binary uses libgmp.so.3. The easiest way to fix this would be to upgrade the CPLEX software to a version which supports the operating system being used, or use the software on the operating system for which it was written (i.e., something really old that actually ships libgmp.so.3).
The most easy way it to install libgmp-dev package, from your linux distribution. GMP is a package library to do multiple precision calculations on large integers, which is probably needed by your program. As you put in some comments, adding -L/usr/lib64/libgmp.so.10 is an error, as -L option allows to add a directory to search for libraries, and not a specific library.
If only the library is needed and no header file is missing in your compilation (this is something strange, but sometimes happen) then you can still link with only the libgmp.so.10 object, but you have to do in a something nasty way. Just add /usr/lib64/libgmp.so.10 as an object file (not a library, with -l option) to your link command.
EDIT
From looking more closely your Makefile I see no reference to the libgmp.so.3 library, so I only can assume this is a indirect reference from some other already compiled library that comes from outside with your package. Just use
ldd lib<nameOfLibrary>.so.x.x
with all the libraries needed by your final executable, so see which shared objetc is the one that requests libgmp.so.3 soname, and then recompile it, reinstall it, or use your system's libraries ONLY, and not mesh anymore with libraries coming from another system. For example you can try (this is an expensive command, but it will get the answer)
find / -name "lib*.so.*" -print | xargs ldd > all_libs.lddout
and then find all_libs.lddout to see which library uses libgmp.so.3 (this will be the outdated library) You'll need to deinstall it or upgrade it, to be able to continue.
Linux systems have a library version system that allows an executable to be able to load different versions of the same library and allow them to live together in the same system. One of two: or you are able to locate the sources of version 3 of the shared libgmp.so.3 library and install it on your system, or you'll need to update the libraries your program uses to be able to link with the libgmp.so.10 already installed on your system.
2ND EDIT
As I see in the comments, you have changed the default compiler on your system by another coming possibly from other linux distribution (as your installed library is libgmp.so.10 while the one cc1 requests is libgmp.so.3, which is not installed on your system.
Installing a different compiler from the one you have installed, and doing that without previously deinstalling the other compiler, can lead you to this kind of problems.
The most reliable thing you can do is to reinstall the compiler from your distribution, or better, reinstall the whole linux system, as you have probably broken many things that will be emerging as you use your system. There's very poor info on what you have done to go further in your problem. Anyway, my recommendation is to not use the comment parts to add new information about your problem, just edit your question and add all those new information to it.

Questions about how libraries work in C

I am a newbie student learning C and wish to use the gLib library functions for a project: http://www.linuxfromscratch.org/blfs/view/svn/general/glib2.html
(I am using Ubuntu)
I have a couple questions about how libraries work in C and what happens when you install one or want to use one:
When I install this (run ./configure && make && make install inside the folder), what exactly is it doing? From what I learned there are shared libraries in C and static libraries in C. Is it true that it is installing library and include files to /usr/lib/ or somewhere?
When using gcc with external libraries, you have to specify -L and -I flags to specify where to look for library and header files. When I install glib, will I need to specify these flags?
If I want to package my executable for another machine, what would happen if the other machine doesn't have glib? I think if I had static libraries I would be able to include it in the binary, but how would it work for glib?
I am familiar with developing with GTK+ and GLIB. As i'm aware library files reside in /usr/lib and include files are found in /usr/include. Some libraries might be in places such as /usr/local/lib. I will attempt to answer your questions as best as I could.
When installing a library through the source package yes it installs files to the various folders /usr/share /usr/lib /usr/include and etc. It's highly recommended you use your distribution's package manager to install library packages and development headers. Installing from source is always bound to fail as necessary dependencies might be required.
This is where tools such as autogen and makefiles come handy. You don't necessarily need to concern yourself with specifying all that. tools such as pkg-config handle all that work. Most libraries will install a package configuration file into /usr/lib/pkgconfig & /usr/share/pkgconfig directories. This helps anyone developing an application easily link their code to the libraries.
Using package config to get the config:
$ pkg-config --cflags --libs glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -lglib-2.0
Linking using GCC & package config:
$gcc example.c `pkg-config --cflags --libs gtk+2.0 glib-2.0` -o example
The above command would link my program with gtk & glib.
Using Makefile to not ever have to enter those long lines again:
Makefile:
OBJS = main.o callbacks.o
CFLAGS = `pkg-config --cflags --libs gtk+-2.0`
program: $(OBJS)
gcc -o program $(OBJS)
main.o: main.c
gcc -c main.c $(FLAGS)
callbacks.o: callbacks.c callbacks.h
gcc -c callbacks.c $(FLAGS)
.PHONY : clean
clean:
rm *.o
rm program
.PHONY : install
install:
cp program /usr/bin
.PHONY : uninstall
uninstall:
rm /usr/bin/program
The above makefile is for a simple GTK+2.0 application as you can tell by what package config is including in CFLAGS to make the program executable all you have to enter in your source directory would be make. pkg-config will only work if you have installed the development packages for the library you are trying to work with. For ubuntu to install GTK+-3.0 and GLIB development files you would enter:
$ apt-get install libgtk-3-dev
I think this is a good concern for portability. No single static library is going to be cross platform. It would have to be compiled for those platforms manually. I reckon to get rid of all the headache you would use Anjuta IDE developed by the GNOME software foundation. It makes developing GLIB & GTK+ apps a breeze supporting both C & C++. It will create the Makefile, configure and other files to make developing code on cross platforms easy and make deployment easy. I could link you some resources, but my reputation on stack overflow is less then 10. So I will just mention the name of some resources below.
Further Reading
Makefile Tutorial
Anjuta IDE (C/C++)): ://anjuta.org/
GTK+-3.0 Hello World with Compiling and linking using pkg-config:
When I install this (run ./configure && make && make install inside
the folder), what exactly is it doing? From what I learned there are
shared libraries in C and static libraries in C. Is it true that it is
installing library and include files to /usr/lib/ or somewhere?
Well it is running first ./configure and then if that succeeds it runs make and if that succeeds it runs make install. configure is a script that takes care of a lot of compatibility issues between systems. They are usually shell scripts as this is the common denominator across systems so the configure script will work across various systems. One of the thing configure does is create a Makefile. The second command make will use the newly created Makefile to build the library or executable. Since you did not specify a target (like you will in the make install) make will build the default target, which is typically the all target. This is just by convention. Makefiles are basically a list of things to build (targets) along with what they depend on (dependencies) and how to build to target (rules). Finally, make install will actually install the necessary components. For libraries this is the library and necessary header files for executables it is just the program. man pages might also be installed. Where you install the libraries depends on where you specify to install them. Typically configure will take the --prefix argument that lets you control where they are installed. If you do not use --prefix you will most likely install in the default location for your system.
When using gcc with external libraries, you have to specify -L and -I
flags to specify where to look for library and header files. When I
install glib, will I need to specify these flags?
Your question is a little unclear, so let me first make sure I understand. Are you asking if after you install glib will you need to use -L and -I to tell gcc where to look for them? If so it depends on where you install them. Typically when you make and install a library you will install the library and header files in the default location or not. If you did then assuming your gcc is configured correctly then no you will not. If you did not then you will most likely have to use -L and -I
If I want to package my executable for another machine, what would
happen if the other machine doesn't have glib? I think if I had static
libraries I would be able to include it in the binary, but how would
it work for glib?
If it doesn't have glib and you used the shared libraries your application will not work. You will need to either have the same version glib libraries on the other machine or build the libraries statically. How to build them statistically depends on the library. This SO question might help.
Regarding configure, make and make install. configure is a shell script that is used to discover (and configure) your development environment. make and make install are convenient way of building your software. Where make would normally involve compiling and linking, where as make install would normally involve copying executables and libraries to standard path and setting up things (also include files if any usually in /usr/include), so that you don't have to explicitly give path before running the executable. What make does can be done by hand, but it's very cumbersome.
For glibc - yes you have to specify those flags. Normally all libraries will come in two flavors on most of the platforms. The binary form are used for dynamic linking when programs are actually loaded. Also - most distributions will have -dev or -devel versions of those libraries. Those are required for building software that makes use of those libraries (configure above can help find out whether devel libraries are installed). Typically when you see a library installed but not it's devel - you are likely to see configure errors. In short you require devel versions if you want to link with those libraries. This step is not needed if you are building libraries also from source using make and make install.
If you want to package your executable for another machine and you are not sure whether another glib is there or you want to be sure that the glib to be installed should be one specific version that you want, you should statically link while building (compiling/linking) the library. this gcc man page has got several details about link options. I believe there should be a way to statically link glib(or glib2). Though normally that may not be required if you have enough applications that are using it already.

Why does my cross-compiling fail?

I'm new to Linux programming and I'm trying to compile a c file including the GTK+ library. My file is called test.c and it's supposed to run on Windows computers. I'm using the command:
i586-mingw32msvc-gcc `pkg-config --cflags gtk+-3.0` -o test test.c `pkg-config --libs gtk+-3.0`
I get an awful error, I tried to figure out what went wrong by myself but didn't manage to understand what's going on here.
This is the output:
You're almost certainly running pkg-config with the host metadata files, such output will likely make your cross-compiler, erm, cross.
Try this tutorial, it explains how to do what you want starting with downloading the required GTK+-3.0 win32 binaries, and setting up your linux environment so that pkg-config picks up the target metadata files:
http://www.tarnyko.net/en/?q=node/45
The job of pkg-config is to provide a straightforward way for one program to determine the compiler and linker requirements, and any dependent libraries for a library it uses. It also makes it easier for autoconf (and the user) to determine the presence, version and dependencies of specific packages. Your examples are using:
pkg-config --cflags gtk+-3.0
pkg-config --libs gtk+-3.0
Those will output the compiler and library flags that a program using gtk+-3.0 needs. Assuming you have a native version installed on your system, the default output will be suitable only for your type of system (paths, library names, dependent libraries etc).
The trick with cross-compiling is to have a separate tree of source, .pc (pkg-config meta-data), libraries and header files (for each targeted architecture). When you run pkg-config during configure/compile, you can set PKG_CONFIG_PATH as in the tutorial above so it picks up the correct .pc files for the targeted architecture.
There's a little bear trap here though: PKG_CONFIG_PATH adds to the start of the search path, so it can still fall back to the wrong package details if you have not installed the required software into your target tree, but you have a "native" version installed. You should usually set PKG_CONFIG_LIBDIR instead, this replaces the default path (typically /usr/lib/pkgconfig). That way when you cross-compile something more elaborate that uses autoconf (configure scripts) you (hopefully) get a sensible diagnostic about missing packages, rather than having the wheels come off mid-way through the compile.
For example, I can use this to list just the OpenWRT MIPS packages I have in one cross-compile tree:
WRTROOT=/openwrt/staging_dir/target-mips_r2_uClibc-0.9.32/
PKG_CONFIG_PATH= PKG_CONFIG_LIBDIR=${WRTROOT}/usr/lib/pkgconfig pkg-config --list-all
Unsetting PKG_CONFIG_PATH prevents it finding extra packages in my /usr/local, setting PKG_CONFIG_LIBDIR means it won't find the native system ones.
In addition to setting the PKG_CONFIG_PATH and PKG_CONFIG_LIBDIR variables, it might be necessary to pass --define-prefix to pkg-config:
PKG_CONFIG_PATH= PKG_CONFIG_LIBDIR=/openwrt/staging_dir/target-mips_34kc_eglibc-2.19/usr/lib/pkgconfig pkg-config --define-prefix --cflags libmodbus
-I/openwrt/staging_dir/target-mips_34kc_eglibc-2.19/usr/include/modbus
Otherwise you get the include path on your host system:
PKG_CONFIG_PATH= PKG_CONFIG_LIBDIR=/openwrt/staging_dir/target-mips_34kc_eglibc-2.19/usr/lib/pkgconfig pkg-config --cflags libmodbus
-I/usr/include/modbus
which might work, provided the host system and the cross-compile environment have the same include files installed.

How can I include a needed C library using GCC?

I am trying to compile the simple C example from this tutorial on Ubuntu using GCC. What do I have to use as arguments for GCC to include the needed libraries for #include <libappindicator/app-indicator.h>?
-I<search path to include files>
-L<search path to the lib file>
-l<libname>
Use the -l command line option. You can specify the library search path with the -L option. E.g:
gcc -o myprogram -lfoo -L/home/me/foo/lib myprogram.c
This will link myprogram with the static library libfoo.a in the folder /home/me/foo/lib.
If you used apt-get, Synaptic Package Manager, etc. to get the appindicator library (vs. building it from source), did you only install the libappindicator1 package or did you also install libappindicator-dev to get the libappindicator header files? Linux packages very often have split the runtime libraries from the compile-time headers. That way people who only need the libraries to satisfy a dynamic link don't have to install unneeded headers. But since you're doing development you need those headers and therefore need the libappindicator-dev package as well.
What I do is:
pkg-config --list-all | grep indicator
Use:
gcc example.c -o example `pkg-config --cflags --libs appindicator-0.1`
pkg-config will fetch the required include and library flags for libappindicator and its dependencies. This assumes libappindictaor-dev package is already installed.
You are trying to make a GTK app, and the previous solutions are as applicable anywhere like using the -l option and -I option,
However, for GTK applications, you may also use pkg-config which makes it easier as your paths can be predefined.
An interesting example can be found in
http://developer.gnome.org/gtk/2.24/gtk-compiling.html

Two method for linking a object using GCC?

I've known that I should use -l option for liking objects using GCC.
that is gcc -o test test.c -L./ -lmy
But I found that "gcc -o test2 test.c libmy.so" is working, too.
When I use readelf for those two executable I can't find any difference.
Then why people use -l option for linking objects? Does it have any advantage?
Because you may have either a static or a shared version of the library in your library directory, e. g. libmy.a and libmy.so, or both of them. This is more relevant to system libraries: if you link to libraries in your local build tree, you know which version you build, static or shared, but you may not know other systems' configuration and libraries mix.
In addition to that, some platforms may have different suffixes. So it's better to specify it in a canonical way.
The main reason is, -lname will search for libname.a (or libname.so, etc.) on the library search list. You can add directories to the library search list with the -L option. It's a convenience built into the compiler driver program, making it easier to find libraries that have been installed in standard places on the system.

Resources