Как решить неразрешенный внешний при использовании пакетов C++ Builder?
я экспериментирую с перенастройкой моего приложения, чтобы использовать пакеты. И я, и другой разработчик, выполняющий аналогичный эксперимент, сталкиваются с некоторыми проблемами при связывании с использованием нескольких разных пакетов. Мы, наверное, оба делаем что-то не так, но Бог знает что :)
ситуация такая:
- первый пакет,
PackageA.bpl
, содержащая класс c++FooA
. Класс объявляется с помощьюPACKAGE
директива. второй пакет,
PackageB.bpl
, содержит класс, наследующий отFooA
, под названиемFooB
. Он включает в себяFooB.h
, и пакет построен с использованием пакетов времени выполнения и ссылок наPackageA
путем добавления ссылки наPackageA.bpi
.-
при строительстве
PackageB
, он компилируется нормально, но связывание не удается с рядом неразрешенных внешних, первые несколько из которых являются:[ILINK32 Error] Error: Unresolved external '__tpdsc__ FooA' referenced from C:blahFooB.OBJ
[ILINK32 Error] Error: Unresolved external 'FooA::' referenced from C:blahFooB.OBJ
[ILINK32 Error] Error: Unresolved external '__fastcall FooA::~FooA()' referenced from blahFooB.OBJ
etc.
запуск TDump на PackageA.bpl
показывает:
Exports from PackageA.bpl
14 exported name(s), 14 export addresse(s). Ordinal base is 1.
Sorted by Name:
RVA Ord. Hint Name
-------- ---- ---- ----
00002A0C 8 0000 __tpdsc__ FooA
00002AD8 10 0001 __linkproc__ FooA::Finalize
00002AC8 9 0002 __linkproc__ FooA::Initialize
00002E4C 12 0003 __linkproc__ PackageA::Finalize
00002E3C 11 0004 __linkproc__ PackageA::Initialize
00006510 14 0007 FooA::
00002860 5 0008 FooA::FooA(FooA&)
000027E4 4 0009 FooA::FooA()
00002770 3 000A __fastcall FooA::~FooA()
000028DC 6 000B __fastcall FooA::Method1() const
000028F4 7 000C __fastcall FooA::Method2() const
00001375 2 000D Finalize
00001368 1 000E Initialize
0000610C 13 000F ___CPPdebugHook
таким образом, класс определенно кажется экспортированным и доступным для ссылки. Я вижу записи для конкретных вещей, которые ILink32 говорит, что ищет и не находит. Запуск TDump в файле BPI показывает аналогичные записи.
другой info
класс действительно происходит от TObject, хотя первоначально перед рефакторингом в пакеты Это был обычный класс C++. (Более подробно ниже. Кажется, "безопаснее" использовать классы в стиле VCL при попытке решить проблемы с очень Delphi-ish, как это в любом случае. Изменение этого только изменяет порядок неразрешенных внешних, чтобы сначала не найти Method1
и Method2
, затем другим.)
декларация FooA
:
class PACKAGE FooA: public TObject {
public:
FooA();
virtual __fastcall ~FooA();
FooA(const FooA&);
virtual __fastcall long Method1() const;
virtual __fastcall long Method2() const;
};
и FooB
:
class FooB: public FooA {
public:
FooB();
virtual __fastcall ~FooB();
... other methods...
};
все методы определенно реализованы в.cpp файлы, так что это не не находить их, потому что они не существуют! Этот.cpp файлы также содержат #pragma package(smart_init)
в верхней части, под включает.
вопросы, которые могут помочь...
- являются ли пакеты надежными с использованием C++ или они могут использоваться только с кодом Delphi?
- связывается с первым пакетом, добавляя ссылку на его BPI правильно - это то, как вы должны сделать это? Я мог бы использовать LIB, но он, кажется, делает второй пакет намного больше, и я подозреваю, что он статически связывается с содержимым первого.
- можем ли мы использовать
PACKAGE
директива только наTObject
-производного классов? Нет предупреждения компилятора, использующего его в стандартных классах c++. - является ли разделение кода на пакеты лучшим способом достижения цели изоляции кода и связи через определенные слои / интерфейсы? Я исследовал этот путь. потому что это похоже на C++Builder / Delphi, и если это сработало, это выглядит привлекательно. Но есть ли лучшие альтернативы?
- я очень новичок в использовании пакетов и знал о них только с помощью компонентов раньше. Любые общие слова совета было бы здорово!
мы используем C++Builder 2010. Я создал имена классов и методов в приведенных выше примерах кода, но кроме этого детали-это именно то, что мы видим.
3 ответов
неразрешенный внешний
неразрешенный Внешний в вашем случае, кажется, потому, что компилятор не может найти путь к данным пакета. Вы должны узнать, если:
- путь существует в списке путей поиска компилятора.
- пакет существует в каталоге пакетов по умолчанию.
если один из них истинен, то путь не является проблемой. Однако как Рихо также упоминает, что это наиболее вероятно причина проблемы. The Embarcadero документация wiki говорится о неразрешенный внешний ошибка:
на именованный символ ссылаются в данном модуле, но не определяется нигде в наборе объектных файлов и библиотек, включенных в ссылку. Убедитесь, что символ написан правильно.
вы обычно увидите эту ошибку из компоновщика для символов C или C++, если любое из следующих происходят:
- вы неправильно соответствовали объявлениям символа
__pascal
и__cdecl
типы в разных исходных файлах.- вы опустили имя объектного файла вашей программы. Необходимо вручную добавить все необходимые пакеты в список required.
- вы не связались в библиотеке эмуляции.
если вы связываете код C++ с модулями C, вы, возможно, забыли обернуть внешние объявления C в extern "C".
вы также может быть несоответствие между двумя символами.
источник: неразрешенный внешний "символ", на который ссылается "модуль".
поскольку это кажется из-хотя и измененные имена классов - это не случай орфографии. Вы также заявляете, что добавили пакет в список требований, поэтому мы также исключаем это. Поскольку вы не связываетесь с модулями C, мы можем опустить и эту часть. Так что это указывает на проблемы с каталогом.
о других вопросах
ваши вопросы действительно интересны, и многие из вопросов-это вопросы, на которые я сам искал ответы, когда начал разрабатывать пакеты и компоненты для C++ Builder.
являются ли пакеты надежными с помощью C++?
пакеты-прекрасное решение для использования в C++ Builder, как C++ Builder построен для поддержки пакетов, так и Pascal written VCL framework. Этот означает, что некоторые реализации в C++ Builder отличаются от других компиляторов. Это необходимо для того, чтобы язык был совместим с его родственным Delphi. По этой причине вы можете использовать пакеты в C++ Builder почти так же легко, как при использовании Delphi.
является ли ссылка на первый пакет, добавив ссылку на его BPI правильно?
начать со второй части вашего вопроса здесь, используя файл lib делает ваш пакет больше, просто потому, что это использование статической компоновки-так что ваша догадка верна. Теперь вернемся к первой части вопроса, ссылка на пакет прекрасна, добавив ссылку на его BPI. Но вам нужно убедиться, что переменная path была установлена правильно как Рихо предполагает в своем ответе.
лично я всегда убеждаюсь, что мои пакеты в соответствующие каталоги в вашей папке пользователей, расположение этого зависит от вашей версии Delphi и версии операционной системы. Насколько я помню он находится под документом и настройками\all users\shared documents\Rad studio (номер версии)\Packages, но я могу ошибаться в этом.
можем ли мы использовать PACKAGE
директива только на TObject
-производного классов?
на PACKAGE
макрос разрешен в __declspec(package)
, вы можете сравнить его с __declspec(dllexport)
. Разница между ними в том, что пакета используется при объявлении в пакете, и С атрибутом dllexport используется при объявлении в DLL. Есть тема об этом на официальных форумах embarcadero под названием _ _ declspec (пакет) vs _ _ declspec (dllexport). Автор оригинального сообщения также задает ваш точный вопрос об этом, но, к сожалению, эта часть вопроса остается без ответа.
_ _ declspec (dllexport) можно использовать для простые функции, переменные данных и не-классы VCL и могут использоваться в простых DLL. _И _declspec(пакет) используется для компонентов VCL и может использоваться только с пакетами.
поэтому, читая его ответ, мне кажется, что пакет просто экспортирует класс, как и dllexport. И поскольку dllexport, насколько я могу прочитать из его ответа, должен использоваться в простых DLL, только вам нужно использовать пакет для экспорта (даже) не классов VCL из пакет.
что интересно обо всем этом, так это то, что пакет по сути является DLL, насколько я помню, но я должен признать, что не могу найти или вспомнить источник этой информации, поэтому возьмите с солью.
является ли разделение кода на пакеты лучшим способом достижения цели изоляции кода?
пакеты имеют некоторые очень заметные преимущества при создании многоразовых компонентов для VCL. Очевидно, что использование пакетов ограничивает использование пользователем C++Builder или Delphi, но для компонентов, написанных, чтобы воспользоваться инфраструктурой VCL, это отличный выбор. Правильно написанные пакеты могут облегчить повторное использование компонентов, и я считаю, что это предпочтительный метод распределения компонентов для VCL.
однако, если ваш код никоим образом не использует преимущества VCL framework, я бы рассмотрел использование обычной библиотеки, статической или динамической, просто для создания более кросс-компилятора дружественный подход.
есть ли лучший подход к изоляции вашего кода, действительно зависит от проекта, над которым вы работаете. Мне нравится хранить код, который взаимодействует с использованием классов VCL в пакетах, но код, который не требует использования каких-либо классов VCL в обычных библиотеках. Имейте в виду, что вы можете легко использовать классы VCL в DLL, но вам нужно обрабатывать специальные случаи, если вы решите экспортировать функции с классами строк VCL в качестве параметров или вернуть ценности.
какие-либо общие советы?
Я сам не самый опытный разработчик пакетов, но я обнаружил, что отключение связывания во время выполнения часто решает многие мои проблемы, в то время как несколько тривиально исправить любые проблемы для вашего собственного кода, Вы можете часто запускать сторонние компоненты, которые имеют проблемы с этим. Сказав это, я не поклонник распространения моих пакетов вместе с моим приложением, как это требуется в этом случае. Но если честно ... это дело вкуса.
лично мне было трудно найти правильные ответы на многие из моих вопросов, когда я начал создавать компоненты и пакеты. Официальный файл справки не самый информативный по этому вопросу, но просматривая исходный код VCL, часто даст вам лучший ответ на ваш вопрос. Кроме того, есть несколько других сайтов, которые могут помочь, многие сайты нацелены на Делфи, но это вы должны привыкнуть хотя.
Delphi Wikia имеет несколько хороших статей о создании компонентов, в частности Создание Компонентов и Создание Пакетов есть еще BCB Journal который является одним из немногих сайтов C++ Builder, он имеет некоторые прекрасные статьи и приемлемый форум. The Delphi страницы на About.com также является хорошим источником информации, я нашел много хороших намеков и приятно знает там, в частности: создание пользовательских компонентов Delphi-внутри и снаружи.
может быть, глупый вопрос, но ваши файлы BPI/BPL в правильном пути, который будет найден компоновщиком? Я создал однажды приложение в BCB5, которое использовало несколько связанных пакетов, но не помню, было ли что-то особенное в их создании.
для меня #Pragma package (smart_init,weak) в файле cpp решена проблема. См. также http://flylib.com/books/en/3.264.1.27/1/ Файл cpp - >obj получает статически связанный, не влияя ни на что другое.