Включая заголовочный файл из статической библиотеки
Я делаю тестовую настройку статической библиотеки C и программы. Код библиотеки, расположенный в подкаталоге "foo" моего проекта, содержит следующие файлы:
Foo/foo.c:
#include <stdio.h>
void foo(void) {
printf("something");
}
Foo/foo.h:
#ifndef foo_h__
#define foo_h__
extern void foo(void);
#endif
Мой программный код выглядит следующим образом:
test.c:
#include "foo.h"
int main() {
foo();
return 0;
}
У меня есть сценарий сборки, называемый "сборка", который содержит следующее:
построить:
#!/bin/bash
gcc -c -Wall -Werror foo/foo.c
ar rcs libfoo.a foo.o
gcc -static -o test test.c libfoo.a # I have also tried -L. -lfoo
Но когда я запускаю сборку, она выдает мне следующую ошибку:
test.c:1:17: fatal error: foo.h: No such file or directory
#include "foo.h"
^
Compilation terminated
Однако он работает, когда я опускаю строку #include, но я бы предпочел использовать заголовочные файлы в моих статических библиотеках. Что я делаю не так, и как мне это исправить?
1 ответ
Заголовки не хранятся в библиотеках. Заголовки хранятся отдельно от библиотек. Библиотеки содержат объектные файлы; Заголовки не являются объектными файлами. По умолчанию стандартные заголовки в системе Unix хранятся в /usr/include
- вы обычно найдете /usr/include/stdio.h
а также /usr/include/string.h
а также /usr/include/stdlib.h
, например. По умолчанию библиотеки хранятся в /usr/lib
(но вы также можете найти некоторые в /lib
). Часто компиляторы также настроены на поиск в других местах. Одно общее альтернативное местоположение находится под /usr/local
, так /usr/local/include
для заголовков и /usr/local/lib
для библиотек. Также обратите внимание, что в одной библиотеке может быть много заголовков, определяющих сервисы. Библиотека по умолчанию является примером. Он имеет функции, соответствующие тем, которые находятся в <stdio.h>
, <string.h>
, <stdlib.h>
и много других заголовков тоже.
Глядя на ваш код:
Если ваш заголовочный файл находится в
./foo/foo.h
тогда вам нужно написать:#include "foo/foo.h"
Или если вы продолжаете использовать
#include "foo.h"
вам нужно указать, где искать заголовок в командной строке компилятора с аргументом:gcc -Ifoo -o test test.c -L. -lfoo
Я сознательно исключил
-static
; это необходимо только тогда, когда есть выбор между статической и общей библиотекой, но у вас есть толькоlibfoo.a
так что компоновщик будет использовать это в любом случае.Обратите внимание, что проблема заключается в ошибке компиляции, а не в ошибке компоновки. Это было бы понятнее, если бы вы разбили сборку программы на два этапа: (1) создать
test.o
и (2) ссылка на программу:gcc -c -Ifoo test.c gcc -o test test.o -L. -lfoo
Ваш охранник заголовка неисправен. Первоначально вы имели (но обновили вопрос, так что эта опечатка больше не присутствует):
#ifndef foo_h__ #define foo_h_
Тебе нужно:
#ifndef foo_h__ #define foo_h__
Имена макросов должны быть одинаковыми в обеих строках. Обратите внимание, что в этом случае орфографические ошибки в основном безвредны, но в Mac OS X
clang
(маскируясь подgcc
) предупредил об этом (хотя я заметил это до того, как сделал какую-либо компиляцию). В некоторых других случаях вы не получите защиту, на которую рассчитаны средства защиты заголовков../foo/foo.h:1:9: warning: 'foo_h__' is used as a header guard here, followed by #define of a different macro [-Wheader-guard] #ifndef foo_h__ ^~~~~~~ ./foo/foo.h:2:9: note: 'foo_h_' is defined here; did you mean 'foo_h__'? #define foo_h_ ^~~~~~ foo_h__ 1 warning generated.
Вы можете законно задуматься:
- Если мне нужно
-Ifoo
при компиляцииtest.c
почему это не было необходимо при компиляцииfoo/foo.c
?
Хороший вопрос!
- Это не повредило бы сборник
foo/foo.c
- GCC ищет заголовки в каталоге, где находится исходный код модуля перевода (поэтому при компиляции
foo/foo.c
выглядит вfoo
каталог для заголовков включен как#include "foo.h"
тем не мение. - Исходный файл
foo/foo.c
должен был включатьfoo.h
тоже; это очень важно, так как компилятор обеспечивает перекрестную проверку, необходимую для обеспечения согласованности. Если бы вы написали#include "foo.h"
компиляция будет работать как описано. Если вы написали (вfoo/foo.c
)#include "foo/foo.h"
затем командная строка для созданияfoo.o
понадобилось бы-I.
так что заголовок можно найти.