如何解决LNK2019错误:未解析的外部符号-函数?

122

我遇到了这个错误,但不知道如何修复它。

我正在使用Visual Studio 2013。我创建了解决方案名称MyProjectTest。这是我的测试解决方案的结构:

The structure

-function.h

#ifndef MY_FUNCTION_H
#define MY_FUNCTION_H

int multiple(int x, int y);
#endif

-function.cpp

#include "function.h"

int multiple(int x, int y){
    return x*y;
}

-main.cpp

#include <iostream>
#include <cstdlib>
#include "function.h"

using namespace std;

int main(){
    int a, b;
    cin >> a >> b;
    cout << multiple(a, b) << endl;

    system("pause");
    return 0;
}

我是一位初学者;这是一个简单的程序,运行时没有错误。 我在网上看到关于单元测试的内容,于是我创建了一个测试项目:

菜单 文件新建项目...已安装模板Visual C++测试本机单元测试项目

名称:UnitTest1
解决方案:添加到解决方案

然后,位置自动切换到当前打开解决方案的路径。

这是解决方案的文件夹结构:

Folder structure

我只编辑了文件 unittest1.cpp

#include "stdafx.h"
#include "CppUnitTest.h"
#include "../MyProjectTest/function.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTest1
{
    TEST_CLASS(UnitTest1)
    {
    public:

        TEST_METHOD(TestEqual)
        {
            Assert::AreEqual(multiple(2, 3), 6);
            // TODO: Your test code here
        }

    };
}

但我得到以下错误:

错误 LNK2019:未解析的外部符号。

我知道函数 multiple 的实现缺失。 我尝试删除 function.cpp 文件并将声明替换为定义,然后它可以运行。但是在同一个文件中编写声明和定义不被推荐。 我该如何修复此错误而不这样做呢?我应该在 unittest.cpp 文件中用 #include "../MyProjectTest/function.cpp" 替换它吗?


13
注意:在Windows环境下,静态库的文件扩展名为.LIB。为了让事情更加复杂,动态链接库(即*.DLL)可以有一个伴随着的导入库,它也有一个.LIB的扩展名。这个导入库会列出所有由*.DLL提供的好东西。获取更多信息,请阅读:连接器入门指南 - Pressacco
11
他为什么需要小心? - marshal craft
12个回答

97
一种选择是将function.cpp包含在您的UnitTest1项目中,但这可能不是最理想的解决方案结构。简短回答您的问题是,在构建UnitTest1项目时,编译器和链接器并不知道function.cpp的存在,也没有任何东西可以连接,其中包含multiple的定义。解决此问题的方法是利用链接库。
由于您的单元测试位于另一个项目中,我假设您的意图是使该项目成为一个独立的单元测试程序。使用您正在测试的函数位于另一个项目中,可以将该项目构建为动态或静态链接库。静态库在构建时链接到其他程序,并具有扩展名.lib,动态库在运行时链接,并具有扩展名.dll。对于我的回答,我会倾向于使用静态库。
您可以通过更改项目属性将第一个程序转换为静态库。在常规选项卡下应该有一项选项,用于将项目设置为构建可执行文件(.exe)。您可以将此更改为.lib.lib文件将构建到与.exe相同的位置。
UnitTest1项目中,您可以转到其属性,在类别“附加库目录”下的链接器选项卡中,添加指向MyProjectTest构建的路径。然后,在链接器-输入选项卡下的“附加依赖项”中,添加您的静态库名称,很可能是MyProjectTest.lib
这应该允许您构建项目。请注意,通过这样做,MyProjectTest将不是一个独立的可执行程序,除非根据需要更改其构建属性,否则将不太理想。

在“链接器->输入”选项卡中,我不得不为静态库添加前缀“(OutDir)”,即“$(OutDir)MyProjectTest.lib”,尽管“MyProject”和“MyTestProject”的位置都保持在同一个根文件夹中。 - Pabitra Dash
23
每次想运行单元测试时,您应该将被测试的项目转换为静态库,每次想要实际运行程序时,将其转换回可执行文件。这怎么成为一个解决方案呢? - A. Smoliak
1
如果MyProjectTest是一个dll,我们能测试它吗?我们只需添加导入库还是必须添加obj文件? - aviit
你可以通过更改项目属性将你的第一个程序转换为静态库。在“常规”选项卡下应该有一个选项,用于设置项目构建为可执行文件(.exe)。你可以将其更改为.lib。.lib文件将构建到与.exe相同的位置。对于我的情况来说,这样做已经足够了。其余的部分已经由VS处理好了。 - Ekrem Solmaz

42

在 Visual Studio 解决方案树中,右键单击项目“UnitTest1”,然后选择添加现有项,选择文件 ../MyProjectTest/function.cpp


4
请注意,实际的文件未被复制或移动到ProjDir。 - Laurie Stearn
该方法解决了在尝试将C++库添加到CLI项目时出现的类似问题。 - Deshan

24

为了让我的项目编译成独立的EXE文件,我将UnitTest项目链接到从function.cpp生成的function.obj文件,并且它可以工作。

右键单击 'UnitTest1' 项目 → 配置属性链接器输入附加依赖项添加“..\MyProjectTest\Debug\function.obj”。


1
当MyProjectTest是一个dll时怎么办?你能为它进行设置吗? - aviit
1
如果我们有许多obj文件,我们能否添加类似于*.obj的东西?您的解决方案对我有效,但我不想手动添加每个新的obj文件。 - aviit

11

我在使用Visual Studio 2013时遇到了这个问题。 显然,现在在同一解决方案中有两个项目并设置了它们之间的依赖关系是不够的。 您需要在它们之间添加项目引用。 要执行此操作:

  1. 右键单击解决方案资源管理器中的项目
  2. 选择“添加” => “引用...”
  3. 单击“添加新引用”按钮
  4. 选中该项目所依赖的项目的框
  5. 单击“确定”

1
设置依赖项是什么意思?我添加了引用,但它仍然报错。https://devblogs.microsoft.com/cppblog/cpp-testing-in-visual-studio/建议这样做就足够了。 - tschumann

9
原来我在使用 .c 文件和 .cpp 文件混淆了。将 .c 重命名为 .cpp 解决了我的问题。

8
另一种导致链接错误的方法(就像我遇到的那样)是如果你从DLL文件中导出一个类的实例,但没有将该类本身声明为import/export。
#ifdef  MYDLL_EXPORTS
   #define DLLEXPORT __declspec(dllexport)
#else
   #define DLLEXPORT __declspec(dllimport)
#endif

class DLLEXPORT Book // <--- This class must also be declared as export/import
{
    public:
        Book();
        ~Book();
        int WordCount();
};

DLLEXPORT extern Book book; // <-- This is what I really wanted, to export book object

因此,尽管我最初只是在导出称为bookBook类实例,但我还必须将Book类声明为导出/导入类,否则在其他DLL文件中调用book.WordCount()会导致链接错误。


3

配置属性常规字符集中检查两个项目的字符集。

我的UnitTest项目使用默认的字符集多字节,而我的库使用的是Unicode

我的函数使用一个TCHAR作为参数。

结果,在我的库中,我的TCHAR转换成了WCHAR,但在我的UnitTest中它是一个char*:最终参数不同,因此符号也不同。


2

我刚刚发现在Visual Studio 2015编译过程中,如果忘记为类内声明的函数提供定义,则会出现LNK2019

链接器错误非常难以理解,但是通过阅读错误信息,我确定了缺少的内容,并在类外部提供了定义,以解决这个问题。


在某些情况下,问题在于包含类定义的头文件都被很好地引用/包含,但是它们对应的cpp文件可能没有被链接器提供。最好的方法是在解决方案资源管理器中查看项目外部依赖项。不过,如果VS能够发出有关错误的文件存在/包含警告,那将会非常有益。 - Laurie Stearn

1

对我而言,如果在与头文件相连的cpp文件中的itemGroup添加以下行,则它可以正常工作。

<ClCompile Include="file.cpp" />

1
在Visual Studio 2017中,如果您想要测试公共成员,只需将真实项目和测试项目放在同一解决方案中,并在测试项目中添加对真实项目的引用即可。有关更多详细信息,请参见MSDN博客上的C++ Unit Testing in Visual Studio。您还可以查看为C/C++编写单元测试以及在Visual Studio中使用Microsoft Unit Testing Framework for C++,后者是如果您需要测试非公共成员并需要将测试放在与真实代码相同的项目中。
请注意,您想要测试的内容需要使用__declspec(dllexport)进行导出。有关更多详细信息,请参见使用__declspec(dllexport)从DLL导出

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接