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;
}
'build'と呼ばれるビルドスクリプトがあり、以下が含まれています。
ビルド:
#!/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行を省略した場合は機能しますが、静的ライブラリでヘッダーファイルを使用できると便利です。何が悪いのですか、どうすれば修正できますか?
ヘッダーはライブラリに保存されません。ヘッダーはライブラリとは別に保存されます。ライブラリにはオブジェクトファイルが含まれます。ヘッダーはオブジェクトファイルではありません。デフォルトでは、Unixシステムの標準ヘッダーは/usr/include
に保存されます。たとえば、通常は/usr/include/stdio.h
と/usr/include/string.h
と/usr/include/stdlib.h
などがあります。デフォルトでは、ライブラリは/usr/lib
に格納されています(ただし、/lib
にもライブラリが含まれている場合があります)。多くの場合、コンパイラは他の場所も検索するように構成されています。一般的な代替の場所の1つは/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
しかないため、リンカはとにかくそれを使用します。
問題はリンクエラーではなく、コンパイルエラーであることに注意してください。プログラムのビルドを2つのステップに分割すると、これはより明確になります。(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
のコンパイルに支障はありません。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.
を必要とするため、ヘッダーが見つかります。