大家好,欢迎来到IT知识分享网。
背景:写这篇博客的原因是:最近在搞嵌入式,需要交叉编译opencv库文件,自己写Makefile,通过arm-linux-g++编译、链接、生成可执行文件,从而实现了移植的过程。平台是Toradex的Apalis TK1,三千多元,买回来我就后悔了,全是英文资料,还各种Bug,迟迟无法上手。早知如此,还不如直接买Nvidia的Jetson TK1呢。
书归正传,今天写一下Makefile文件中,动态链接库和静态链接库的生成与调用。
一、概念
动态链接库:是一种不可执行的二进制程序文件,它允许程序共享执行特殊任务所必需的代码和其他资源。Windows平台上动态链接库的后缀名是”.dll”,Linux平台上的后缀名是“.so”。Linux上动态库一般是libxxx.so;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。
静态链接库:这类库的名字一般是libxxx.a;利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。
Makefile:利用IDE开发调试的人员可能对Makefile不大理解,其实Makefile就是完成了IDE中的编译、链接、生成等工作,并遵循shell脚本中变量定义与调用的规则。
二、编写Makefile实现编译与链接
1、准备文件
我们写一个简单的工程吧,此工程包含3个文件,分别是main.cpp,func.cpp和func.h。代码如下:
1)main.cpp源文件:包含入口函数 int main()。该源文件中添加了“func.h”头文件,在入口函数中调用func()函数。func函数中在func.cpp中定义,在func.h中原型声明。
# main.cpp
#include "func.h"
int main()
{
func();
return 0;
}
2)func.h头文件:对void func()函数进行原型声明。
# func.h
#ifndef __FUNC_H
#define __FUNC_H
#include <iostream>
void func();
#endif
3)func.cpp源文件:对void func()函数的定义或实现。
# func.cpp
#include "func.h"
void func()
{
std::cout << "Hello World !" << std::endl;
}
2、编写Makefile文件
1)定义变量
首先定义SOURCE,OBJS和TARGET变量,用于指代我们项目中的源文件、目标文件和可执行文件。
2) 设置编译参数
CC:配置编译器为g++,
LIBS:需要调用的链接库(-l开头,去掉lib和.so。例:对 libopencv_core.so链接库的调用要写作:-lopencv_core),
LDFLAGS:链接库的路径(-L开头),
INCLUDE:头文件的路径。
3)链接生成
此步骤生成可执行文件(ELF),链接需要用到目标文件,由下一步产生
4)编译
此步骤生成目标文件(.o)
5)清理
此步骤清理可执行文件和所有的目标文件
#######################
# Makefile
#######################
# source object target
SOURCE := main.cpp func.cpp
OBJS := main.o func.o
TARGET := main
# compile and lib parameter
CC := g++
LIBS :=
LDFLAGS := -L.
DEFINES :=
INCLUDE := -I.
CFLAGS :=
CXXFLAGS:=
# link
#$(TARGET):$(OBJS)
$(CC) -o $@ $^
# compile
#$(OBJS):$(SOURCE)
$(CC) -c main.cpp -o main.o
$(CC) -c func.cpp -o func.o
# clean
clean:
rm -fr *.o
rm -fr $(TARGET)
上述Makefile是将编译和链接两个步骤分开写的,我们同样可以直接从源文件生成可执行文件,自动进行编译链接等工作。
方法:将上述Makefile中的:
# link
#$(TARGET):$(OBJS)
$(CC) -o $@ $^
# compile
#$(OBJS):$(SOURCE)
$(CC) -c main.cpp -o main.o
$(CC) -c func.cpp -o func.o
修改为:
all:
$(CC) -o $(TARGET) $(SOURCE)
其他内容,不作变化。
6)编译、执行、清理
make
./main
make clean
三、动态链接库的生成与调用
引言:仍然利用上文中的main.cpp, func.cpp和func.h文件。下面,我们将func.cpp源文件制作成动态链接库libfunc.so,然后调用该动态库对main.cpp进行编译链接。
1、动态链接库的生成
Makefile如下:
#######################
# Makefile
#######################
# compile and lib parameter
CC := g++
LIBS :=
LDFLAGS :=
DEFINES :=
INCLUDE := -I.
CFLAGS :=
CXXFLAGS:=
# link parameter
LIB := libfunc.so
#link
$(LIB):func.o
$(CC) -shared -o -fPIC -o $@ $^
#compile
func.o:func.cpp
$(CC) -c -fPIC $^ -o $@
# clean
clean:
rm -fr *.o
执行make命令之后,就可以在当前目录生成libfunc.so的动态链接库了。
注意:动态链接库必须“以lib开头,以.so结尾”。
注:缺少 -fPIC错误
linux生成动态库时,如果遇到了relocation R_X86_64_32 against `.rodata‘ can not be used when making a shared object; recompile with -fPIC错误。
解决方法:
由于我的系统是AMD64位的,所以需要在编译的时候添加 -fPIC选项,重新清理编译。
例如:
#link
$(LIB):func.o
$(CC) -shared -o -fPIC -o $@ $^
#compile
func.o:func.cpp
$(CC) -c -fPIC $^ -o $@
2、动态链接库的调用
引言:在第一部分中,我们将main.o和func.o两个目标文件进行链接,便生成了main可执行文件。如果甲方并没有提供func.cpp和func.o,只是提供了libfunc.so这个链接库,我们如何生成可执行文件呢?下文就是讲述如何利用动态库链接生成可执行文件。
Makefile如下:
1)编译的时候需要通过INCLUDE指明头文件的路径
2)链接的时候需要通过LDFLAGS 和 LIBS指明动态库的路径和名称。这里需要注意的是,指明动态库名称时需要“掐头去尾”,例:我们需要用到 libfunc.so库,LIBS必须定义为 -lfunc 。
3)执行的时候,需要把libfunc.so动态库拷贝到系统环境变量包含的路径下(比如/lib或/usr/lib),这样程序在运行时才能调用到动态库。
#######################
# Makefile
#######################
# target
TARGET := main
# compile and lib parameter
CC := g++
LDFLAGS := -L/path/to/libfunc.so
LIBS := -lfunc
DEFINES :=
INCLUDE := -I/path/to/func.h
CFLAGS :=
CXXFLAGS:=
# link
$(TARGET):main.o
$(CC) -o $@ $^ $(LDFLAGS) $(LI
#compile
main.o:main.cpp
$(CC) $(INCLUDE) -c $^crm -fr $(TARGET)
clean:
rm -fr *.o
rm -fr $(TARGET)
四、静态链接库的生成和调用
1、静态链接库的生成
引言:仍然利用上文中的main.cpp, func.cpp和func.h文件。下面,我们将func.cpp源文件制作成静态链接库func.a,然后调用该静态库对main.cpp进行编译链接。
Makefile如下:
注意:AR:配置链接器为ar
#######################
# Makefile
#######################
# compile and lib parameter
CC := g++
LIBS :=
LDFLAGS :=
DEFINES :=
INCLUDE := -I.
CFLAGS :=
CXXFLAGS:=
# link parameter
AR := ar
LIB := func.a
#link
$(LIB):func.o
$(AR) -r $@ $^
#compile
func.o:func.cpp
$(CC) -c $^ -o $@
# clean
clean:
rm -fr *.o
执行make命令之后,就可以在当前目录生成func.a的静态链接库了。
注意:静态链接库必须“以.a结尾”。
2、静态链接库的调用
引言:在第一部分中,我们将main.o和func.o两个目标文件进行链接,便生成了main可执行文件;第二部分,我们将main.o和libfunc.so进行链接,也可以生成main可执行文件。如果我们既没有func.o也没有func.so,该如何生成可执行文件呢?下文就是讲述如何利用静态库func.a链接生成可执行文件。
Makefile如下:
1)编译的时候需要通过INCLUDE指明头文件的路径
2)链接的时候需要通过LDFLAGS 和 LIBS指明静态库的路径和名称。这里不需要像动态库那样“掐头去尾”,直接写作func.a即可。
3)执行的时候,不需要拷贝func.a至环境变量包含的路径,直接执行即可。
#######################
# Makefile
#######################
# target
TARGET := main
# compile and lib parameter
CC := g++
LDFLAGS := -L.
LIBS := func.a
DEFINES :=
INCLUDE := -I.
CFLAGS :=
CXXFLAGS:=
# link
$(TARGET):main.o
$(CC) -o $@ $^ $(LIBS)
#compile
main.o:main.cpp
$(CC) -c $^ -o $@
# clean
clean:
rm -fr *.o
rm -fr $(TARGET)
参考 :
linux 生成动态库时提示relocation R_X86_64_32 against `.rodata’ can not be used when making a shared object;
Linux下的动态链接库和静态链接库
Makefile选项CFLAGS,LDFLAGS,LIBS
linux 生成和使用动态链接库和静态链接库的Makefile编写
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/21077.html