List of relocatables integrated into static library - c

Below archive file(shuffler.a) is created with below command:
$ go install github.com/myhub/cs61a
$
$
$ file pkg/linux_amd64/github.com/myhub/cs61a/shuffler.a
pkg/linux_amd64/github.com/myhub/cs61a/shuffler.a: current ar archive
$
$
But there is more than one than file(relocatable) integrated in archive file:
$ ar -t pkg/linux_amd64/github.com/myhub/cs61a/shuffler.a
__.PKGDEF
_go_.o
$
$
_go_.o is a relocatable binary form of src/github.com/myhub/cs61a/shuffler/shuffle.go source code
What does __.PKGDEF signify? ar –rcs libourown.c one.o two.o in C world does not add this file

Since go code is organized by package, while C code is not, and since go libraries/binaries are compiled package by package, I would take the wild guess that PKGDEF has information about the go language package from which the code was compiled.

Related

Shared library not found when compiling a C program

So, I have a simple program which looks like so:
#include <amqp.h>
#include <amqp_framing.h>
int main(int argc, char const * const *argv) {
amqp_connection_state_t conn;
conn = amqp_new_connection();
amqp_destroy_connection(conn);
return 0;
}
This program depends on rabbitmq-c library. I compiled it with no errors. So, when I run
$ ls /rabbitmq-c/_install/include/
I get all its header files, that I need:
amqp.h
amqp_framing.h
amqp_tcp_socket.h
And when I run
$ ls /rabbitmq-c/_build/librabbitmq/
I see all needed ".so" files:
CMakeFiles
Makefile
cmake_install.cmake
config.h
librabbitmq.a
librabbitmq.so
librabbitmq.so.4
librabbitmq.so.4.4.1
And finally I compile my own program like so:
$ gcc -I/rabbitmq-c/_install/include/ -g -Wall -c main.c
$ gcc -L/rabbitmq-c/_build/librabbitmq/ -g -Wall -o rabbit main.o -lrabbitmq
It compiles with no errors. However, when I do:
$ ldd ./rabbit
I get this message:
librabbitmq.so.4 => not found
So, what am I missing and how can I fix it?
When you link shared library into an executable, the linker will recorder the library name (in this case librabbitmq.so.4) into the executable. It is the job of the dynamic linker (ld.so), to locate the libraries, and combine them for execution.
To locate the libraries, the dynamic linker constructs a search path (similar to PATH). This include:
LD_LIBRARY_PATH
Hard-coded directories added to the executable.
Default folders (/lib, /usr/lib, etc.).
In the above case, looks like neither #1 nor #2 were used, and the library is not in the default location. Can be fixed using #1 or #2
# Option 1.
# Both gcc, and ldd consult LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/rabbitmq-c/_build/librabbitmq
gcc -g -Wall -o rabbit main.o -lrabbitmq
ldd ./rabbit
# Option #2
# Inject SO directory into the executable with -Wl,-rpath,...
gcc -L/rabbitmq-c/_build/librabbitmq/ -Wl,-rpath,/rabbitmq-c/_build/librabbitmq/ -g -Wall -o rabbit main.o -lrabbitmq
ldd ./rabbit
Consult man ld.so for the full details.
From personal experience, when dealing with 'one-off' libraries, better to use the 'rpath' (#2) approach. Trying to add lot of locations into LD_LIBRARY_PATH can easily result in hard to manage, long, LD_LIBRARY_PATH. Using LD_LIBRARY_PATH works best when a wrapper script is created to launch the program
File: rabbit-run (same folder as executable)
# Prepend rabbitmq SO location to current LD_LIBRARY_PATH
LD_LIBRARY_PATH=LD_LIBRARY_PATH=/rabbitmq-c/_build/librabbitmq${LD_LIBRARY_PATH+:$X}
# Execute the binary, from the same location of the launcher
${0%/*}/./rabbit
If your binary don't find your "librabbitmq.so.4", that means this shared object is not found by ld (the dynamic linker)
First step, do a "ldconfig". Does this solve your problem ?
Yes ? Cool.
if not, then you have to tell ldconfig where to look to find "librabbitmq.so.4".
So either you move it in a knowed folder (LD_LIBRARY_PATH for exemple) or add it so it will be knowed by ld.
echo '/rabbitmq-c/_build/librabbitmq' > '/etc/ld.so.conf.d/name_this_file_yourself.conf'
ldconfig
This should fix your issue.

macOS: library not found for -lpaho-mqtt3c

What I have done:
git clone https://github.com/eclipse/paho.mqtt.c
cd paho.mqtt.c
make
sudo make install
Then, I tried compiling a simple C program that includes the MQTT C library like this:
#include <MQTTClient.h>
The command I used was:
$ gcc -o mqttTest mqttTest.c -lpaho-mqtt3c
What I got was ...
... even though the libraries are clearly present in /usr/local/lib:
What do I need to do to compile my code?
I already tried adding -L/usr/local/lib to the compile command, to no avail.
I found the answer on GitHub. See VilleViktor's post here: https://github.com/eclipse/paho.mqtt.cpp/issues/150
All I had to do was:
$ mv /usr/local/lib/libpaho-mqtt3a.so.1.0 /usr/local/lib/libpaho-mqtt3a.so.1
$ mv /usr/local/lib/libpaho-mqtt3as.so.1.0 /usr/local/lib/libpaho-mqtt3as.so.1
$ mv /usr/local/lib/libpaho-mqtt3c.so.1.0 /usr/local/lib/libpaho-mqtt3c.so.1
$ mv /usr/local/lib/libpaho-mqtt3cs.so.1.0 /usr/local/lib/libpaho-mqtt3cs.so.1
Maybe that saves someone else a lot of time on Google ...

When compiling C code in the linux terminal, what is the difference between make <filename> and cc <filename>?

I'm new to C, and I understand that both of those commands accomplish the same thing, but does one of them do something different than the other along the way?
First of all, if you are using make then for hello.c you will call make as make hello and not make hello.c. Also, note that make is most of the times used with a Makefile. Nonetheless, you can build executable binary from single source file using make as you have shown.
If the executable (hello) does not exist, then both will have same effect - create the executable from source file.
However, if the executable already exists, then make will run the build commands only if it thinks that the source code has changed after last build, whereas cc will always do the build.
For example:
$ make hello
cc hello.c -o hello
$ make hello
make: 'hello' is up to date. # make does not think source file has changed
$ touch hello.c # Update the timestamp of hello.c
$ make hello
cc hello.c -o hello # make thinks source file changed. Builds again
$
However, cc will not check if the source has changed or not. It will always do the required build.
$ cc hello.c -o hello
$ ls -l hello | cut -d ' ' -f '8-'
12:18 hello
$ cc hello.c -o hello # Build again without changing source
$ ls -l hello | cut -d ' ' -f '8-'
12:21 hello # hello was built again
$
Above description was for GNU make and GNU cc. Not sure about other implementations.
P.S.: make is not a compiler. It only calls the compiler when it thinks it should, as seen in the example above. Whereas cc is a compiler.
P.S. If you run cc hello.c, the excutable is named a.out, and not hello.
make(1) is a program that will run commands. You create a file named "Makefile" in a directory. The Makefile has a recipe with a specific syntax that is beyond the scope of this answer. You then invoke the make command in the directory with the file named Makefile
cc $filename will invoke a C compiler upon the $filename
cc or gcc or clang will invoke the compiler.
make is used when you have many files to compile.
In make you will give name of .o file and include header file location.

where does stdio.o live in linux machine?

I am trying to manually do all the compilation steps of my program. In the last step where I use the linker command ld, I need to specify the object file for library(stdio as I have used printf in my code) then only I can make and .exe file. Where does this object file reside?
I'd suggest that you run gcc -v your_file.c. That will let you see exactly what commands your linker is using. You probably don't have an stdio.o file to link against. Instead this is included in the C runtime library and the exact file will depend on your system configuration.
stdio is part of the C standard library. The exact location of the standard library is system-specific, but it is often in a file called libc.a or libc.so.
In my machine this can be found in:
/usr/lib/x86_64-linux-gnu/libc.a
/usr/lib/x86_64-linux-gnu/libc.so
You can ask ld for the search directory: ld --verbose | grep SEARCH_DIR.
libc.a is an ar (man) archive, and you can extract stdio.o from the libc.a archive using ar command:
$ # list archive member with `ar t`
$ ar t /usr/lib/x86_64-linux-gnu/libc.a | grep ^stdio
stdio.o
$ # extract stdio.o with `ar x`
$ ar x /usr/lib/x86_64-linux-gnu/libc.a stdio.o
its probably under root
Somthing like /usr/lib or /usr/lib***

What is the simplest way to create source Debian package?

Suppose you have hello.c
int main() { return 0; }
and Makefile
hello: hello.c
gcc hello.c -o hello
install: hello
install -m 755 hello /usr/bin/
The quickest and easiest way to get binary package seems to be to use checkinstall:
fakeroot checkinstall --pkgname hello -y -D --install=no --backup --nodoc --fstrans --pkgversion 0.0.1 make install
How to do similar thing, but for source package (to put it to some source repository or use "dpkg-buildpackage" on it)?
The officicial text is rather long: orig.tar.gz, changelog, control file... Is there something like checkinstall, but for source packages? Additional bonus whould be if it also figures out dependencies automatically (at least partially).

Resources