LINUX.ORG.RU

C++ ld тупит, а может я..


0

0

$ make -f Makefile_srv
g++ -c -O0 -DDEBUG -static -g -Wno-deprecated -I../../include -I/usr/local/pgsql/include db2k_srv.cpp
g++  -o db2kd db2kd.o db2k_srv.o locallog.o -lpthread
db2k_srv.o: In function `new_allocator':
/home/mike/devel/sakt_2knew6.8/src/sakt_db2k_api/db2k_srv.cpp:43: multiple definition of `db2k_filetowrite'
db2kd.o:/home/mike/devel/sakt_2knew6.8/src/sakt_db2k_api/db2kd.cpp:412: first defined here
collect2: выполнение ld завершилось с кодом возврата 1
make: *** [db2kd] Ошибка 1

Ругается что у меня ultiple definition of `db2k_filetowrite', где db2k_filetowrite - это std::map <string, string> db2k_filetowrite;

В строках на которые указывает ld вообще нет ничего связанного с этим map'ом.. он объявлен совсем в другом файле..

Поможите, люди дабрые:)) Чего это ld на меня разозлился?

Ответ на: комментарий от tailgunner

Ну да, именно в заголовочном файле я его и определил. У нас в проекте так все глобальные структуры и переменные определены. Я не понял, что в этом такого? Больше ведь ни на что не ругается.

golodranez ★★★★
() автор топика
Ответ на: комментарий от golodranez

> Ну да, именно в заголовочном файле я его и определил.

То есть у тебя в заголовочном файле прям так и написано:

std::map <string, string> db2k_filetowrite;

да? Если да, то... без обид, ты на Си++ вообще работал?

Препроцессор вставит твой заголовочный файл в файлы с исходным кодом, и получится, что в каждом файле есть свое определение db2k_filetowrite. Понятно, что линкер скажет то, что он говорит.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Фигня какаято....

int sock_descr;
int finish_work_flag;
db2k_errorcode err_code;
char err_message[ERROR_MESSAGE_LENGTH];
char db2k_database_directory[255];
char db2k_database_logfilename[255];
db2k_byte_order byte_order;
char current_max_file_name[DB2K_NUMOF_TABLES][64];
time_t current_max_file_time[DB2K_NUMOF_TABLES];
char current_min_file_name[DB2K_NUMOF_TABLES][64];
time_t current_min_file_time[DB2K_NUMOF_TABLES];
char current_write_file_name[DB2K_NUMOF_TABLES][64];
time_t current_write_file_time[DB2K_NUMOF_TABLES];
char *data_to_write;
int data_to_write_ptr;
std::map <string, string> db2k_filetowrite;

И ругается ld только на db2k_filetowrite, почему тогда на остальные переменные не ругается?

И как он может вставить исходник во все файлы? Зачем тогда #ifndef в хедере?

golodranez ★★★★
() автор топика
Ответ на: комментарий от golodranez

> И как он может вставить исходник во все файлы?

если у тебя a.c и b.c и в каждом инклюдится хедер, то (ведь a.c и b.c компилируются независимо) в обоих объектниках будет одинаковый объект.

> Зачем тогда #ifndef в хедере?

для ситуаций когда один хедер инклюдит другой хедер. Например a.c инклюдит a.h и b.h, и b.h сам тоже инклюдит a.h. Тогда без ifdef получилось бы двукратное включение a.h в одну и ту же единицу компиляции.

dilmah ★★★★★
()
Ответ на: комментарий от golodranez

<ужоснах поскипан>

> ld только на db2k_filetowrite, почему тогда на остальные переменные не ругается?

Интересный вопрос. Скорее всего, всё это перемнные простых типов, и линкер их молча объединяет, а у db2k_filetowrite есть конструктор.

> И как он может вставить исходник во все файлы?

Добавь флаг -E и посмотри препроцессированный файл.

> Зачем тогда #ifndef в хедере?

Смотря какой. Скорее всего, для предотвращения повторного включения, что не имеет отношения к проблеме на руках.

tailgunner ★★★★★
()
Ответ на: комментарий от golodranez

:-) Так не бывает!

А где у тебя #ifndef?

#ifndef в начале хедера нужен для того, чтобы он 2 раза не включался, если рекурсивное включение имеется.

В твоем случае, скорее всего, он ругается на первую ошибку и отваливается.

Убери std::map <string, string> db2k_filetowrite; -- что будет?

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>Убери std::map <string, string> db2k_filetowrite; -- что будет?

Если убираю std::map <string, string> db2k_filetowrite; из хедера и всё что с ним связано из других файлов, то всё компилится.

А где его тогда объявлять, если не в хедере?

Например в хедере есть класс - 

//MyClass.h
class MyClass
{
   private:
       map <string, string> db2k_filetowrite;
   public:
       тут куча всякого
};
______________________________________

//MyClass.cpp
#include "MyClass.h"

тут реализация функций класса.
________________________________________

Если я не могу тут объявить вот так private переменную класса, то как её можно объявить?

golodranez ★★★★
() автор топика
Ответ на: комментарий от golodranez

> А где его тогда объявлять, если не в хедере?

Его там надо именно объявлять, а не определять. Поставь перед определением в хэдере extern, и положи объявление в какой-нибудь *.cc-файл.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

> Скорее всего, всё это перемнные простых типов, и линкер 
их молча объединяет, 

Интересно!

Мой линкер ругается на простые  int, и на все, не только 
не первую:

файл trymm.cpp:
int a=1;
int b=2;

int aa(void);
int bb(void);
int main(void)
{
   return aa()+bb();
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
файл aa.cpp:
int a=1;
int aa(void){
   return a;
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
файлbb.cpp:
int b=2;
int bb(void){
   return b;
}

$g++ aa.cpp bb.cpp trymm.cpp 
/tmp/ccADmzrD.o:(.data+0x0): multiple definition of `b'
/tmp/cc4z10st.o:(.data+0x0): first defined here
/tmp/ccADmzrD.o:(.data+0x4): multiple definition of `a'
/tmp/ccy8T72l.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status

Die-Hard ★★★★★
()
Ответ на: комментарий от tailgunner

Сделал примерно так - 

//MyClass.h
class MyClass
{
   private:
       extern map <string, string> db2k_filetowrite;
   public:
       тут куча всякого
};
______________________________________

$ make -f Makefile_srv
g++ -c -O0 -DDEBUG -static -g -Wno-deprecated -I../../include -I/usr/local/pgsql/include db2k_srv.cpp
db2k_srv.h:286: ошибка: storage class specified for ‘db2k_filetowrite’

???

golodranez ★★★★
() автор топика
Ответ на: комментарий от tailgunner

Ну а так как поступить? если я объявляю map как переменную класса, ld также ругается на множественные определения.

golodranez ★★★★
() автор топика
Ответ на: комментарий от tailgunner

> А если их не инициализировать?

То же самое!

Даже вообще не используемые, типа int a; int aa(void){return 1;} -- ругается!

Die-Hard ★★★★★
()
Ответ на: комментарий от golodranez

В хедере:

extern std::map <string, string> db2k_filetowrite;

И в каком-нибудь ОДНОМ cpp-файле (например globals.cpp):

std::map <string, string> db2k_filetowrite;

Аналогично для всех глобальных переменных.

Deleted
()
Ответ на: комментарий от golodranez

> Ну а так как поступить?

Поступить так: 0) вернуться к варианту программы, соотвествующему началу топика; 1) поместить extern перед объявлением db2k_filetowrite в заголовочном файле; 2) поместить определение db2k_filetowrite в db2k_srv.cpp; 3) скомпилировать и доложить об ошибках; 4) попросить у Die-Hard ссылку на учебник по Си++ и начать его читать.

tailgunner ★★★★★
()
Ответ на: комментарий от golodranez

> Ну а так как поступить?

Сказали же: в хедере объявляешь как extern, а то, что у тебя сейчас в хедере, помещаешь в один (ТОЛЬКО ОДИН) файл.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>> А если их не инициализировать?

> То же самое!

Сильно умные компоновщики пошли... какой линкер и какая версия?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Блин, но ведь на переменные простых типов вообще не ругается.

Щас проверю с первоначальным вариантом. И всёже, как быть если мне нужна переменная _класса_?

golodranez ★★★★
() автор топика
Ответ на: комментарий от tailgunner

> Сильно умные компоновщики пошли... какой линкер и какая версия?

Старый, кстати --не обновлялся несколько лет... ld -v: GNU ld version 2.16.91.0.2 20050720 (SuSE Linux)

Die-Hard ★★★★★
()
Ответ на: комментарий от golodranez

> И всёже, как быть если мне нужна переменная _класса_?

# Сказали же: в хедере объявляешь как extern, а то, что у тебя сейчас в хедере, помещаешь в один (ТОЛЬКО ОДИН) файл. Die-Hard (*) (05.05.2008 14:56:43)

Другой вариант объявить ее static, но тогда в разных единицах компиляции это будут разные объекты:)

dilmah ★★★★★
()
Ответ на: комментарий от tailgunner

Сделал как было изначально, добавил extern и определение в db2k_srv.cpp

/home/mike/devel/sakt_2knew6.8/src/sakt_db2k_api/db2k_srv.cpp:45: multiple definition of `db2k_filetowrite'
db2kd.o:/home/mike/devel/sakt_2knew6.8/src/sakt_db2k_api/db2kd.cpp:412: first defined here

Вот так.

golodranez ★★★★
() автор топика
Ответ на: комментарий от dilmah

db2k_srv.cpp:45 - Db2k_srv_interact::SetFinishFlag()
db2kd.cpp:412 - то вообще последняя строка в файле, так только "}" и всё.

В этих строчках вообще нет ничего связанного с db2k_filetowrite.

golodranez ★★★★
() автор топика
Ответ на: комментарий от Die-Hard

убрал - всё собралось и слинковалось.

Теперь остался только вопрос - как быть если мне нужна переменная класса? Как мне её объявлять и определять?

golodranez ★★★★
() автор топика
Ответ на: комментарий от dilmah

>там походу еще и cppшники инклудятся:)

Не инклудятся у меня cppшники:)

golodranez ★★★★
() автор топика
Ответ на: комментарий от golodranez

> убрал - всё собралось и слинковалось.

Это означает, что в твоем Makefile'е нпревильно прописаны (или вообще отсутствуют) зависимости.

>Теперь остался только вопрос - как быть если мне нужна переменная класса? Как мне её объявлять и определять?

В чем проблема? Точно так же! Объявляешь ее extern в хедере и инстанцируешь в одном файле.

Только недер с определением класса должен быть заинклужен раньше.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>В чем проблема? Точно так же! Объявляешь ее extern в хедере и инстанцируешь в одном файле.

Я уже так пробовал - 

Сделал примерно так - 

//MyClass.h
class MyClass
{
   private:
       extern map <string, string> db2k_filetowrite;
   public:
       тут куча всякого
};
______________________________________

$ make -f Makefile_srv
g++ -c -O0 -DDEBUG -static -g -Wno-deprecated -I../../include -I/usr/local/pgsql/include db2k_srv.cpp
db2k_srv.h:286: ошибка: storage class specified for ‘db2k_filetowrite’

golodranez ★★★★
() автор топика
Ответ на: комментарий от tailgunner

>Как обычно, без extern.

Без extern ругается на множественные объявления, как и раньше. На простые переменные типа -

private: int i;

не ругается, а на map ругается.

golodranez ★★★★
() автор топика
Ответ на: комментарий от golodranez

> class MyClass { private: extern map <string, string> db2k_filetowrite;

вернемся к вопросу, прозвучавшему в первых постах: "без обид, ты на Си++ вообще работал?"

dilmah ★★★★★
()
Ответ на: комментарий от golodranez

> Теперь остался только вопрос - как быть если мне нужна переменная класса? Как мне её объявлять и определять?

Совершенно не ясно что вам тут нужно. Приведите пример кода =).

Deleted
()
Ответ на: комментарий от dilmah

>вернемся к вопросу, прозвучавшему в первых постах: "без обид, ты на Си++ вообще работал?"

Блин, я конечно не обижаюсь, но так посоветовал Die-Hard :)) Я знаю что так делать нельзя, но попробовать стоило:) На си++ я работаю постоянно, с переменными простых типов таких проблем небыло никогда, тут понадобился map и на тебе:) И ещё, с++ я знаю плохо, я не отрицаю, занимаюсь в основном алгоритмами.

Вопрос в том, как её объявить в классе? если просто пишу private: map <string, string> db2k; то ругается линковщик.

golodranez ★★★★
() автор топика
Ответ на: комментарий от golodranez

> Вопрос в том, как её объявить в классе? если просто пишу private: map <string, string> db2k; то ругается линковщик.

без extern правильно. Теперь показывай как объявляются объекты типа MyClass.

dilmah ★★★★★
()
Ответ на: комментарий от golodranez

Глобальные переменные зло по определению.

Используй так называемый синглетон - заверни все глобальные переменные в с++ класс с единственным instance. Головной боли будет меньше на порядок.

vtVitus ★★★★★
()
Ответ на: комментарий от dilmah

>Теперь показывай как объявляются объекты типа MyClass.

Не совсем понял..

Db2k_srv_interact *serv = 0;
serv = new Db2k_srv_interact;

Вот так объявляется объект у меня.

golodranez ★★★★
() автор топика
Ответ на: комментарий от vtVitus

>> Синглтоны зло.

> Не зло, а костыль.

Ненужный костыль. Нефиг тащить жабовские привычки в Си++.

> Зло это с++

Его нечем заменить там, где он действительно нужен.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Линкер ругается если я пишу -

//MyClass.h

class MyClass { private: map<string, string> db2k; ... bla-bla-bla... };

ld говорит - multiple definition

golodranez ★★★★
() автор топика
Ответ на: комментарий от tailgunner

>Ненужный костыль. Нефиг тащить жабовские привычки в Си++.

?? Для глобальных переменных самое то. Особенно, когда глобальные переменные начинают зависеть от друг дружки и располагаться в разных модулях компиляции.

>Его нечем заменить там, где он действительно нужен.

4.2 Его везде можно заменить.

vtVitus ★★★★★
()
Ответ на: комментарий от golodranez

> ...но так посоветовал Die-Hard :))

Фигасе! В отвечал на вопрос: "...если мне нужна переменная класса? Как мне её объявлять и определять?". Это -- СОВСЕМ ДРУГОЙ вопрос!

> если просто пишу private: map <string, string> db2k; то ругается линковщик.

Так не бывает!

Убери опять все объектные файлы и повтори процедуру с private: map <string, string> db2k;

Die-Hard ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.