Linux中g++将C++代码编译为动态库.so文件
前言
GCC(GNU Compiler Collection)
是由GNU项目开发的编程语言编译器,支持多种编程语言,如C、C++、Objective-C、Fortran、Ada、Go等。gcc主要负责将源代码编译成机器码或中间代码。
Make
是一种在Unix和类Unix操作系统中广泛使用的自动化构建工具,它根据Makefile(或称为makefile)文件中定义的规则来自动编译和链接程序。
-
gcc:直接对单个或多个源文件进行编译,生成目标文件或可执行文件。
-
make:通过分析Makefile文件中的指令,自动判断哪些文件需要被重新编译,并执行相应的编译命令。它支持增量编译,即只重新编译那些自上次编译以来被修改过的文件,从而提高编译效率。
-
gcc:
通常用于编译单个文件或少量文件的项目。
-
make:
更适用于大型项目
,特别是那些包含大量源文件且源文件之间存在复杂依赖关系的项目。通过Makefile,可以清晰地定义项目结构,简化编译过程。
目标:将cpp文件生成动态库so文件
在Linux中,想要将C++代码
编译成动态链接库(.so文件
,即Shared Object),需要使用编译器(如g++)的-shared和-fPIC选项。这些选项会告诉编译器生成一个位置无关的代码(Position Independent Code, PIC),这是共享库所必需的,以便它们可以在不同的内存地址加载。
以下是一个简化的过程,说明如何将你的代码编译成.so文件:
假设你有以下文件:只有一个头文件和cpp
header1.h
:包含Class1的声明
source1.cpp
:包含Class1的实现
header1.h
cpp
#ifndef HEADER1_H
#define HEADER1_H
class Class1 {
public:
void method1();
};
#endif
source1.cpp
source1.cpp
cpp
#include "header1.h"
#include <iostream>
void Class1::method1() {
std::cout << "Class1's method1 called" << std::endl;
}
单个cpp文件编译成.so文件命令:
打开你的终端(命令行界面),然后使用g++编译你的代码,并指定输出为.so文件,此处只需要将其名称改为你的文件名:
bash
g++ -shared -fPIC -o libclass1.so source1.cpp
这里,-shared选项告诉g++生成一个共享对象文件,而-fPIC选项则确保生成的代码是位置无关的。-o libclass1.so指定了输出文件的名称
。注意,按照惯例,共享库文件通常以lib开头,但这并不是强制性的。
注意:
包含的.h头文件一般跟cpp放于同一路径,编译器会自己查找,在命令行中并不用包含.h头文件名称等等
假设你有以下文件:有两个或多个头文件和cpp
你想要创建动态链接库(.so文件),你可以直接将这两个.cpp文件编译成.so文件,而无需先生成目标文件(尽管在某些情况下,你可能仍然希望分步骤进行,以便于调试或并行编译)。
header1.h:
包含类Class1的声明
source1.cpp:
包含类Class1的实现
header2.h:
包含类Class2的声明
source2.cpp:
包含类Class2的实现
多个cpp文件编译成.so文件命令:
在终端(命令行界面)中,使用g++(或你选择的任何C++编译器)编译这两个.cpp文件,并生成一个.so文件。这里是一个例子:
bash
g++ -shared -fPIC -o libmylibrary.so source1.cpp source2.cpp
这条命令会编译source1.cpp和source2.cpp,并将它们链接成一个名为libmylibrary.so的共享库文件。-shared选项告诉g++生成一个共享对象,而-fPIC选项则确保生成的代码是位置无关的。
注意事项
- 确保你的头文件(header1.h和header2.h)被正确地包含在你的.cpp文件中。
- 如果你的类使用了模板或需要在头文件中实现某些成员函数(例如模板类的成员函数或内联函数),请确保这些实现放在头文件中,或者使用inline关键字在.cpp文件中实现它们(但请注意,对于模板来说,通常推荐将声明和实现都放在头文件中,或者使用隐式模板实例化等技术)。
- 如果你在编译过程中遇到未定义的引用错误,可能是因为某个函数或变量在.cpp文件中声明了但在任何.cpp文件中都没有定义,或者某个.cpp文件没有包含它需要的所有头文件。
- 在使用生成的.so文件时,确保你的程序在链接时能够找到它。这通常意味着你需要在编译时通过-L和-l选项指定库的位置和名称,或者将库文件放在标准库路径下,并更新系统的库缓存(如果使用的是像/usr/lib或/usr/local/lib这样的标准库路径的话)。
使用.so文件
一旦你有了.so文件,你就可以在其他C++程序中通过动态链接来使用它。为了做到这一点,你需要在编译时指定库文件的路径(使用-L选项)(这里的L其实就是Lib的首字母)
和库名称(使用-l选项,注意省略lib前缀和.so后缀,这里即class1)
。此外,你还需要在代码中包含相应的头文件。
例如,如果你有一个使用Class1的程序main.cpp,你可以这样编译它:
bash
g++ main.cpp -L. -lclass1 -o my_program
注意,这里-L.告诉编译器在当前目录下查找库文件。如果你的库文件位于其他目录,你需要将.替换为库文件所在的目录路径。
另外,确保在运行你的程序时,动态链接器(ld.so)能够找到你的.so文件。这通常通过设置LD_LIBRARY_PATH环境变量来完成,或者将你的库文件安装到标准库路径下。例如:
bash
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./my_program
或者,将库文件安装、复制
到如/usr/local/lib这样的标准库路径
下,并确保运行
bash
ldconfig //来更新系统的库缓存。
这样的好处就是你不用写库路径
,它会自己去标准库路径下找。