工作问题随笔

最近工作中需要将公司中的一个项目移植到Linux平台下,该项目采用的是wxWidgets+boost的方式来开发的。项目编译采用的是bakefile的方式,该项目在windows平台下编译没有问题,但是在Linux下的编译是困难重重。现在将在移植的过程中遇到的问题记录一下,方便以后来回顾。Linux版本是CentOS 5.6 32位系统、wxWidgets 2.8.10、boost 1.46.1.
1.CentOS 5.6系统自带的python版本为2.4.3的,这个版本太低,由于项目编译需要使用到bakefile,这个版本的python在使用bakefile的命令时候会报警告。所以需要对python进行升级。
在CentOS5中自带的Python版本是2.4,但是目前许多基于Python的应用软件要求的Python版本应要高于2.4。升级python版本的时候千万不能卸载python 2.4,再安装python2.7,这样会有无穷无尽的麻烦,保守的方式是直接安装python2.7的源码包,也就是python两个版本共存。(因为Centos里面有很多程序是依赖着python,所有最好不要尝试去卸载python2.4)。

下载Python2.7.2.tgz(wget http://www.python.org/ftp/python/2.7.2/Python-2.7.2.tgz)
tar zxf Python2.7.2.tgz
cd ./Python2.7.2
./configure
make && make install

自此,python2.7安装后路径默认是在/usr/local/lib/python2.7

查看python版本:/usr/local/bin/python2.7 -V

正常情况下即使python2.7安装成功后,系统默认指向的python仍然是2.4版本,考虑到yum命令是基于
python2.4才能正常工作,不敢轻易卸载。如何实现将系统默认的python指向到2.7版本呢?

mv /usr/bin/python /usr/bin/python.bak (备份/usr/bin目录下原有的python2.4版本文件) 
ln -sf /usr/local/bin/python2.7 /usr/bin/python (建立软链接/usr/bin/python指向/usr/local/bin/python2.7文件)
检验python指向是否成功 :python -V 

解决系统python软链接指向python2.7版本后,yum命令不能正常工作的问题:

vi /usr/bin/yum
将文本编辑显示的第一行
#!/usr/bin/python修改为#!/usr/bin/python2.4,保存修改即可。

2.CentOS 5.6系统自带的gcc版本为4.1.2的,版本太低,有些东西无法编译,所以需要将gcc版本进行升级。下面是自己整理的一种升级方式,如果系统的wget命令无法用的话,那么可以直接从下面的网址进行下载也是一样的。

系统版本:CentOS 5.6 32位
原GCC版本:4.1.2
新GCC版本:4.6.1

下载gcc包:wget http://ftp.gnu.org/gnu/gcc/gcc-4.6.1/gcc-4.6.1.tar.bz2

gcc包的安装依赖gmp、mpc、mpfr包的安装,而且版本要对应。其实在gcc安装包的解压文件./contrib/download_prerequisites文件中列出了当前版本的gcc需要依赖的其他版本库的安装包,请注意查看。通过查看可以知道gcc-4.6.1版本的安装包依赖gmp-4.3.2.tar.bz2、mpc-0.8.1.tar.gz、mpfr-2.4.2.tar.bz2,使用以下命令来获取这几个包:

wget ftp://gcc.gnu.org/pub/gcc/infrastructure/{gmp-4.3.2.tar.bz2,mpc-0.8.1.tar.gz,mpfr-2.4.2.tar.bz2}

下面是解压和安装,源码包的安装有一个顺序:GMP、MPFR、MPC、GCC
安装GMP:tar jxf gmp-4.3.2.tar.bz2 && cd gmp-4.3.2/ ; ./configure –prefix=/usr/local/gmp/ && make && make install
安装MPFR:tar jxf mpfr-2.4.2.tar.bz2 && cd mpfr-2.4.2/ ; ./configure –prefix=/usr/local/mpfr –with-gmp=/usr/local/gmp && make && make install
安装MPC:tar xzf mpc-0.8.1.tar.gz && cd mpc-0.8.1 ; ./configure –prefix=/usr/local/mpc –with-mpfr=/usr/local/mpfr –with-gmp=/usr/local/gmp && make && make install
安装GCC:tar jxf gcc-4.6.1.tar.bz2 && cd gcc-4.6.1 ; ./configure –prefix=/usr/local/gcc –enable-threads=posix –disable-checking –disable-multilib –enable-languages=c,c++ –with-gmp=/usr/local/gmp –with-mpfr=/usr/local/mpfr/ –with-mpc=/usr/local/mpc/

注意:这时先不要急着对gcc进行make && make install操作,因为还要将gmp、mpfr、mpc的库文件路径配置一下,否则编译gcc的时候会报错。还有这里的gcc支持的编译语言选项配置–enable-languages=c,c++,这里指定为只支持C和C++,如果指定为all即支持所有的编程语言,那么编译时间会非常的长,所以在这里我只选择了C和C++这两个我的项目中用到的语言。

执行export  LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/mpc/lib:/usr/local/gmp/lib:/usr/local/mpfr/lib/命令,将库的路径加入到库搜索路径中。

强烈建议将上面的export命令加入到/etc/profile文件中,这样任何时候都能够生效了。
执行完了export命令之后,就可以开始对gcc进行编译和安装了。

cd gcc-4.6.1
make && make install

这个编译安装的过程比较慢,请耐心等待。
编译安装完毕之后,我们需要建立一些软链接来使gcc生效。

mkdir -p /usr/bin/gccbackup        //在/usr/bin/目录中建立一个gcc的备份目录
mv /usr/bin/{gcc,g++} /usr/bin/gccbackup     //将/usr/bin/目录下的gcc和g++文件移动到gccbackup目录中
ln -sf /usr/local/gcc/bin/gcc /usr/bin/gcc //建立软链接/usr/bin/gcc指向/usr/local/gcc/bin/gcc
ln -sf /usr/local/gcc/bin/g++ /usr/bin/g++ //建立软链接/usr/bin/g++指向/usr/local/gcc/bin/g++

软链接建立好之后,可以使用gcc -v命令来查看gcc的版本为4.6.1说明安装成功了。


3.编译工程代码是遇到了一些编译出错的问题。
工程代码中使用了一些c++0x的新特性比如Lambda函数与Lambda表达式(具体c++0x的新特性可以百度相关资料),由于以前是在visual studio 2010版本下编译的,而VS2010版本的编译器是完全支持c++0x的而且不需要特别的设置。gcc4.6.1版本的编译器也支持c++0x,但是必须要将-std=c++0x加入到gcc的编译参数中来打开对c++0x的编译支持选项,否则编译会失败。


4.链接libboost_filesystem.so出现的错误
在对工程代码修改完成后进行编译工作,在最后的一步准备链接libboost_filesystem.so来生成可执行文件的时候出错了,错误信息如下:

Debug/DssDb_EncryManager.o: in the function EncryManager::decode()
boost/filesystem/v3/operations.hpp:303:undefined reference to `boost::filesystem3::detail::copy_file(boost::filesystem3::path const&, boost::filesystem3::path const&, boost::filesystem3::copy_option, boost::system::error_code*)`

这个链接报错的信息咋看起来很莫名其妙,我在EncryManager::decode()函数中使用了boost库中的copy_file函数,而且我确认包含了boost库的相关头文件并引入了正确的命名空间,但是链接却莫名其妙的报错了。可以使用nm命令来查看文件中的一些symbol来发现一些问题。
首先使用nm命令来查看Debug/DssDb_EncryManager.o文件:

nm -Ca Debug/DssDb_EncryManager.o | grep copy_file     //指定-Ca选项后输出的symbol是以函数的形式来输出地,比较直观

大致输出如下:

U  boost::filesystem3::detail::copy_file(boost::filesystem3::path const&, boost::filesystem3::path const&, boost::filesystem3::copy_option, boost::system::error_code*)

其中U表示Unknown的意思,表示是一个无法确定的符号,需要从外部来进行链接。请注意其需要链接的函数的原型声明:
boost::filesystem3::detail::copy_file(boost::filesystem3::path const&, boost::filesystem3::path const&, boost::filesystem3::copy_option, boost::system::error_code*)
再使用nm命令来查看libboost_filesystem.so文件:

nm -Ca /usr/local/lib/libboost_filesystem.so | grep copy_file

大致输入如下:

T  boost::filesystem3::detail::copy_file(boost::filesystem3::path const&, boost::filesystem3::path const&, boost::filesystem3::copy_option::enum_type, boost::system::error_code*)

其中T表示Global text符号,表示是一个确定的符号有了实现了。请注意这里libboost_filesystem.so中的函数的原型声明:
boost::filesystem3::detail::copy_file(boost::filesystem3::path const&, boost::filesystem3::path const&, boost::filesystem3::copy_option::enum_type, boost::system::error_code*)
我这个比较笨,而且不够细心仔细,所以一直都没有发现这两个函数原型有什么不同,一直都认为是一样的,所以就一直都觉得明明在libboost_filesystem.so文件中有了对应的函数为什么却一直链接不上去呢?其实只要仔细观察这两个函数原型声明就会发现发现函数原型中的第3个参数的类型是不一致的,
一个是
boost::filesystem3::copy_option
一个是
boost::filesystem3::copy_option::enum_type
函数原型不一致,所以Debug/DssDb_EncryManager.o文件一直链接不上去,我真该死,我错怪Debug/DssDb_EncryManager.o文件了。
根据链接的报错信息,查看boost/filesystem/v3/operations.hpp文件的303行,发现是一个如下的函数:

 inline
  void copy_file(const path& from, const path& to,   // See ticket #2925
                 BOOST_SCOPED_ENUM(copy_option) option)
                   {detail::copy_file(from, to, option);}

 而在这个函数里面又调用了detail命名空间里面的copy_file函数,其函数声明如下:

 void copy_file(const path& from, const path& to,
                    BOOST_SCOPED_ENUM(copy_option) option,  // See ticket #2925
                    system::error_code* ec=0);

这里的第3个参数BOOST_SCOPED_ENUM(copy_option)是一个宏定义,具体的定义在文件boost/detail/scoped_enum_emulation.hpp中,下面是这个文件的内容

#ifndef BOOST_SCOPED_ENUM_EMULATION_HPP
#define BOOST_SCOPED_ENUM_EMULATION_HPP


#include <boost/config.hpp>


#ifdef BOOST_NO_SCOPED_ENUMS


# define BOOST_SCOPED_ENUM_START(name) struct name { enum enum_type
# define BOOST_SCOPED_ENUM_END };
# define BOOST_SCOPED_ENUM(name) name::enum_type


#else


# define BOOST_SCOPED_ENUM_START(name) enum class name
# define BOOST_SCOPED_ENUM_END
# define BOOST_SCOPED_ENUM(name) name


#endif


#endif  // BOOST_SCOPED_ENUM_EMULATION_HPP

在文件的开头有一段注释:

//  Generates C++0x scoped enums if the feature is present, otherwise emulates C++0x
//  scoped enums with C++03 namespaces and enums. The Boost.Config BOOST_NO_SCOPED_ENUMS
//  macro is used to detect feature support.

看来这个貌似又是与C++0x的新特性有关的,这个是C++0x的包含作用域的枚举类型新特性带来的问题。由于我们使用./bjam install的方式来编译和安装的boost库文件其中编译时预定义了BOOST_NO_SCOPED_ENUMS宏,所以BOOST_SCOPED_ENUM(copy_option)宏展开就是copy_option::enum_type类型的。但是我们在编译DssDb_EncryManager.cpp文件时却没有预定义BOOST_NO_SCOPED_ENUMS宏,所以BOOST_SCOPED_ENUM(copy_option)宏展开就是copy_option类型的。这也就是在最开始使用nm命令来查看Debug/DssDb_EncryManager.o文件和/usr/local/lib/libboost_filesystem.so文件中copy_file函数的原型声明不一致的原因。
解决办法也很简单:在编译项目工程中的所有源代码文件的时候都加入-DBOOST_NO_SCOPED_ENUMS的预定义宏,然后在和libboost_filesystem.so文件进行链接就没有问题。
由此可见:编译的报错一定是有原因的,要注意这些错误信息的细节。Linux下的nm命令蛮强大的。


5.运行可执行程序后报错

错误信息如下:/usr/lib/libstdc++.so.6:version "GLIBC_3.4.15" not found

这个错误信息表示当前的libstdc++.so.6库文件的版本太低了。可以使用strings命令来查看一下
strings能输出文件中的可打印字符串(可指定字符串的最小长度),通常用来查看非文本文件(如二进制可执行文件)中的可读内容。比如:

strings  /usr/lib/libstdc++.so.6 | grep GLIBC
输出如下:
GLIBC_2.0
GLIBC_2.1
GLIBC_2.1.1
GLIBC_2.1.2
GLIBC_2.1.3
GLIBC_2.2
GLIBC_2.2.1
GLIBC_2.2.2
GLIBC_2.2.3
GLIBC_2.2.4
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4

可见当前版本的libstdc++.so.6库确实版本太低了。刚开始我直接从网上下载了一个libstdc++.6.0.17的库文件,但是却由于依赖其他的一些文件而无法使用。
后来发现libstdc++.so文件应该是在安装gcc的时候自带的,那么我们刚才安装升级了gcc版本,那么我想应该会也自带了一个更高版本的libstdc++.so库文件吧。
查看/usr/local/gcc/lib/目录,果然发现有一个libstdc++.so.6.0.17库文件。
可以使用strings命令来查看libstdc++.so.6.0.17文件发现其中包含GLIBC_3.4.15信息,说明该版本的libstdc++.so.6.0.17库文件满足要求。
于是进行以下的操作:

mkdir -p /usr/lib/libstdc++backup
mv /usr/lib/libstdc++* /usr/lib/libstdc++backup
vim /etc/ldconfig/ld.conf.d/stdc++.conf
在/etc/ldconfig/ld.conf.d/stdc++.conf文件中加入libstdc++.so.6.0.17的路径/usr/local/gcc/lib/
随后执行ldconfig命令来更新系统库信息。
这样执行之后,在执行可执行文件就不会在报错了。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值