您的位置:首页 > 运维架构 > Linux

Linux学习笔记——例说makefile 增加自定义共享库

2014-07-05 20:20 344 查看
0.前言

从学习C语言开始就慢慢开始接触makefile,查阅了很多的makefile的资料但总感觉没有真正掌握makefile,如果自己动手写一个makefile总觉得非常吃力。所以特意借助博客总结makefile的相关知识,通过例子说明makefile的具体用法。

例说makefile分为以下几个部分,更多内容请参考【例说makefile索引博文

1.只有单个C文件
2.含有多个C文件
3.需要包括头文件路径

4.增加宏定义
5.增加系统共享库
6.增加自定义共享库
7.一个实际的例子

【代码仓库】——makefile-example
代码仓库位于bitbucket,可借助TortoiseHg(GUI工具)克隆代码或者在网页中直接下载zip包。

【本例说明】
本例分为两个过程,先***一个共享库,然后在使用这个共享库。共享库采用动态链接方式,后缀为.so。

1.gcc复习
【1】gcc指令中使用共享库使用前缀-l,共享库查找目录使用-L。
【2】一般情况下DLIBS中加入共享库,而LDFLAGS中加入共享库查找目录。

2.共享库源文件
和生成共享库有关的文件位于libtest目录中,在makefile最后把共享库复制到同级的lib目录中。具体内容请参考代码仓库并复制zip包。
【libtest.h】
指定接口,给出相应声明
#ifndef __LIBTEST_H
#define __LIBTEST_H
int sub(int a, int b);
int add(int a, int b);
#endif

【test-add.c】
int add(int a, int b)
{
    return a+b;
}

【test-sub.c】
int sub(int a, int b)
{
    return a-b;
}


3.共享库的makefile
请替换其中的[tab],并以代码仓库中的makefile文件为主。
# 指令编译器和选项
CC = gcc
CFLAGS = -Wall -std=gnu99

# 目标文件
TARGET = libtest.so
# C文件
SRCS = test-add.c test-sub.c
# 目标文件
OBJS = $(SRCS:.c=.o)

# 链接为可执行文件
$(TARGET):$(OBJS)
[tab]$(CC) -shared -o $@ $^
[tab]mv $(TARGET) ../lib

clean:
[tab]rm -rf $(TARGET) $(OBJS)

# 编译规则 $@代表目标文件 $< 代表第一个依赖文件
%.o:%.c
[tab]$(CC) $(CFLAGS) -o $@ -fPIC -c $<


【说明】
【1】目标为libtest.so,请务必以lib开头 .so结尾,在使用该共享库时系统会自动的去除lib和.so,使用时写成-ltest。
【2】多数内容和学习笔记中的多个文件相同。
【3】在链接过程中加入-shared参数,意为共享形式的目标文件。
【4】在编译过程中加入-fPIC参数,意为生成和地址无关的目标文件。
【5】在链接完成之后,通过mv指令把libtest.so移动到同级的lib目录中。
【6】如果有必要,可以把libtest.so复制到/usr/lib目录中,这样使用起来会更加方便。

【验证】

ldd test

linux-vdso.so.1 => (0x00007fffde960000)

libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ffe55b18000)

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffe55750000)

/lib64/ld-linux-x86-64.so.2 (0x00007ffe55e38000)

【编译和执行】
make clean && make

【控制台输出】
rm -rf libtest.so test-add.o test-sub.o

gcc -Wall -std=gnu99 -o test-add.o -fPIC -c test-add.c

gcc -Wall -std=gnu99 -o test-sub.o -fPIC -c test-sub.c

gcc -shared -o libtest.so test-add.o test-sub.o

mv libtest.so ../lib

【1】编译过程中加入了-fPIC选项。

【2】链接过程中加入-shared选项。

【3】共享库为libtest.so。

【4】最后,共享库被移动到上一级的lib目录中。


4.源文件
调用共享库指定的接口,add和sub函数。
#include <stdio.h>
#include <libtest.h>
int main(void)
{
    int a = 3;
    int b = 2;
       
    printf("a=%d\n", a);
    printf("b=%d\n", b);
   
    printf("a+b=%d\n", add(a, b));
    printf("a-b=%d\n", sub(a, b));
    return 0;
}


5.makefile
请替换其中的[tab],并以代码仓库中的makefile文件为主。
# 指令编译器和选项
CC = gcc
CFLAGS = -Wall -std=gnu99

# 目标文件
TARGET = test
# C文件
SRCS = test.c
# 头文件查找路径
INC = -I.
# 库文件和库查找路径
DLIBS = -ltest
LDFLAGS = -L./lib
# 指定运行时的库文件路径
RPATH = -Wl,-rpath=./lib

# 目标文件
OBJS = $(SRCS:.c=.o)

# 链接为可执行文件
$(TARGET):$(OBJS)
[tab]$(CC) -o $@ $^ $(LDFLAGS) $(DLIBS) $(RPATH)

clean:
[tab]rm -rf $(TARGET) $(OBJS)

# 连续动作,请清除再编译链接,最后执行
exec:clean $(TARGET)
[tab]@echo 开始执行
[tab]./$(TARGET)
[tab]@echo 执行结束

# 编译规则 $@代表目标文件 $< 代表第一个依赖文件
%.o:%.c
[tab]$(CC) $(CFLAGS) $(INC) -o $@ -c $<


6.具体说明
【1】DLIBS = -ltest 指定共享库,请注意共享库的名称为libtest.so,而-l参数只取test部分,去掉前缀lib和后缀.so。
【2】LDFLAGS = -L./lib 指定共享库路径,请注意上一步中已经把共享库复制到lib目录中。
【3】INC = -I./lib 指定libtest.h目录,也可把libtest.h复制到test.c所在的目录。
【4】$(CC) -o $@ $^ $(LDFLAGS) $(DLIBS) 链接过程指定共享库查找路径,指定共享库名称。
【5】第【1】和第【2】点只在链接过程有效,在执行过程中需要通过-Wl,-rpath=<path>指定共享库路径。


【编译和链接】
make clean && make
【控制台输出】
rm -rf test test.o

gcc -Wall -std=gnu99 -I./lib -o test.o -c test.c

gcc -o test test.o -L./lib -ltest -Wl,-rpath=./lib

【执行】
在执行之前还可以通过ldd test查看libtest是否链接成功。
./test

a=3

b=2

a+b=5

a-b=1
从控制台的输出结果可以看出,共享库运行正常。

7.总结
【1】-l指定共享库名称,-L指定共享库路径。

8.参考资料
【1】gcc中的-Wl,rpath=<your_lib_dir>选项
【2】makefile学习经验(三)----编译生成动态库文件(方式一)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: