Я экспериментирую с реконфигурированием моего приложения для создания поднимающегося использования пакетов. И я и другой разработчик, выполняющий подобный эксперимент, сталкиваемся с небольшим количеством проблемы при соединении использования нескольких различных пакетов. Мы, вероятно, оба делаем что-то не так, но кто его знает что :)
Ситуация - это:
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:\blah\FooB.OBJ
[ILINK32 Error] Error: Unresolved external 'FooA::' referenced from C:\blah\FooB.OBJ
[ILINK32 Error] Error: Unresolved external '__fastcall FooA::~FooA()' referenced from blah\FooB.OBJ
и т.д.
Работа 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 показывает подобные записи.
Класс действительно убывает от TObject, хотя первоначально прежде, чем осуществить рефакторинг в пакеты, это был нормальный класс C++. (Больше детали ниже. Это кажется "более безопасными" классами стиля VCL использования при попытке решить проблемы с очень вещь выхода Delphi как это так или иначе. Изменение этого только изменяется, порядок неразрешенного внешнего облика к первому не находят 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)
около вершины, при включении.
PACKAGE
директива только по TObject
- производные классы? Нет никакого предупреждения компилятора с помощью него на стандартных классах C++.Мы используем Разработчика C++ 2010. Я изготовил имена классов и имена методов в вышеупомянутых примерах кода, но кроме этого детали точно, что мы видим.
Неразрешенное внешнее значение в вашем случае, похоже, связано с тем, что компилятор не может найти путь к данным пакета. Вы должны выяснить, если:
Если одно из них истинно, проблема не в пути. Однако, как отмечает Рихо , это наиболее вероятная причина проблемы. В вики-странице документации Embarcadero говорится следующее о неразрешенной внешней ошибке:
Именованный символ упоминается в данном модуле, но не определен нигде в наборе объектных файлов и библиотек. включены в ссылку. Убедитесь, что символ написан правильно.
Вы обычно увидите эту ошибку компоновщиком для символов C или C ++, если произойдет одно из следующих событий:
- Вы неправильно сопоставили объявления символа
__ pascal
и__ cdecl
] типы в разных исходных файлах.- Вы пропустили имя объектного файла, который нужен вашей программе. Вам необходимо вручную добавить все необходимые пакеты в список «Требуется».
- Вы не сделали ссылку в библиотеке эмуляции.
Если вы связываете код C ++ с модулями C, возможно, вы забыли заключить внешние объявления C в extern «C».
У вас также может быть несовпадение регистра между двумя символами.
Источник: Неразрешенный внешний «символ», на который имеется ссылка из «модуля» .
Поскольку, судя по измененным именам классов, это не случай неправильного написания. Вы также заявляете, что добавили пакет в список требований, поэтому мы также исключаем это. Поскольку вы не связываетесь с модулями C, мы также можем опустить эту часть. Значит, это указывает на проблемы с каталогом.
Все ваши вопросы действительно интересны, и многие из них - это вопросы, на которые я сам искал ответы, когда начинал разрабатывать пакеты и компоненты для C ++ Builder.
Пакеты - прекрасное решение для использования в C ++ Builder, C ++ Builder создан для поддержки пакетов и VCL-фреймворка, написанного на языке Pascal. Это означает, что некоторые реализации в C ++ Builder отличаются от других компиляторов. Это необходимо для того, чтобы язык был совместим с его родным братом Delphi. По этой причине вы можете использовать пакеты в C ++ Builder почти так же легко, как при использовании Delphi.
Начнем со второй части вашего вопроса: использование файла lib увеличивает размер вашего пакета просто потому, что он использует статическое связывание - так что ваш предположение верное.Теперь вернемся к первой части вопроса. Можно установить ссылку на пакет, добавив ссылку на его BPI. Но вам нужно убедиться, что переменная пути установлена правильно, как предлагает Рихо в своем ответе.
Лично я всегда убеждаюсь, что мои пакеты находятся в правильных каталогах в вашей папке пользователей, расположение которых зависит от вашей версии Delphi и версии операционной системы. Насколько я помню, он находится в папке Document and Settings \ all users \ shared documents \ Rad studio (номер версии) \ Packages, но я могу ошибаться в этом.
PACKAGE
только для классов, производных от TObject
? Макрос PACKAGE
преобразован в __ declspec (package)
, вы можете сравнить его с __ declspec (dllexport)
. Разница между ними в том, что package используется при объявлении в пакете, а dllexport используется при объявлении в DLL. На официальном форуме embarcadero есть тема под названием __ declspec (package) vs __declspec (dllexport) . Автор исходного сообщения также задает ваш точный вопрос по этому поводу, но, к сожалению, эта часть вопроса остается без ответа.
Однако у меня есть теория, и я должен подчеркнуть, что это не более чем теория. Реми Лебо пишет в ответ на вопрос в сообщении на форуме:
__ declspec (dllexport) может использоваться для простых функций, переменных данных и классов, не относящихся к VCL, и может использоваться в простых библиотеках DLL.__declspec (package) используется для компонентов VCL и может использоваться только с пакетами.
Итак, читая его ответ, мне кажется, что пакет просто экспортирует класс, как это делает dllexport. И поскольку dllexport, насколько я могу понять из его ответа, должен использоваться в простых библиотеках DLL, только вам нужно использовать пакет для экспорта (даже) классов, отличных от VCL, из пакета.
Что интересно во всем этом, так это то, что, насколько я помню, пакет по сути является DLL, но я должен признать, что не могу найти или запомнить источник этой информации, так что относитесь к нему с недоверием.
Пакеты обладают некоторыми очень сильными сторонами при создании повторно используемых компонентов для VCL. Очевидно, что использование пакетов ограничивает пользователя использованием C ++ Builder или Delphi, но для компонентов, написанных с использованием преимуществ инфраструктуры VCL, это отличный выбор. Правильно написанные пакеты могут облегчить повторное использование компонентов, и я считаю, что это предпочтительный метод распространения компонентов для VCL.
Однако, если ваш код каким-либо образом не использует преимущества инфраструктуры VCL, я бы подумал об использовании обычной библиотеки, статической или динамической, просто для создания более удобного для кросс-компилятора подхода.
Есть ли лучший подход к изоляции вашего кода, это действительно зависит от проекта, над которым вы работаете. Мне нравится хранить код, который обменивается данными с помощью классов VCL в пакетах, но код, который не требует использования каких-либо классов VCL в обычных библиотеках. Однако имейте в виду, что вы можете легко использовать классы VCL в DLL, но вам нужно обрабатывать особые случаи, если вы решите экспортировать функции с классами VCL String в качестве параметров или возвращаемых значений.
Я сам не самый опытный разработчик пакетов, но обнаружил, что отключение связывания во время выполнения часто решает множество моих проблем, в то время как исправить любые проблемы для ваш собственный код, вы часто можете столкнуться со сторонними компонентами, которые не могут справиться с этим. Сказав это, я не поклонник распространения моих пакетов вместе с моим приложением, как это требуется в данном случае. Но если честно, это дело вкуса.
Лично мне было трудно найти какие-то правильные ответы на многие из моих вопросов, когда я начал создавать компоненты и пакеты. Официальный файл справки не самый информативный по этому вопросу, но просмотр исходного кода VCL часто дает вам лучший ответ на ваш вопрос. Кроме того, есть несколько других веб-сайтов, которые могут предоставить помощь, хотя многие из них нацелены на Delphi, но к этому вам нужно привыкнуть.
В Delphi Wikia есть несколько хороших статей о создании компонентов, в частности Создание компонентов и Создание пакетов Также есть BCB Journal , который является одним из немногих C ++ Конкретные сайты Builder, у него есть несколько хороших статей и приемлемый форум. Страницы Delphi на сайте About.com также являются хорошим источником информации, я нашел там много хороших советов и приятно знать, в частности: Создание пользовательских компонентов Delphi - внутри и снаружи .
Может быть, глупый вопрос, но правильно ли находятся ваши файлы BPI / BPL, чтобы их мог найти компоновщик? Я однажды создал приложение в BCB5, которое использовало несколько связанных пакетов, но не помню, было ли что-нибудь особенный в их изготовлении.