Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++;库交叉依赖关系-从llvm移植到gcc 我试图把我最初在Mac LLVM上写的一些C++代码移植到Windows CygWin GCC上。在这个项目中,我将一个exe静态链接到两个库(我使用的是cmake):_C++_Gcc_Cmake_Llvm_Clion - Fatal编程技术网

C++;库交叉依赖关系-从llvm移植到gcc 我试图把我最初在Mac LLVM上写的一些C++代码移植到Windows CygWin GCC上。在这个项目中,我将一个exe静态链接到两个库(我使用的是cmake):

C++;库交叉依赖关系-从llvm移植到gcc 我试图把我最初在Mac LLVM上写的一些C++代码移植到Windows CygWin GCC上。在这个项目中,我将一个exe静态链接到两个库(我使用的是cmake):,c++,gcc,cmake,llvm,clion,C++,Gcc,Cmake,Llvm,Clion,在lib1中有一个类,它声明了一个虚拟方法: lib1/Class1.h: class Class1 { public: void method1(); virtual void method2(); }; #include "Class1.h" class Class2 { private: Class1 c1; public: void call_c1(); }; lib1/Class1.cpp: #include "Class1.h" void Cl

lib1
中有一个类,它声明了一个虚拟方法:

lib1/Class1.h:

class Class1 
{
public:
    void method1();
    virtual void method2();
};
#include "Class1.h"

class Class2
{
private:
    Class1 c1;
public:
    void call_c1();
};
lib1/Class1.cpp:

#include "Class1.h"
void Class1::method1() {
    // do work
}
// Note that method2 is not defined!
#include "Class2.h"

void Class1::method2() {
    // do some other work
}

void Class2::call_c1() {
    c1.method2();
}
Class1::method2
不是从
lib1
调用的,因此它可以正常工作

lib2
中定义了
Class1::method2

lib2/Class2.h:

class Class1 
{
public:
    void method1();
    virtual void method2();
};
#include "Class1.h"

class Class2
{
private:
    Class1 c1;
public:
    void call_c1();
};
lib2/Class2.cpp中的

#include "Class1.h"
void Class1::method1() {
    // do work
}
// Note that method2 is not defined!
#include "Class2.h"

void Class1::method2() {
    // do some other work
}

void Class2::call_c1() {
    c1.method2();
}
当我在MacOS下编译并将其与llvm链接时,所有这些都可以正常工作。当我尝试在Windows/Cygwin上使用gcc构建这个时,我遇到了各种链接器错误,比如
未定义对vtable的引用
未定义对'Class1:method2'的引用
。实际错误取决于
target\u link\u库
call中lib的顺序

是否有任何命令行选项可以传递给gcc/cmake以使其正常工作?或者最好在Windows上考虑另一个工具链?事实上,我现在正在两个平台上使用IntelliJ CLion


提前感谢您的帮助。

您在lib1中对
Class1
的定义不完整-您将其定义为虚拟方法,而不是纯虚拟方法

尝试链接lib1时,必须为虚拟方法提供实现,否则链接将失败-链接器将无法找到任何
void Class1::method2()
的实现,因为不存在任何实现。我不确定其他编译器是如何允许这一点的;也许这是其他编译器中的一个bug,或者您的构建环境与您所说的不完全一样

如果将该方法标记为纯虚拟方法,这将改善这种情况,因为它将允许编译lib1(尽管还有更多问题):

不过还有一些更大的问题-您试图在不同于Class1.cpp的文件中定义Class1的方法,然后尝试使Class2能够在Class1中编译和调用此方法

看起来您确实在尝试使用继承—您希望Class1::method2()是纯虚拟的,Class2从Class1继承,并让Class2为method2()提供一个实现

类别1.h:

class Class1
{
    public:
        void method1();
        virtual void method2() = 0;
};
类别1.cpp:

#include "Class1.h"

void Class1::method1() {
    // do work
}
类别2.h:

#include "Class1.h"

class Class2 : public Class1
{
    public:
        virtual void method2();
};
Class2.cpp:

#include "Class2.h"

//        - Pay close attention to this small but important change.
//        V
void Class2::method2() {
    // do some other work
}
然后,您将直接调用method2(),而不是调用Class2::call_c1():

SomeFile.cpp:

#include "Class2.h"

int main() {
    Class2 someInstance;

    someInstance.method2();
}

编译器可能会向lib1发出
Class1
的vtbl,其中包含对
Class1::method2
的引用。如果lib2中的一个编译单元(即对象文件)定义了
method1
,而另一个引用了
Class1
,那么库就会相互依赖。由于链接器(至少GNULD)在默认情况下在一次传递模式下工作,因此必须两次指定lib2,一次在lib1之前,一次在lib1之后。因此,cmake指令是
目标链接库(myexe lib2 lib1 lib2)

GNU ld还可以通过使用
--start group
--end group
来封装一组库,从而解决这些库之间的所有依赖关系,从而降低链接性能。您可以通过gcc通过
-Wl、-start group
等方式传递它们。不过,我不知道如何让cmake做到这一点

这背后的原因是,库不是作为一个整体链接的,而是在编译单元的基础上链接的,因此,只有库中实际需要的部分最终会出现在可执行文件中。在本例中,当链接lib2时,从主程序引用
Class2
会导致对
Class1
vtbl的引用无法解析。链接lib1满足此引用,但会创建另一个未解析的lib1到
Class1::method2
,因为此方法的地址是vtbl的一部分。所以链接器必须重新检查lib2才能解决这个问题

请注意,只有当lib2中引用vtbl的编译单元不是定义
Class1::method2
的编译单元时,才会出现此问题;在这种情况下,符号定义已经存在,不需要第二次传递lib2。也许这就是为什么对你的问题的评论说你的例子很好


链接器以一次通过模式工作,从左到右检查库,因为这种类型的相互依赖性很少见,并且完全解析会降低性能(在核心内存不足且穿孔卡堆栈不容易随机访问的情况下,出于历史原因,这可能也是默认设置).

您的示例在我的cygwin设置中运行良好,可能是您的cmake文件错误,或者您的示例没有正确地表示您的示例。请检查您在机器上发布的示例。同时发布你的cmake文件。提到您的g++版本可能会有所帮助。我不知道vtbl是在哪个编译单元中发出的,但这在clang和gcc之间可能有所不同。也许gcc会造成两个LIB相互依赖的情况。链接(至少使用GNU ld)是一个从左到右的过程,因此您必须将依赖的lib放在提供的lib之前,并且如果链接lib2引入了对lib1的新依赖,您可能需要多次指定lib,如
-llib1-llib2-llib1
。@roland-w,非常感谢您的评论。您建议在cmake中的
target\u link\u libraries()
中多次指定libs,这确实解决了问题。如果您将您的评论转换为答案,我会将其标记为正确。@tejas-您也是对的。我已经在我的cygwin环境中编写了这个示例,并进行了编译和链接。显然,没有链接的实际代码还有其他一些副作用,这些副作用导致了问题的出现。成员函数实际上是在哪个编译单元中定义的并不重要。无论如何,符号只能在链接时间解析。@RolandW-他的原始帖子似乎表明这是链接时间问题:“实际错误取决于顺序