CC=g++
AR=ar
OBJ_PATH=./objs
CPP_SOURCES = $(wildcard *.cpp)
CPP_OBJS = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(CPP_SOURCES))
INCDIR= -I/usr/local/freetds0.91/include \
-I/usr/local/include \
-I/usr/include \
-I../../redis-2.6.13/deps
CCFLAG=-g
ifeq ($(MAKECMDGOALS), so)
CCFLAG= -g -fPIC
endif
ar:init deps $(CPP_OBJS)
$(AR) -rsv libcomponent.a $(CPP_OBJS)
so:init deps $(CPP_OBJS)
$(CC) -shared -fPIC -o libcomponent.so $(CPP_OBJS)
init:
mkdir -p $(OBJ_PATH)
deps:
cd jsoncpp && make
cd ../../redis-2.6.13/deps && make hiredis && make jemalloc && make linenoise && make lua
cd ../../redis-2.6.13/src && make
$(CPP_OBJS):$(OBJ_PATH)/%.o:%.cpp
$(CC) $(CCFLAG) $(INCDIR) -o $@ -c $<
clean:
rm -rf *.o *.a *.so objs
cd ../../redis-2.6.13/deps && make distclean
cd ../../redis-2.6.13/src && make clean
help:
@echo "make: default compile static lib --libcomponent.a"
@echo "make so: compile dynamic lib --libcomponent.so"
@echo "make deps: compile jsoncpp redis"
@echo "make clean: clean obj lib"
L13——L16:根据编译目标定义不同的编译选项,动态库编译源文件时要添加-fPIC编译选项。
关于-fPIC选项:
不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位的.(因为它里面的代码并不是位置无关代码)
如果被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了.(因为so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)这样就失去了共享库的好处,实际上和静态库的区别并不大,在运行时占用的内存是类似的,仅仅是二进制代码占的硬盘空间小一些.而且在加载时才重定位的开销也很大(这一点使得这种做法更加没有意义).
我们总是用fPIC来生成so,也从来不用fPIC来生成a.
fPIC与动态链接可以说基本没有关系,libc.so一样可以不用fPIC编译,只是这样的so必须要在加载到用户程序的地址空间时重定向所有表目.
因此,不用fPIC编译so并不总是不好.
如果你满足以下4个需求/条件:
1.该库可能需要经常更新
2.该库需要非常高的效率(尤其是有很多全局量的使用时)
3.该库并不很大.
4.该库基本不需要被多个应用程序共享