By default librtmp compile produces librtmp.so.1 file and symlink librtmp.so. I need to have librtmp.so without number suffix as andorid does not support it.
I was able to modify Makefile to get librtmp.so file:
#SO_VERSION=1
#SO_posix=.${SOX}.${SO_VERSION}
SO_posix=${SOX}
so the file produced file is now librtmp.so
But android can't load it as it still tries to load librtmp.so. (with dot):
Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1891]: 170 could not load needed library 'librtmp.so.' for 'libffmpeg.so' (load_library[1093]: Library 'librtmp.so.' not found)
If a shared library has DT_SONAME dynamic tag of foobar.so.56, then no matter what you call the actual file (e.g. foo.so, or libbar.so), when you use that library to link an executable, the SONAME is recorded in the executable (as DT_NEEDED dynamic tag), and not the actual file name.
It follows that your librtmp.so has a DT_SONAME of librtmp.so.. You can confirm that with:
readelf -d librtmp.so | grep SONAME
So what do you need to do to get rid of SONAME? Get rid of -Wl,--soname=... somewhere in your Makefile.
how can i check executable if it uses SONAME or filename
The executable will always use SONAME (if present). You can check the libraries that executable needs by looking for DT_NEEDED tags in the executable's dynamic section:
readelf -d a.out | grep NEEDED
Related
Right now, I have:
GetModuleFileNameA to get the executable that has loaded my DLL as a charstring
MapAndLoad, which only accepts charstrings, to look at that executable's metadata
I want to remove the filename and just get the directory of the executable, so I can load a DLL that's specifically in the same directory. Yet, PathCchRemoveFileSpec doesn't take charstrings. What do I do?
I have a program that statically links glib library and dynamically links a shared library that in turn also statically links the same glib library. When I run the program I get a segfault. After debugging in gdb I found that there is a global static variable defined in glib that's being set and it had different values in one call trace and than a later call trace. I then noticed that the variable addresses were different as well. So it seems like there are two copies of the global static variable? Shouldn't the executable override the symbol from shared library so there is only one global static variable in the executable during dynamic linking?
The other part of the story is that there is another executable that does the same as above, which seems to behave okay i.e., no segfault (haven't debugged to see if the different code paths load the same static variable). So perhaps this behavior is not deterministic.
The following issue is happening with gcc (8.3.1) on Linux (centos 7).
executableA (segfault) executableB (no segfault)
| \ | \
| (static) \(shared) |(static) \(shared)
| \ | \
libglib-2.0.a libA.so libglib-2.0.a libA.so
| |
| (static) |(static)
| |
libglib-2.0.a libglib-2.0.a
So it seems like there are two copies of the global static variable?
Yes, that is expected.
Shouldn't the executable override the symbol from shared library so there is only one global static variable in the executable during dynamic linking?
A static variable by definition has local linkage -- it is not accessible from any other compilation unit, and is not exported from the shared library(ies).
You would have to make this variable (and any other similar variables) non-static and exported from both shared libraries. Only then will the dynamic loader bind all references to this variable to a single instance.
Note that linking separate copies of libglib-2.0.a into shared libraries without controlling symbol visibility is asking for trouble. Whatever you hoped to achieve by doing that, you are not achieving.
there is another executable that does the same as above, which seems to behave okay
Ah, programming by coincidence. The mine you stepped on didn't explode, so it should be ok to continue doing that.
How to get CMake to link an executable to an external shared library that is not build within the same CMake project?
Just doing target_link_libraries(GLBall ${CMAKE_BINARY_DIR}/res/mylib.so) gives the error
make[2]: *** No rule to make target `res/mylib.so', needed by `GLBall'. Stop.
make[1]: *** [CMakeFiles/GLBall.dir/all] Error 2
make: *** [all] Error 2
(GLBall is the executable)
after I copied the library into the binary dir bin/res.
I tried using find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)
Which fails with RESULT-NOTFOUND.
arrowdodger's answer is correct and preferred on many occasions. I would simply like to add an alternative to his answer:
You could add an "imported" library target, instead of a link-directory. Something like:
# Your-external "mylib", add GLOBAL if the imported library is located in directories above the current.
add_library( mylib SHARED IMPORTED )
# You can define two import-locations: one for debug and one for release.
set_target_properties( mylib PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/res/mylib.so )
And then link as if this library was built by your project:
TARGET_LINK_LIBRARIES(GLBall mylib)
Such an approach would give you a little more flexibility: Take a look at the add_library( IMPORTED) command and the many target-properties related to imported libraries.
I do not know if this will solve your problem with "updated versions of libs".
Set libraries search path first:
link_directories(${CMAKE_BINARY_DIR}/res)
And then just do
target_link_libraries(GLBall mylib)
I assume you want to link to a library called foo, its filename is usually something link foo.dll or libfoo.so.
1. Find the library
You have to find the library. This is a good idea, even if you know the path to your library. CMake will error out if the library vanished or got a new name. This helps to spot error early and to make it clear to the user (may yourself) what causes a problem.
To find a library foo and store the path in FOO_LIB use
find_library(FOO_LIB foo)
CMake will figure out itself how the actual file name is. It checks the usual places like /usr/lib, /usr/lib64 and the paths in PATH.
You already know the location of your library. Add it to the CMAKE_PREFIX_PATH when you call CMake, then CMake will look for your library in the passed paths, too.
Sometimes you need to add hints or path suffixes, see the documentation for details:
https://cmake.org/cmake/help/latest/command/find_library.html
2. Link the library
From 1. you have the full library name in FOO_LIB. You use this to link the library to your target GLBall as in
target_link_libraries(GLBall PRIVATE "${FOO_LIB}")
You should add PRIVATE, PUBLIC, or INTERFACE after the target, cf. the documentation:
https://cmake.org/cmake/help/latest/command/target_link_libraries.html
If you don't add one of these visibility specifiers, it will either behave like PRIVATE or PUBLIC, depending on the CMake version and the policies set.
3. Add includes (This step might be not mandatory.)
If you also want to include header files, use find_path similar to find_library and search for a header file. Then add the include directory with target_include_directories similar to target_link_libraries.
Documentation:
https://cmake.org/cmake/help/latest/command/find_path.html
and
https://cmake.org/cmake/help/latest/command/target_include_directories.html
If available for the external software, you can replace find_library and find_path by find_package.
Let's say you have an executable like:
add_executable(GLBall GLBall.cpp)
If the external library has headers, give the path to its include folder:
target_include_directories(GLBall PUBLIC "/path/to/include")
Add the library directory path:
target_link_directories(GLBall PUBLIC "/path/to/lib/directory")
Finally, link the library name
target_link_libraries(GLBall mylib)
Note that the prefix and extension of the library file are removed:
libmylib.a ➜ mylib
mylib.so ➜ mylib
One more alternative, in the case you are working with the Appstore, need "Entitlements" and as such need to link with an Apple-Framework.
For Entitlements to work (e.g. GameCenter) you need to have a "Link Binary with Libraries"-buildstep and then link with "GameKit.framework". CMake "injects" the libraries on a "low level" into the commandline, hence Xcode doesn't really know about it, and as such you will not get GameKit enabled in the Capabilities screen.
One way to use CMake and have a "Link with Binaries"-buildstep is to generate the xcodeproj with CMake, and then use 'sed' to 'search & replace' and add the GameKit in the way XCode likes it...
The script looks like this (for Xcode 6.3.1).
s#\/\* Begin PBXBuildFile section \*\/#\/\* Begin PBXBuildFile section \*\/\
26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks \*\/ = {isa = PBXBuildFile; fileRef = 26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/; };#g
s#\/\* Begin PBXFileReference section \*\/#\/\* Begin PBXFileReference section \*\/\
26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System\/Library\/Frameworks\/GameKit.framework; sourceTree = SDKROOT; };#g
s#\/\* End PBXFileReference section \*\/#\/\* End PBXFileReference section \*\/\
\
\/\* Begin PBXFrameworksBuildPhase section \*\/\
26B12A9F1C10543B00A9A2BA \/\* Frameworks \*\/ = {\
isa = PBXFrameworksBuildPhase;\
buildActionMask = 2147483647;\
files = (\
26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks xxx\*\/,\
);\
runOnlyForDeploymentPostprocessing = 0;\
};\
\/\* End PBXFrameworksBuildPhase section \*\/\
#g
s#\/\* CMake PostBuild Rules \*\/,#\/\* CMake PostBuild Rules \*\/,\
26B12A9F1C10543B00A9A2BA \/\* Frameworks xxx\*\/,#g
s#\/\* Products \*\/,#\/\* Products \*\/,\
26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/,#g
save this to "gamecenter.sed" and then "apply" it like this ( it changes your xcodeproj! )
sed -i.pbxprojbak -f gamecenter.sed myproject.xcodeproj/project.pbxproj
You might have to change the script-commands to fit your need.
Warning: it's likely to break with different Xcode-version as the project-format could change, the (hardcoded) unique number might not really by unique - and generally the solutions by other people are better - so unless you need to Support the Appstore + Entitlements (and automated builds), don't do this.
This is a CMake bug, see http://cmake.org/Bug/view.php?id=14185 and http://gitlab.kitware.com/cmake/cmake/issues/14185
It has been a long time since the question was posted but I am leaving this one just for reference.
I have a blog post describing step-by-step almost what you (or anyone else) were trying to do.
Please check here: https://michae9.wordpress.com/2022/09/01/shared-lib-to-be-used-by-client-programs-with-cmake/
I have to make ELF file to use absolute paths for libraries instead of searching in default paths (RPATH).
This is result from readelf:
readelf -d example
Dynamic section at offset 0xe28 contains 24 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
But I want to get something like this:
readelf -d example
Dynamic section at offset 0xe28 contains 24 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [/lib/libc.so.6]
Are there any linker options to achieve this?
The tool you want is ldd, because those absolute paths are not part of the ELF file but are decided by the dynamic loader. ldd is a wrapper around environment variables that cause the dynamic loader to output the paths to the libraries that would be (or have been, depending on how you see it) loaded.
Of course, library resolution is a system-specific task and your results may vary across installs even of the same distribution.
AFAIK specifying the .so file as a normal input, using the absolute path, will result in a binary that also refers to the .so using that same absolute path.
Not sure how that works with default libs like libc, but you could try adding /lib/libc.so.6 as the first linker input.
I have a question regarding an article of JNI at http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html.
gcc -o libnativelib.so -shared -Wl,-soname,libnative.so
-I/export/home/jdk1.2/include
-I/export/home/jdk1.2/include/linux nativelib.c
-static -lc
I guess I am still a little confused with the function of '-o libnativelib.so' and '-Wl,-soname,libnative.so'.
'-o libnativelib.so' specify the name of output file of gcc to be libnativelib.so. From what i understand it is the library name to load from JAVA side as shown in the article:
static {
System.loadLibrary("nativelib");
}
So what's the use of '-Wl,-soname,libnative.so'?
I found following info on ld option manual:
-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.
So what does it mean? When final executable is run, linker will attempt to load ?? rather than ?? in the name of ??
This is useful for a system, where one library can be present under several names, for example: libz.so, libz.so.1, libz.so.1.2.3. All these libraries are symlinks to one file, and DT_SONAME inside it points to "libz.so.1". When you link your code against libz.so, it will record dependency on "libz.so.1" in the executable file. And when your file is executed on another system, which contains, say, libz.so.1.2.5, it will still work, because it will look for libz.so.1. But if the destination system will have much newer version, like libz.2.3.4, it will fail, because libz.so.2, but not libz.so.1 will be present.
DT_SONAME field is used only by linker. When you use System.loadLibrary(), the file name is specified by you, and the value of this option is not used. If you want, you can implement a similar versioning scheme for you libnative, to ensure that you java code always load a compatible version.
From GCC-HOWTO:
Each library has a soname. When the linker finds one of these in a library it is searching, it embeds the soname into the binary instead of the actual filename it is looking at. At runtime, the dynamic loader will then search for a file with the name of the soname, not the library filename. Thus a library called libfoo.so could have a soname libbar.so, and all programs linked to it would look for libbar.so instead when they started.
In your case, the soname libnative.so is different from the file name libnativelib.so.
You'll have to symlink libnative.so to libnativelib.so to allow the dynamic loader to find the shared lib.