Як вирішити помилку LNK2019: невирішений зовнішній символ - функція?


99

Я отримую цю помилку, але не знаю, як її виправити.

Я використовую Visual Studio 2013. Я створив ім'я рішення MyProjectTest Це структура мого тестового рішення:

Структура

- функція.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 Рішення: Додати до рішення Потім місце розташування автоматично переключилося на шлях поточного відкритого рішення Це структура папок рішення:

Структура папок

Я лише відредагував файл 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, і я замінив декларацію визначенням, і він запустився. Але писати декларацію та визначення в одному файлі не рекомендується. Як я можу виправити цю помилку, не роблячи цього? Чи слід замінити #include "../MyProjectTest/function.cpp"на файл unittest.cpp? (Я не дуже добре володію англійською мовою. Дякую)



6
ОБЕРЕЖНО У середовищі Windows статичні бібліотеки мають .LIBрозширення файлу. Щоб ускладнити ситуацію ... бібліотеки динамічних посилань (тобто *.DLL) можуть мати супровідну бібліотеку імпорту, яка також має .LIBрозширення файлу. У цій бібліотеці імпорту перераховані всі смаколики, надані *.DLL. Для отримання додаткової інформації, будь ласка, прочитайте: Посібник для початківців до
лінкерів

4
Чому він повинен бути обережним ??
маршал ремесла

Відповіді:


80

Одним із варіантів було б включити function.cppу свій UnitTest1проект, але це може бути не найбільш ідеальна структура рішення. Коротка відповідь на вашу проблему полягає в тому, що під час побудови вашого UnitTest1проекту компілятор та компонувальник не мають уявлення про те, що function.cppіснує, а також не мають чого посилатись, що містить визначення multiple. Спосіб виправити це - використання посилань на бібліотеки.

Оскільки ваші модульні тести перебувають в іншому проекті, я припускаю, що ви маєте намір зробити цей проект автономною програмою модульного тестування. За допомогою функцій, які ви тестуєте, розташованих в іншому проекті, можна побудувати цей проект як у динамічно, так і у статично пов’язаній бібліотеці. Статичні бібліотеки пов'язані з іншими програмами під час побудови та мають розширення .lib, а динамічні бібліотеки пов'язані під час виконання та мають розширення .dll. Для моєї відповіді я віддаю перевагу статичним бібліотекам.

Ви можете перетворити свою першу програму на статичну бібліотеку, змінивши її у властивостях проектів. На вкладці Загальне має бути параметр, де проект налаштовано на створення виконуваного файлу ( .exe). Ви можете змінити це на .lib. .libФайл буде будувати на те саме місце, що і .exe.

У своєму UnitTest1проекті ви можете перейти до його властивостей, а на вкладці Linker у категорії Додаткові каталоги бібліотеки додати шлях до якого MyProjectTestбудуються. Потім для додаткових залежностей на вкладці Linker - Input додайте, швидше за все, назву вашої статичної бібліотеки MyProjectTest.lib.

Це має дозволити вашому проекту будуватись. Зверніть увагу, що, роблячи це, MyProjectTestне буде автономною виконуваною програмою, якщо ви за необхідності не зміните її властивості збірки, що було б менш ніж ідеально.


У "Linker-> Input Tab" мені потрібно було вставити префікс "(OutDir)" для статичної бібліотеки, тобто "$ (OutDir) MyProjectTest.lib", хоча розташування "MyProject" і "MyTestProject" зберігалося в одній кореневій папці .
Pabitra Dash

13
Отже, кожного разу, коли ви хочете запускати модульні тести, ви повинні перетворити свій проект тестування в статичну бібліотеку, і кожен раз, коли ви насправді хочете запустити свою програму, ви перетворюєте його назад у виконуваний файл, як це рішення?
А. Смоляк

1
Якщо MyProjectTest - це dll, чи можемо ми його перевірити? Ми просто додаємо імпорт lib або ми повинні додати файли obj?
aviit

"Ви можете перетворити свою першу програму на статичну бібліотеку, змінивши її у властивостях проектів. На вкладці" Загальне "має бути параметр, де проект налаштовано на створення виконуваного файлу (.exe). Ви можете змінити це на .lib Файл .lib буде побудований там же, де і .exe "" Це було достатньо для мого випадку. Рештою вже займався В.С.
Екрем Солмаз

39

У дереві рішень Visual Studio клацніть правою кнопкою миші на проекті 'UnitTest1', потім Додати -> Існуючий елемент -> виберіть файл ../MyProjectTest/function.cpp


4
Зверніть увагу, що фактичні файли не копіюються та не переміщуються до ProjDir.
Laurie Stearn

Цей метод вирішив подібні проблеми, що виникали при спробі додати c ++ lib до проекту CLI.
Дешан

17

Оскільки я хочу, щоб мій проект скомпілювався до автономного EXE, я зв’язав проект UnitTest із файлом function.obj, згенерованим із function.cpp, і він працює. Клацніть правою кнопкою миші на проекті "UnitTest1"> Властивості конфігурації> Посилання> Введення> Додаткові залежності> додайте ".. \ MyProjectTest \ Debug \ function.obj"


1
Як щодо випадку, коли MyProjectTest - це dll? Чи можете ви налаштувати це?
aviit

Якщо у нас багато файлів obj. ми можемо додати щось подібне * .obj? Ваше рішення працювало зі мною, але я не хочу вручну додавати кожен новий файл obj.
aviit

10

Я щойно зіткнувся з цією проблемою у Visual Studio 2013. Очевидно, зараз мати два проекти в одному рішенні та встановити залежності недостатньо. Вам потрібно додати посилання на проект між ними. Для цього:

  1. Клацніть правою кнопкою миші на проекті в дослідженні рішення
  2. Натисніть Додати => Посилання ...
  3. Натисніть кнопку Додати нове посилання
  4. Установіть прапорці для проектів, на які покладається цей проект
  5. Клацніть OK

Що ви маєте на увазі під встановленням залежностей? Я додав посилання, але воно все одно скаржилось. devblogs.microsoft.com/cppblog/cpp-testing-in-visual-studio припустив, що цього буде достатньо.
tschumann

8

виявилось, що я використовую файли .c із файлами .cpp. перейменування .c на .cpp вирішило мою проблему.


6

Інший спосіб отримати цю помилку компонувальника (як я був) - це якщо ви експортуєте екземпляр класу з dll, але не оголосили цей клас як імпорт / експорт.

 #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

Отже, хоча в першу чергу я експортував лише екземпляр класу Book, названий bookвище, мені довелося оголосити Bookклас як клас експорту / імпорту, а в іншому випадку виклик book.WordCount()в іншій dll викликав помилку посилання.


2

Це сталося зі мною, тому я подумав, що можу поділитися своїм рішенням, настільки простим, наскільки це було:

Перевірте набір символів обох проектів у Властивості конфігурації -> Загальне -> Набір символів

Мій проект UnitTest використовував багатобайтовий набір символів за замовчуванням, тоді як мої бібліотеки знаходились в Unicode .
Моя функція використовувала TCHAR як параметр. В результаті в моїй бібліотеці мій TCHAR був перетворений на WCHAR, але це був символ * на моєму UnitTest: символ був іншим, оскільки параметри насправді були не однакові в підсумку.


1

Я щойно виявив, що LNK2019відбувається під час компіляції у Visual Studio 2015, якщо забув надати визначення для оголошеної функції всередині класу.

Помилка компонувальника була дуже загадковою, але я звузив те, чого не вистачало, прочитавши помилку і надавши визначення поза класом, щоб це прояснити.


Проблема в деяких випадках полягає в тому, що на заголовки, що містять клас defs, добре посилаються / включаються, але відповідні CPP можуть не бути доступними для лінкера. Найкращий спосіб перевірки - це перегляд зовнішніх залежностей проекту у Провіднику рішень. Для VS було б вигідно видати якесь попередження про існування файлу / включення щодо помилки.
Laurie Stearn

1

у моєму випадку встановіть для файлу cpp значення "Компілятор C / C ++" у властивості -> загальне вирішення помилки LNK2019.


0

Для мене працює, якщо я додаю цей рядок , наведену нижче в .vcxprojв itemGroupCPP файл, який підключений до заголовків файлів.

<ClCompile Include="file.cpp" />

0

У Visual Studio 2017, якщо ви хочете протестувати публічних учасників, просто помістіть свій реальний проект і тестовий проект в одне і те ж рішення та додайте посилання на ваш реальний проект у тестовому проекті.

Докладніше див. У розділі Тестування модулів C ++ у Visual Studio із блогу MSDN. Ви також можете перевірити Написати модульні тести для C / C ++ у Visual Studio , а також скористатися Microsoft Unit Testing Framework для C ++ у Visual Studio , останній, якщо вам потрібно протестувати непублічних членів і потрібно поставити тести в одному проекті як ваш реальний код.

Зверніть увагу, що речі, які ви хочете протестувати, потрібно експортувати за допомогою __declspec(dllexport). Докладніше див. У розділі Експорт із DLL за допомогою __declspec (dllexport) .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.