cygwin中动态库链接的问题

问题的出现

(这里解释得比较累赘, 要找到答案, 可以直接进入第二章节)

看书(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

程序运行正常.

解决动态库问题方法一: .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
重新登录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

你可能感兴趣的:(Linux,&,Unix,C)