C++编译动静、态库(包含Makefile与CMake例子)
在Linux中,我们难免会用到各种各样的库,如静态库.a文件,动态库.so文件,我们要了解,库有什么用?库里面包含什么,通俗来讲,其实库里面包含了各种函数,调用库相当于调用库里面的函数。写这篇博客的意图源自于这两天使用到了库,但却对其不熟悉,调用总显示未定义。这篇博客将从三方面对库的使用进行讨论:
- 首先是使用基本的g++编译器,以及ar工具生成动、静态库,并对cpp源文件进行编译;
- 然后是编写Makefile文件来自动生成动静态库并对源文件进行编译;
- 最后则是编写CMakeLists.txt文件来自动生成Makefile,再通过Makefile编译好程序。
其实,在现实的工程项目中,我们最常用到的是第三种。下面将以实际的例子来去告诉大家如何使用,一步一步来。
编写demo
这里我们在同一个目录下创建三个文件足以,function.cpp
和function.h
里写需要用的函数,并生成库,而main.cpp
用来调用function生成的库里的函数。
main.cpp
:该文件用于调用下面类的函数。
#include <iostream>
#include "function.h"
using namespace std;
int main(void)
{
//实例化function类
function test=function();
//使用实例test调用function类的Sumab函数
cout <<" 10 + 20 = " <<test.Sumab(10,20) << endl;
return 0;
}
function.cpp
:该文件编写具体的函数功能。
#include "function.h"
function::function(){};
function::~function(){};
int function::Sumab(int a, int b)
{
int c = a + b;
return c;
}
function.h
:该文件用于定义类与函数。
#ifndef FUNCTION_H
#define FUNCTION_H
#include <iostream>
class function
{
public:
function();
int Sumab(int a, int b);
~function();
};
#endif //FUNCTION_H
那么,经典的三文件形式就写好了。
只使用g++和ar
直接编译
g++ main.cpp function.cpp function.h -o output_without_lib
./output_without_lib
可以看到生成了一个output_without_lib
可执行文件,执行没问题。
好了,接下来咱们把function.cpp做成一个库的形式。
静态库
g++ -c function.cpp
ar cr libfunction.a function.o
g++ main.cpp -o output_a -static -lfunction -L.
./output_a
第一条是把function.cpp编译成function.o
第二条是把.o文件生成静态库.a文件
第三条是使用库对main.cpp进行编译,最后生成output_a可执行文件
动态库
g++ -shared -fPIC -o libfunction.so function.o
sudo cp libfunction.so /usr/lib
g++ main.cpp -L. -lfunction -o output_so
./output_so
第一条是把function.c编译成动态库
第二条是把.so文件移动到路径中,这样编译才能找到
第三条是编译main.cpp
使用Makefile
如果文件多了,我们会发现编译起来很费劲,每次都要写一大堆的命令,为了更加方便,Makefile由此诞生,使用它可以很好地管理编译命令,而且我们只需要输入make,即可编译,下面使用Makefile直接编译看看。
Makefile编译(无库)
Makefile
:
# Makefile
# source object target
SRC := $(wildcard *.cpp)
OBJS := $(SRC: %.cpp=%.o)
TARGET := output_without_lib_makefile
# compile and lib parameter
CC := g++
LDFLAGS := -L.
INCLUDE := -I.
all:
$(CC) -o $(TARGET) $(SRC)
# clean
clean:
rm -fr *.o
rm -fr $(TARGET)
Makefile解析:
SOURCE表示需要编译的文件,这里用了wildcard,作用就是找到所有的.cpp文件,非常暴力。
OBJS表示的是对应的.o文件,通过变量的替换操作,可得到对应的.o文件列表。
TARGET表示最后生成的可执行文件的名字。
CC,LDFLAGS,INCLUDE表示编译的参数:CC:=g++表示使用g++编译(C++)语言,LDFLAGS表示库路径,INCLUDE表示头文件路径,都是当前路径。
文件解析完了,让我们执行make
语句,会生成output_without_lib_makefile
文件,愉快地执行吧。
执行完之后,还可以试试make clean
,看看编译的文件是否被删除。
Makefile生成静态库并编译
Makefile静态库生成:
重新编写Makefile程序
# Makefile
# source object target
SRC := $(wildcard *.cpp)
OBJS := $(SRC: %.cpp=%.o)
LIB := libfunction_makefile.a
AR := ar
# compile and lib parameter
CC := g++
INCLUDE := -I.
#link
$(LIB):function.o
$(AR) -r $@ -o $^
function.o:function.cpp
$(CC) -c $^ -o $@
# clean
clean:
rm -fr *.o
此时生成了一个libfunction_makefile.a
文件。
Makefile静态库使用:
# Makefile
TARGET := output_makefile_a
# compile and lib parameter
CC := g++
INCLUDE := -I.
LDFLAGS := -L.
LIBS := libfunction_makefile.a
# link
$(TARGET):main.o
$(CC) -o $@ $^ $(LIBS)
#compile
main.o:main.cpp
$(CC) -c $^ -o $@
# clean
clean:
rm -fr *.o
执行make
,多出了一个output_makefile_a
可执行文件。
Makefile生成动态库并编译
Makefile动态库生成:
# Makefile
# compile and lib parameter
CC := g++
INCLUDE := -I.
LIBS := libfunction_makefile.so
# link
$(LIBS): function.o
$(CC) -shared -o $@ $^
function.o:function.cpp
$(CC) -c $^ -o $@
# clean
clean:
rm -fr *.o
执行make,生成libfunction_makefile.so
然后我们把它移动到/usr/lib
里
mv libfunction_makefile.so /usr/lib
为什么要移动到/usr/lib呢?因为该路径是链接库的标准路径,可以运行链接动态库,或者也可以指定 LD_LIBRARY_PATH。
Makefile动态库使用:
# Makefile
TARGET := output_makefile_so
# compile and lib parameter
CC := g++
INCLUDE := -I.
LIBS := -lfunction_makefile
# link
$(TARGET): main.o
$(CC) $^ -o $(TARGET) -lfunction_makefile
main.o:main.cpp
$(CC) -c $^ -o $@
# clean
clean:
rm -fr *.o
再次make,得到output_makefile_so,便可以执行了。
使用Cmake
懒得写了~这里就只说一下Cmake如何使用库吧!因为在实际工程中,一般都是调用别人写好的库,也就是常说的API。
这里举例说明如何使用静态库:
我们把一些不必要的.o文件、可执行文件删除掉,再路径先放好。留如下文件:(build文件夹是用来进行编译的文件,这样编译的文件就不会和主目录混在一起啦,这个称之为外部编译)
这里默认你已经掌握linux常用的rm、mkdir、touch命令。
CMakeLists.txt
:
cmake_minimum_required(VERSION 3.0)
project(output_cmake)
set(CMAKE_CXX_STANDARD 11)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include)
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/lib)
add_executable(output_cmake main.cpp)
TARGET_LINK_LIBRARIES(output_cmake libfunction.a)
其中,
set(CMAKE_CXX_STANDARD 11)
指的是c++版本号
INCLUDE_DIRECTORIES
为头文件目录,存放.h文件
LINK_DIRECTORIES
为库文件目录,存放.a文件
TARGET_LINK_LIBRARIES
指的是链接相关库
然后,我们移动到build下,编译运行:
mv build/
cmake ..
make
./output_cmake
到这里就结束了。
如果我的文章对你有帮助,欢迎关注,点赞,评论。
参考:
https://blog.csdn.net/u011964923/article/details/73297443
https://www.cnblogs.com/prettyshuang/p/5552328.html
https://www.cnblogs.com/fengliu-/p/10216723.html
https://blog.csdn.net/u013870094/article/details/84899188