Система сборки для встроенного проекта C / C ++ - PullRequest
6 голосов
/ 30 сентября 2011

Я ищу систему / инструмент сборки высокого уровня, который может помочь организовать мой встроенный C-проект в «модули» и «компоненты».Обратите внимание, что эти два термина очень субъективны, поэтому мои определения приведены ниже.

  • Модуль - это сплоченная коллекция файлов c и h, но только с одним открытым файлом h, видимым для других модулей.
  • Компонент (или уровень), с другой стороны, представляет собой набор модулей (например, прикладной уровень, уровень библиотеки, уровень драйвера, уровень RTOS и т. Д.).

Система / инструмент сборки должны -

  • Предотвращать циклические зависимости между компонентами и модулями (циклические зависимости внутри модулей в порядке)
  • предотвращать доступ к частнымбарьеры модуля.Если другие модули пытаются включить заголовочный файл, который является частным для модуля, система сборки должна выдать ошибку.Однако файлы в частном барьере должны иметь возможность включать в себя другие файлы внутри этого барьера.
  • поддерживает автоматическое построение и выполнение модульных тестов (быстрый цикл обратной связи для TDD) на хосте
  • поддерживает модульные тестыдля запуска на целевом симуляторе
  • поддержка статического анализа кода
  • поддержка генерации кода
  • поддержка обнаружения дублирования кода (применение принципа СУХОЙ)
  • украшение кода поддержки
  • поддержка генерации метрик покрытия кода модульного теста
  • поддержка генерации метрик качества кода
  • независимость от платформы

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

Ответы [ 2 ]

4 голосов
/ 30 сентября 2011

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

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

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

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

Рассмотрим пару модулей, ModuleA и ModuleB, и программу Program1, в которой используются оба модуля.

base/include
        ModuleA.h
        ModuleB.h
base/ModuleA
        ModuleA.h
        ModuleA1.c
        ModuleA2.c
base/ModuleB
        ModuleB.h
        ModuleB1.c
        ModuleB2.c
base/Program1
        Program1.c

При компиляции Program1.c вполне законно включить и ModuleA.h, и ModuleB.h, если он использует службы обоих модулей. Таким образом, ModuleA.h не может жаловаться, если ModuleB.h включен в тот же модуль перевода (TU), и также не может ModuleB.h жаловаться, если ModuleA.h включен в тот же TU.

Предположим, что для ModuleA является законным использование возможностей ModuleB. Поэтому при компиляции ModuleA1.c или ModuleA2.c не должно быть проблем с включением обоих ModuleA.h и ModuleB.h.

Однако, чтобы предотвратить циклические зависимости, вы должны иметь возможность запретить коду в ModuleB1.c и ModuleB2.c использовать ModuleA.h.

Насколько я могу видеть, единственный способ сделать это - это какой-то метод, который требует частного заголовка для ModuleB, который говорит: «ModuleA уже включен», хотя это не так, и это включается до того, как ModuleA.h когда-либо включены.

Каркас ModuleA.h будет стандартным форматом (и ModuleB.h будет аналогичным):

#ifndef MODULEA_H_INCLUDED
#define MODULEA_H_INCLUDED
...contents of ModuleA.h...
#endif

Теперь, если код в ModuleB1.c содержит:

#define MODULEA_H_INCLUDED
#include "ModuleB.h"
...if ModuleA.h is also included, it will declare nothing...
...so anything that depends on its contents will fail to compile...

Это далеко не автоматически.

Вы можете выполнить анализ включенных файлов и потребовать, чтобы существовал топологический вид зависимостей без петель. Раньше в системах UNIX существовала программа tsort (и сопутствующая программа lorder), которые вместе предоставляли необходимые услуги для создания статической (.a) библиотеки, содержащей объектные файлы в порядке, не требует повторного сканирования архива. Программа ranlib и, в конечном итоге, ar и ld взяли на себя обязанности по управлению повторным сканированием одной библиотеки, что делает lorder особенно избыточным. Но tsort имеет более общее использование; он доступен в некоторых системах (например, MacOS X; RHEL 5 Linux).

Итак, используя отслеживание зависимостей от GCC плюс tsort, вы сможете проверить, существуют ли циклы между модулями. Но с этим нужно обращаться осторожно.

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

2 голосов
/ 30 сентября 2011

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

Упакуйте каждый модуль в пакет Debian (что выполняется очень быстро, когда он ужеautoconf'd), объявляйте Build-Depends правильно и собирайте пакеты в среде pbuilder.Это гарантирует, что доступны только общедоступные заголовки каждого модуля (поскольку в пакетах .deb установлены только те, которые установлены pbuilder для сборки других пакетов), а также есть отличные инструменты для просмотра деревьев пакетов Debian и проверки их цикличностибесплатно.

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

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