difference between -h <name> and -o <outputfile> options in cc (C++) - c++

I am building .so library and was wondering - what is the difference b/w -h and -o cc complier option (using the Sun Studio C++) ?
Aren't they are referring to the same thing - the name of the output file?

-o is the name of the file that will be written to disk by the compiler
-h is the name that will be recorded in ELF binaries that link against this file.
One common use is to provide library minor version numbers. For instance, if
you're creating the shared library libfoo, you might do:
cc -o libfoo.so.1.0 -h libfoo.so.1 *.o
ln -s libfoo.so.1.0 libfoo.so.1
ln -s libfoo.so libfoo.so.1
Then if you compile your hello world app and link against it with
cc -o hello -lfoo
the elf binary for hello will record a NEEDED entry for libfoo.so.1 (which you can
see by running elfdump -d hello ).
Then when you need to add new functions later, you could change the -o value to
libfoo.so.1.1 but leave the -h at libfoo.so.1 - all the programs you already built
with 1.0 still try to load libfoo.so.1 at runtime, so continue to work without being
rebuilt, but you'll see via ls that it's 1.1.
This is also sometimes used when building libraries in the same directory they're
used at runtime, if you don't have a separate installation directory or install
via a packaging system. To avoid crashing programs that are running when you
overwrite the library binary, and to avoid programs not being able to start when
you're in the middle of building, some Makefiles will do:
cc -o libfoo.so.1.new -h libfoo.so.1 *.o
rm libfoo.so.1 ; mv libfoo.so.1.new libfoo.so.1
(Makefiles built by the old Imake makefile generator from X commonly do this.)

They are referring to different names. Specifically, the -o option is the file's actual name - the one on the filesystem. The -h option sets the internal DT_SONAME in the final object file. This is the name by which the shared object is referenced internally by other modules. I believe it's the name that you also see when you run ldd on objects that link to it.

The -o option will name the output file while the -h option will set an intrinsic name inside the library. This intrinsic name has precedence over the file name when used by the dynamic loader and allows it to use predefined rules to peek the right library.
You can see what intrinsic name was recorded into a given library with that command:
elfdump -d xxx.so | grep SONAME
Have a look here for details:
http://docs.oracle.com/cd/E23824_01/html/819-0690/chapter4-97194.html

Related

Compile mex function with external libraries

I'm trying to generate a mex function usigin external libraries. I'm using Ubuntu 18 and Matlab R2021a.
In particular I want to compile my file.cpp that uses my cpp library called model.
What I did is
mex -I<path_library_include> -L<path_library_so_file> -lmodel.so -lboost_system -lstdc++ file.cpp -v
where in -I i put the path where is the include of the library in -L the path in which the libmodel.so is located, then I added 2 more libraries and at the end the source file that I want to compile.
In this way I can compile my source but when I try to execute the mex function I get:
libmodel.so: cannot open shared object file: No such file or directory
I also tested the library outside matlab and works fine, this is the command that I use to compile the library outside Matlab
gcc -Wall -I<path_library_include> -L<path_library_so_file> main.cpp -lmodel -lboost_system -lstdc++ -o main
What could be the problem with Matlab?
Thanks to 273K that gave me the right direction.
The problem was that the LD_LIBRARY_PATH was not configured well in fact running /sbin/ldconfig -v my library was not present. So to add the shared library i created a new file as root in /etc/ld.so.conf.d/ called mylib.conf it is not important the name just the extension. Then I run
sudo ldconfig
after that the library was present in fact running
/sbin/ldconfig -v | grep model
where model is the name of my library. it is possible to see the output.

How gnu linker choose which dynamic library to link

I was using gpgpu-sim, a GPU simulator, to conduct researches. There are several .so files in my own folder:
And there are some alternatives .so in Nvidia's cudart lib folder:
And there are some .o files and need to be linked with libcudart.so, when I type in the command:
g++ -L "Path/to/MyFolder" -l cudart *.o
I hope the generated a.out would link to libcudart.so, but it just linked to a strange so file:
libcudart_gpgpu-sim_git-commit-6443f21d433f1b642003867e56fe1f54efae55e3_modified_0.so => not found
And when I typed this code:
g++ -L "Path/to/NvidiaFolder" -l cudart *.o
The program can sussessfully find libcudart.so.9 in my LD_LIBRARY_PATH folder,but it shows that the version can't match!:
./a.out: /path/to/myFolder/libcudart.so.9.0: version `libcudart.so.9.0'not found (required by ./a.out)
Can anybody tell me how ld works and how to solve those problems?
I finally find out the reason.
if you use this code to link objects to generate a shared library:
g++ -shared -Wl,-soname,libNAME_A.so -o libNAME_B.so
then, if some on is trying to link NAME_B.so using:
g++ <INPUT> -lNAME_B -o <OUTPUT>
the output will finally look for libNAME_A.so.
refer to g++ man page:
-Wl,option
Pass option as an option to the linker. If option contains commas,
it is split into multiple options at the commas. You can use this
syntax to pass an argument to the option. For example,
-Wl,-Map,output.map passes -Map output.map to the linker. When
using the GNU linker, you can also get the same effect with
-Wl,-Map=output.map.
and for ld man page:
-soname=name
When creating an ELF shared object, set the internal DT_SONAME
field to the specified name. When an executable is linked with a
shared object which has a DT_SONAME field, then when the executable
is run the dynamic linker will attempt to load the shared object
specified by the DT_SONAME field rather than the using the file
name given to the linker.
There is nothing to do with CUDA here, it's just a linking and runtime environment setup problem.
The ld linker searches for objects and library archives following the order specified by -L option parameters, and only after into default system directories. The linker will link the object code that first match this search.
At runtime, if you linked against dynamic libraries (.so files) you will need to properly define the LD_LIBRARY_PATH environment variable with a list of paths to look for dynamic libraries, separated by colon (:).
So if you link to your objects using libraries from your local path (assuming you are looking for libcudart.so):
g++ -o myprogram *.o -L "/Path/to/myFolder" -lcudart
you need to set LD_LIBRARY_PATH as follows before running your program:
export LD_LIBRARY_PATH="/Path/to/myFolder:$LD_LIBRARY_PATH"
./myprogram
I hope this help and clarify your understanding. Frankly I don't understand the origin of your libcudart_gpgpu-sim_git-commit match

Can a Crystal library be statically linked to from C?

I've read through the "C bindings" in the tutorial but I'm a novice at C stuff.
Could someone please let me know if a Crystal program can be built as a static library to link to, and if so could you please provide a simple example?
Yes, but it is not recommended to do so. Crystal depends on a GC which makes it less desirable to produce shared (or static) libraries. Thus there are also no syntax level constructs to aid in the creation of such nor a simple compiler invocation to do so. The C bindings section in the documentation is about making libraries written in C available to Crystal programs.
Here's a simple example anyhow:
logger.cr
fun init = crystal_init : Void
# We need to initialize the GC
GC.init
# We need to invoke Crystal's "main" function, the one that initializes
# all constants and runs the top-level code (none in this case, but without
# constants like STDOUT and others the last line will crash).
# We pass 0 and null to argc and argv.
LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
end
fun log = crystal_log(text: UInt8*): Void
puts String.new(text)
end
logger.h
#ifndef _CRYSTAL_LOGGER_H
#define _CRYSTAL_LOGGER_H
void crystal_init(void);
void crystal_log(char* text);
#endif
main.c
#include "logger.h"
int main(void) {
crystal_init();
crystal_log("Hello world!");
}
We can create a shared library with
crystal build --single-module --link-flags="-shared" -o liblogger.so
Or a static library with
crystal build logger.cr --single-module --emit obj
rm logger # we're not interested in the executable
strip -N main logger.o # Drop duplicated main from the object file
ar rcs liblogger.a logger.o
Let's confirm our functions got included
nm liblogger.so | grep crystal_
nm liblogger.a | grep crystal_
Alright, time to compile our C program
# Folder where we can store either liblogger.so or liblogger.a but
# not both at the same time, so we can sure to use the right one
rm -rf lib
mkdir lib
cp liblogger.so lib
gcc main.c -o dynamic_main -Llib -llogger
LD_LIBRARY_PATH="lib" ./dynamic_main
Or the static version
# Folder where we can store either liblogger.so or liblogger.a but
# not both at the same time, so we can sure to use the right one
rm -rf lib
mkdir lib
cp liblogger.a lib
gcc main.c -o static_main -Llib -levent -ldl -lpcl -lpcre -lgc -llogger
./static_main
With much inspiration from https://gist.github.com/3bd3aadd71db206e828f

ldconfig is not seeing custom library

We created a custom shared library from some C++ code using
g++ -c -fPIC customTest.cpp
g++ -shared -o libcustomTest.so customTest.o
And we put it in the project directory and in our makefile we have the default target being
main: main.o
nvcc $^ -o main -lcustomTest -L.
And this works just fine.
The problem is, we'd like to move our library to /usr/lib/ or any arbitrary folder and still have the program locate it and use it but this hasn't been happening as we want it to.
We have a folder in our root that we created called libTest and in that folder we put our library customTest.so.0.1. Then we edited ld.so.conf in /etc/ to had /libTest in it.
Then we went to the directory of our program files and ran
ldconfig -v
which looked like this but larger
libpanel.so.5 -> libpanel.so.5.9
libt1.so.5 -> libt1.so.5.1.2
libbluetooth.so.3 -> libbluetooth.so.3.11.4
libgck-1.so.0 -> libgck-1.so.0.0.0
libdca.so.0 -> libdca.so.0.0.0
a lot of links are created and what not, but libcustomTest.so is not one of them. Not surprisingly, when we run make the custom library can't be located.
Can anyone point us in the right direction with what we are doing wrong? By the way we are on Ubuntu 11.10
g++ -shared -o libcustomTest.so customTest.o
This will create a shared library with SONAME not set.
We have a folder in our root that we created called libTest and in that folder we put our library customTest.so.0.1
Don't do that. Just copy libcustomTest.so into /libTest, and be done with it.
a lot of links are created and what not, but libcustomTest.so is not one of them.
That's expected result. ldconfig creates symlinks from SONAME to actual implementation binary. Since you didn't set SONAME, no symlink for you.
Unless you understand what SONAME is for, don't bother setting it (via -Wl,--soname=... flag) either. On Linux, SONAME and external library versioning is usually the wrong answer, as symbol versioning provides much better approach anyway.

Build a Linux executable using GCC

I'm using Ubuntu 8.10 (Intrepid Ibex) and compiling C++ files with GCC, but when I compile, gcc makes an a.out file that is the executable. How can I make Linux executables?
That executable is a "Linux executable" - that is, it's executable on any recent Linux system. You can rename the file to what you want using
rename a.out your-executable-name
or better yet, tell GCC where to put its output file using
gcc -o your-executable-name your-source-file.c
Keep in mind that before Linux systems will let you run the file, you may need to set its "executable bit":
chmod +x your-executable-name
Also remember that on Linux, the extension of the file has very little to do with what it actually is - your executable can be named something, something.out, or even something.exe, and as long as it's produced by GCC and you do chmod +x on the file, you can run it as a Linux executable.
To create an executable called myprog, you can call gcc like this:
gcc -c -o myprog something.c
You could also just rename the *.out file gcc generates to the desired name.
That is the executable. If you don't like a.out, you can pass an -o flag to the compiler. If the executable isn't marked with an executable bit, you need to do so yourself:
chmod u+x ./a.out
./a.out