C++ Новичок в Linker Hell


Использование g++ и наличие ошибок компоновщика. У меня есть простая программа, разделенная на два модуля: main.cpp и кости.h кости.СРР.

Главная.cpp:

#include <iostream>
#include "Dice.h"

int main(int argc, char **argv) {

    int dieRoll = Dice::roll(6);
    std::cout<<dieRoll<<std::endl;

    std::cin.get();

    return 0;
}

Кости.h:

#ifndef DieH
#define DieH

namespace Dice
{
    int roll(unsigned int dieSize);
}

#endif

Кости.cpp:

#include <ctime>
#include <cstdlib>
#include "Dice.h"

namespace Dice
{
    int roll(unsigned int dieSize)
    {
        if (dieSize == 0)
        {
            return 0;
        }
        srand((unsigned)time(0));
        int random_int = 0;
        random_int = rand()%dieSize+1;

        return random_int;
    }
}

Я компилирую и связываю эти файлы с помощью g++ следующим образом:

g++ -o program main.cpp Dice.cpp

И я получаю следующую ошибку компоновщика:

Undefined symbols:
"Dice::roll(int)", referenced from:
  _main in ccYArhzP.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

Я совершенно сбита с толку. Любая помощь будет очень признательна.

3 2

3 ответа:

Ваш код хорошо сформирован.

Убедитесь, что у вас нет конфликтующих имен файлов, файлы существуют и содержат то, что вы думаете, что они делают. Например, возможно, у вас есть Dice.cpp, который пуст, и вы редактируете недавно созданный где-то в другом месте.

Сведите к минимуму возможные расхождения, удалив ненужные файлы; есть только main.cpp, dice.h, и dice.cpp.

Ваши ошибки не соответствуют вашему коду: "Dice::roll(int)". Обратите внимание, что это ищет int, но ваши функции принимают unsigned int. Убедитесь, что ваш заголовок совпадает.


Попробуйте следующее:

g++ main.cpp -c

Это создаст main.o, скомпилированный, но не связанный код для main. Сделайте то же самое с dice.cpp:

g++ dice.cpp -c

Теперь у вас есть два объектных файла, которые необходимо связать вместе. Сделайте это с помощью:

g++ main.o dice.o

И посмотреть, если это работает. Если нет, сделайте следующее:

nm main.o dice.o

Это перечислит все доступные символы в объекте, и должно дать вам что-то вроде этого:

main.o:
00000000 b .bss
00000000 d .ctors
00000000 d .data
00000000 r .eh_frame
00000000 t .text
00000098 t __GLOBAL__I_main
00000069 t __Z41__static_initialization_and_destruction_0ii
         U __ZN4Dice4rollEj
         U __ZNSi3getEv
         U __ZNSolsEPFRSoS_E
         U __ZNSolsEi
         U __ZNSt8ios_base4InitC1Ev
         U __ZNSt8ios_base4InitD1Ev
         U __ZSt3cin
         U __ZSt4cout
         U __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
00000000 b __ZStL8__ioinit
         U ___gxx_personality_v0
         U ___main
00000055 t ___tcf_0
         U _atexit
00000000 T _main

dice.o:
00000000 b .bss
00000000 d .data
00000000 t .text
00000000 T __ZN4Dice4rollEj
         U _rand
         U _srand
         U _time

C++ искажает имена функций, поэтому все выглядит так странно. (Обратите внимание, что не существует стандартного способа искажения имен, это делает GCC 4.4).

Обратите внимание, что dice.o и main.o относятся к одному и тому же символу: __ZN4Dice4rollEj. Если они не совпадают, это ваша проблема. Например, если я изменю часть dice.cpp следующим образом:
// Note, it is an int, not unsigned int
int roll(int dieSize)

Затем nm main.o dice.o производит следующее:

main.o:
00000000 b .bss
00000000 d .ctors
00000000 d .data
00000000 r .eh_frame
00000000 t .text
00000098 t __GLOBAL__I_main
00000069 t __Z41__static_initialization_and_destruction_0ii
         U __ZN4Dice4rollEj
         U __ZNSi3getEv
         U __ZNSolsEPFRSoS_E
         U __ZNSolsEi
         U __ZNSt8ios_base4InitC1Ev
         U __ZNSt8ios_base4InitD1Ev
         U __ZSt3cin
         U __ZSt4cout
         U __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
00000000 b __ZStL8__ioinit
         U ___gxx_personality_v0
         U ___main
00000055 t ___tcf_0
         U _atexit
00000000 T _main

dice.o:
00000000 b .bss
00000000 d .data
00000000 t .text
00000000 T __ZN4Dice4rollEi
         U _rand
         U _srand
         U _time
Обратите внимание, что это дает два разных символа. main.o ищем это: __ZN4Dice4rollEj и dice.o содержащий это __ZN4Dice4rollEi. (Последняя буква отличается).

При попытке скомпилировать эти несовпадающие символы (с g++ main.o dice.o), я получаю:

undefined reference to `Dice::roll(unsigned int)'

Ваша проблема заключается в том, что вы вызываете Dice::roll(int) и вы написали функцию Dice::roll(unsigned int). Функция, которую он ищет, на самом деле не существует (внутренне типы аргументов функции имеют такое же значение, как и ее имя; именно так работает перегрузка). Попробуйте передать ему unsigned int (6u, например) и посмотрите, работает ли это. Кроме того, ваш заголовочный файл может не совпадать как в файлах, так и в основном.cpp считает, что ваша функция принимает (signed) int.

Я знаю, что вы не хотите слышать ничего подобного, но "это работает для меня!".

Ваши ошибки выглядят подозрительно старыми - какую версию GCC вы используете? Это похоже на GCC 2.х! Кроме того, попробуйте ввести dieRoll в main.cpp как unsigned, что может решить проблему пространства имен на этом старом компиляторе.