50th article: About library file _ Library

Source: Internet
Author: User
Tags function prototype pprint

Reproduced in: About the library file some understanding _wei_sucre_ Sina Blog
Http://blog.sina.com.cn/s/blog_8f3985400100uw5k.html

A library file is typically a compiled binary that is used to generate an executable file together with the target code during the link phase, or to run an executable file to invoke a piece of code in the library file. It is the same as the executable file: both are compiled binaries (the binaries we're talking about in this article are the most common elf formats above Linux); Unlike executables: library files cannot be executed directly (intuitively, there is no main function in the source code, But only some function module's definition and the implementation, did not run the Portal main function, therefore cannot directly execute. We develop the program, whether it is running, or compile, link, usually need to use some library to implement their functions, and rarely directly through the program source code to generate completely independent executable files. There are many well-known libraries used to develop or run programs, such as QT libraries, GTK libraries, and even standard C libraries, so that you can fully appreciate the benefits of modular programming and code reuse. This article gives a brief introduction to the compilation, generation and use of Linux libraries, and illustrates them with a simple example (developing their own libraries).

Main content
Principle
Example
Other

Principle
To facilitate understanding, we can divide the library into three types: static library, shared library, dynamic loading library. The following are described separately.
One, Static library
A static library is actually a collection of object files (generally ending with. O), which is generally terminated by a. A, and is used only for chain deliveries into executable stages. Specifically, the C program, for example, when we compile the source code of the program, the process is generally like this: the source file with the suffix of. c is compiled to generate the. o target file, with the. o suffix of the target file through the chain to deliver the final executable file. We can link the. o Target file directly in the link, or you can package the. O Target files together, and unify the links, and this package generates a collection of all. o files, which is a static library. The static library is used only when the program is linked, and the linker copies the code used in the program from the library file to the application, and once the link is finished generating the executable, the static library is not needed to execute the program. Because every application that uses a static library needs to copy the code of the function used, therefore, static link generated executable file will be relatively large, more than one program to occupy memory space (each program has a duplicate static library code), but because the runtime does not have to load from the external dynamic additional library, Speed is faster than shared libraries. We will see the concrete process of the generation and application of the static library in the following example.

Second, shared library
1, the concept of shared library
Shared libraries to. So end. (so = = Share object) When the program link is not the same as the static library copy from the library to use the function code to the generated executable file, but just make some markup, and then when the program started running, dynamically loading the required library (module). Therefore, the application still needs the support of the shared library when it is running. Shared libraries are linked to an executable file that is much smaller than a static library, which takes up more memory space than a static library (because there is only one copy of the shared library code in memory), but is slightly slower because of a dynamic loading process.

2, the name of the shared library
Generally a shared library has three names: Soname, Real-name, Linker-name.
Soname is the name used to differentiate the version, which may be a link to the real-name (if there is a file), in the form of a name usually lib*.so. X.Y (The x,y here is the representative version number).
Real-name is the implementation file that contains the real code.
Linker-name is the name passed to the connector, used for the search of the link, generally it may be to point to soname connection, the form of the name is generally lib*.so.
The main purpose of this is to allow multiple versions of the library file to coexist in the system, and it is customary to name a library file in the same way as soname.
Let's look at an example:
[Quietheart@lv-k test]$ ls-l/usr/lib/libncurses*
lrwxrwxrwx 1 root 2010-07-26 16:51 libncurses.so->/lib/libncurses.so.5
lrwxrwxrwx 1 root 2010-07-26 17:18 libncurses.so.5-> libtermcap.so

The libncurses.so.5 above is Soname, where ncurses is the library name, 5 is the major version number (major), and, of course, the minor version number (minor) and the issue number (release). (similar to libncurses.so.5.0.0). The ". So" here represents a shared library. Usually soname is only a link to real name. And libtermcap.so is the real-name of the NCurse library, which is a file containing the real code implementation. LIBNCURSES.SO is linker name, and a search name used for the application link is passed to the linker for a link. It is usually a link to the Soname, in the form of libname.so.

In fact, every library has a soname, when the connector finds a name in the library it is looking for, the connector embeds soname into the binary in the link, rather than the actual file name it is running, and the program looks for files with soname names during the execution of the program. Rather than the file name of the library, in other words, soname is the distinguishing mark of the library.

3, the shared library of the load
(1) in all GNU GLIBC systems (including Linux, of course), a special program loader is automatically loaded and run when an elf binary execution program is launched. In Linux, the program loader is/lib/ld-linux.so.x (X is the version number). It finds and loads all shared libraries that the application relies on. The directory being searched is saved in the/etc/ls.so.conf file, but if the path to the library you are using is not in the search list, then you have to add it yourself. Of course, if the program to start every time to search again, will be inefficient and unbearable. Linux systems have taken this into account, with cache management for shared libraries. Ldconfig is the tool that implements this function by default reading/etc/ld.so.conf files, establishing symbolic connections to all shared libraries according to certain specifications, and then writing information to/etc/ld.so.cache. Each time the search is actually through Ld.so.cache this cache file to search, the existence of/etc/ld.so.cache greatly accelerated the start of the program speed. Of course, after each modification of the ld.so.conf file, you should run the "ldconfig" command to update the information to the cached file.

(2) You can also set the path of the LD's mount by setting the environment variable Ld_library_path. The loader then searches for the variable's directory first and then the default directory. But remember, Ld_library_path is for development and testing, and you can put some of the alternative shared libraries that are used for testing into that variable, similar to the role of/etc/ld.so.preload. However, the variable should not be used for normal users ' normal programs.

(3) If you do not use the LD_LIBRARY_PATH environment variable, you can pass the path to the loader in the following ways:
[Quietheart@lv-k test]$/lib/ld-linux.so.2--library-path Path executable
In short, if you want your shared library to be loaded, then you typically go through three ways: Copy your library to the default library search path/usr/lib. or set the environment variable Ld_library_path, where you add the path to your library. or modify the configuration file/etc/ld.so.conf Add the path to your library and refresh the cache ldconfig.

Third, dynamic Loading library
1. The concept
Dynamic load library (dynamically loaded (DL) libraries) is a library of functions that can be loaded while the program is running. Rather than being loaded as a shared library at the time the program starts. DL is useful for implementing plug-ins and modules because they allow programs to wait for Plug-ins to load when allowed. In Linux, the file format of a dynamic library is no different from a shared library, the main difference being that a shared library is loaded when the program starts, and the dynamic loading library is loaded during the run.

2. Use
There is a special set of APIs for the completion of open dynamic Library, find symbols, processing errors, turn off the dynamic library functions. These interface functions are described in the following:
(1) Dlopen
Function prototype: void *dlopen (const char *libname,int flag);
Feature Description: Dlopen must be called before Dlerror,dlsym and Dlclose, indicating that the library is to be loaded into memory and ready for use.
If the library you want to load depends on other libraries, you must first mount the dependent library. Returns a null value if the Dlopen operation fails, and Dlopen returns the same handle if the library has already been loaded.
The libname in the parameter is generally the full path of the library, so that the Dlopen will load the file directly, and if only the library name is specified, the following mechanism will be searched in Dlopen: Depending on the environment variable Ld_library_path find according to/etc/ld.so.cache Lookups are found in/lib and/usr/lib directories, in turn.

The flag parameter represents how an undefined function is handled and can be used with Rtld_lazy or Rtld_now. Rtld_lazy means to temporarily not deal with undefined functions, first load the library into memory, and so on, and then use the undefined function; Rtld_now says to check for undefined functions immediately, and if so, Dlopen fails.

(2) Dlerror
Function prototype: char *dlerror (void);
Function Description: Dlerror can get the error message for the most recent dlopen,dlsym or dlclose operation, and NULL to indicate no error. Dlerror also clears the error message when it returns an error message.

(3) Dlsym
Function prototype: void *dlsym (void *handle,const char *symbol);
Function Description: After Dlopen, the library is loaded into memory. Dlsym can get the position (pointer) of the specified function (symbol) in memory.
If the specified function is not found, DLSYM returns a null value. But the best way to determine whether a function exists is to use the Dlerror function,

(4) Dlclose
Function prototype: int dlclose (void *);
Function Description: Reduce the already loaded library handle by one, and if the handle is reduced to 0, the library is unloaded. If a destructor exists, the destructor is invoked after Dlclose.

[Example] 
to demonstrate the development, use, and deployment of the three libraries described earlier, through a specific instance. The
first gives the source code for the program we need: &NBSP
[quietheart@lv-k test]$ ls 
main.cpp  myfile.cpp   MYFILE.H&NBSP
[quietheart@lv-k test]$ cat main.cpp
//main.cpp file to generate the source code for the executable file. &NBSP
#include <iostream> 
#include "myfile.h" &NBSP;
using std::cout; 
Using std:: endl; 
int main (int argc, char *argv[])  

cout<< ' begin Test ' <<endl; 
Printinfo ();  
return 0; 

[quietheart@lv-k test]$ cat myfile.h
//myfile.h, library header file  
#ifndef __myfile_h 
#define __MYFILE_H&NBSP
void Printinfo ();  
#endif  
[ Quietheart@lv-k test]$ cat myfile.cpp
//myfile.cpp, library Implementation code  
#include "myfile.h" &NBSP;
#include < IOSTREAM>&NBSP
using std::cout; 
using std::endl; 
void Printinfo ()  

cout<< "Hello" <<endl; 
}

From the above we can know that our code is only one file: Main.cpp,myfile.h, and MyFile.cpp.

First, do not use the library
As long as you have a bit of Linux programming knowledge readers will know that with these three files, we can through the "g++ main.cpp myfile.cpp" command, build our executable file and run. The specific process is as follows:
[Root@lv-k test]# ls
Main.cpp MyFile.cpp myfile.h
[Root@lv-k test]# g++ main.cpp myfile.cpp
[Root@lv-k test]# ls
A.out main.cpp myfile.cpp myfile.h
[Root@lv-k test]#./a.out
Begin Test
Hello
In the process of generating executables above, we didn't use any concept of libraries, which meant that we made all the files as part of an executable file, and eventually generated a build, link, or runtime that didn't depend on any library. Executable files that are executed independently (essentially, the executable is still dependent on the library, at least it relies on the iostream library, which is not considered here). With the "terminology" of friends who have downloaded many software, the program we are building now is a "green" software ^_^ that is free of installation. If the source code structure of the program is very complex, then the shortcomings of this compilation is very obvious, that is, the program is compiled in a modular way, at least not to meet the characteristics of reusability. Later we will introduce the use of libraries to achieve modular compilation of this program.

Ii. use of the library
We are going to organize our programs in the following ways:
1 corresponding to our application, that is, the executable file code only one, that is the main.cpp file.
2 Our executable file is generated or run, relying on some external libraries, such as iostream, and the corresponding library of myfile.h (named my), where we focus on our own definition of the library.
3) The myfile.h and MyFile.cpp are compiled separately to build the library my, the library my implementation is actually generated by myfile.cpp, and the role of myfile.h is to let the program that uses this library know what function the library contains, that is, the header file of the library is just a function of letting other programs use the library The interface file. The function of this library is to allow the program that uses it to be included by #include "myfile.h", thus declaring some of the necessary functions in the library.
This allows for modularity, dividing the entire program into executable parts, as well as the relatively independent portions of the libraries used by the executable file. The idea of how to actually implement this division in the context of compilation execution is described later.

1. Static Library mode
In the following manner:
1.1 Generating a static library:
1) Only compile myfile.cpp generation MYFILE.O
[Quietheart@lv-k Test] $g + +-C myfile.cpp
2) According to MYFILE.O build library libmy.a
[Quietheart@lv-k Test] $ar R libmy.a MYFILE.O
3) Delete MYFILE.O and MyFile.cpp
[Quietheart@lv-k test] $rm myfile.cpp MYFILE.O
In this way, we use the AR command in step 2nd to add the. o file to the LIBMY.A, packaging the generated lib*.a file, which is the static library (the relative dynamic library is the lib*.so file). About the AR command, in addition to the R option and C,s options: R indicates that the module is added to the static library, c means that the static library is created, and S represents the production index. See the user manual for the AR command specifically. Also here, for simplicity, we removed the MYFILE.O and myfile.cpp files.

1.2 Use a static library link and run:
1 Compile the connection using LIBMY.A:
[Quietheart@lv-k Test] $g + + main.cpp-l./-lmy
2) Running the program:
[Quietheart@lv-k Test]$./a.out
Here, you can modify the name of the Libmy.a libmy2.a, so that the corresponding use of "g++ main.cpp-l./-lmy2" to link. This will only need to link to the static library at compile time, after generating the executable file, the static library is not used for this program (of course it may be useful for other programs to build), the resulting executable file can also be called the "green Software" ^_^ without installation.
Further notes:
Here's the-l option, using-L. Represents adding the current directory to the library search path. Otherwise, the default library search path is used to search the library file, which is the/usr/lib directory.
Another similar easily confusing parameter-I, which represents the path of the search header file. Use it so that GCC looks up header files first to the directory I specified, then the system default directory, which is/usr/include.
Here the-l option,-lname represents the Libname.a or libname.so file in the Library search directory, which is one of the reasons why the library files start with lib, if your library file is not libmy, but my. That cannot be compiled with the-l parameter. You can do this:
[Quietheart@lv-k Test] $g + + main.cpp-l. My.a-o Test
Note: $g + +-L.-lmy main.o-o test will make an error.
The reason is:-L is the linker option and must be placed behind the compiled file. So the-lmy in the above command must be placed behind the MAIN.O.

2. Shared library mode
In the following manner:
1.1 Building shared libraries:
1) Only compile myfile.cpp generation MYFILE.O
[Quietheart@lv-k Test] $g + +-C myfile.cpp
2) Generate dynamic library according to MYFILE.O libmy.so
[Quietheart@lv-k Test] $g + +-shared-fpci-o libmy.so myfile.o
3) Delete MYFILE.O and MyFile.cpp
[Quietheart@lv-k test] $rm myfile.cpp MYFILE.O
Here, the libmy.so we generate in step 2nd is the Dynamic Connection library (shared library). Practice found that GCC is also a good use, but also available "g++-shared-o libmy.so myfile.o."
Further notes:-fpic or-fpic indicates the creation of the position independent code, which is usually required to create a shared library. In addition,-WL indicates that parameters are passed to the linker, so here-soname, Library_name is the argument to the linker. -shared indicates the use of shared libraries.
The following is an example of creating a shared library using A.C and B.C:
Gcc-fpic-g-c-wall A.C
Gcc-fpic-g-c-wall B.C
Gcc-shared-wl,-soname, Libmyab.so.1-o libmyab.so.1.0.1 a.o B.O-LC
Description: LC = = libc
There are a few places to note:
A. It is not recommended to use the strip process shared library, and it is best not to use the-fomit-frame-pointer compilation option.
B.-fpic and-fpic can produce target independent code, depending on the platform,-fpic is always work,
Although the resulting target file may be larger,-fpic produces code that is small and executes faster, but may have platform-dependent limits.
C. In general, the-wall,-soname,your_soname compilation option is required. Of course, the-share option should not be lost.

1.2 Use shared library libmy.so for links:
1) Compile Link:
[Quietheart@lv-k Test] $g + + main.cpp-l./-lmy
Here, do not conflict with the LIBMY.A, if the presence of LIBMY.A and libmy.so will be preferred to choose libmy.so. The compilation options are similar to the previous reference to the link static library, when the option.

1.3 Runtime load Shared library libmy.so:
1 Move the dynamic library to a standard path such as/usr/lib:
[Quietheart@lv-k Test] $sudo CP libmy.so/usr/lib
2) Running the program:
[Quietheart@lv-k Test]$./a.out
Note that unlike static libraries, you also need to move shared libraries to specific locations, because shared libraries are useful after they are run.
There are actually three ways to get a running program to load into your shared library file:
A) Copy shared library files to/usr/lib
b) or SET environment variable Ld_library_path plus the path of your shared library file
c) or modify the configuration file/etc/ld.so.conf Add the path to your shared library file and refresh the cache Ldconfig
The resulting program is not an installation-free "green" software, because you want your program to run on a machine, in addition to the executable itself, you have to copy the library that the executable relies on to a directory in the system to load when it runs, and the process of the copy "pollutes" the system so that it is not " Green. "

3, dynamic Loading library mode
Dynamic loading of the library, that is, the start of the program does not have to compile the library before loading, but in the use of dynamic loading library, this way is often used in the way plug-ins loaded. We need to modify our Main.cpp file as follows:
[Quietheart@lv-k Test] $vim main.cpp
#include <iostream>
#include <dlfcn.h>
Using Std::cout;
Using Std::cerr;
Using Std::endl;
int main (int argc, char *argv[])
{
Initial variable
void *handle;
void (*pprint) (void);
Char *error;

cout<< "Begin to call:" <<endl;
Dynamic Loading library, rtld_lazy that if the label does not exist, do not do processing, but the runtime to say.
Handle = Dlopen ("./libmy.so", Rtld_lazy);
if (handle = NULL)
{
Cerr<<dlerror () <<endl;
Exit (1);
}

Find the function to be called, the label is not the Printinfo in the source code of the library file,
But through the "nm libmy.so" or "readelf-s libmy.so" query that the label name is: _z9printinfov
Pprint = (void (*) ()) Dlsym (handle, "_z9printinfov");
Error = Dlerror ();
if (Error!= NULL)
{
cerr<<error<<endl;
Exit (1);
}

Call function
Pprint ();

Shut down
Dlclose (handle);
return 0;
}
From the above, using dynamic loading, you can use functions in the library without having to include the library's header file in the executable file. Also, the search path for a library file can be "hard" in the code to specify where to load the library, in addition to the system determination as before.
The specific compilation run process is as follows.

3.1, generate the dynamic library file:
1) Only compile myfile.cpp generation MYFILE.O
[Quietheart@lv-k Test] $g + +-C myfile.cpp
2) Generate dynamic library according to MYFILE.O libmy.so
[Quietheart@lv-k Test] $g + +-shared-fpci-o libmy.so myfile.o
3) Delete MYFILE.O and MyFile.cpp
[Quietheart@lv-k test] $rm myfile.cpp MYFILE.O
Here, the libmy.so we build in step 2nd is the dynamically loaded library (the way it is built and shared).

3.2, compile the link to execute the executable program:
1 to generate the executable file:
[Quietheart@lv-k Test] $g + + MAIN.CPP-LDL
2) Running:
[Quietheart@lv-k Test]$./a.out
Here, we need to specify "-LDL" in order to use those functions provided by dynamic loading technology.
In addition, note: In the source code main.cpp we can see that when using Dlsym, the label used is not the printinfo in the source code myfile.cpp of the library file, but actually through "nm libmy.so" or "readelf-s Libmy.so "Query learned that the label name is:" _z9printinfov "function. In this way, load, you can use the library's function without the header file of the library. Please guess, this time the software, is green. ^_^

Other
1. NM command to check for possible symbols in a library
NM has a lot of symbols listed, there are three kinds of common, one is called in the library, however, it is not defined in the library (indicating the need for additional library support), represented by U; one is the function defined in the library, which is the most common in T, and the other is the so-called "weak" symbol, which, although defined in the library, However, it may be overwritten by a symbol of the same name in another library, expressed in W.
* View all symbols in the library
$NM libhello.so

* Suppose the developer wants to know if printf () is defined in the Hello Library mentioned above:
$NM libhello.so |grep printf
U printf
U denotes that the symbol printf is referenced, but is not defined within the function, and it can be inferred that to use the Hello library properly, you must have other library support, and then use the LDD command to see which libraries Hello depends on:
$LDD Hello
Libc.so.6=>/lib/libc.so.6 (0x400la000)
/lib/ld-linux.so.2=>/lib/ld-linux.so.2 (0x40000000)
From the results above you can continue to see where printf ends up being defined.

2. The LDD command can query which shared libraries a program relies on:
* View a program that relies on those shared libraries:
[Root@lv-k test]# ldd a.out
Linux-gate.so.1 => (0x00322000)
Libdl.so.2 =>/lib/libdl.so.2 (0x002f3000)
Libstdc++.so.6 =>/usr/lib/libstdc++.so.6 (0x025ab000)
Libm.so.6 =>/lib/libm.so.6 (0x002c8000)
Libgcc_s.so.1 =>/lib/libgcc_s.so.1 (0x0013d000)
Libc.so.6 =>/lib/libc.so.6 (0x0016d000)
/lib/ld-linux.so.2 (0x0014e000)

3. Use readelf to see whether a file is an executable file or a library file.
In general, the executable and library files in Linux are both Elf binaries, so take the elf file as an example, and the command is also targeted at the elf format file.
Readelf more command options should look at the man manual, and here are a few simple examples.
* See if a file is a library file:
[Root@lv-k test]# readelf-h libmy.so
ELF Header:
magic:7f 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class:elf32
Data:2 ' s complement, little endian
Version:1 (current)
Os/abi:unix-system V
ABI version:0
Type:dyn (Shared object file)
Machine:intel 80386
version:0x1
Entry Point address:0x550
Start of program headers:52 (bytes into file)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.