clang: ошибка: команда компоновщика завершилась неудачно с кодом выхода 1 (используйте -v, чтобы увидеть вызов) *о глобальных переменных

У меня проблема с компиляцией файлов. Я скомпилировал и получил это сообщение

"Undefined symbols for architecture x86_64:
"_airport_label", referenced from:
  FlightMap::pathfind_before(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> > const&,             
std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> > const&) in FlightMap-9a7ab0.o
  FlightMap::pathfind(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> > const&,  
std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> > const&) in FlightMap-9a7ab0.o
"_dijkstra", referenced from:
  FlightMap::findShortestRoute(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> > const&, 
std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> > const&) in FlightMap-9a7ab0.o
  FlightMap::pathfind_before(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> > const&, 
std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> > const&) in FlightMap-9a7ab0.o
  FlightMap::fun_dijkstra(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> > const&) in FlightMap-9a7ab0.o
 (maybe you meant: __ZN9FlightMap12fun_dijkstraERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE)
"_distance_label", referenced from:
  FlightMap::pathfind_before(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> > const&, 
std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> > const&) in FlightMap-9a7ab0.o
  FlightMap::pathfind(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> > const&, 
std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> > const&) in FlightMap-9a7ab0.o
"_path", referenced from:
FlightMap::pathfind(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> > const&, 
std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> > const&) in FlightMap-9a7ab0.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)"

Я думаю, что есть некоторые проблемы с глобальной переменной в файле FlightMap.h.
(я редактировал Flight.h -> FlightMap.h) Я объявил 4 глобальные переменные типа

stack<string> path;
map<string, string > airport_label;
map<double, string > distance_label;
map<string, double > dijkstra;

Я уже пытался поставить "extern" перед каждой глобальной переменной, но это не работает.

В коде файла FlightMap.h (отредактированный Flight.h -> FlightMap.h)

#ifndef LAB6_FLIGHTMAP_H
#define LAB6_FLIGHTMAP_H

#include <iostream>
#include <string>
#include <stdexcept>
#include <map>
#include <list>
#include <vector>
#include <stack>
#include "AdjacencyListDirectedGraph.h"

 extern stack<string> path;
 extern map<string, string > airport_label;
 extern map<double, string > distance_label;
 extern map<string, double > dijkstra;
 .
 .
 .

Кроме того, эти глобальные переменные используются в файле FlightMap.cpp (я редактировал!)

я думаю тут и проблемы


person Community    schedule 03.07.2019    source источник
comment
Как вы его компилируете? Flight.cpp или Flight.o включены в командную строку?   -  person Ted Lyngmo    schedule 03.07.2019
comment
Кроме того, пожалуйста, выберите один из g++ или clang (или ни одного, так как речь идет не о конкретном компиляторе).   -  person Acorn    schedule 03.07.2019
comment
Я пытался выполнить g++ -std=c++11 -O2 -Wall %s FlightMap.cpp %s -o %s, но ошибка говорит clang:error...   -  person    schedule 03.07.2019
comment
В первую очередь вы получили эту ошибку не при компиляции, а при компоновке. Это очень важная деталь для понимания вашей проблемы.   -  person Slava    schedule 03.07.2019
comment
Вы пытаетесь просто скомпилировать FlightMap.cpp в объектный файл? Тогда вам не хватает параметра -c. Без clang или gcc пытается собрать исполняемый файл   -  person Slava    schedule 03.07.2019
comment
Любое количество ссылок подскажет вам, как правильно объявлять и определять глобальные переменные. Важным моментом является то, что вы объявляете их в Flight.h с помощью extern, а также определяете их в Flight.cpp без использования extern. Вам нужно сделать оба. Это не сложно, но не то, что вы, вероятно, получите правильно, угадав.   -  person john    schedule 03.07.2019
comment
@john Вау, я решил проблему. Я объявил глобальные переменные с помощью extern в FlightMap.h, а также объявил без extern в FlightMap.cpp. Могу ли я получить какое-то объяснение, почему я могу устранять ошибки?   -  person    schedule 03.07.2019
comment
Вы объявили с помощью extern, но определили без него. Каждой переменной/функции требуется ровно одно определение (но может быть любое количество объявлений, включая ноль, если они соответствуют друг другу).   -  person Radosław Cybulski    schedule 03.07.2019
comment
@rocketsssss Вы должны понимать разницу между объявлениями и определениями. С extern это объявление, без определения. Ваша глобальная переменная должна быть определена ровно один раз. Таким образом, вы помещаете определение в один файл cpp. Но ваши глобальные переменные могут быть объявлены столько раз, сколько вам нужно, поэтому вы помещаете объявления в заголовочный файл, где их можно включать много раз, не получая множественных ошибок определения. Все, что нужно компилятору, чтобы сгенерировать код, — это объявление, но компоновщику нужно увидеть ровно одно определение, чтобы связать программу.   -  person john    schedule 03.07.2019
comment
@rocketsssss Таким образом, приведенный выше метод поддерживает компилятор и компоновщик.   -  person john    schedule 03.07.2019


Ответы (1)


Используйте полные имена в объявлениях вашего заголовочного файла:

#ifndef LAB6_FLIGHTMAP_H
#define LAB6_FLIGHTMAP_H

//#includes ...

extern std::stack<std::string> path;
extern std::map<std::string, std::string> airport_label;
extern std::map<double, std::string> distance_label;
extern std::map<std::string, double> dijkstra;
...
#endif

И в FlightMap.cpp вам нужно определить эти глобальные переменные:

std::stack<std::string> path;
std::map<std::string, std::string> airport_label;
std::map<double, std::string> distance_label;
std::map<std::string, double> dijkstra;

extern сообщает компилятору, что переменная будет определена где-то в другой единице трансляции, и оставляет решение этого вопроса компоновщику. Компоновщик теперь должен найти определение в любом из скомпилированных файлов, но не может, так как определения нигде нет. Поместив определение (то есть без extern) в один файл (и только в один файл), компоновщик будет счастлив.

person Ted Lyngmo    schedule 03.07.2019
comment
Спасибо за ваше учение! У меня есть быстрый вопрос. Насколько я знаю, extern используется, когда я объявляю некоторые глобальные переменные в исходном файле и использую их в другом исходном файле. Но в этой ситуации я объявил глобальные переменные в FlightMap.h и использовал их в FlightMap.cpp. Несмотря на эту ситуацию, должен ли я использовать ключевое слово extern? - person ; 03.07.2019
comment
extern обычно используется в файле .h или .hpp, который предполагается использовать более чем в одном файле .cpp, или если сами переменные упоминаются в заголовке. Переменные, объявленные таким образом, могут затем использоваться во всех файлах .cpp, включающих этот файл .h/.hpp. Однако только один .cpp должен фактически определять переменные. - person Ted Lyngmo; 03.07.2019