Link with archive that contains other static library archive files - c++

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.

Related

How do I use CMake to make a custom library?

I am trying to make a custom library to install with CMake. This is a personal utilities library so contains things like an extended math library, extended vectors, file IO functions etc.
I am very new to CMake and I am struggling to build/install this as a library. I would like this to be a single output file which I install. And I would like to be able to include it (and all sub libraries) with
#include <MaxLib.h>
and by adding -LMaxLib to my makefile.
My file structure is like this:
- MaxLib.h
- CMakeLists.txt
- File
- File.cpp
- File.h
- CMakeLists.txt
- Geom
- File.cpp
- File.h
- CMakeLists.txt
I have tried compiling the individual sublibraries i.e:
add_library(File SHARED ${CMAKE_CURRENT_SOURCE_DIR}/File.cpp)
target_include_directories(File)
and I have tried joining them all together with:
add_library(${PROJECT_NAME} STATIC
${CMAKE_CURRENT_SOURCE_DIR}/MaxLib.h
)
add_subdirectory(File)
add_subdirectory(Geom)
target_link_libraries(MaxLib File)
target_link_libraries(MaxLib Geom)
And although this compiles and I can install it, the object files for File and Geom are not becoming linked with MaxLib
I get the impression that I'm doing this all wrong... What is the correct way to make a library?
Should I be attempting to make a static or shared library like this?
Should it just be one makefile in the root folder which builds a single static object?
Any advice is welcome! Thanks in advance
Reference to previous question

C++ linux executable keeps trying to use library that does not exist

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.

How to tell CMake when using add_library to not include a specific object file

I am trying to make a static library, for example my_lib.a.
This library is depending from a gSoap code - file2.cpp.o, which is generated because of this CMake instruction (and 2 custom commands):
add_library(${TARGET_NAME} ${SRC_FILES}
${GENERATED_SRC_FILES} ${GENERATED_H_FILES} ${GENERATED_RES_FILES})
file2.cpp is present in GENERATED_SRC_FILES. Everything runs fine until the moment of linking.
/usr/bin/ar cr ../lib/my_lib.a CMakeFiles/my_lib.dir/src/file1.cpp.o
CMakeFiles/my_lib.dir/src/file2.cpp.o
If I let Make to use this command, the library my_lib.a will contain
file1.cpp.o and file2.cpp.o. But in fact I do not need the file2.cpp.o
in my *.a library.
Does anyone know how I have to manage this case in a way to obtain a my_lib.a which contains only the file1.cpp.o?
I think I found a solution.
The idea is to compile some *.o files with a different target which will not be the official one. Than in the official target you can put these files you consider as important ones. In my case I have only one file that I do not want to include in the *.a file.. So :
the first target is:
add_library(gSoap_files OBJECT ${GENERATED_SRC_FILES} ... )
and the official one is:
add_library(${TARGET_NAME} ${SRC_FILES})
I inspired myself from this page:
http://www.cmake.org/Wiki/CMake/Tutorials/Object_Library

Mongoose statically linking with libssl?

I want to compile moongose with static library of libssl .
I have given .a file with -L option.
But still it is loading .so file.
why ?
how can I force it to use static lib ?
Run compilation under strace, to look where .a file is being searched and why .so is loaded instead.
EDIT
By default moongose loads SSL dynamically. To change this compile it with NO_SSL_DL macro. Add -DNO_SSL_DL to compilation command line. See this link.

How do I link against libtool static la library?

I have compiled this library successfully. It generates a libcds2.la file that I am trying to link into my own project. I have all files (including the .h file) in the same directory as my project file. When I try to link and use the functions of said library, using:
g++ -o test -I/opt/include/ -L/opt/lib/ -lcds2 libcdsNoptrs.cpp util.cpp
comes back with
./test: error while loading shared libraries: libcds2.so.2:
cannot open shared object file: No such file or directory
whatever that is. But the point is that most of the time it just doesn't recognize the library. I assume I'm doing something wrong with the file paths, but can't figure it out. My test file is a C++ file including #include "libcds2/array.h" and everything is installed in opt/lib, opt/include, ugly, I know, but that's what the Makefile generated.
Any pointers?
The libtool .la is a 'meta data' file. After building the cds2 library, it's expected that libtool will also be used in 'link' mode to build any of the package's tests, etc.
Typically, the in the directory you find the .la file, you will find the .a and .so under the .libs subdirectory. The .libs/libcds2.a file will be found there, provided configure was given the --enable-static option (or it is enabled by default). But, my understanding is that you've installed the package in /opt :
g++ -I/opt/include/ libcdsNoptrs.cpp util.cpp -o test /opt/lib/libcds2.a
Otherwise, if libcds2 isn't installed, just supply a path to: .../libcds2/lib/.libs/libcds2.a
Unless you want to use libtool in --link mode with -static to handle everything. But learning the advantages of libtool is usually an exercise for a rainy day:)