У меня повторяющаяся проблема со статически связанной библиотекой, которую я написал (или в некоторых случаях код был собран из открытых источников).
Эта библиотека, MFC Toolbox Library по имени, имеет много бесплатных функций, классов и т. Д., Которые поддерживают программирование MFC, API Win32, а также почтенную C-библиотеку и более новый C ++. стандартная библиотека.
Короче говоря, это рабочая библиотека с инструментами, применимыми к моей повседневной работе, которую я накопил за более чем десятилетие, и она необходима для наших продуктов. Как таковой, он имеет богатую смесь утилит и дополнений для всех этих различных технологий и часто внутренне смешивает использование всех этих технологий для создания дополнительной поддержки.
Например, у меня есть String Utilities.h и String Utilities.cpp , которые предоставляют множество свободных функций, связанных со строками, и даже один или два класса.
И часто я обнаруживаю, что у меня есть пара функций, одна из которых работает без необходимости MFC или его CStrings, а другая функция-брат, которая нуждается в этих вещах. Например:
////////////////////////////////////////////////////////////////////////
// Line Terminator Manipulation
////////////////////////////////////////////////////////////////////////
// AnsiToUnix() Convert Mac or PC style string to Unix style string (i.e. no CR/LF or CR only, but rather LF only)
// NOTE: in-place conversion!
TCHAR * AnsiToUnix(TCHAR * pszAnsi, size_t size);
template <typename T, size_t size>
T * AnsiToUnix(T (&pszBuffer)[size]) { return AnsiToUnix(pszBuffer, size); }
inline TCHAR * AnsiToUnix(Toolbox::AutoCStringBuffer & buffer) { return AnsiToUnix(buffer, buffer.size()); }
// UnixToAnsi() Converts a Unix style string to a PC style string (i.e. CR or LF alone -> CR/LF pair)
CString UnixToAnsi(const TCHAR * source);
Как видите, AnsiToUnix не требует CString. Поскольку Unix использует одиночный возврат каретки в качестве ограничителя строки, а строки ANSI Windows используют CR + LF в качестве ограничителя строки, я гарантирую, что результирующая строка поместится в исходное буферное пространство. Но для обратного преобразования строка почти гарантированно увеличивается, добавляя дополнительный LF для каждого вхождения CR, и, следовательно, желательно использовать CString (или, возможно, std :: string), чтобы обеспечить автоматический рост строка.
Это всего лишь один пример, и сам по себе он не слишком уместен, чтобы рассмотреть возможность преобразования из CString в std :: string, чтобы убрать зависимость от MFC из этой части библиотеки. Тем не менее, есть и другие примеры, когда зависимость гораздо более тонкая, и работа по ее изменению еще труднее. Далее, код хорошо протестирован как есть. Если я пойду и попытаюсь удалить все зависимости MFC, я, скорее всего, внесу в код тонкие ошибки, которые потенциально могут поставить под угрозу наш продукт, и увеличить количество времени, необходимое для выполнения этой, по сути, не совсем необходимой задачи.
Важно отметить, что здесь у нас есть набор функций, очень тесно связанных друг с другом (ANSI-> UNIX, UNIX-> ANSI), но где одна сторона использует MFC, а другая - только использует массивы символов. Итак, если я пытаюсь предоставить заголовок библиотеки, который можно использовать повторно, насколько это возможно, желательно разбить функции, которые все зависят от MFC, на один заголовок и функции, которые не относятся к другому, чтобы было легче распространять указанные файлы в другие проекты, которые не используют MFC (или какую-либо технологию, о которой идет речь: например, было бы желательно иметь все функции, которые не требуют заголовков Win32 - которые просто являются дополнениями к C ++, иметь свой собственный заголовок, и и др.).
Мой вопрос ко всем вам, как вы решаете эти проблемы - Технологическая зависимость и связанные функции находятся в одном месте?
Как вы разбиваете свои библиотеки - делите вещи? Что идет с чем?
Возможно, важно добавить мою мотивацию: я хотел бы иметь возможность публиковать статьи и делиться кодом с другими, но, вообще говоря, они, как правило, используют части библиотеки MFC Toolbox, которые сами используют другие части, создавая глубокая паутина зависимостей, и я не хочу обременять читателя / программиста / потребителя этих статей и проектов кода таким большим багажом!
Я, конечно, могу выделить только те части, которые необходимы для данной статьи или проекта, но это кажется трудоемким и бессмысленным делом. На мой взгляд, было бы гораздо разумнее очистить библиотеку таким образом, чтобы мне было легче делиться вещами, не таща за собой всю библиотеку. т.е. реорганизовать это один раз, вместо того, чтобы копать вещи каждый раз ...
Вот еще один хороший пример:
UINT GetPlatformGDILimit()
{
return CSystemInfo::IsWin9xCore() ? 0x7FFF : 0x7FFFFFFF;
}
GetPlatformGDILimit () является довольно общей, утилитарной бесплатной функцией. Это действительно не имеет ничего общего с CSystemInfo, кроме как клиент. Так что это не относится к "SystemInfo.h". И это всего лишь одна свободная функция - наверняка никто не попытался бы поместить ее в собственный заголовок? Я поместил его в "Win32Misc.h", в котором есть целый ряд таких вещей - бесплатные функции, которые в основном дополняют Win32 API. Тем не менее, эта, казалось бы, безобидная функция зависит от CSystemInfo, который сам использует CStrings и целый ряд других библиотечных функций, чтобы сделать его способным эффективно выполнять свою работу, или с меньшим количеством строк кода, или более надежно, или со всем вышеперечисленным.
Но если у меня есть демонстрационный проект, который ссылается на одну или две функции в заголовке Win32Misc.h, то я попадаю в границу необходимости извлекать только те отдельные функции, которые нужны проекту (и все, от чего зависят эти функции) и все, от чего зависят эти сущности и т. д.) - или я должен попытаться включить Win32Misc.h и его .cpp - что тянет с собой еще больше нежелательных накладных расходов (только для того, чтобы демо-проект компилировался).
Так какое эмпирическое правило люди используют, чтобы направлять себя относительно того, где провести черту - что с чем? Как сохранить библиотеки C ++ от превращения дерева зависимостей в ад? ;)