Что такое хорошая структура каталогов для больших проектов C++ с помощью Make-файла?
Это - то, как моя структура каталогов смотрит в данный момент:
lib/ (class implementations *.cpp)
include/ (class definitions *.h)
tests/ (main.cpp for quick tests)
Теперь, я не уверен, как мой Make-файл должен быть похожим..., это, кажется, не работает, когда .cpp файлы и.h файлы не находятся в том же каталоге. Кто-либо мог указать на меня на общую структуру каталогов с сопроводительным Make-файлом так, чтобы я не изобретал велосипед?
Не существует какой-либо конкретной или обязательной структуры каталогов.
Вы можете настроить его как хотите. Решить вашу проблему несложно. Просто дайте команду Makefile заглянуть в подкаталоги или поместить скомпилированные объекты в подкаталоги вместо использования только текущего каталога.
Вы могли бы просто использовать в Makefile пути:
%.o : %.cpp
заменить на
bin/%.o : %.cpp
Таким образом, он проверит, существует ли двоичный файл в каталоге bin
и т. Д., Вы можете применить то же самое к местам, где находятся файлы составлен.
Есть способы добавлять / удалять / изменять пути к исходным и объектным файлам.
См. gnu make manual , в частности раздел 8.3 Функции для имен файлов и предыдущий 8.2 Функции для подстановки и анализа строк .
Вы можете сделать что-то вроде:
получить список объектов из списка исходных файлов в текущем каталоге:
OBJ = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
Вывод:
Application.o Market.o ordermatch.o
Если двоичные объекты находятся в подкаталоге bin
, но исходный код находится в текущем каталоге, вы можете применить префикс bin
к сгенерированным объектным файлам:
OBJ = $(addprefix bin/,$(patsubst %.cpp, %.o, $(wildcard *.cpp)))
Вывод:
bin/Application.o bin/Market.o bin/ordermatch.o
И так далее.
Разделение .cpp файла .h не всегда является хорошим решением. Обычно я разделяю их оба, когда он используется в качестве библиотеки (публичный заголовок во включении и частный заголовок с исходным кодом).
Если это библиотека, с этой структурой все в порядке.
lib/ (class implementations *.cpp .h)
include/ (class definitions *.h) <- Only those to be installed in your system
tests/ (main.cpp for quick tests)
doc/ (doxygen or any kind of documentation)
Если это приложение
src/ (source for the application)
lib/ (source for the application library *.cpp *.hpp)
include/ (interface for the library *.h)
tests/ (main.cpp for quick tests) <- use cppunit for this part
doc/ (doxygen or any kind of documentation)
Используйте флаг -I $ (PROJECT_BASE) / include, чтобы указать путь включения для компиляции
Если это большой проект, может быть полезно использовать такой инструмент, как autoconf / automake или cmake для сборки всего. Это облегчит развитие.
Если у вас много исходных файлов, то хорошей идеей может быть дальнейшее разделение каталога исходных текстов. Например, один подкаталог для основной функциональности вашего приложения, другой для графического интерфейса и т.д.
src/core
src/database
src/effects
src/gui
...
Это также заставит вас избегать ненужных связей между вашими "модулями", что является предпосылкой для хорошего и многократно используемого кода.
Не существует "хорошей структуры каталогов". Выберите структуру, которая вам удобна, и придерживайтесь ее. Кому-то нравится размещать исходные файлы (заголовки и файлы реализации) в каталоге src/
, так что в корневом каталоге проекта нет ничего, кроме makefile, readme и почти ничего другого. Некоторые любят размещать вспомогательные библиотеки в каталоге lib/
, unittests в test/
или src/test/
, документацию в doc/
и т.д.
Однако я еще не слышал, чтобы кто-то разделял заголовочные файлы и файлы реализации на две разные директории. Лично мне не очень нравится разделять файлы по каталогам. Обычно я помещаю все исходные тексты в один каталог, а всю документацию - в другой. Если я все равно полагаюсь на хорошие инструменты поиска, то нет необходимости в сложной структуре каталогов.
make может работать с такой структурой, когда make-файл находится в другом каталоге, чем исходный текст. Единственное, он будет вызывать правила из каталога make-файла - компиляторы обычно не испытывают проблем с компиляцией исходного текста, находящегося в каком-то подкаталоге. Вам не нужно указывать относительные пути в ваших #include
s; просто укажите путь включения с помощью флагов компилятора (флаг gcc -I
и т.д.).
Если вы не видели его раньше, прочтите Рекурсивный метод «Считается вредным» .
Краткая, краткая версия: Несмотря на то, что рекурсивная идиома make очень распространена, она менее чем оптимальна и становится все хуже по мере того, как проекты становятся больше и сложнее. Представлена альтернатива.
Ссылка по теме: Каков ваш опыт работы с нерекурсивным make?