Как я решаю неразрешенное внешнее при использовании Разработчика C++ пакеты?

Я экспериментирую с реконфигурированием моего приложения для создания поднимающегося использования пакетов. И я и другой разработчик, выполняющий подобный эксперимент, сталкиваемся с небольшим количеством проблемы при соединении использования нескольких различных пакетов. Мы, вероятно, оба делаем что-то не так, но кто его знает что :)

Ситуация - это:

  • Первый пакет, 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) около вершины, при включении.

Вопросы, которые могли бы помочь...

  • Являются пакеты надежным использованием C++, или действительно ли они только применимы с кодом Delphi?
  • Соединение к первому пакету путем добавления, что ссылка на ее корректный BPI - является этим, как Вы, как предполагается, делаете это? Я мог использовать LIB, но это, кажется, делает второй пакет намного больше, и я подозреваю, что это статически связывается в содержании первого.
  • Мы можем использовать PACKAGE директива только по TObject- производные классы? Нет никакого предупреждения компилятора с помощью него на стандартных классах C++.
  • Разделяет код на пакеты лучший способ достигнуть цели изоляции кода и передачи через определенные слои / интерфейсы? Я исследовал этот путь, потому что это, кажется, Разработчик C++ / Delphi Путь, и если это работало, это выглядит привлекательным. Но есть ли лучшие альтернативы?
  • Я очень плохо знаком с использованием пакетов и только знал о них посредством использования компонентов прежде. Любые обычные небольшие советы были бы большими!

Мы используем Разработчика C++ 2010. Я изготовил имена классов и имена методов в вышеупомянутых примерах кода, но кроме этого детали точно, что мы видим.

8
задан David 26 October 2010 в 17:06
поделиться

2 ответа

Неразрешенное внешнее

Неразрешенное внешнее значение в вашем случае, похоже, связано с тем, что компилятор не может найти путь к данным пакета. Вы должны выяснить, если:

  • Путь существует в списке путей поиска компилятора.
  • Пакет существует в каталоге пакетов по умолчанию.

Если одно из них истинно, проблема не в пути. Однако, как отмечает Рихо , это наиболее вероятная причина проблемы. В вики-странице документации Embarcadero говорится следующее о неразрешенной внешней ошибке:

Именованный символ упоминается в данном модуле, но не определен нигде в наборе объектных файлов и библиотек. включены в ссылку. Убедитесь, что символ написан правильно.

Вы обычно увидите эту ошибку компоновщиком для символов C или C ++, если произойдет одно из следующих событий:

  • Вы неправильно сопоставили объявления символа __ pascal и __ cdecl ] типы в разных исходных файлах.
  • Вы пропустили имя объектного файла, который нужен вашей программе. Вам необходимо вручную добавить все необходимые пакеты в список «Требуется».
  • Вы не сделали ссылку в библиотеке эмуляции.

Если вы связываете код C ++ с модулями C, возможно, вы забыли заключить внешние объявления C в extern «C».

У вас также может быть несовпадение регистра между двумя символами.

Источник: Неразрешенный внешний «символ», на который имеется ссылка из «модуля» .

Поскольку, судя по измененным именам классов, это не случай неправильного написания. Вы также заявляете, что добавили пакет в список требований, поэтому мы также исключаем это. Поскольку вы не связываетесь с модулями C, мы также можем опустить эту часть. Значит, это указывает на проблемы с каталогом.

О других вопросах

Все ваши вопросы действительно интересны, и многие из них - это вопросы, на которые я сам искал ответы, когда начинал разрабатывать пакеты и компоненты для C ++ Builder.

Надежны ли пакеты при использовании C ++?

Пакеты - прекрасное решение для использования в C ++ Builder, C ++ Builder создан для поддержки пакетов и VCL-фреймворка, написанного на языке Pascal. Это означает, что некоторые реализации в C ++ Builder отличаются от других компиляторов. Это необходимо для того, чтобы язык был совместим с его родным братом Delphi. По этой причине вы можете использовать пакеты в C ++ Builder почти так же легко, как при использовании Delphi.

Правильно ли связываться с первым пакетом путем добавления ссылки на его BPI?

Начнем со второй части вашего вопроса: использование файла 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 - внутри и снаружи .

9
ответ дан 5 December 2019 в 14:01
поделиться

Может быть, глупый вопрос, но правильно ли находятся ваши файлы BPI / BPL, чтобы их мог найти компоновщик? Я однажды создал приложение в BCB5, которое использовало несколько связанных пакетов, но не помню, было ли что-нибудь особенный в их изготовлении.

2
ответ дан 5 December 2019 в 14:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: