Как правильно разделить проект Delphi на BPL? - PullRequest
10 голосов
/ 12 августа 2011

Компания, в которой я работаю, разрабатывает систему в Delphi, которая содержит десятки exe-модулей, и каждый из них в определенной степени идентичен, если речь идет об исходном коде. К сожалению, никто никогда не заботился об использовании библиотек для добавления общего кода. Это означает, что каждый раз, когда в коде, который разделяют все эти модули, есть исправление ошибки, программист должен вносить исправления во все из них по отдельности! Это всегда занимает так много времени ...

Я решил найти способ поместить общий код в библиотеки. Я рассмотрел DLL и BPL. В этом случае BPL казались намного более дружественными для программиста и намного менее хлопотными, особенно в том, что код используется только в нашем программном обеспечении и только в Delphi.

Я поместил весь код, совместно используемый всеми exe-модулями, в BPL, и все выглядит нормально, но есть некоторые вещи, которые я не понимаю, и был бы признателен, если бы вы мне их объяснили.

  1. Что я ожидал после разделения кода на BPL, так это того, что будет достаточно развернуть exe-файлы с BPL, которые я создал. Но оказалось, что им нужны также rtl100.bpl и vcl100.bpl. Почему это так? Я хочу развернуть exe и только мои BPL. Я не хочу предоставлять конечным пользователям целую кучу библиотек, поставляемых Borland и сторонними компаниями :). Я хочу, чтобы они были скомпилированы в exes, как раньше. Возможно ли это сделать?

  2. То, что я до сих пор делал, было:

    • Я поместил все общие блоки pas в BPL. Каждый BPL содержит блоки, принадлежащие к одной и той же категории, поэтому программистам понятно, какой код ожидать в данном BPL.
    • Каждый BPL - это библиотека времени выполнения и времени разработки.
    • Каждый BPL «перестраивается явно». Два последних являются настройками проекта по умолчанию для BPL.
  3. А если речь идет о проектах exe:

    • Я удалил все единицы, которые я ранее поместил в BPL.
    • Я установил свои BPL из меню Сервис-> Установить пакет в BDS 2006.
    • В моих настройках exe-проекта я установил опцию «строить с пакетами времени выполнения» и перечислил все свои пакеты BPL в поле редактирования ниже (только мои пакеты, так как я очистил все остальные, которые там появились).

Это все, что я сделал. Проекты exe компилируются должным образом, но у меня нет доступа к исходному коду BPL (я не могу перейти к этому коду из моих проектов exe), даже если все BPL хранятся вместе с их файлами исходного кода. Зачем? Мне кажется странным.

Я всегда склонен писать длинные описания - извините за это :). Я буду признателен за вашу помощь. Мне просто нужно несколько слов объяснения по поводу упомянутых мной моментов: развертывание exe только с моими BPL, правильность того, что я сделал в целом, и невозможность перехода к исходным кодам BPL. Заранее большое спасибо!


Спасибо всем за обсуждение. Некоторые говорили, что подход, который я выбрал, не был хорошей идеей. Наше программное обеспечение состоит из более чем 100 модулей (большинство из них являются драйверами для разных устройств). Большинство из них используют один и тот же код - в большинстве случаев это классы. Проблема в том, что эти классы не всегда помещаются в отдельные, самостоятельные единицы. Я имею в виду, что общий код часто помещается в блоки, содержащие код, специфичный для модуля. Это означает, что когда вы исправляете ошибку в совместно используемом классе, недостаточно скопировать модуль pas, в котором он определен, во все программные модули и перекомпилировать их. К сожалению, вы должны копировать и вставлять фиксированные фрагменты кода в каждый модуль, один за другим, в соответствующий модуль и класс. Это занимает много времени, и это то, что я хотел бы устранить, выбрав правильный подход - пожалуйста, помогите мне.

Я думал, что использование BPL было бы хорошим решением, но оно имеет некоторые недостатки, как некоторые из вас упоминали.Худшая проблема заключается в том, что если для каждого EXE-файла требуется несколько BPL, специалистам службы технической поддержки нужно будет знать, для каких EXE-файлов нужны какие-либо BPL, а затем предоставить конечным пользователям надлежащие файлы.Пока у нас нет программы обновления программного обеспечения, это будет очень полезно как для наших технических специалистов, так и для конечного пользователя.Они наверняка потеряются и рассердятся: - /.

Также могут возникнуть проблемы совместимости - если один BPL используется многими EXE-файлами, модификация одного BPL может быть полезной для одного EXE и плохой для некоторых других -@Warren P.

Что мне нужно сделать, чтобы быстрее исправлять ошибки во многих проектах?Я думаю об одном из следующих подходов.Если у вас есть идеи получше, пожалуйста, дайте мне знать.

  • Поместите общий код в отдельные и отдельные модули pas, поэтому, когда в одном из них есть исправление ошибки, достаточно скопировать его на всепроекты (перезаписать старые файлы) и перекомпилировать все из них.

Это решение, кажется, подходит для постороннего изменения кода.Но у нас также есть блоки с функциями и процедурами общего назначения, которые часто не требуют изменений - мы добавляем новые функции там, где это необходимо, но в отдельных проектах.Итак, представьте, что вы пишете новую функцию в одном из 100 модулей и помещаете ее в модуль общего пользования.Через месяц или два вы модифицируете другой модуль и думаете, что вам нужна та же функция, которую вы написали 2 месяца назад.Вы должны найти модуль (это сложно, если вы не помните, какой он был) и скопировать функцию в свой код.И очевидно - единицы общего использования становятся совершенно разными в каждом модуле, если они хранятся в каждом проекте отдельно.И затем, если нужно исправить ошибку ... вся история повторяется.

  • Создайте BPL для всего общего кода, но свяжите их с EXE-файлами, чтобы EXE-файлы были автономными.

Для меня это кажется лучшим решением сейчас, но есть несколько минусов.Если я исправлю ошибку в BPL, каждый программист должен будет обновить BPL на своем компьютере.Что если они забудут?Но все же, я думаю, что это небольшая проблема.Если мы позаботимся о том, чтобы информировать друг друга об изменениях, все должно быть хорошо.

  • @ CodeInChaos: Я не знаю, правильно ли я вас понял.Вы имеете в виду обмен файлами между проектами?Как это сделать?Мы храним исходники в SVN.Это означает, что нам придется хранить общий код в отдельной папке и заставить все проекты искать этот код там, верно?И загрузите из SVN проект и все папки, от которых он зависит ...

Пожалуйста, помогите мне выбрать хорошее решение.Я просто не хочу, чтобы компания теряла гораздо больше времени и денег, чем необходимо, на исправления ошибок только из-за глупого подхода к разработке программного обеспечения.

Большое спасибо.

Ответы [ 4 ]

8 голосов
/ 08 сентября 2011

Несмотря на то, что на этот вопрос есть принятый ответ, я собираюсь нанести удар.

Заголовок спрашивает, как разделить проект на bpls, но реальный вопрос, по-видимому: «Какой лучший способ поделиться кодом между проектами?»

Есть несколько способов сделать это:

  • Общие единицы
  • Dlls
  • 1012 * ВР *

Независимо от того, в каком направлении вы идете, вам, скорее всего, придется реструктурировать свои проекты. Из вашего описания звучит так, будто каждый проект разрабатывается в относительной изоляции. Код передается с использованием функции копирования / вставки, что быстро нарушает синхронизацию и приводит к большим дублирующим усилиям. Итак, давайте рассмотрим каждый из методов обмена кодом.

Общие единицы


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

Компилятор должен быть в состоянии найти ваши общие модули. Есть 4 способа указать компилятору, где искать.

  1. Добавить их в проект - SHIFT + F11 - Добавляет ссылку на устройство в файлы проекта (dpr, dproj). В среде IDE обычно используются относительные пути, если устройство находится в том же дереве каталогов, что и файлы проекта, в противном случае будут использоваться абсолютные пути, что может быть проблематично, если машины разработчика не настроены одинаково.
  2. Путь поиска проекта - CTRL + SHIFT + F11 Delphi Compiler> Путь поиска - Добавить каталог, и компилятор будет посмотрите там, чтобы найти модули, упомянутые в разделе использования любого модуля в проекте. Лучше всего использовать относительные пути, если можете. Вы также можете использовать переменные окружения: $ (MyPath)
  3. Глобальный путь поиска - Инструменты> Параметры> Параметры среды> Параметры Delphi> Библиотека - Win32> Путь к библиотеке - любые пути, перечисленные здесь, доступны для всех проектов на компьютере. Это зависит от машины
  4. Командная строка - Если вы строите из скрипта или средства автоматизации сборки, вы можете установить путь поиска с помощью переключателя -U dcc32 или /property:UnitSearchPath= msbuild.

Варианты 1 и 2 будут наиболее полезными.

Что касается вашего репозитория SVN, у вас есть несколько вариантов организации проектов и общих модулей. Простейшим было бы поместить все проекты в одну магистраль вместе с общими блоками:

Projects
    trunk
        ProjectA
        ProjectB
        ProjectC
        Library (shared units)

Если по какой-либо причине описанная выше структура невозможна, вы можете попробовать эту альтернативу:

ProjectA
    trunk
        Library (branch of main library)
ProjectB
    trunk
        Library (branch of main library)
ProjectC
    trunk
        Library (branch of main library)
Library
    trunk (main library)

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

Dlls


Dlls позволяют вам делиться кодом, связываясь с ним во время выполнения. Они предоставляют функции, которые можно вызывать из основного исполняемого файла или другой библиотеки DLL.

Хотя библиотеки DLL всегда связаны во время выполнения, вы решаете, будут ли они загружены при запуске приложения или только при необходимости. Загрузка при запуске называется статическая загрузка , а в Delphi это выполняется с помощью директивы external. Подавляющее большинство классов rtl / vcl, которые переносят системные вызовы API, используют статическую загрузку. Динамическая загрузка позволяет отложить загрузку DLL, пока она не потребуется. При этом используются функции WinAPI LoadLibrary и GetProcAddress. Соответствующий вызов FreeLibrary выгрузит DLL.

К сожалению, стандартные dll ограничивают типы передаваемых данных. Если вам нужен доступ к DLL из не-Delphi проектов, вам нужно ограничиться использованием типов данных в стиле c. Если вы будете использовать dll только с проектами Delphi, вы можете безопасно использовать строки и динамические массивы Delphi, если вы используете модуль SharedMem в dll и любые проекты, которые его используют.

Вы можете безопасно использовать объекты внутри dll без проблем, но если вы хотите передавать объекты между dll и приложением, вам нужно извлечь данные объекта и передать их как примитивные типы и собрать их в объект на другом конец. Это называется (де) сериализацией или сортировкой, и есть гораздо более простые способы сделать это, чем сворачивать свои собственные.

COM (объектная модель компонентов) хорошо поддерживается в Delphi, но имеет некоторую кривую обучения. Потребление объектов COM довольно просто, но разработка одного займет некоторое время, если вы не знакомы с COM. Преимущество COM заключается в том, что он не зависит от языка и поддерживается на большинстве языков, ориентированных на платформу Windows (включая языки, нацеленные на платформу .NET).

1078 * ВР * Bpls (также называемые просто «пакетами») - это специально отформатированные dll, которые значительно облегчают работу с объектами. Как и стандартные библиотеки, они связаны во время выполнения и могут быть статически или динамически загружены. Их легче изучать и использовать, чем COM-библиотеки, и они обеспечивают больше интеграции в ваши проекты, чем COM. Пакеты состоят из двух частей: bpl и dcp. Dcp похож на файлы dcu, сгенерированные при компиляции обычного файла модулей, за исключением того, что он содержит целую кучу модулей. Использование класса, скомпилированного в bpl, так же просто, как добавление dcp в список пакетов проекта, а затем добавление модуля в условие использования одного из модулей проекта. При развертывании приложения вам также необходимо установить bpl. Как уже отмечали другие, вы должны как минимум включать пакет rtl и, скорее всего, пакет vcl, если вы используете какие-либо формы. Существует способ развернуть поставленные Borland BPL с вашими проектами. Вы можете создать «мини» пакет RTL, который содержит только те единицы, которые нужны вашему проекту. Трудно определить, какие единицы включить. Резюме


Из приведенного вами описания создание библиотеки совместно используемых файлов юнитов для статической ссылки может оказаться наиболее целесообразным путем. Я также предложил бы попробовать программу под названием Simian . Это поможет вам найти дубликаты кода в вашей кодовой базе для включения в общую библиотеку. Он не поддерживает паскаль напрямую, но выполняет достаточно приличную работу, используя анализатор простого текста с небольшой настройкой его конфигурации.

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

8 голосов
/ 12 августа 2011

Представьте, что у вас есть проект с EXE и двумя разными модулями BPL, и где-то в этой кодовой базе есть строка с надписью if MyObject is TStringList then DoSomething;. Оператор is работает, проверяя метаданные класса объекта, сохраненные в VMT, а затем следуя цепочке VMT через указатель ClassParent, чтобы определить, соответствует ли какой-либо из них ссылка на класс (также указатель VMT) для TStringList. Чтобы убедиться, что это будет работать правильно, должен быть один VMT для TStringList, который будет одинаковым во всей вашей программе, независимо от того, на сколько BPL он разделен, что означает, что он должен быть в своем собственном пакете. Вот почему необходимы такие среды выполнения системы, как rtl * .bpl и vcl * .bpl, и с этим ничего не поделаешь. Это часть стоимости использования BPL.

Что касается невозможности отладки, вам необходимо убедиться, что BPL созданы с включенной информацией отладки и что отладчик знает, как найти папку, в которой находится DCP (файл, содержащий информацию отладки для BPL) расположен. И вы не сможете отследить системные BPL, поскольку DCP с поддержкой отладки не поставлялись с вашей версией. Они были добавлены довольно недавно, я думаю, в XE, но, возможно, это было в D2010.

2 голосов
/ 12 августа 2011

Почему я не могу просмотреть свой исходный код? Есть ли способ это исправить?

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

configuring your search path

Я решил это путем добавления каталогов в путь поиска проекта. Таким образом, компилятор не знает об этих файлах (и не пытается перекомпилировать их), но в среде IDE вы можете просматривать их содержимое и отлаживать их.

1 голос
/ 13 августа 2011

"В моих настройках exe-проекта я установил опцию" сборка с пакетами времени выполнения "

Именно поэтому вы не можете развернуть без BPL и т. Д. - эта опция сбивает с толку многих разработчиков - "«Сборка с пакетами времени выполнения» означает, что вам потребуется подарок bpl во время выполнения. Снимите этот флажок, и пакеты будут связаны с вашим exe-файлом в compileTime. (Ваш exe-файл будет увеличиваться в размере.) Идея «сборки с«Пакеты времени выполнения» - это сохранение размера exe-файла и предоставление возможности нескольким приложениям делиться общими bpl-файлами, поскольку они НЕ связаны с exe @ compileTime - это и есть обратная сторона. Недостаток, который вы сейчас испытываете - вы должны распространять свои bpl-файлы вместе с exe-файлом.

...