質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

make

make は、ビルド作業を自動化するツールです。さまざまなファイルの最終変更時刻を比較し、従属するファイルよりも「ターゲット」のファイルが古いことがわかったときユーザーが設定していた命令を実行する事が可能です。

makefile

make は、プログラムのビルド作業を自動化するツールです。コンパイル、リンク、インストール等のルールを記述したテキストファイルをmakefileと呼び、このルールに従ってmakeが自動的にビルドを実行する。

Q&A

解決済

2回答

8304閲覧

C言語でMakefileの実行時、インクルードしているはずの変数が"undeclared"となる原因

minato_hy

総合スコア68

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

make

make は、ビルド作業を自動化するツールです。さまざまなファイルの最終変更時刻を比較し、従属するファイルよりも「ターゲット」のファイルが古いことがわかったときユーザーが設定していた命令を実行する事が可能です。

makefile

make は、プログラムのビルド作業を自動化するツールです。コンパイル、リンク、インストール等のルールを記述したテキストファイルをmakefileと呼び、このルールに従ってmakeが自動的にビルドを実行する。

0グッド

1クリップ

投稿2016/12/17 08:38

編集2016/12/18 10:30

###前提・実現したいこと
組み込み系のソフト開発で、GNUツールチェーンでの開発環境構築を試みています。
CYPRESSのアプリケーションノートを参考に、Makefileを記述しCソースのコンパイルをしようとしているのですが、インクルードしたヘッダファイル内で#defineされているはずの変数が、undeclaredでエラーになります。
なお問題の変数は、EEPROM領域のデータを読み出して変数として定義したものです。
EEPROM領域というのは、マイコンメモリのflash領域の一部をEEPROMとみなしてデータを格納している部分という大雑把な認識なのですが、不正確ならすみません。

申し訳ありませんが対象のプロジェクトは外部に出せないものなので、以降それをイメージした簡易なプロジェクト例で説明させていただきます。また、この簡易プロジェクトだと同様のエラーを再現できていませんので、あくまでイメージとさせてください。

###問題の内容

makeでヘッダファイルを見つけられていないなら、エラー内容は

source_b/Ret.c:1:10: fatal error: 'header_a.h' file not found #include "header_a.h" ^ 1 error generated.

というようなものになると思うのですが、実際には

source_b/Ret.c:3:12: error: `HEADER_A' undeclared (first use in this function) int x = HEADER_A * 2; ^ 1 error generated.

というエラーが出ています。

このように、Makefileでインクルードされているヘッダ自体は見つけられているようなのに、そのヘッダ内で#defineされている変数は探せていないというのは、どういう場合が考えられるのでしょうか?

###再現のための簡易プロジェクト
ディレクトリ構成

TestProject┬─/header_a/─header_a.h │ ├─/source_a/─Main.c │ ├─/source_b/─Ret.c │ ├─/dep/─Main.o.d │ └─Ret.o.d │ └─Makefile

Makefile

1CC = gcc 2AS = as 3LD = ld -v 4CP = gobjcopy 5 6PROJECT = test-mf 7 8SRC = $(shell find source_a source_b -name *.c) 9ASRC = $(shell find source_a source_b -name *.s) 10INCDIR = -I./header_a 11OBJS = $(SRC:.c=.o) $(ASRC:.s=.o) 12 13OPT = -O0 14 15CPFLAGS+= -Wall 16CPFLAGS += -MD -MP -MF ./dep/$(@F).d 17 18all:ROM 19ROM: ASFLAGS += eedefsym Debug_RAM=0 20ROM: clean $(OBJS) $(PROJECT)_rom.elf $(PROJECT)_rom.hex 21ROM: $(PROJECT)_rom.bin 22 23%.o : %.c 24 @echo "--compiling--" 25 $(CC) -c $(CPFLAGS) -I . $(INCDIR) $< -o $@ 26 27%.o : %.s 28 @echo "--assembling--" 29 $(AS) $(ASFLAGS) $< -o $@ 30 31%rom.elf: $(OBJS) 32 @echo "--linking--" 33 $(CC) $(OBJS) -o $@

Main.c

C

1int main(void){ 2 extern int ret_a(void); 3 int a = ret(); 4 5 return 0; 6} 7

Ret.c

C

1#include "header_a.h" 2int ret_a(void){ 3 int x = HEADER_A * 2; 4 int y = HEADER_B * 2; 5 return x + y; 6}

header_a.h

C

1#define HEADER_A eeprom_data[0x01] * 10 //EEPROM領域のデータ 2#define HEADER_B eeprom_data[0x02] * 10

###補足情報(言語/FW/ツール等のバージョンなど)
C言語
GNUツールチェーン

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

source_b/Ret.c:3:12: error: 'HEADER_A' undeclared (first use in this function)

return HEADER_A * 2;

このエラーが出ているならHEADER_A#defineされていないか、#undefされているか、プリコンパイルヘッダ(.pch)が更新されていないかのいずれかだと思います。gccのプリコンパイルヘッダについてはよく知らないので、最初の可能性に着目すると#if/#ifdef/#ifndef/#else/#elif/#endifなどのスイッチの綴りミスや条件間違い等々の影響によって#define HEADER_A ...の行がスキップされているか#include自体がスキップされているといった原因が考えられると思います。

まずは#define HEADER_A ...の直前に#error defining HEADER_Aという行を挿入してコンパイルすれば、このヘッダーの該当位置が本当に生きているか(実際にincludeされていて#ifなどででスキップされてないか)が確実にわかるのではないでしょうか。このエラー(defining HEADER_A)が出なければスキップされているのは確実と思えるので前述したコンパイルスイッチによってどの部分がスキップされているか確認すべきと思います。

投稿2016/12/17 15:17

編集2016/12/17 15:19
KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

minato_hy

2016/12/18 05:26

なるほど、Makefileの記述の問題ではなく、ヘッダファイル側の問題かもしれないということですね。週明けに試させていただきます。
minato_hy

2016/12/19 03:53

#error行を追加しmakeを実行したところ、確かにdifiningのエラーは出なかったのですが、同時にHEADER_Aがundeclaredだというエラーも出なくなり、Ret.oが生成されてしまいました。 これは、どう考えればいいのかちょっとよく解らないです。
KSwordOfHaste

2016/12/21 10:25

ということはどこか別の場所で#defineされていたのでしょうね。そちらの定義でコンパイルできたということなのでしょう。makefileはソースやオブジェクトなどのファイルの依存関係と更新日付で適切なアクションを取るのですがファイルを書き換えてうまくいったなら「どこかに更新日付が不適切になっていてそれがたまたま解消されたから」といった原因かも知れません。 詳しくはmakefileの全容と全ての依存ファイルの状態をみて調べるしかないと思います。 蛇足ですが、なぜうまくいったのかは明確に原因をおさえておいた方がよい気がします。原因がわかればどこかにあるかも知れないミスに気づけることがあり、それが後々のトラブル防止につながるからです。
guest

0

makeファイルの問題ではありません。

eeprom_dataを配列宣言する前に使用しているので、警告が
出ているものかと思います。

#define 文ですが、だだの文字列置き換えです。 int ret_a(void){ return eeprom_data[0x01] * 10 * 2; }

投稿2016/12/17 14:15

nagaetty

総合スコア1106

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

minato_hy

2016/12/18 01:50

解りにくくてすみません、EEPROMにアクセスする関数がコンパイラで用意されていたりすると思うのでeeprom_dataはそれだと思ってください。 それともEEPROMにアクセスしている場合、Makefileでコンパイラの指定以外になにか特別な記述が必要なのでしょうか?
nagaetty

2016/12/18 13:00

EEPROMのアドレス情報が定義されている値が代入されている、定義がheaderにあったりするかと思います。もしくは、Linkerで後で割り当てを定義するのですが。ヘッダのソースを眺めてみることをお勧めします。
minato_hy

2016/12/18 13:10

確認してみます。ただ、EEPROMのアドレス情報の定義などが問題だった場合、この場所で「変数が`undeclared`だ」というエラーが出るのではなく、別の場所で出るか別のエラーになる気がするのですが。私の勘違いか、もしくはコンパイラによって違ったりするのでしょうか。
nagaetty

2016/12/18 14:18

エラーができるのは、型宣言がないからだと思います。 (unsigned int *) eeprom_data = 0xf3420000 ; のような宣言定義があって、代入式がこないとエラーになるかと思います。
nagaetty

2016/12/19 13:57

CYPRESSのアプリケーションノートを参照しましたが、makefileにTRGET指定がないので、メモリマップが存在しないことになっているようなので、エラーになっているものと思います。 EEPROM領域は組み込みターゲットで電源をOFFにしているときにもデータを保持しているメモリエリア。(JTAGやROMライタなどで書込みを行う領域)組込みのC開発では、プログラム領域、データ領域とワークメモリ領域を明確に割り当てて作成します。
minato_hy

2016/12/20 13:13

問題のプロジェクトではターゲットもEEPROMの各種定義もちゃんと設定されていました。 また、上の方のアンサーへのコメントで書いたように、#error行を追加するとコンパイルが通るというよく解らないことが起こっています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問