- 締切済み
makeでのコンパイルについての質問
makeについてお尋ねします。Gnu MakeでWindowsとかWSLでの利用です。 makefileの一部に以下のようなところがあります。 ----- .f90.o: $(SRC) $(FC) -c $< ----- SRCにはa.f90, b.f90, c.f90が含まれており、ターゲットとしてa.o,b.o,c.oを作成するという意味でしょうか。 そのあとの$<というのは最初の必須項目のファイル名を指すと本にあります。とすると、a.f90だけが対象という風に見えるのですが。全部コンパイルしてほしいので、それでいいのかなと思います。 また、ターゲットファイルとしてオブジェクトファイル以外にmodファイル(モジュール)も出力されることになりますが、これだけでいいのでしょうか。この部分が通らないのでいろいろ試している中で思いついたのですが。なお、エラーは以下のようです。 process_begin: CreateProcess(NULL, m2c -o a.o a.mod, ...) failed. make (e=2): 指定されたファイルが見つかりません。 make: *** [a.o] Error 2 また、上記とは別ですが、以下の部分は何をしているのでしょうか。 ----- all: $(TARGET) ----- コメントアウトしても結果は同じだったようです。これが有効に作動する場合もあるのでしょうか。 makeの本(Gnu Make)を見ながら勉強しているのですが、これはルールブックであり、どうして?と聞く部分はあんまりないようです。 事情に従っていくしかないわけですが、上記の部分はどのような事情でしょうか。
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- wormhole
- ベストアンサー率28% (1626/5665)
以下の部分について確認したいのですが、 >この部分は、 >>.f90.o: $(SRC) >> $(FC) -c $< > >以下でよいということでしょうか。 >>.f90.o: >> $(FC) -c $< 私が#2に書いている事をもう少しよく読んで考えて欲しいのですけど単純にそうはいえないです。 分割コンパイルを考慮したソースファイルの分割をされているのなら、そういえるのですが、 a.f90 b.f90 c.f90 のどれか一つでも更新されたら a.o を再コンパイルして作り直さなければならない(b.o c.o についても同様)、そういうソースファイルの分割をされてるなら .f90.o: $(SRC) は、直させないです。
- wormhole
- ベストアンサー率28% (1626/5665)
>----- >.f90.o: $(SRC) > $(FC) -c $< >----- >SRCにはa.f90, b.f90, c.f90が含まれており、ターゲットとして>a.o,b.o,c.oを作成するという意味でしょうか。 ぱっと見make初心者が見たらダメなmakefileに思えてきましたが・・・(もしくはソースファイルの書き方、分割の仕方に問題があるのか) まず、 .f90.o: $(FC) -c $< はサフィックスルールといって上記の場合、サフィックスが .f90 のファイルから .o のファイルを作るときのルールを定義してます。 ですので、これだけで a.o は a.f90 に依存し、a.f90 の更新日時が a.o の更新日時より新しければ $(FC) -c a.f90 を実行する(a.f90 は a.o が依存するファイルの最初のファイルになるので $< は a.f90 に展開される)。 b.o は b.f90 に依存し、以下略 c.o は c.f90 に依存し、以下略 というルール定義になります。 「.f90.o:」の後の記述は、f.90から.oを作成する際の追加の依存ファイル指定になりますから、 .f90.o: a.f90 b.f90 c.f90 $(FC) -c $< というのは、 a.o は a.f90,a.f90, b.f90,c.f90 に依存し、a.f90, b.f90,c.f90 いずれかの更新日時が a.o の更新日時より新しければ $(FC) -c a.f90 を実行する。 b.o は b.f90,a.f90, b.f90,c.f90 に依存し、以下略 c.o は c.f90,a.f90, b.f90,c.f90 に依存し、以下略 となります。 >この部分が通らないのでいろいろ試している中で思いついたのですが。なお、エラーは以下のようです。 > >process_begin: CreateProcess(NULL, m2c -o a.o a.mod, ...) failed. >make (e=2): 指定されたファイルが見つかりません。 >make: *** [a.o] Error 2 色々試されてエラーが出たというのはわかりますが・・・
- asciiz
- ベストアンサー率70% (6803/9674)
makeは非常に単純なツールです。 makefileには、 (生成物) : (元となるソース等) (実行コマンド) っていうのが延々と書かれているだけです。 一般的には変数を使って書かれますが、直接ファイル名を書いても構いません。 ただしこの「元となるソース等」は、「生成物」一つを作るのに必要な依存関係がある物を書きます。 例えば、コンパイルするべきソースファイルと、インクルードするヘッダファイルなどです。(Fortranにインクルードとかあるかどうか知りませんが) 一つ、C言語の例で書いてみます。 ----makefile例1 mainprog: mainprog.c public.h suba.o subb.o gcc mainprog.c suba.o subb.o suba.o: suba.c public.h gcc -c suba.c subb.o: subb.c public.h gcc -c subb.c ---- gccの -c オプションは、コンパイルのみでリンクは実行しない指示です。 なので、「gcc -c suba.c」は、suba.c をコンパイルしてsuba.o を生成するだけとなります。 この状態で「make」とだけ売って実行すると、一番最初の依存関係を解決しようとします。 mainprog と、依存するファイル mainprog.c public.h suba.o subb.o のタイムスタンプを比較し、1つでも更新されていれば(生成物が無ければ常に)、その次の行が実行されます。 今回、suba.c が更新されていたとします。そうすると、「suba.o: suba.c public.h」を解決しなければ行けないので、先に「gcc -c suba.c」が実行されます。 suba.o が更新されたなら、最初の依存関係を解決するため、「gcc mainprog.c suba.o subb.o」が実行されます。 そうすると、最終的に mainprog が生成され、実行終了となります。 ---- このコンパイル作業をやるには、実のところ単純なバッチファイル(シェルスクリプト)でも良いのです。 上の例で言えば、3行の gcc -c suba.c gcc -c subb.c gcc mainprog.c suba.o subb.o っていうバッチファイルにすれば、これ一つ実行するだけで全ソースをコンパイルして最終プログラムを作れます。 でもそれだと、毎回更新していないソースまでコンパイルすることになりますし、そのソースが巨大だったり、サブプログラムの数も多かったりすると、無駄なコンパイル作業が増えて、プログラム生成までの総時間がどんどんかかるようになります。(特に昔のコンピュータほど遅いので…) そこで、makeツールが考案され、「必要なところだけ再コンパイルさせる」って言うことを出来るようにしました。 -- 最後に all 行なんですが、これは生成したい実行プログラムが2つ以上あるときとかに使います。 ----makefile例2 mainprog1: mainprog1.c public.h suba.o subb.o gcc mainprog1.c suba.o subb.o mainprog2: mainprog2.c public.h suba.o subc.o gcc mainprog2.c suba.o subc.o suba.o: suba.c public.h gcc -c suba.c subb.o: subb.c public.h gcc -c subb.c subc.o: subc.c public.h gcc -c subc.c -- mainprog1 は subAとsubBが必要、mainprog2はsubAとsubCが必要、ってわけですね。 でもこれで「make」って打つと、一番最初に書いてある mainprog1 しか更新してくれません。 そこで上記makefileの一番最初に、 ---- all: mainprog1 mainprog2 (※実行コマンド無し) ---- と書いておきます。 これで、「make all」とコマンドを実行すると、「all」というオブジェクトの実態はないのですが、依存関係として mainprog1 mainprog2 と書いてあるので、その依存関係を見に行きます。 以後はそれぞれ 「mainprog1: mainprog1.c public.h suba.o subb.o」 と 「mainprog2: mainprog2.c public.h suba.o subc.o」 の依存関係をそれぞれ解決(=オブジェクト生成)して、makeの実行が終わります。 -- makefileの最初にいろいろ変数定義するのは、もちろん今後書き換えるときのことを考えているからです。 インクルードファイルが増えたり、プログラム全般にわたってコンパイルオプション(最適化レベルなど)を変えて生成したかったり。 場合によっては、違うバージョンのコンパイラでプログラム全体を再コンパイルすることなんかもあるのかもしれません。 でもそのような必要がなければ、この回答に書いたように、変数定義無し、コンパイルプログラムも必要ファイルも直接記述してしまって良い訳です。 変数で書いた場合は、その部分が置き換わるだけです。
お礼
懇篤な回答を頂き有難うございます。 私は今まで、数万行程度のプログラムなら、全部1つにまとめてコマンドライン1行でのコンパイルだけをやってきました。ソースプログラムがファイルごとに多数に分割されたままの環境での作業を行ってきませんでした。そういう視点からみるとmakeの目的はコンパイルに必要なソースやオブジェクトの収集だと思っていたのですが、依存関係の処理が重要ということですね。それも実は聞いていて、それをmakeが助けてくれるもの、すなわちユーザは依存関係に頓着せずにmakeがよきに計らってくれるものだと思っていたのです。そうではなくて、makeに向かって依存関係をユーザが提示するということですね。 その辺が私のボタンの掛け違いのように思いました。 依存関係を明確に示す、という観点からmakefileを見直すと少し道が開けるようです。
お礼
回答ありがとうございます。 以下の部分について確認したいのですが、 この部分は、 >.f90.o: $(SRC) > $(FC) -c $< 以下でよいということでしょうか。 >.f90.o: > $(FC) -c $< この例だと、ソースファイルがどれなのかを指定していません。同一フォルダの中の.f90となっているものそれぞれすべてに対応するということでしょうか。.f90.o: $(SRC)の$(SRC)は必須だと書いてあったようなのですが。 .f90.oが.f90から.oを作成するということになっているというような想像できなくはないですが、確信には至れません。もし、想像だけでmakefileを理解するとしたら想像の直列つなぎ(その次も想像)になるので思い違いによる修正が難しいだろうにと思います。