Linux---动静态库

前言

在初学Linux的时候,简单的提到过动静态库,但当时只是简单的讲述了一下什么是动态库,什么是静态库,我们可以在此基础上更进一步---制作库。在使用gcc编译器的时候,是默认使用动态链接的。

静态库

静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静
态库。

我们可以先自己设计一个库,只是制作一个简单的小程序,当作一个库,进行演示。

#pragma once

#include 

int add(int x, int y);
int mul(int x, int y);
int div(int x, int y);
#include "mymath.h"

int add(int x, int y)
{
    return x + y;
}

int mul (int x, int y)
{
    return x * y;
}

int div (int x,int y)
{
    if (y == 0) {
        std::perror("0");
        return -1;
    }
    return x / y;
}

一个简单的计算+*/的小程序。如果有人想用我写的这个小程序, 1. 把源文件直接给他 2. 把我们的源代码想办法打包成库。

我们采取第二种方法,想办法将源代码打包成库。

touch Makefile创建一个Makefile文件,然后将.c文件生成.o文件,如果.o文件特别多,可以将.o文件打个包命名为libXXX.a---所有.o文件的集合,在编译的时候,main.c变成.o的时候,与静态库一结合,就能运行了。

lib=libmymath.a

$(lib):mymath.o
	ar -rc $@ $^
mymath.o:mymath.cc
	g++ -c $^

.PHONY:clean
clean:
	rm -f *.h *.a

生成静态库:ar -rc libxxx.a xxx.o xxx.o | ar是gnu归档工具,rc表示(replace and create)

Linux---动静态库_第1张图片


一个简单的静态库,我们已经制作完成了,那么怎么将他发布呢?

lib=libmymath.a

$(lib):mymath.o
	ar -rc $@ $^
mymath.o:mymath.cc
	g++ -c $^

.PHONY:clean
clean:
	rm -f *.h *.a lib

.PHONY:output
output:
	mkdir -p lib/include
	mkdir -p lib/mymathlib
	cp *.h lib/include
	cp *.a lib/mymathlib

这样就可以了。未来别人要是想用我的库,只需要把lib文件夹给他就行了。

Linux---动静态库_第2张图片


#include "lib/include/mymath.h"

int main()
{
    std::cout << add(1, 1) << std::endl;
    return 0;
}

然后就可以使用自己所创建的静态库写代码了,但是在使用库的时候,头文件可不是这样写的,而是直接写mymath.h

#include "mymath.h"

int main()
{
    std::cout << add(1, 1) << std::endl;
    return 0;
}

但是,当你编译这个文件的时候,却会出现错误,这是因为在编译的时候,有一个预处理阶段,这个阶段会进行头文件展开这个工作,再展开的时候,会默认去系统指定的目录和当前目录进行搜索。

但是系统里并不存在我刚刚写的小程序。lib在我当前的目录中,

系统不会自动的去当前目录的lib中去搜索,所以在编译的时候,我们可以加一个 -I 选项(-I 头文件路径),告诉系统在编译的时候去指定的目录寻找。

此时还是有问题,但问题已经不再是头文件找不到了,而是main函数中的add函数没找到。根本原因是因为找不到add函数的实现。但是我们已经把add的实现放在了libmymath.a里面吗?报错是报找不到add的实现,这就是因为找不到静态库,这不跟上面的问题一样吗?系统搜索库,会去系统中和当前目录中搜索,我自己实现的这个库是找不到的,这个情况下可以在编译的时候加上 -L选项(-L 静态库路径)

还是没找到。这是因为 ./lib/mymathlib/ 下的静态库可能有多个,系统不会自动的去寻找对应的库。所以还需要一个 -l选项(-l库名字)

库的名字是:去掉lib,去掉.a之后才是库的名字。


在使用第三方库的时候,就需要使用这样的方法。

动态库

动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

现在我创建了四个文件 mylog.h和myloc.cc,myprintf.h和myprintf.cc文件,这两个.cc文件中都提供了两个简单的函数。

// mylog.h
#pragma once

#include 

void Log(const char* str);

#include "mylog.h"

void Log(const char* str)
{
    printf("mylog.cc :: %s\n", str);
}
// myprint.h
#pragma once

#include 

void print();

#include "myprint.h"

void print()
{
	printf("hello world"\n);
}

上面就是新建的头文件和源文件的代码实现,现在将这几个文件创建成一个动态库,其实思路跟静态库非常相似,要制作库,得先把源文件编译成.o文件。然后再将.o文件打包就行了。


在我们编译的时候,要加上一个fPIC(产生位置无关码)选项,下面会说。

在编译静态库的时候,通过ar -rc将.o文件打包形成一个静态库,静态库在形成的时候,g++不需要加任何选项,在形成动态库的时候,要先把文件形成.o。

这样就把刚才新增的文件变成.o文件了。

下一步就可以把.o文件打包了,ar是专门用来打包静态库的。要形成动态库,我们继续使用g++,因为g++是默认使用动态库的。

通过 g++ -shared( shared: 表示生成共享库格式 ) -o libmymethod.so *.-o可以把所有.o文件打包形成一个名为libmymethod.so的静态库。

Linux---动静态库_第3张图片

制作的这个动态库其实是有X权限的,因为动态库也是一个可执行文件,但是他不能单独执行,需要别人来调用他。

这就是手动打包的过程。


dy-lib=libmymethod.so
static-lib=libmymath.a

.PHONY:all
all:$(dy-lib) $(static-lib)

$(static-lib):mymath.o
	ar -rc $@ $^
mymath.o:mymath.cc
	g++ -c $^

$(dy-lib):mylog.o myprint.o
	g++ -shared -o $@ $^
mylog.o:mylog.cc
	g++ -fPIC -c $^
myprint.o:myprint.cc
	g++ -fPIC -c $^

.PHONY:clean
clean:
	rm -f *.a mylib *.so *.o

.PHONY:output
output:
	mkdir -p mylib/include
	mkdir -p mylib/lib
	cp *.h mylib/include
	cp *.a mtlib/lib
	cp *.so mylib/lib

这是一个makefile文件,带static的是静态库,带dy的是动态库。

Linux---动静态库_第4张图片

Linux---动静态库_第5张图片

这样就可以将我自己的库给别人用了。

但是,直接编译.cc文件的话,还是不能编译的,需要加上-I -L -l这三个选项。


解决加载找不到动态库的方法:

  1. 拷贝到系统默认的库路径 /lib64
  2. 在系统默认的库路径下建立软链接
  3. 将自己的库所在的路径,添加到系统的环境变量中 LD_LIBRARY_PATH中
  4. /etc/ld.so.conf.d 建立自己的动态库路径的配置文件,然后重新ldconfig即可

你可能感兴趣的:(Linux,linux,服务器)