Заголовочные файлы в нескольких каталогах: передовой опыт
Я новичок
Я пишу много кода на динамических языках (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
заявлении, как в#include "../src/foo.h"
- используйте
-I
переключатель, чтобы сообщить компилятору о местах включения
Пока мне нравится -I
решение с переключением, потому что оно не требует изменения исходного кода при изменении структуры каталогов.
Ответов (4)4
Для test_foo.c вам просто нужно указать компилятору, где можно найти файлы заголовков. Например
gcc -I../src -c test_foo.c
Затем компилятор также заглянет в этот каталог, чтобы найти файлы заголовков. Затем в test_foo.c вы пишете:
#include "foo.h"
РЕДАКТИРОВАТЬ : чтобы связать с foo.c, на самом деле с foo.o, вам нужно упомянуть его в списке объектных файлов. Я предполагаю, что у вас уже есть объектные файлы, а затем выполните:
gcc test_foo.o ../src/foo.o -o test
Обычный способ сделать это - чтобы файлы заголовков, используемые одним файлом C, были названы так же, как этот файл C, и в том же каталоге, а файлы заголовков, используемые многими файлами C (особенно теми, которые используются всем проектом), чтобы находиться в каталоге include
, параллельном исходному каталогу C.
Я также редко использую автоинструменты 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 [email protected] $<
Как видите, я не фанат встроенных директив. Также обратите внимание на -I
переключатель.
Получить список объектных файлов для каталога немного сложнее:
get_objects = $(patsubst %.c,%.o,$(wildcard $(1)/*.c))
test_objects = $(call get_objects,test)
Следующее правило будет создавать объекты для ваших тестов:
test : $(test_objects)
test
Правил не должен просто сделать объектные файлы, но исполняемые файлы. Как написать правило зависит от структуры ваших тестов: например, вы можете создать исполняемый файл для каждого .c
файла или только один, который проверяет все.