Использование общих библиотек против одного исполняемого файла - PullRequest
7 голосов
/ 16 сентября 2009

Мой коллега утверждает, что мы должны разбить наше приложение C ++ (C ++, Linux) на разделяемые библиотеки, чтобы улучшить модульность кода, тестируемость и повторное использование.

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

Кроме того, обертывание классов C ++ с интерфейсами C-функций IMHO делает его более уродливым.

Я также думаю, что однофайловое приложение будет намного проще удаленно обновить на сайте клиента.

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

Ответы [ 9 ]

8 голосов
/ 16 сентября 2009

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

Но зачем вам оборачивать классы C ++ в интерфейсы C-функций, за исключением, может быть, создания объектов?

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

5 голосов
/ 16 сентября 2009

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

РЕДАКТИРОВАТЬ: Я действительно не вижу причины, почему вам нужно обернуть ваши классы C ++ с использованием интерфейсов C - это делается за кулисами. В Linux вы можете использовать общие библиотеки без какой-либо специальной обработки. Однако в Windows вам потребуется ___ declspec (экспорт) и ___ declspec (импорт).

4 голосов
/ 16 сентября 2009

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

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

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

2 голосов
/ 17 сентября 2009

Рассмотрение аргументов вашего коллеги

Если он полагает, что разбиение вашего кода на разделяемые библиотеки улучшит модульность кода, тестируемость и повторное использование, тогда я предполагаю, что это означает, что он полагает, что у вас есть некоторые проблемы с вашим кодом, и что принудительное использование архитектуры «разделяемой библиотеки» исправит это .

Модульность

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

Теперь это можно сделать и с помощью статических библиотек.

Тестирование

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

Теперь это можно сделать и с помощью статических библиотек.

Повторное использование кода?

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

Заключение

Точки 1 и 2 все еще могут быть достигнуты с помощью статических библиотек. 3 сделает общие библиотеки обязательными.

Теперь, если у вас есть более одной глубины связывания библиотек (я думаю о связывании двух статических библиотек, которые уже были скомпилированы, связывая другие библиотеки), это может быть сложно. В Windows это приводит к ошибке связывания, поскольку на некоторые функции (обычно на функции времени выполнения C / C ++, когда они связаны статически) ссылаются более одного раза, и компилятор не может выбрать, какую функцию вызывать. Я не знаю, как это работает в Linux, но я думаю, это тоже может произойти.

Разбирая свои аргументы

Ваши собственные аргументы несколько предвзяты:

Бремя компиляции / компоновки разделяемых библиотек?

Бремя компиляции и связывания с общими библиотеками по сравнению с компиляцией и связыванием со статическими библиотеками отсутствует. Так что этот аргумент не имеет значения.

Динамически загружать / выгружать?

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

Предоставление кода C ++ с интерфейсами C?

Что касается использования интерфейса C-функций для вашего кода C ++, я не понимаю: вы уже связываете статические библиотеки с интерфейсом C ++. Связывание разделяемых библиотек ничем не отличается.

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

Отдельный двоичный файл проще?

Ты прав.

В Windows разница незначительна, но, тем не менее, по-прежнему существует проблема DLL Hell , которая исчезает, если вы добавляете версию в имена своей библиотеки или работаете с Windows XP.

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

Вывод: кто прав?

Теперь ваша проблема не в том, "прав ли мой коллега?" Он. Как и вы тоже.

Ваша проблема:

  1. Чего вы действительно хотите достичь?
  2. Стоит ли работа, необходимая для этой задачи?

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

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

Нет способа ответить на этот скрытый вопрос ...

^ _ ^

2 голосов
/ 16 сентября 2009

Краткий ответ: нет.

Более длинный ответ: динамические библиотеки ничего не добавляют к тестированию, модульности или повторному использованию, что нельзя сделать так же легко в монолитном приложении. Единственное преимущество, о котором я могу подумать, это то, что оно может заставить создание API в команде, у которой нет дисциплины, делать это самостоятельно.

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

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

1 голос
/ 16 сентября 2009

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

Для целей доставки, если вы хотите собрать библиотеки и отправить один большой исполняемый файл, вы всегда можете ссылаться на них статически.

Если модульность поможет в разработке, т. Е. Вы всегда сталкиваетесь с другими разработчиками из-за изменений в файлах, то библиотеки могут помочь, но это тоже не гарантия. Использование хорошего объектно-ориентированного дизайна кода поможет независимо.

И нет никаких причин заключать какие-либо функции в C-вызываемые интерфейсы, необходимые для создания библиотеки, если только вы не хотите, чтобы она вызывалась из C.

1 голос
/ 16 сентября 2009

В Linux (и Windows) вы можете создать общую библиотеку с использованием C ++ и не загружать ее с помощью экспорта функций C.

То есть вы встраиваете classA.cpp в classA.so, и вы встраиваете classB.cpp в classB (.exe), который ссылается на classA.so. Все, что вы действительно делаете, это разбиваете ваше приложение на несколько двоичных файлов. Это имеет то преимущество, что они быстрее компилируются, легче управляются, и вы можете писать приложения, которые загружают только этот библиотечный код для тестирования.

Все по-прежнему C ++, все ссылки, но ваш .so отделен от статически связанного приложения.

Теперь, если вы хотите загрузить другой объект во время выполнения (то есть вы не знаете, какой из них загрузить до выполнения), вам нужно будет создать общий объект с помощью c-export, но вы также будете загрузка этих функций вручную; Вы не сможете использовать компоновщик, чтобы сделать это для вас.

1 голос
/ 16 сентября 2009

Проведите простой анализ затрат / выгод - вам действительно нужны модульность, тестируемость и повторное использование? У вас есть время потратить на рефакторинг вашего кода, чтобы получить эти функции? Что наиболее важно, если вы выполните рефакторинг, будут ли ваши выгоды оправдывать время, которое потребовалось для проведения рефакторинга?

Если у вас нет проблем с тестированием, я бы рекомендовал оставить ваше приложение как есть. Модуляризация хороша, но в Linux есть своя собственная версия «DLL-ада» (см. ldconfig), и вы уже указали, что повторное использование не является необходимостью.

1 голос
/ 16 сентября 2009

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

IMO, библиотеки в целом обеспечивают лучший код, более тестируемый код и позволяют более эффективно создавать будущие проекты, потому что вы не изобретаете колесо.

Короче, я согласен с вашим коллегой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...