Libraries are essential to any programmer. The so-called library refers to the code that has been compiled for you to use. They often provide common functionality, such as a linked list and a two-fork tree that can be used to hold any data, or a specific feature such as a database server interface, like MySQL.
Most large software projects contain several components, some of which you find can be used in other projects, or you separate components for organizational purposes only. When you have a reusable and logically clear function, it's useful to build it into a library so that you don't copy the source code into your source, and compile them again every time. In addition, you can ensure that the modules of your program are isolated so that when you modify one of the modules, it will not affect other modules. Once you've written a module and tested it, you'll be able to reuse it safely indefinitely, which can save a lot of time and hassle.
Building a static library is so simple that we have little trouble with it. I don't want to explain how to build a static library. I'm only talking about shared libraries here, because it's more difficult for most people to understand.
Before we get started, let's outline what's going on between the source code and the running program:
Preprocessing: This phase processes all preprocessing directives. Basically all the lines in the source code that start with #, such as #define and #include.
Compile: Once the source file is preprocessed, the next step is to compile. This step is also known as "compilation proper" because many people refer to compilation as the whole process of building a program. This procedure converts the. c file to an. o file.
Connection: To this point you should connect all your object files and libraries together to make them the final executable program. It should be noted that the static libraries are actually implanted into your program, and the shared libraries only contain references to them in the program. Now you have a complete program that can be run at any time. When you start it from the shell, it is passed to the loader.
Load: This step occurs when your program starts. First, the program needs to be scanned to refer to the shared library. All the referenced references in the program take effect immediately, and the corresponding libraries are mapped to the program.
Steps 3rd and 4th are the secrets of shared libraries.
Now, let's start with a simple example.
Foo.h:
Copy Code code as follows:
#ifndef foo_h__
#define Foo_h__
extern void foo (void);
#endif//foo_h__
FOO.C:
Copy Code code as follows:
#include <stdio.h>
void foo (void)
{
Puts ("Hello, I ' m a shared library");
}
MAIN.C:
Copy Code code as follows:
#include <stdio.h>
#include "foo.h"
int main (void)
{
Puts ("This is a shared library test ...");
Foo ();
return 0;
}
Oo.h defines an interface to connect our libraries, a simple function, foo (). FOO.C contains the implementation of this function, MAIN.C is a driver that uses our library.
To better illustrate this example, all the code is placed under the/home/username/foo directory.
Step 1: Compile the unconstrained bit code
We need to compile the source files of our library into unconstrained bit code. The unconstrained bit code is the machine code stored in the main memory, independent of the absolute address when executing.
Copy Code code as follows:
$ gcc-c-wall-werror-fpic foo.c
Step 2: Create a shared library from an object file
Now let's turn the object file into a shared library. We'll name it libfoo.so:
Copy Code code as follows:
$ gcc-shared-o libfoo.so foo.o
Step 3: Connect shared libraries
As you can see, everything is simple. We now have a shared library. Now we compile our main.c and connect it to Libfoo. We'll name the final run program test. Note: The-lfoo option is not search foo.o, but libfoo.so. The GCC compiler assumes that all libraries start with Lib, ending with. So or. A (. So) is a shared object share or shared libraries shared library,. A is a archive file, or a static connection library.
Copy Code code as follows:
$ Gcc-wall-o Test Main.c-lfoo
/usr/bin/ld:cannot Find-lfoo
Collect2:ld returned 1 exit status
Tell GCC where to find a shared library.
uh-oh! connectors don't know where to find Libfoo. GCC has a default search list, but our catalog is not in that list. We need to tell GCC where to find libfoo.so. This will take the-l option. In this case, we'll use the current directory/home/username/foo:
Copy Code code as follows:
$ Gcc-l/home/username/foo-wall-o Test Main.c-lfoo
Step 4: Runtime usage libraries
OK, no abnormalities. Let's Run the program:
Copy Code code as follows:
$./test
./test:error while loading shared libraries:libfoo.so:cannot open Shared object file:no such file or directory
Oh no! The loader could not find a shared library. We didn't install it to the standard location, so we needed to help a bunch of loaders. We have two options: Use environment variables Ld_library_path or rpath. Let's take a look at Ld_library_path first:
Using Ld_library_path
Copy Code code as follows:
There's nothing at the moment. Now add our working directory to Ld_library_path:
Copy Code code as follows:
$ Ld_library_path=/home/username/foo: $LD _library_path
$./test
./test:error while loading shared libraries:libfoo.so:cannot open Shared object file:no such file or directory
Why also reported wrong? Although our catalogue is in Ld_library_path, we have not yet exported it. In Linux, if you do not export modifications to an environment variable, these modifications are not inherited by the quilt process. The loader and our test program did not inherit the changes we made, but rest assured that it is easy to fix the problem:
Copy Code code as follows:
$ export Ld_library_path=/home/username/foo: $LD _library_path
$./test
This is a shared library test ...
Hello, I ' m a shared library
Well, it's working! Ld_library_path is ideal for fast testing, especially if you don't have administrator privileges. On the other hand, exporting Ld_library_path variables means that other programs that rely on Ld_library_path may have problems, so it's a good idea to revert to the Ld_library_path before you finish testing.
Using Rpath
Now let's try Rpath, first we need to clear the ld_library_path and make sure we're using rpath to search for the library files. Rpath, or run path, is a way to embed a shared library location in a program so that you do not have to rely on the default location and environment variables. We use rpath in the connection link. Note the "-wl,-rpath=/home/username/foo" option. -WL sends a comma-delimited option to the connector, so we send the-rpath option to the connector via it. (Translator: There are no spaces after the comma delimiter, but immediately after the option you want to send.) This example is-rpath. Be sure to note that there are no spaces between "-wl,-rpath". )
Copy Code code as follows:
$ unset Ld_library_path
$ Gcc-l/home/username/foo-wl,-rpath=/home/username/foo-wall-o Test Main.c-lfoo
$./test
This is a shared library test ...
Hello, I ' m a shared library
Very good, it worked. The Rpath method is great because each program can list its own shared library location separately, so different programs no longer search for ld_library_path on the wrong path.
Rpath and Ld_library_path
Rpath also has some reaction surface. First, it requires that the shared library be installed in a fixed location so that all users can access the library in the same location. This means that there is not enough flexibility in the system configuration. Second, if the Library involves NFS mounts or other network drivers, you may experience delays or worse when starting the program.
Use Ldconfig to modify ld.so
What if we want all users on the system to be able to use my library? For this, you need administrator privileges. There are two reasons: first, put the library in a standard location, most likely/usr/lib or/usr/local/lib, where ordinary users are not write permission. Second, you need to modify the ld.so configuration file and cache it. Act as root:
Copy Code code as follows:
$ cp/home/username/foo/libfoo.so/usr/lib
$ chmod 0755/usr/lib/libfoo.so
The file is now in a standard location and is readable to everyone. We now need to tell the loader library file to be available, so let's update the cache:
Copy Code code as follows:
This creates a link to our shared library and updates the cache so that it can take effect immediately. Let's check again:
Copy Code code as follows:
$ ldconfig-p | grep foo
Libfoo.so (LIBC6) =>/usr/lib/libfoo.so
Now that we have the library installed, before we start testing it, we have to clean up something else first:
Just in case, clean up the Ld_library_path:
Copy Code code as follows:
Reconnect our executable program. Note: We do not need the-l option, because our library is saved in the default location, we can not use the rpath option:
Copy Code code as follows:
$ Gcc-wall-o Test Main.c-lfoo
Let's confirm that we will use the example of our library in/usr/lib, using the LDD command:
Copy Code code as follows:
$ LDD Test | grep foo
libfoo.so =>/usr/lib/libfoo.so (0x00a42000)
Very well, now run the program:
Copy Code code as follows:
$./test
This is a shared library test ...
Hello, I ' m a shared library
The above is all. We talked about how to build a shared library, how to connect, and how to deal with the most common shared library loading problems, and the pros and cons of various methods.
Report:
1. Shared libraries (shared library) and static libraries (static library) differences
Shared libraries are files with the. So (Windows platform. Dll,os x platform. dylib) as the suffix. All the library-related code is in this file, and the program references it at run time. A program that uses a shared library will only refer to the piece of code that it uses in the shared library.
A static library is a file that has a suffix of. A (Windows platform. Lib). All the library-related code is in this file, and the static library is directly linked to the program at compile time. A program that uses a static library copies the code it wants to use from the static library to itself. (Windows also has a. lib file that is used to reference. dll files, but they are the same as the first case.) )
Both kinds of libraries are different.
Using shared libraries can reduce the number of duplicate code in your program and make your program less bulky. It also allows you to replace shared objects with a functionally identical object, which allows you to increase performance without recompiling those programs that use the library. However, using a shared library can increase the cost of executing a function by a small amount, as well as increasing the cost of loading the runtime, because symbols in shared libraries need to be associated with what they use. A shared library can be loaded into a program at run time, which is the most common implementation mechanism of binary plug-in systems.
Static libraries generally increase the volume of the program, but it also means you don't have to carry a copy of the library you want to use anytime, anywhere. Because code is already associated at compile time, there is no additional consumption at run time.
2. GCC first searches the library file in/usr/local/lib, followed by/usr/lib, and then searches the-l parameter to specify the path, and the search order and the-l parameter give the same order of the paths.
3. Default GNU loader ld.so, search for library files in the following order:
Search the Dt_rpath area of the program first, unless there is a dt_runpath area.
Next search Ld_library_path. If the program is Setuid/setgid, skip this step for security reasons.
Search the Dt_runpath area unless the program is Setuid/setgid.
Search Cache file/etc/ld/so/cache (use '-Z nodeflib ' loader parameters to deactivate this step)
Search for the default directory/lib, and then/usr/lib (use '-Z nodeflib ' loader parameters to deactivate this step)