zoukankan      html  css  js  c++  java
  • 由一次 symbol lookup error 引发的思考

    开发一个跨平台的项目的时候,大部分时候都是在VS下进行编码,所以也就使用了VS的解决方案来管理项目。
    因为要跨平台,当时网上看scons这个工具不错,所以在linux下就使用了scons来作为编译脚本。

    linux(gcc)下与windows(vs)下的对于链接这一步稍有不同。当目标文件是一个(共享)库的时候,VS会在链接的时候就去解析所有用到的符号,而gcc则不会,只有在生成最终可执行程序的时候才会去解析。
    所以在VS下,一直都没有问题。linux下进行测试的时候也没有问题(因为不是所有的代码都被调用了)。

    这几天在一次移植过程中出现了如下的问题

    /a.out: symbol lookup error: ./uds_file_storage_module.so: undefined symbol: _ZN8unispace13us_ini_config9from_fileERKNS_10us_ustringEPS0_
    

    错误很简单,就是us_ini_config::from_file这个函数没有找到,说明没有将其添加到动态导出符号表中。(uds_file_storage_module.so是运行时动态加载的,所以编译的时候没有提示错误)

    VC中导出符号需要使用到dllexport,而gcc下则默认是不需要。所以这个问题很是疑惑。

    考虑用的gcc版本比较高,是不是它将-fvisibility的参数默认设置为hidden呢?查看了gnu的wiki之后也没有发现这个。

    https://gcc.gnu.org/wiki/Visibility

    这里还是有收获的,看到一段好的跨平台代码。

    #if defined _WIN32 || defined __CYGWIN__
      #ifdef BUILDING_DLL
        #ifdef __GNUC__
          #define DLL_PUBLIC __attribute__ ((dllexport))
        #else
          #define DLL_PUBLIC __declspec(dllexport) // 注记:实际上gcc似乎也支持这种语法。
        #endif
      #else
        #ifdef __GNUC__
          #define DLL_PUBLIC __attribute__ ((dllimport))
        #else
          #define DLL_PUBLIC __declspec(dllimport) // 注记:实际上gcc似乎也支持这种语法。
        #endif
      #endif
      #define DLL_LOCAL
    #else
      #if __GNUC__ >= 4
        #define DLL_PUBLIC __attribute__ ((visibility ("default")))
        #define DLL_LOCAL  __attribute__ ((visibility ("hidden")))
      #else
        #define DLL_PUBLIC
        #define DLL_LOCAL
      #endif
    #endif
    
    extern "C" DLL_PUBLIC void function(int a);
    class DLL_PUBLIC SomeClass
    {
       int c;
       DLL_LOCAL void privateMethod();  // Only for use within this DSO
    public:
       Person(int _c) : c(_c) { }
       static void foo(int a);
    };
    

    然后添加了__attribute__((visibility("default")))进行修饰,发现编译的结果没有改变(md5sun判断)。

    然后又在链接的时候添加-rdynamic参数,将所有符号都添加到动态符号表,编译结果也没有变。

    在仔细查看了SConstruct脚本之后,发现问题在于没有将对应的源文件添加到脚本中。也就是编译的时候完全就没有编译us_ini_config::from_file所在的源文件。
    这样问题就很清晰明了了,修改脚本之后重新编译就可以了。


    说到这里,就该反思一下了。
    这个项目早期确实是直接写的Makefile来进行编译的,使用SOURCES = $(shell find $(SRC_DIR)$(PROJECT)/ -name "*.cpp")来自动发现cpp文件,这本来是很好的。对于贸然使用自己不熟悉的scons,又没有进行有效的学习,这是很不好的。
    对于这个项目,还是直接使用qmake来做跨平台的编译脚本比较好。

  • 相关阅读:
    如何使用Junit
    CSS简单动画效果
    编程类软件下载地址
    常用的工具包-下载地址
    连接数据库常用工具类(二)------C3P0Utils工具类
    连接数据库时常用的工具类(一)-------C3P0XmlUtils
    浏览器输入服务器端口号来访问html网页
    使用C/S结构实现客户端上传本地文件到服务器
    冒泡排序
    一个注册界面
  • 原文地址:https://www.cnblogs.com/oloroso/p/6283248.html
Copyright © 2011-2022 走看看