Can not find object file with cmake link_directories - object

I want to add several .o files to the link process. If I do it like this:
TARGET_LINK_LIBRARIES(FFMPEGTest stdc++fs -pthread /home/stiv2/jsoft/nv-ffmpeg/ffmpeg/libswresample/audioconvert.o ...some more stuff... )
then it finds the file. All of these files are in the same directory, so I want to add them semultaneously:
link_directories(/home/stiv2/jsoft/nv-ffmpeg/ffmpeg/libswresample/)
TARGET_LINK_LIBRARIES(FFMPEGTest stdc++fs -pthread audioconvert.o ...some more stuff... )
but this doesn't work:
/usr/bin/ld: cannot find -laudioconvert.o
how do I fix this?

Documentation for target_link_libraries doesn't allow a relative path (audioconvert.o) to be a parameter to that command. It should be either absolute path (/home/stiv2/jsoft/nv-ffmpeg/ffmpeg/libswresample/audioconvert.o) or a plain library name (like z for libz.a library).
Because the object file audioconvert.o is not a library, it cannot be specified with a plain library name. You have no other choice than specify an absolute path for the object files.
For specify several object files in some directory you may use foreach loop:
foreach(obj audioconvert.o foo.o bar.o)
target_link_libraries(FFMPEGTest /home/stiv2/jsoft/nv-ffmpeg/ffmpeg/libswresample/${obj})
endforeach()
Actually, every parameter <param> to target_link_libraries, which doesn't look like an absolute path (and doesn't corresponds to a library target), is transformed into -l<param> option for the linker.
The linker interprets this parameter as a plain library name, and searches for a file named lib<param>.a or lib<param>.so in the link directories.
So, with parameter -laudioconvert.o the linker searches a file with a name libaudioconvert.o.a - obviously, this is not what do you want.

Related

How is the -fprofile-prefix-path option supposed to work?

When compiling code for coverage instrumentation (to use with lcov later on), we're compiling from a base directory tree (let's call it A), and we want the .gcda files to be produced at a different place (because the target directory tree is different - let's call it B).
So, the compilation command looked like this:
gcc -O0 -g --coverage -fprofile-dir=B -c -fPIC -Wall -o A/otherpath/to/mySourceFile.o A/path/to/mySourceFile.c
When checking the contents of mySourceFile.o (with the strings command), I saw that the mySourceFile.gcda file was set to be generated in B/A/otherpath/to/mySourceFile.gcda
Which is the mangling of the path given through the -fprofile-dir option with the exact absolute path of the object file created - just as written in the documentation. So far, no problem - except that what I want would be the mySourceFile.gcda file to be generated from the B directory, WITHOUT the A part.
So, the documentation also mentions the -fprofile-prefix-path option, which is supposed to allow you to remove part of the path, so that the mangling doesn't add the old path to the new.
I tried using it in the following way:
gcc -O0 -g --coverage -fprofile-dir=B -fprofile-prefix-path=A -c -fPIC -Wall -o A/otherpath/to/mySourceFile.o A/path/to/mySourceFile.c
However, after checking through strings, once again, in the generated object file, the path was still B/A/otherpath/to/mySourceFile.gcda, whereas I expected it to be B/otherpath/to/mySourceFile.gcda (that is, I expected the A part to have been stripped by the -fprofile-prefix-path option.)
Obviously, it didn't work. Any insight why ?
( Compiler used is GCC 11.2.1, which is a version recent enough to know about the option. )
Ok, after some tinkering, I got results. Maybe not exactly what I was expecting, but close enough.
Let me start by saying that the A and B "directories" I mentioned in my question were absolute paths. And it didn't work well.
However, while keeping the absolute B (target) path, I tried not using the full A (source) path while compiling. More precisely, I didn't use it to specify the OUTPUT file name, for the object. Instead, I went to the base directory (the A path), and then, ran the command by specifying the output file path relative to the current (A) directory
Which would give the following command:
(From directory A)
gcc -O0 -g --coverage -fprofile-dir=B -fprofile-prefix-path=A -c -fPIC -Wall -o otherpath/to/mySourceFile.o path/to/mySourceFile.c
This time, the source command did show an interesting result, for the mySourceFile.gcda file:
B#otherpath#to#mySourceFile.gcda
As you can see, it's not exactly what I wanted (there are # instead of /), but mentions to A disappeared, and overall, I'm confident it should work as intended. Not utterly sure yet (I still have to test it on the target platform, which will need tinkering with the way the makefiles currently work), but confident nonetheless.
Also, if I didn't use the -fprofile-prefix-path in the command, then the string would mention the A path, like this (with the '/' inside the A path being replaced with '#' characters, obviously):
B#A#otherpath#to#mySourceFile.gcda
So, the option works, but only when using relative paths, not when using absolute ones, for the object file. Hope that helps people.
PS: I checked by changing the path to the source (.c) file. Whether specified using absolute, or relative, paths, it didn't change the outcome. What matters is specifying the path to the object file in a relative manner.

Qemu and LD_LIBRARY_PATH variable

When I exec qemu-aarch64 with a binary which is using shared libraries I get the following:
qemu-aarch64 -L /usr/aarch64-linux-gnu ./test
./test: error while loading shared libraries: testlibrary.so.1: cannot open shared object file: No such file or directory
Obviously it is because test does not know where the shared libraries are.
Thus:
qemu-aarch64 -L /usr/aarch64-linux-gnu -E LD_PRELOAD="/home/test/libraries/testlibrary.so.1 /home/test/libraries/testlibrary2.so.1" ./test
hi!
Ok, it works; but when I use LD_LIBRARY_PATH it does not work:
qemu-aarch64 -L /usr/aarch64-linux-gnu -E LD_LIBRARY_PATH="/home/test/libraries ./test
./test: error while loading shared libraries: testlibrary.so.1: cannot open shared object file: No such file or directory
The difference between LD_PRELOAD and LD_LIBRARY_PATH, from ld.so man:
LD_PRELOAD:
A list of additional, user-specified, ELF shared objects
to be loaded before all others. This feature can be used
to selectively override functions in other shared objects.
The items of the list can be separated by spaces or
colons, and there is no support for escaping either
separator. The objects are searched for using the rules
given under DESCRIPTION. Objects are searched for and
added to the link map in the left-to-right order specified
in the list.
In secure-execution mode, preload pathnames containing
slashes are ignored. Furthermore, shared objects are
preloaded only from the standard search directories and
only if they have set-user-ID mode bit enabled (which is
not typical).
Within the names specified in the LD_PRELOAD list, the
dynamic linker understands the tokens $ORIGIN, $LIB, and
$PLATFORM (or the versions using curly braces around the
names) as described above in Dynamic string tokens. (See
also the discussion of quoting under the description of
LD_LIBRARY_PATH.)
There are various methods of specifying libraries to be
preloaded, and these are handled in the following order:
(1) The LD_PRELOAD environment variable.
(2) The --preload command-line option when invoking the
dynamic linker directly.
(3) The /etc/ld.so.preload file (described below).
And,
LD_LIBRARY_PATH:
A list of directories in which to search for ELF libraries
at execution time. The items in the list are separated by
either colons or semicolons, and there is no support for
escaping either separator. A zero-length directory name
indicates the current working directory.
This variable is ignored in secure-execution mode.
Within the pathnames specified in LD_LIBRARY_PATH, the
dynamic linker expands the tokens $ORIGIN, $LIB, and
$PLATFORM (or the versions using curly braces around the
names) as described above in Dynamic string tokens. Thus,
for example, the following would cause a library to be
searched for in either the lib or lib64 subdirectory below
the directory containing the program to be executed:
$ LD_LIBRARY_PATH='$ORIGIN/$LIB' prog
(Note the use of single quotes, which prevent expansion of
$ORIGIN and $LIB as shell variables!)
Why does it work with LD_PRELOAD and not with LD_LIBRARY_PATH?
The library you're opening with LD_PRELOAD is "testlibrary.so.1", but the library that the dynamic loader otherwise looks for is "testlibrary.so.3", which suggests there's a mismatch between the library version you have and the library version the binary is linked against, which maybe the LD_PRELOAD is side-stepping. Does LD_LIBRARY_PATH work if you make sure that you have the file in that directory that the binary is looking for ?

How to add_library with pattern for sources?

I want to use regular expression to add all files to add_library, but it does not work.
I tried this :
add_library(8021qbg SHARED
8021QBG/"*.h"
8021QBG/"*.cpp"
)
And get this:
CMake Error at CMakeLists.txt:128 (add_library):
Cannot find source file:
8021QBG/"*.h"
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
I tried this:
file(GLOB 8021x
8021x/"*.h"
8021x/"*.cpp"
)
add_library(8021x SHARED
${8021x}
)
And at compiling make command does not see sources to compile.
I want to build shared library using something not to write down every source file (regular expression, I suppose).
How to do it?
You need to ask cmake to list all matching files into a variable:
file(GLOB SOURCE_FILES
8021QBG/*.h
8021QBG/*.cpp
)
and then use this variable:
add_library(8021qbg SHARED
${SOURCE_FILES}
)
More on file(GLOB) command.
Generate a list of files that match the and store it into the . Globbing expressions are similar to regular expressions, but much simpler.
With the following addition cmake is able to determine the name of the lib being added thus making the script context agnostic.
# libname = current directory name
get_filename_component(libname "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
# .c and .h files
file(GLOB thislibsrc ${CMAKE_CURRENT_SOURCE_DIR}/*.c ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
# include it only once
include_guard(GLOBAL)
# and use it
add_library(${libname} STATIC ${thislibsrc} )
...
I have such little components saved in some central directory so I can call them later like:
include(../addlibscr.cmake)

Including header files in cygwin

As you know the getch() and getche() functions don't work with the cygwin, a linux oriented one.
But can I include the conio.h header file of borland c and call the functions getch in my makefiles?
Will it work and can anyone tell me how to include the header files from different directories in cywgin.
I have a header file strcal.h in directory c:/makk/string/.
How do I include that header file in my makefile?
gcc -I/string small.c
It is not working and my current directory is makk.
In stdio.h, there is a getchar() function which is what you need. You can't just bring across the Borland header file since that just declares the function, it doesn't define it. Standard C has no need for getch().
To include header files in different areas, you use the -I directives of gcc to set up search paths.
So, if you have a /xyz/myheader.h file, you can do something like:
gcc -I /xyz myprogram.c
To get at c:/makk/string/strcal.h, you may have to use gcc -I /cygdrive/c/makk/string or, if you know you're actually in that makk directory, you can use -I string (note the lack of leading / since you want a relative path, not an absolute one).

SCons: Get abspath of original file (as though I hadn't set variant_dir)

I can use File('foo.bar').abspath to get the location of a file, but if I've got variant_dir set then the returned path will be in variant_dir rather than it's original location. If I have duplicate=0 set, then the file returned won't actually exist.
Obviously SCons knows where the original file is, as it's passed as an argument when the file's actually built (eg gcc -c -o variant/foo.o orig/foo.c).
Is there some sort of File('foo.bar').origpath that I can use?
If it came to it I could use os.path.join(Dir('#').abspath, 'orig') but that requires the SConscript to know which directory it's in, which is messy.
You can use srcnode(). To quote the man page:
The srcnode() method returns another
File or Dir object representing the
source path of the given File or Dir.
This will give you the absolute path in the source directory:
File('foo.bar').srcnode().abspath

Resources