Я разрабатываю коллекцию классов C ++ и борюсь с тем, как поделиться кодом таким образом, чтобы поддерживать организацию без ущерба для простоты компиляции для пользователя коллекции.
Варианты, которые я видел, включают:
В настоящее время я использую третий вариант, в котором для каждого класса я хочу включить символическую ссылку на каждый класс заголовков и исходные файлы (например, ln -s <path_to_class folder>/myclass.cpp
) Это работает хорошо, за исключением того, что я не могу переместить местоположение папки проекта (оно разрывает все символические ссылки), и мне нужно, чтобы все эти символические ссылки оставались рядом.
Мне нравится второй вариант (он имеет вид Java), но я беспокоюсь о раздувании размера кода, если все объявлено встроенным.
Пользователь коллекции будет где-то создавать папку проекта и каким-то образом включать коллекцию в процесс компиляции.
Я хотел бы, чтобы было возможно несколько вещей:
gcc *.cpp
из папки проекта)Меня не волнует документация (об этом позаботится Doxygen) или время компиляции: общие модули невелики, и даже самые крупные проекты на самых медленных машинах не будут компилироваться более чем за несколько секунд.
Я использую компилятор GCC, если это имеет какое-либо значение.
Библиотека — лучший вариант (на мой взгляд) из трех, которые вы подняли. Затем укажите заголовочные файлы в пути включения и библиотеку в пути компоновщика.
Поскольку вы также хотите распространять библиотеку в форме исходного кода, я был бы склонен предоставить сжатый архив (gzip, 7-zip, tarball или другой предпочтительный формат) в центральном хранилище.
Если я правильно понимаю, вы не хотите, чтобы пользователи включали файлы .cpp в свою сборку, а вместо этого просто хотите, чтобы они использовали либо: (i) заголовки напрямую, (ii) использование скомпилированной формы библиотеки lib.
Ваши требования немного необычны, но они могут быть выполнены. Мне кажется, что вы могли бы организовать свой код следующим образом. Во-первых, имейте глобальное определение, которое определяет, компилируете ли вы библиотеку:
// global.h
// ...
#define LIB_SOURCE
// ...
Затем в каждом заголовочном файле вы проверяете, установлено ли это определение: если библиотека распространяется как статическая / разделяемая библиотека, определения не включаются, в противном случае файл .cpp включается из заголовочного файла.
// A.h
#ifndef _A_H
#include "global.h"#ifdef LIB_SOURCE
#include "A.cpp"#endif
// ...
#endif
где «A.cpp» будет содержать фактическую реализацию.
Опять же, это очень странный способ ведения дел, и я бы на самом деле советовал против такой практики. Лучший способ (но тот, который требует больше работы) — всегда распространять разделяемую библиотеку. Но чтобы сохранить независимость от компилятора, напишите слой C вокруг него. Таким образом, у вас есть переносимая, поддерживаемая библиотека.
Что касается некоторых других требований:
Я закончил тем, что использовал встроенные заголовки для всего кода. Вы можете увидеть библиотеку здесь:
https://github.com/libpropeller/libpropeller/tree/master/libpropeller
Библиотека структурирована как:
С этой структурой я могу распространять библиотеку как источник, и все, что нужно сделать пользователю, это включить -I/path/to/library
в их makefile, и #include "library/classA/classA.h"
в их исходных файлах.
И, как оказалось, наличие встроенных заголовков на самом деле уменьшает размер кода. Я сделал полный анализ этого, и оказывается, что встроенный код в заголовках позволяет компилятору сделать окончательный двоичный файл примерно на 5% меньше.