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

StackOverflow https://stackoverflow.com/questions/1432777

  •  07-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

Анализ рассуждений вашего коллеги

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

Модульность?

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

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

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

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

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

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

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

Заключение

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

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

Анализ ваших собственных аргументов

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

Бремя компиляции / компоновки общих библиотек?

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

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

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

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

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

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

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

Ты прав.

В Windows эта разница незначительна, но проблема в аде DLL , который исчезает, если вы добавляете версию к именам своей библиотеки или работаете с Windows & nbsp; XP.

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

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

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

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

<Ол>
  • Чего вы действительно хотите достичь?
  • Стоит ли работа, необходимая для этой задачи?
  • Первый вопрос очень важен, так как мне кажется, что ваши аргументы и аргументы вашего коллеги необъективны, чтобы привести к выводу, который кажется более естественным для каждого из вас.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    scroll top