问题的出现
(这里解释得比较累赘, 要找到答案, 可以直接进入第二章节)
看书(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)
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
程序运行正常.
解决动态库问题方法一: .so改为.dll
链接的时候, 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
解决动态库问题方法二: 使用动态库的全名
链接动态库的时候, 使用全名:
- .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