LINUX.ORG.RU

[cmake] [мольба] В одном месте не получается использовать конструкторы класса

 


0

1

Граждане, какая-то жесть. Уже много часов тщетно пытаюсь выловить баг.

Суть такова: есть класс. Его хедер в src/soils/soil.h. У него есть конструктор. Так вот этот самый конструктор получается использовать, только если исходник, в котором он используется, лежит в src/ или src/soils.

Почему такое может быть? Все остальные методы используются нормально, а конструктор — ни-ни, ld ругается, мол undefined reference to `qfgui::Soil::Soil(...)'.

Уверен, что что-то накосячил с cmake, но там всё хорошо выглядит. Что не так-то? :(

Может, кто-нибудь на свежую голову найдёт проблему? Вот проект: http://obey.su/qfrost.tar.gz. Проблема в undo/newsoilcommand.cpp, не выходит использовать конструкторы класса Soil.

★★★★★

Даже так: в src/, src/soils/ и некоторых других директориях конструкторы Soil можно использовать без проблем, а в некоторых не выходит.

Obey-Kun ★★★★★
() автор топика

Да, кстати, это тот самый проект, который я вот уже больше года пилю. Я начал изучать C++ и Qt, взявшись за него.

И ЛОР мне с ним очень помог, за что я всем очень благодарен.

Obey-Kun ★★★★★
() автор топика

Давненько не приходилось писать на C++, но не нужно ли было при реализации метода заодно указывать и namespace, т.е., в soil.cpp заменить Soil::Soil(const QString &name..) на qfgui::Soil::Soil(const QString &name...) ?

Kirakishou
()

> Все остальные методы используются нормально, а конструктор — ни-ни

Это потому что остальные медоты определены «на месте», в soil.h, и для их использвания не нужно дополнительно ни с чем линковаться.

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

Даже есть перенести реализацию метода в хедер, не работает.

но не нужно ли было при реализации метода заодно указывать и namespace

Там using.

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

Вот так дела! Стоит добавить использование конструктора в SoilsModel, так ошибка исчезает. Что за бред?

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

> Вот так дела! Стоит добавить использование конструктора в SoilsModel, так ошибка исчезает. Что за бред?

Серьёзно, стоит только добавить использование любого конструктора Soil в любое место SoilsModel, и ошибка исчезает. Почему так?

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

Стоит добавить такую конструкцию в конструктор SoilsModel:

    if (time(NULL) == 100) {
        return;
    }
    new Soil(nextName(), nextColor(), this);

... и всё компилируется. Кто-нибудь может мне объяснить, что это за бред?

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

> ничего не стало ясно

Не понимаю.
Вы уверены, что дело в cmake. make VERBOSE=1 показывает Вам командные строки для компилятора и линкера. Причем тут cmake?

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

Я там не увидел ничего странного.

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

Undefined reference to vtable

Исходники не смотрел, но знаю, что это происходит, например, когда у материнского класса есть чисто-виртуальный(pure virtual) метод в поле public:

public:
   virtual void pure_virtual_ololo() = 0;

и вы его не имплементировали в дочернем классе(а это обязательно надо сделать).

Ещё один источник ошибки: вы могли забыть указать заголовочный файл в файлах проекта (*.pro, например), для Qt4 это важно. Советую только qmake, меньше боли в неудобных местах.

blinkenlichten
()
Ответ на: комментарий от Obey-Kun

>> Давненько не приходилось писать на C++, но не нужно ли было при реализации метода заодно указывать и namespace, т.е., в soil.cpp заменить Soil::Soil(const QString &name..) на qfgui::Soil::Soil(const QString &name...) ?

Там using.

Смутно помнится, что using это для юзания, а когда тушка метода пишется ее надо завертывать в namespace. Представьте что у Вас два usinga стоят, как компайлер угадает из какого namespace Вы метод определяете?

Скорей всего у линкера как раз и не хватает телепатических способностей (поскольку ошибка его), а вот если Вы этот метод где то еще явно юзаете, он его как то опознает.

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

и вы его не имплементировали в дочернем классе

В данном случае «не имплементировали» означает «объявили, но не определили». А вообще за что вы так русский язык ненавидите?

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

Скорей всего у линкера как раз и не хватает телепатических способностей

using до линкера вообще не доходит.

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

Полагаю, что англицизмы сильно укоренились в моём понимании программирования ввиду частого чтения документации на английском языке.
Русский язык не изучал, т.к. не есть гражданин РФ, поэтому не всегда удается найти правильные слова :-)

blinkenlichten
()

у меня собралось, только warnings было миллион

/usr/include/qt4/QtCore/qlist.h:399: warning: will never be executed
/usr/include/qt4/QtCore/qlist.h:399: warning: will never be executed
/usr/include/qt4/QtCore/qlist.h:399: warning: will never be executed
/usr/include/qt4/QtCore/qlist.h:399: warning: will never be executed
...

former_anonymous ★★★
()

У меня не дошло до твоих ошибок. У тебя в проекте буст древний или как-то ты его не так приготовил.

In file included from /tmp/qfrost/src/../libs/boost/geometry/algorithms/overlay/get_turns.hpp:53:0,
                 from /tmp/qfrost/src/../libs/boost/geometry/algorithms/equals.hpp:51,
                 from /tmp/qfrost/src/../libs/boost/geometry/iterators/segment_iterator.hpp:26,
                 from /tmp/qfrost/src/../libs/boost/geometry/algorithms/centroid.hpp:25,
                 from /tmp/qfrost/src/../libs/boost/geometry/geometry.hpp:39,
                 from /tmp/qfrost/src/geometry/boost_geometry_adaptation.h:23,
                 from /tmp/qfrost/src/geometry/block_within_polygon.h:23,
                 from /tmp/qfrost/src/computations/computationthread.cpp:26:
/tmp/qfrost/src/../libs/boost/geometry/algorithms/sectionalize.hpp: In function ‘void boost::geometry::sectionalize(const Geometry&, Sections&)’:
/tmp/qfrost/src/../libs/boost/geometry/algorithms/sectionalize.hpp:572:9: error: could not convert template argument ‘max_segments_per_section’ to ‘long unsigned int’
/tmp/qfrost/src/../libs/boost/geometry/algorithms/sectionalize.hpp:572:29: error: invalid type in declaration before ‘;’ token
/tmp/qfrost/src/../libs/boost/geometry/algorithms/sectionalize.hpp:575:31: error: invalid use of qualified-name ‘::apply’

Убрал слишком крутые оптимизации(это не для моей системы)

-set (MY_OPTIMISATION_FLAGS -march=core2 -mssse3 -msse4.1 -mcx16 -pipe -fomit-frame-pointer )
+set (MY_OPTIMISATION_FLAGS -march=native -pipe -fomit-frame-pointer )

Обо мне

user@host:/tmp/qfrost$ uname -a
Linux host 2.6.38-2-amd64 #1 SMP Thu Apr 7 04:28:07 UTC 2011 x86_64 GNU/Linux
user@host:/tmp/qfrost$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.0-2' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-gold --enable-ld=default --with-plugin-ld --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.1 20110329 (prerelease) (Debian 4.6.0-2) 

gogi
()
Ответ на: комментарий от former_anonymous

> /usr/include/qt4/QtCore/qlist.h:399: warning: will never be executed

Это в кьютовских хедерах косяк.

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

Он лежит у меня в libs, но требует большую версию буста, видимо

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от blinkenlichten

Не люблю слово это, действительно мистика.
Какая архитектура OS? Можно предоставить полный лог сборки проекта?

obey@damnbook ~ % uname -a
Linux damnbook 2.6.38-ARCH #1 SMP PREEMPT Wed Mar 30 08:47:36 CEST 2011 x86_64 Intel(R) Core(TM)2 Solo CPU U3500 @ 1.40GHz GenuineIntel GNU/Linux
obey@damnbook ~ % gcc -v
Используются внутренние спецификации.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/lto-wrapper
Целевая архитектура: x86_64-unknown-linux-gnu
Параметры конфигурации: /build/src/gcc-4.5-20110127/configure --prefix=/usr --enable-languages=c,c++,fortran,objc,obj-c++,ada --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-gnu-unique-object --enable-lto --enable-plugin --enable-gold --with-plugin-ld=ld.gold --disable-multilib --disable-libstdcxx-pch --with-system-zlib --with-ppl --with-cloog --with-cloog-include=/usr/include/cloog-ppl --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info
Модель многопоточности: posix
gcc версия 4.5.2 20110127 (prerelease) (GCC)

http://paste.kde.org/13663/

Да, только что версию проекта по ссылке из топика обновил до текущей.

Obey-Kun ★★★★★
() автор топика

> undefined reference to `qfgui::Soil::Soil(...)'

ld сначала должен увидеть библиотеку, которая использует символ, и только потом - библиотеку, которая этот символ определяет. Возможно косяк в том, что не прописаны где нужно traget_link_libaries, вот cmake и скармливает их линкеру в неправильном порядке..

Стоит добавить такую конструкцию ... и всё компилируется.


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

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

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

Надо было писать не «make», а «make VERBOSE=1».

Ещё вроде в CMakelists.txt можно будет вставить:

set ( CMAKE_VERBOSE_MAKEFILE ON )
Это будет тоже самое.

pathfinder ★★★★
()

В общем там такая ситуация. Есть библиотека libqfrost_undo.a, которая зависит от libqfrost_soils.a. А libqfrost_soils.a в свою очередь зависит от libqfrost_undo.a. Ну ты понел, рекурсия.

Хотя я сам никогда не сталкивался с подобными ситуациями. Не знаю, как линкер должен обрабатывать такие ситуации.

pathfinder ★★★★
()

Если у тебя такая перекрестная зависимость, то может не стоит делать кучу библиотек, и потом склеивать их в бинарник, а сразу делать бинарник.

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

> Не знаю, как линкер должен обрабатывать такие ситуации.

Чтобы ld такое обработал, ему нужно скормить эти либы по нескольку раз, чередуя. Сомневаюсь, что это можно нормально сделать в cmake.

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

--library=archive Add archive file archive to the list of files to link. This option may be used any number of times. ld will search its path-list for occurrences of «lib archive .a» for every archive specified.

On systems which support shared libraries, ld may also search for libraries with extensions other than ".a". Specifically, on ELF and SunOS systems, ld will search a directory for a library with an extension of ".so" before searching for one with an extension of ".a". By convention, a ".so" extension indicates a shared library.

The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again.

See the -( option for a way to force the linker to search archives multiple times.

You may list the same archive multiple times on the command line.

This type of archive searching is standard for Unix linkers. However, if you are using ld on AIX , note that it is different from the behaviour of the AIX linker.

Вроде бы все так, как Manhunt сказал. Может надо в target_link_libraries несколько раз одну и ту же библиотеку указать, или воспользоваться опцией -(

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

А почему обычные методы там получается использовать?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Manhunt

Насколько я понял, тут получается так, что у меня не выходит использовать только глобальные методы и конструкторы. А прочее используется нормально. Разве тут может быть линкер виноват?

Причём если заюзать конструктор от Soil в любом месте входящего в libsoil, оно компилит всё нормально.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Sorcerer

Можешь подсказать, как в моём случае поступить? Исходники с CMakeLists.txt по ссылке в топике.

Obey-Kun ★★★★★
() автор топика
 
[ 11%] Building CXX object src/soils/CMakeFiles/qfrost_soils.dir/parseredit.cpp.o
In file included from /home/user/Downloads/qfrost/src/soils/parseredit.cpp:29:0:
/home/user/Downloads/qfrost/src/soils/parser.h:23:22: фатальная ошибка: muParser.h: Нет такого файла или каталога
Компиляция прервана.
make[2]: *** [src/soils/CMakeFiles/qfrost_soils.dir/parseredit.cpp.o] Ошибка 1
make[1]: *** [src/soils/CMakeFiles/qfrost_soils.dir/all] Ошибка 2
make: *** [all] Ошибка 2

Система:

[bastilie 16] ~/Downloads/qfrost/build > uname -a 
Linux bastilie 2.6.37.6-smp #2 SMP Thu Apr 7 08:48:45 CDT 2011 i686 

Intel[bastilie 18] ~/Downloads/qfrost/build > gcc -v      
Спецификации прочитаны из /usr/lib/gcc/i486-slackware-linux/4.5.2/specs
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i486-slackware-linux/4.5.2/lto-wrapper
Целевая архитектура: i486-slackware-linux
Параметры конфигурации: ../gcc-4.5.2/configure --prefix=/usr --libdir=/usr/lib --mandir=/usr/man --infodir=/usr/info --enable-shared --enable-bootstrap --enable-languages=ada,c,c++,fortran,java,objc,lto --enable-threads=posix --enable-checking=release --with-system-zlib --with-python-dir=/lib/python2.6/site-packages --disable-libunwind-exceptions --enable-__cxa_atexit --enable-libssp --enable-lto --with-gnu-ld --verbose --with-arch=i486 --target=i486-slackware-linux --build=i486-slackware-linux --host=i486-slackware-linux
Модель многопоточности: posix
gcc версия 4.5.2 (GCC) 
(R) Core(TM)2 Duo CPU     T7500  @ 2.20GHz GenuineIntel GNU/Linux

cmake version 2.8.4

splinter ★★★★★
()
Ответ на: комментарий от Obey-Kun

Извиняюсь, поставил, теперь то очем собственно речь :

[100%] Building CXX object src/CMakeFiles/../qfrost.dir/qrc_resources.cxx.o
Linking CXX executable ../qfrost
undo/libqfrost_undo.a(newsoilcommand.cpp.o): In function `qfgui::NewSoilCommand::NewSoilCommand(qfgui::SoilsModel*, qfgui::Soil const*, QUndoCommand*)':
newsoilcommand.cpp:(.text+0xc3): undefined reference to `qfgui::Soil::Soil(QString const&, QColor const&, QObject*)'
newsoilcommand.cpp:(.text+0x149): undefined reference to `qfgui::Soil::Soil(QString const&, QColor const&, qfgui::Soil const&)'
collect2: выполнение ld завершилось с кодом возврата 1
make[2]: *** [src/../qfrost] Ошибка 1
make[1]: *** [src/CMakeFiles/../qfrost.dir/all] Ошибка 2
make: *** [all] Ошибка 2

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