Заголовочные файлы в нескольких каталогах: лучшие практики - PullRequest
8 голосов
/ 28 февраля 2009

Я C Newb

Я пишу много кода на динамических языках (javascript, python, haskell и т. Д.), Но сейчас я изучаю C для аспирантуры и понятия не имею, что делаю.

Проблема

Первоначально я собирал весь свой исходный код в одном каталоге, используя make-файл, который работал довольно хорошо. Тем не менее, мой проект развивается, и я хотел бы разделить источник на несколько каталогов (модульные тесты, утилиты, ядро ​​и т. Д.). Например, мое дерево каталогов может выглядеть следующим образом:

.
|-- src
|   |-- foo.c
|   |-- foo.h
|   `-- main.c
`-- test
    `-- test_foo.c

test/test_foo.c использует как src/foo.c, так и src/foo.h. Используя make-файлы, какой лучший / стандартный способ построить это? Предпочтительно было бы одно правило для построения проекта и одно для построения тестов.

Примечание

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

Любые рекомендации или советы будут оценены. Спасибо!

[редактировать]

Итак, три решения, приведенные к настоящему моменту, таковы:

  • Поместите глобально используемые заголовочные файлы в параллельную директорию include
  • используйте путь в #include satement как в #include "../src/foo.h"
  • используйте переключатель -I, чтобы сообщить компилятору о включаемых местоположениях

Пока мне нравится решение с коммутатором -I, потому что оно не требует изменения исходного кода при изменении структуры каталогов.

Ответы [ 4 ]

3 голосов
/ 28 февраля 2009

Для test_foo.c вам просто нужно указать компилятору, где можно найти заголовочные файлы. Например.

gcc -I../src -c test_foo.c

Затем компилятор также заглянет в этот каталог, чтобы найти файлы заголовков. В test_foo.c вы пишете тогда:

#include "foo.h"

EDIT : Для ссылки на foo.c, фактически на foo.o, вы должны указать это в списке объектных файлов. Я предполагаю, что у вас уже есть объектные файлы, затем сделайте следующее:

gcc test_foo.o ../src/foo.o -o test
2 голосов
/ 28 февраля 2009

Я также редко использую автоинструменты GNU. Вместо этого я помещу один созданный вручную make-файл в корневой каталог.

Чтобы получить все заголовки в исходном каталоге, используйте что-то вроде этого:

get_headers = $(wildcard $(1)/*.h)
headers := $(call get_headers,src)

Затем вы можете использовать следующее, чтобы объектные файлы в тестовом каталоге зависели от этих заголовков:

test/%.o : test/%.c $(headers)
    gcc -std=c99 -pedantic -Wall -Wextra -Werror $(flags) -Isrc -g -c -o $@ $<

Как видите, я не фанат встроенных директив. Также обратите внимание на переключатель -I.

Получение списка объектных файлов для каталога немного сложнее:

get_objects = $(patsubst %.c,%.o,$(wildcard $(1)/*.c))
test_objects = $(call get_objects,test)

Следующее правило сделало бы объекты для ваших тестов:

test : $(test_objects)

Правило test должно создавать не только объектные файлы, но и исполняемые файлы. Как написать правило, зависит от структуры ваших тестов: например, вы можете создать исполняемый файл для каждого .c файла или только один, который тестирует все.

0 голосов
/ 28 февраля 2009

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

#include "../src/foo.h"
0 голосов
/ 28 февраля 2009

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

...