I tried to add my Fortran modules and a shared library (.so) into an extensive library. The code does not complain about the modules. It knows where to find .mod files. However, I do not know what option should be put in configure.ac to make it consider the shared library .so.
By far, I tried the following commands separately in configure.ac but no success:
Option 1)
medys_LDADD = -L/PathToDirectory -lnamelib
Option 2)
LDADD=PathToDirectory/namelib.so
Option 3)
AM_LDADD = PathToDirectory/namelib.so
Related
I am successfully using Boost Python to build a series of Python libraries. These libraries are built conditionally, depending on the settings the user specifies at build time (via CMake).
Now what I would like to do is to merge them all together into a single library, which would contain a series of modules (one per old library) only if they were needed.
So for example, if before I had:
A.so # Always built
B.so # Compiled if B was set
C.so # Compiled if C was set
Now I'd like to have:
MyLib.so # Always built
---
import MyLib
MyLib.A # always works
MyLib.B # works only if MyLib was compiled with B set
MyLib.C # works only if MyLib was compiled with C set
I already know how to create namespaces with Boost Python (via class_), but I'm not sure how I could setup the project so that this final result was possible.
With CMake I can conditionally add files to compile, but I don't know how to define the MyLib module in C++ so that I can add parts to it in separate files.
For now I've added some ifdefs inside the exporting functions which limit the exports based on defines created in CMake.
It's not bad although I'd have preferred to keep the code clean from this, but for now it's my only solution.
I am trying to write a simple application with GLFW on Linux. Right now the main file (the only file) is basically just a few lines of code to make sure the dynamic library linked correctly. Here it is:
#include <GLFW/glfw3.h>
#include <iostream>
int main()
{
glfwInit();
std::cout << "It works this far!" << std::endl;
glfwTerminate();
}
The include files are stored in a directory labelled "include" and the library files are stored in a directory labelled "lib". As of right now, I am compiling the program with the following line:
g++ -Wl,-Rlib -Iinclude -Llib test.cpp -o test -lglfw.3.2
It compiles and links just fine, but when I try to execute it, I get the following error:
./test: error while loading shared libraries: libglfw.so.3: cannot open shared object file: No such file or directory
Now, before you rush to downvote this question into oblivion and mark it as a duplicate, at least allow me to explain why I believe my question is different enough to not be a duplicate. I already attempted the solutions that the other questions presented, but it was unsuccessful. As you can see, I tried setting the path to the library during linking with the -Wl,-Rlib tag. I also tried setting LD_LIBRARY_PATH to point to the location of my libraries (the 'lib' folder), but it still threw the same error. (It didn't matter if the path was relative or absolute.)
So, the next thing I tried was running the ldd command on the executable. I got some other dependencies that were working just fine, but importantly, I got this:
libglfw.so.3 => not found
For some reason, it insists on looking for libglfw.so.3. It will not have it any other way. Upon renaming the library from libglfw.3.2.so to libglfw.so.3, the program executed just fine and printed It works this far! as if there were no problems at all.
Why would this happen?
For some reason, it insists on looking for libglfw.so.3. ... Upon renaming the library from libglfw.3.2.so to libglfw.so.3 ...
The ELF executables contain the exact name of the dynamic libraries used.
If the executable contains the library name "libglfw.so.3" the file must be named exactly like this.
The file naming scheme is intentionally done in a way that not the "full" version is coded into the file name: This way a later version ("libglfw.so.3.15") will work with the executable.
Normally there should be a symbolic link to the latest version of the library installed:
libglfw.so.3 -> libglfw.so.3.2
This symbolic link seems to be missing on your computer. I would say that this is an installation problem!
EDIT
The question could be: Why is the file name stored in the executable file not libglfw.3.2.so but libglfw.so.3?
The answer has to do with the backward compatibility when a new version of a library is installed:
Normally you would use the switch -lglfw and a symbolic link named libglfw.so is looked up.
If you stored the file name libglfw.so in the executable file and a new, incompatible version if this library (libglfw.so.4) is installed you would have no chance to get the program running by having both versions of the library installed.
To enable backward compatibility by having both versions of the library installed the "real" symbolic link name of the library (libglfw.so.3) must be stored in the executable file.
Therefore the "expected" file name of a library is stored in the library itself: Inside the file libglfw.so.3.2 you'll find some information that the file expects itself to be stored as libglfw.so.3.
The linker will use this information about the file name because it assumes that the library name given in the linker switch (-lglfw) is less "precise" than the name stored in the library itself.
For some reason, it insists on looking for libglfw.so.3. It will not have it any other way.
This is the Linux convention for shared libraries which is described here among other places. For Linux libfoo.so.x.y.z is considered to have the same ABI as libfoo.so.x. Usually when shared libraries are installed (e.g. via rpm, dpkg, etc.) there's an invocation of ldconfig that happens so that the just installed libraries have a symlink following the convention installed that references the library. Also these libs (if installed to a "trusted location"), are added to a linker cache for performance reasons.
It compiles and links just fine, but when I try to execute it, I get the following error:
./test: error while loading shared libraries: libglfw.so.3: cannot open shared object file: No such file or directory
libglfw.so.3 isn't on ld-linux.so's path.
As you can see, I tried setting the path to the library during linking with the -Wl,-Rlib
Still won't find it -- libglfw.so.3 isn't on ld-linux.so's path. You can add it by doing something like:
ldconfig -n /path/to/lib
Which should output the requisite libglfw.so.3 symlink for your lib.
IIRC setting the rpath might require a full path.
I also tried setting LD_LIBRARY_PATH to point to the location of my libraries
Again, libglfw.so.3 isn't on ld-linux.so's path.
Situation
My project uses CMake and compiles without problems on Ubuntu 16.04.
When starting the compiled application I get the message cannot
open shared object file.
All the shared object libs are available in the same non-standard
folder (and I need them there).
For some reason some can be found, but others cannot.
What I need
The reason why some shared objects can be found and others cannot be found. The project is pretty big with many CMake files. I tried to find the differences between the libs that can be loaded and the ones that can't, but without success. Any help that point me to the right place is welcome.
A solution within CMake to make it find all the shared objects.
ldd
The ldd output shows me that most shared objects can be found. Here are some examples:
libboost_filesystem.so.1.55.0 => /path/to/libs/boost/lib/libboost_filesystem.so.1.55.0 (0x00007f2ed1fa0000)
libboost_filesystem.so.1.55.0 => /path/to/libs/boost/lib/libboost_filesystem.so.1.55.0 (0x00007f96af1f5000)
libboost_program_options.so.1.55.0 => /path/to/libs/boost/lib/libboost_program_options.so.1.55.0 (0x00007f96aef85000)
libboost_system.so.1.55.0 => /path/to/libs/boost/lib/libboost_system.so.1.55.0 (0x00007f96aed80000)
For some reason a few others cannot be found. For example:
libboost_iostreams.so.1.55.0 => not found
libboost_chrono.so.1.55.0 => not found
There are other non-boost libs that showing the same behavior, but for simplicity I am just showing the boost examples.
Workarounds already tried
Below are the workarounds that already work successfully. But I am really interested in the two points in the What I need section.
Copying to standard folders like /usr/lib and running ldconfig
Adding the path to LD_LIBRARY_PATH
tldr; Check that the imported library is imported as SHARED or UNKNOWN and not STATIC, and has an IMPORTED_SONAME property.
You should check how the library is being imported that you're linking.
I've analyzed a few of the config mode exported targets for static and dynamic libraries, and they are a little different in the properties they set for the target.
For example for zlib, here's the version for static libraries:
add_library(ZLIB::zlibstatic STATIC IMPORTED)
set_target_properties(ZLIB::zlibstatic PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_NOCONFIG "C"
IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libz.a"
)
However, for dynamic libraries it's:
add_library(ZLIB::zlib SHARED IMPORTED)
set_target_properties(ZLIB::zlib PROPERTIES
IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libz.so.1.2.11"
IMPORTED_SONAME_NOCONFIG "libz.so.1"
)
In a find_package module mode script, you might think you're importing a static library, when in fact the found library is a .so, so it may use the incorrect target properties. In config mode this is not likely because it's much more explicit when defining the target. Though, module mode (cmake/findXXX.cmake), you're often defining these properties as a result of FIND_PACKAGE_HANDLE_STANDARD_ARGS _LIBRARIES variable, and it's hard to tell what you're going to get. You can use libFoo.a in the search to be more explicit or playing with CMAKE_FIND_LIBRARY_SUFFIXES.
I am trying to use the NBIS library from NIST:
http://www.nist.gov/itl/iad/ig/nbis.cfm
NBIS is composed of several different related libraries that they compile into multiple archive files. They give you an option when installing it to install either all of the individual .a files or to bundle them into a single, monolithic .a file. I had been using the multiple library files but decided to try to use the single, monolithic file to make things easier. But I am getting an error when trying to link against it when using -lnbis in my link step (using g++, which uses ld):
libnbis.a: error adding symbols: Archive has no index; run ranlib to add one
Looking at the archive, it contains the other individual .a files:
$ ar t libnbis.a
liban2k.a
libbozorth3.a
libcblas.a
... and so forth
The line in the Makefile that generates the archive is: $(AR) -ru libnbis.a *.a
I have tried running ranlib libnbis.a and that does not modify it.
So, my question is: How can I link to the NBIS library? I know which individual libraries inside the libnbis.a file I need to link to if I need that. Will it work this way? Or are NIST doing something wrong trying to merge their individual libraries into one archive file?
I have tried searching around to find similar problems and it seems like the answer to the above is that they are doing it wrong. For instance, answers to this question suggest unpacking the individual .a files and repacking the .o files into the conglomerate archive:
How to merge two "ar" static libraries into one
There is also a comment suggesting using libtool:
https://stackoverflow.com/a/8170851/196561
So it looks like I have a couple options if I want to build the libnbis.a file myself. I just wanted to make sure there was not some way to use the .a files in the archive as-is before I do that.
I recently switch from Autotools to CMake because CMake seems to be better for cross platform development and what I've noticed is when I build a static library of my C++ code all the files inside have a suffix .cpp.o
ar -t PA8/libgenericTZR.a
genericTZR.cpp.o
I've looked at other libraries built by other tools and they don't do that. I'm not sure if this is really a bad thing but, how can I get CMake to build the static libraries without the .cpp added file extension?
This is my CMake File
add_executable(PA8 ISP_Charges.cpp genericTZR.cpp genericTZR.h)
set(LIBSRC genericTZR.c genericTZR.h)
add_library(genericTZR SHARED ${LIBSRC})
add_library(genericTZR SHARED $<TARGET_OBJECTS:myObjects>)
add_library(genericTZR-static STATIC ${LIBSRC})
set_target_properties(genericTZR-static PROPERTIES OUTPUT_NAME $
install (TARGETS PA8 DESTINATION bin)
install (TARGETS genericTZR genericTZR-static DESTINATION lib)
install (FILES "${PROJECT_BINARY_DIR}/PA8/genericTZR.h" DESTINA$
Thanks
According to this thread on cmake list (and I agree with it), it is not a good idea to try to change the output file names.
Consider the example gave in the link:
add_executable(foo foo.c foo.cpp)
Generated objects would be foo.c.o and foo.cpp.o. They would conflict if you forced them to have just the .o extension.
You can try to use the non-documented, internal, might-change-in-the-future
set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
I don't know if they're still available or if works at all. I've never used them.
As comments on your post have clarified it, the names inside the static lib aren't really used, you shouldn't worry about them.