• 由于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++的时候,链接顺序一定不要搞错!

  • 相关阅读:
    2w字 + 40张图带你参透并发编程!
    完了,这个硬件成精了,它竟然绕过了 CPU...
    一文详解 Java 并发模型
    详解匈牙利算法与二分图匹配
    机器学习 | 详解GBDT在分类场景中的应用原理与公式推导
    Python | 浅谈并发锁与死锁问题
    LeetCode 91,点赞和反对五五开,这题是好是坏由你来评判
    LeetCode 90 | 经典递归问题,求出所有不重复的子集II
    【Azure DevOps系列】什么是Azure DevOps
    MSIL入门(四)之委托delegate
  • 原文地址:https://www.cnblogs.com/qrlozte/p/4464487.html
Copyright © 2020-2023  润新知