Snake游戏中用了ncurses库开发,使用时只需要包含头文件<ncurses.h>即可。虽然整个程序运行通过,但是移植的时候别的机器不能直接运行,因为别人的机器上不一定就安装了ncurses,所以就需要机器下载ncurses。想想吧,现在的程序都讲究人性化,玩家下载了游戏后就直接可以玩,如果还让用户下载另一个依赖的库,可以预见会有大部分玩家会放弃这款游戏,虽然我这只是一个普普通通的shell端游戏,但是这点策略还是应该有的。
首先想到的就是找到ncurses.h所包含的头文件及头文件所涉及其他头文件,这里只需要ncurses.h和ncurses_dll.h,把这两个文件移到工程中,并新建include文件,将这两个头文件放于此,这时就需要将程序中<ncurses.h>更改为"include /ncurses.h"。有了头文件后编译就能通过了,但是链接时需要ncurses.h中相关函数的实现文件,这时就需要ncurses的动态库帮忙了,whereis libncurses.so,找到动态库存放的路径,你会发现有好几个版本的动态库,到底需要哪个呢?
确定到底动态加载了哪个版本的库,就需要ldd帮忙了,ldd会列出可执行文件依赖的动态库,执行ldd testSnake:
linux-gate.so.1 => (0xb77d4000)
libX11.so.6 => /lib/libX11.so.6 (0x4574b000)
libncurses.so.5 => /usr/lib/libncurses.so.5 (0x4702a000)
./lib/libIrrKlang.so (0xb7742000)
libtinfo.so.5 => /usr/lib/libtinfo.so.5 (0x47006000)
libstdc++.so.6 => /lib/libstdc++.so.6 (0x45925000)
libm.so.6 => /lib/libm.so.6 (0x4556c000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x455d8000)
libpthread.so.0 => /lib/libpthread.so.0 (0x45599000)
libc.so.6 => /lib/libc.so.6 (0x453b1000)
libxcb.so.1 => /lib/libxcb.so.1 (0x45727000)
libdl.so.2 => /lib/libdl.so.2 (0x45565000)
/lib/ld-linux.so.2 (0x4538e000)
libXau.so.6 => /lib/libXau.so.6 (0x45721000)
可以看到程序依赖/usr/lib/libncurses.so.5和/ust/lib/libtinfo.so.5,这样将这两个动态库拷贝到工程中lib/目录中。这样是否就可以了呢?
此时你运行程序,然后执行ldd后会发现程序依然依赖的是之前的动态库,这时我们就要告诉链接器到lib/中寻找而不是/usr/lib/中寻找。
这就涉及到改变程序加载动态库默认搜索路径问题,有3个方法,
1)在配置文件/etc/ld.so.conf中指定动态库搜索路径,并用命令ldconfig使修改后的配置生效。
2)通过环境变量LD_LIBRARY_PATH指定动态库搜索路径,多个路径之间使用:分隔。
3)在编译目标代码时指定该程序的动态库搜索路径。
此处我使用了第3种方法,在编译目标代码时指定程序的动态库搜索路径-Wl,表示后面的参数将传给link程序ld。通过gcc的参数"-Wl,-rpath,"指定。当指定多个动态库搜索路径时,路径之间用冒号":"分隔。
-lX11 ./lib/libncurses.so.5 ./lib/libIrrKlang.so ./lib/libtinfo.so.5 -Wl,-rpath,./lib
这样上面列出的3个动态库就从指定的./lib中搜到得到,其他依赖的动态库则依然从默认的搜索路径中得到。
动态库是有搜索顺序的,动态库的搜索路径搜索的先后顺序是:
1.编译目标代码时指定的动态库搜索路径;
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;
4.默认的动态库搜索路径/lib;
5.默认的动态库搜索路径/usr/lib。