zoukankan      html  css  js  c++  java
  • 由于link顺序错误导致的undefined reference

    其实我之前就遇到过这个问题,也强调过,GNU-G++在link阶段是依赖输入的.o或者.a文件的顺序的。如果顺序错误会导致undefined reference错误

    见这篇随笔:http://www.cnblogs.com/qrlozte/p/4137704.html

    刚才我遇到的问题是什么呢?

    代码demo.cpp:其中ZJ::open_max在util.h中声明,在$(PATH_ONE)/libutil.a中;err_sys在apue.h中声明,在$(PATH_TWO)/libapue.a中,这里我用makefile里的$(PATH_XXX)来表示路径的宏值

    #include "apue.h"
    #include "util.h"
    
    #include <iostream>
    
    int main(void)
    {
        const long opmax = ZJ::open_max();
        std::cout << "opmax = " << opmax << std::endl;
        err_sys("test err_sys");
        return 0;
    }

    编译链接成功,可运行。

    其中链接命令为:

    g++ -L$(PATH_ONE) -L$(PATH_TWO) -o bin/test_exe obj/demo.o -lapue -lutil

    但是,如果把err_sys那一行代码删掉,再把#include "apue.h"删掉,makefile内容不变,就会报错:

    $(PATH_ONE)/libutil.a(util.o): In function `ZJ::open_max()': util.cpp:(.text+0x56): undefined reference to `err_sys(char const*, ...)'

    这里,我知道的是:ZJ::open_max中有对err_sys的调用,我不明白的是:如果确实有undefined reference错误,我没删那两行的时候就该报错了吧?我又没改makefile,这是什么情况?

    后来经过几番折腾,终于发现这个不起眼的错误,就是在makefile里面:

    g++ -L$(PATH_ONE) -L$(PATH_TWO) -o bin/test_exe obj/demo.o -lapue -lutil

    正确的应该是:

    g++ -L$(PATH_ONE) -L$(PATH_TWO) -o bin/test_exe obj/demo.o -lutil -lapue

    为什么?

    因为$(PATH_ONE)/libutil.a里面主要包含2个函数,ZJ::open_max和ZJ::path_max,这二者都依赖于$(PATH_TWO)/libapue.a中的err_sys

    对于-lapue -lutil的情况,在链接的时候,linker先看到-lapue,在demo.o中也看到了对err_sys的调用,那么linker就知道在$(PATH_TWO)/libapue.a中能找到的err_sys的入口,同理,然后linker也能知道应该去$(PATH_ONE)/libutil.a中找ZJ::open_max的入口

    但是,如果你删除了demo.cpp中对err_sys的声明和调用,那么linker就无法直接知道err_sys可以在$(PATH_TWO)/libapue.a中能找到,因此linker就开始顺序查找-lapue -lutil

    首先linker开始检查demo.o中的函数调用,在main函数的第一行找到了对ZJ::open_max的调用,显然,此时linker依次查看-lapue(没有,因此跳过),-lutil(找到),因此linker就去$(PATH_ONE)/libutil.a中去找到ZJ::open_max的入口,然后在ZJ::open_max中找到了对err_sys的调用,但是,此时因为-lapue已经被linker跳过了,所以linker只会继续在-lutil中查找(当然找不到),然后再看-lutil后面还有没有-l参数(没有了),因此报错undefined reference to err_sys(当然,g++ linker的实现我不知道,我这里是纯属推测)不会再回头去看-lapue中能不能找到err_sys(而Microsoft的CL.EXE就不存在这个问题)。

    对于-lutil -lapue的情况,上述的问题就不存在了,因为linker发现-lutil找不到err_sys,就会继续往下找,从而在-lapue中找到err_sys

    废话这么多,总结:用GNU-GCC/G++的时候,链接顺序一定不要搞错!

  • 相关阅读:
    C# 反射 通过类名创建类实例
    c#委托把方法当成参数
    PPT美化大师
    以Outlook样式分组和排列数据项
    使用windows服务和MSMQ和进行日志管理(解决高并发问题)
    springboot配置filter
    filter 中用spring StopWatch 监控请求执行时间
    spring计时工具类stopwatch用法
    Spring异步任务处理,@Async的配置和使用
    注解用法详解——@SuppressWarnings
  • 原文地址:https://www.cnblogs.com/qrlozte/p/4464487.html
Copyright © 2011-2022 走看看