(这里解释得比较累赘, 要找到答案, 可以直接进入第二章节)
看书(Ruminations on C++)时, 以章节为单位写了一些独立的小程序(使用cygwin g++作为编译器, sublime text 2作为编辑器). 以下是目录结构, 后来将写日志的函数提取出来, 放到common/common.h(.cpp), 并生成libcommon.so动态库, 供其他程序调用.
MJN@MJN-THINK ~/src/ruminations_on_c++ $ ls -1 05_surrogate_classes 06_handles_part1 07_handles_part2 08_an_object_oriented_program 09_analysis_of_classroom_exercise_part1 common
我使用的makefile的公共代码来自于$HOME/make/make.inc, 其大概内容如下:
include ${HOME}/src/make/make.local
include_dirs=${HOME}/src/ruminations_on_c++/common
lib_dirs=${HOME}/src/ruminations_on_c++/common
#------------------------------------------------
# c compiler
#------------------------------------------------
Linux_CC = gcc
AIX_CC = cc
SunOS_CC = CC
#------------------------------------------------
# c compiler flags
#------------------------------------------------
Linux_CCFLAGS = -std=c99 -g -Wall
AIX_CCFLAGS = -g -q$(OBJECT_MODE) -D_BIG_ENDIAN_ -D$(OBJECT_MODE_BIT)
SunOS_CCFLAGS =
#------------------------------------------------
# c++ compiler
#------------------------------------------------
Linux_CXX = g++
AIX_CXX = xlC
SunOS_CXX = CC
#------------------------------------------------
# DLL CC
#------------------------------------------------
AIX_DLLCC = ar -X$(OBJECT_MODE) rv
#------------------------------------------------
# DLL CC1
#------------------------------------------------
Linux_DLLCC1 = ar rvs -o
AIX_DLLCC1 = xlC -q$(OBJECT_MODE) -brtl -qmkshrobj -o
AIX_DLLSUFFIX = so
#------------------------------------------------
# c++ compiler flags
#------------------------------------------------
Linux_CXXFLAGS = -g -Wall
AIX_CXXFLAGS =
SunOS_CXXFLAGS =
#------------------------------------------------
# real variable
#------------------------------------------------
CC = $($(OSTYPE)_CC)
CXX = $($(OSTYPE)_CXX)
CCFLAGS = $($(OSTYPE)_CCFLAGS)
CXXFLAGS = $($(OSTYPE)_CXXFLAGS) -I$(include_dirs)
DLLCC = $($(OSTYPE)_DLLCC)
DLLCC1 = $($(OSTYPE)_DLLCC1)
DLLSUFFIX = $($(OSTYPE)_DLLSUFFIX)
#clear old suffixes
.SUFFIXES:
.SUFFIXES: .c .cpp .o .exe
.cpp.o:
$(CXX) -c -o $*.o $< $(CXXFLAGS)
.cpp.exe:
$(CXX) -c -o $*.o $< $(CXXFLAGS)
$(CXX) -o $* $(objs) $*.o $(CXXFLAGS) -L$(lib_dirs) -lcommon
.PHONY: clean all build
clean:
rm -f *.o
for i in `echo $(exes) | sed s/.exe//g`; \
do \
rm -f $$i; \
done
common目录的内容很简单:
MJN@MJN-THINK ~/src/ruminations_on_c++/common $ ls common.cpp common.h makefile
commcon/makefile的大概内容
MJN@MJN-THINK ~/src/ruminations_on_c++/common
$ cat makefile
include ${HOME}/src/make/make.inc
objs = common.o
all: $(objs)
dll: all
g++ -shared -o libcommon.so $(objs)
现在进入目录08_an_object_oriented_program, 其源文件为:
MJN@MJN-THINK ~/src/ruminations_on_c++/08_an_object_oriented_program $ ls Binary_node.cpp Expr.cpp main.cpp Unary_node.cpp Binary_node.h Expr.h makefile Unary_node.h Exp_node.cpp Integer_node.cpp Ternary_node.cpp UseCount.cpp Exp_node.h Integer_node.h Ternary_node.h UseCount.h
makefile大概内容如下
MJN@MJN-THINK ~/src/ruminations_on_c++/08_an_object_oriented_program
$ cat makefile
include ${HOME}/src/make/make.inc
objs = Integer_node.o Unary_node.o Binary_node.o Expr.o UseCount.o Ternary_node.o
exes = main.exe
all: $(objs)
build: $(exes)
现在尝试编译出libcommon.so:
MJN@MJN-THINK ~/src/ruminations_on_c++/common $ make dll g++ -c -o common.o common.cpp -g -Wall -I/home/MJN/src/ruminations_on_c++/common g++ -shared -o libcommon.so common.o
编译08_an_object_oriented_program目录下的代码:
MJN@MJN-THINK ~/src/ruminations_on_c++/08_an_object_oriented_program $ make all && make build g++ -c -o Integer_node.o Integer_node.cpp -g -Wall -I/home/MJN/src/ruminations_on_c++/common g++ -c -o Unary_node.o Unary_node.cpp -g -Wall -I/home/MJN/src/ruminations_on_c++/common g++ -c -o Binary_node.o Binary_node.cpp -g -Wall -I/home/MJN/src/ruminations_on_c++/common g++ -c -o Expr.o Expr.cpp -g -Wall -I/home/MJN/src/ruminations_on_c++/common g++ -c -o UseCount.o UseCount.cpp -g -Wall -I/home/MJN/src/ruminations_on_c++/common g++ -c -o Ternary_node.o Ternary_node.cpp -g -Wall -I/home/MJN/src/ruminations_on_c++/common g++ -c -o main.o main.cpp -g -Wall -I/home/MJN/src/ruminations_on_c++/common g++ -o main Integer_node.o Unary_node.o Binary_node.o Expr.o UseCount.o Ternary_node.o main.o -g -Wall -I/home/MJN/src/ruminations_on_c++/common -L/home/MJN/src/ruminations_on_c++/common -lcommon /usr/lib/gcc/i686-pc-cygwin/4.7.3/../../../../i686-pc-cygwin/bin/ld: cannot find -lcommon collect2: 错误:ld 返回 1 /home/MJN/src/make/make.inc:67: recipe for target 'main.exe' failed make: *** [main.exe] Error 1
在链接的时候, 找不到动态库libcommon.so
静态编译libcommon.a:
MJN@MJN-THINK ~/src/ruminations_on_c++/common $ ar rvs -o libcommon.a common.o ar: 正在创建 libcommon.a a - common.o MJN@MJN-THINK ~/src/ruminations_on_c++/08_an_object_oriented_program $ ./main ((-5)*(3+4))=-35 (((-5)*(3+4))*((-5)*(3+4)))=1225 (?:,0,((-5)*(3+4)),(((-5)*(3+4))*((-5)*(3+4))))=1225
将生成的libcommon.a复制到08_an_object_oriented_program目录, 并使用该库链接main:
MJN@MJN-THINK ~/src/ruminations_on_c++/08_an_object_oriented_program $ make build g++ -c -o main.o main.cpp -g -Wall g++ -o main Integer_node.o Unary_node.o Binary_node.o Expr.o UseCount.o Ternary_node.o main.o -g -Wall libcommon.a
程序运行正常.
链接的时候, cygwin会找后缀为.dll(windows中的动态库后缀)的动态库, 生成动态库的时候, 文件名后缀改为.dll, 或者建立到libcommon.so的软链接libcommon.dll
MJN@MJN-THINK ~/src/ruminations_on_c++/common $ ln -s libcommon.so libcommon.dll
可以正常地链接:
MJN@MJN-THINK ~/src/ruminations_on_c++/08_an_object_oriented_program $ make build g++ -c -o main.o main.cpp -g -Wall g++ -o main Integer_node.o Unary_node.o Binary_node.o Expr.o UseCount.o Ternary_node.o main.o -g -Wall -L/home/MJN/src/ruminations_on_c++/common -lcommon MJN@MJN-THINK ~/src/ruminations_on_c++/08_an_object_oriented_program $ ./main /home/MJN/src/ruminations_on_c++/08_an_object_oriented_program/main.exe: error while loading shared libraries: libcommon.so: cannot open shared object file: No such file or directory
但是在运行的时候, 程序找不到动态库. 这里有一个很关键的一点, 就是一定要把动态库目录放到$PATH环境变量中, 不然运行的时候无法找到动态库:
#.bash_profile
export PATH=$PATH:$HOME/src/ruminations_on_c++/common
重新登录shell, 使环境变量生效, 运行main就正常了.
.cpp.exe:
$(CXX) -c -o $*.o $< $(CXXFLAGS)
$(CXX) -o $* $(objs) $*.o $(CXXFLAGS) -L$(lib_dirs) -l:libcommon.so
这样就可以正确链接了.
但是在执行前, 也一定要把动态库目录放到$PATH环境变量中, 不然运行的时候无法找到动态库.
[1] stackoverflow: cygwin g++ Linker doesn't find shared library