移植性の高いmakefileの作成
C言語で書かれたソースファイルをmakeツールでビルドしています。
もともとコンパイラとして「Borland C++ Compiler 5.5.1」を使用し、Borland C++ 同ツール付属のmakeツール「MAKE Version 5.2」を使用していました。
makeの基本文法は理解しており、Borlandのコンパイラを使用している間は特に問題ありませんでした。
しかし最近、新たにGCC系列のMinGWという開発環境一式と、補助ツールMSYSを導入し、既存のmakefileをGCCおよびGNUmakeに対応させることにしました。
具体的には、
GMAKEを起動した場合はgccでコンパイルする。
Borland make を起動した場合にはbcc32でコンパイルする。
という切り替えを同一のmakefileで行おうと考えました。
しかし、ここで問題が発生しました。
makeの依存関係部分はborland付属make(以下Bmakeとします)とGNUmakeであまり違いはないのですが、単一のmakefileで対応しようとすると、どうしてもコンパイラオプションやコンパイルコマンドを切り替える部分が必要です。しかし、ifdefやincludeディレクティブに関してはお互いにまったく互換性がなく、片方のmakeで有効なフラグをつかってifdefで分岐しようとしても、もう片方では完全に文法エラーです。
例えば、ifdefやincludeディレクティブは、Bmakeでは先頭に!が必要ですが、GNUmakeには必要ありません。
以下の書籍でポータブルなmakefileの記述に関していろいろ調べたのですが、Bmakeの特殊な文法についての言及がなく、対応策が見つかりません。
様々な環境でビルドされるFireFox3.0のソースコードも参考にしようとmakefileと思われるファイルを全て検索したところ、1769個ほど見つかりました。
その中で!ifdefディレクティブを使用しているのは極わずかで、Makefile.winという名称のものがいくつかあっただけでした。
しかもそれらは最後の方にincludeディレクティブも使っていました。
例えば、MozillaFirefox3.0のソースコードにあるmakefaileの内、firefox-3.0-source.tar\mozilla\dbm\src\Makefile.winは「include <$(DEPTH)/config/rules.mak>等」、という一文がある一方、その他のifなどのディレクティブは頭に!をつけられており、全体としてはBmake(多分ターゲットはMSVC++だと思いますが。)です。
これはBmakeではエラーになるはずなのですが、動作機構は不明です。
また、条件付マクロというテクニックで、ある値が定義されていれば左値を、定義されてなければ右値を使ってマクロ置換するテクニックがあったので、これでディレクティブをマクロ置換してやろうと考えました。しかし、ディレクティブをマクロ定義することはできないようでこれも失敗しています。
#INCLUDE というマクロを定義して、
INCLUDE = $(_GNUMAKE_?include:!include)
#マクロをディレクティブ命令として使う
$(INCLUDE) testmake.mk
それぞれのmake専用makefileを作るのは簡単ですが、新しいプログラムを追加するたびに複数のmakefileを書き直すのは避けたいのです。
長々と書きましたが、解決策として次の2つのいずれかのようなものがあれば教えていただきたいです。
1. ifやincludeディレクティブに代わる、GNUmakeとBmake両方に使えるテクニック。
2. 起動したmakeによって条件分岐、もしくは読み込むファイルを切り替えるテクニック。
よろしくお願いいたします。
開発環境
OS: winXP
コンパイラ: 「Borland C++ Builder 6.0」「Borland C++ Compiler 5.5.1」「gcc version 3.4.5 (mingw special)」
make: 「MAKE Version 5.2 (C++ BuilderとC++ Compiler 5.5.1はおなじmakeを使用している模様)」「GNU Make version 3.79.1」
参考文献
1. 「GNU Make 第3版」オライリージャパン、2005年
2. 「C言語逆引き大辞典」秀和システム、2003年
3. 「GNUソフトウェアプログラミング」、?年
No.1ベストアンサー
- 回答日時:
GNU make 用には GNUmakefile という名前にするのはどうだろうか.
もちろん共通なものは両方から include するようにして.
この回答への補足
今後、同じ内容で質問される方のために補足で情報をまとめときます。参考までに。
同じ環境内でGNUMakeとBorlandMake(MSVC++のmakeであるnmakeとほぼ互換)を使用できるようにする。
依存関係ファイルは書式が共通なので、ひとつのファイルにまとめる。ファイル名「ComonMakefile.in」。
このファイルを読み込むmakeファイルを2系統作る。ファイル名指定無しで、デフォルトで読み込むファイル名の違いを使って、二つのmakeを使い分ける。
GNUMakeは最初に「GNUmakefile」というファイルを読み込むので、このファイルにGNUmake特有の設定やincludeを行う。
Borland Makeは最初に「makefile」を読み込む(Win環境ではMakefileと同じ)ので、このファイルにBmake特有の設定や !include などを行う。
以下に3つのファイルの例を挙げときます。
「GNUmakefile」
# コンパイルとリンク
CC = gcc -o
#コンパイルのみ(compile only)
CCO = gcc -c -o
# リソースの付加
RC = #
# ファイルの消去
RM = rm -f
# 通常使うプログラムの依存関係makefile
include ComonMakefile.in
# 一個ずつコンパイルするときに、フルネームでなく短いターゲット名を使うためのメイクファイル
include sname.mk
# 正式ではない、テスト段階のプログラムのメイクファイル
include testmake.mk
「makefile」
# コンパイルとリンク
CC = bcc32 -e
# コンパイルのみ(compile only)
CCO = bcc32 -c -o
# リソースの付加
RC = brc32 -v
# ファイルの消去
RM = del
# 通常使うプログラムの依存関係makefile
!include ComonMakefile.in
# 一個ずつコンパイルするときに、フルネームでなく短いターゲット名を使うためのメイクファイル
!include sname.mk
# 正式ではない、テスト段階のプログラムのメイクファイル
!include testmake.mk
「ComonMakefile.in」
# サフィックスルール
.c.exe:
____CC $(*<).c
ALLEXE = hello.exe helloC.exe
all: $(ALLEXE)
clean:
____$(RM) *.obj
____$(RM) *.tds
____$(RM) icon\*.res
____$(RM) *.bak
hello.exe: hello.obj Lib-helloprint.obj
____$(CC)hello.obj Lib-helloprint.obj
helloC.exe: helloC.obj Lib-helloprint.obj
____$(CC)helloC.obj Lib-helloprint.obj
# 本体の依存関係
hello.obj: hello.c
____$(CCO)hello.obj hello.c
helloC.obj: helloC.c
____$(CCO)helloC.obj helloC.c
# ライブラリの依存関係
Lib-helloprint.obj: Lib-helloprint.c
____$(CCO)Lib-helloprint.obj Lib-helloprint.c Lib-testprint.h
回答ありがとうございます。
依存関係ファイルを共有にし、それを読み込むファイルを切り替えるということですね?
調べてみたところ、
GNUMakeは、「GNUmakefile」、「makefile」、「Makefile」の順でファイルを探す。
それ以外のmakeは「makefile」か「Makefile」というファイルを探す。
ということですので、この方法で良さそうです。考えてみたら、includeされるファイルを切り替えるより、最初に読み込まれるファイルを切り替えて共有の依存関係を読み込むほうが自然ですね・・・。
ご助言を参考に以下の3ファイルを作り、現在正常に動いております。
GNUmakefile ・・・・・GNUMakeに読み込まれて、GNUMake用のマクロを設定し、依存関係ファイルComonMakefile.inを読み込む。
makefile ・・・・・・BorlandMakeに読み込まれて、BMake用のマクロを設定し、ComonMakefile.inを読み込む。
ComonMakefile.in・・・依存関係と、マクロを使った明示的な構築ルール、サフィックスルールを設定する。
これでうまくいきそうです。ありがとうございました。
No.2
- 回答日時:
たいへんよく調べられているようなので、より良い方法がありそうですが、そこまでMakefileを複雑にさせる方法もありですが、
ご自身のソフトを広く配布するのでなければ、
makefile.B
から
makefile.GCC
を自動生成するくらい、あなたなら簡単そうに思えます。
ご助言ありがとうございます。
>makefile.GCC
>を自動生成する
ということですが、autoconfとautomakeを使うという解釈でよろしいでしょうか?
まったく使用したことがないので試してみたのですが、どちらもGNU系のツールで、Windows環境に単独では対応してないようです。
msys用のパッケージがあったのでインストールして、今やり方を調べているところですが、一筋縄ではいきそうもありません。
現在、Tacosan氏の助言を参考に、3種類のmakefileを作るという方法で対応してみました。
時間はかかりますが、せっかくですので、autoconfもできるようになっておこうと思います。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
0除算して、落ちるプログラムと...
-
C++ で、「)」が必要 というエ...
-
コンパイルできない
-
Eclipseの環境設定について
-
io.hをincludeするとそのような...
-
C++でアボート(Abort)で処理が...
-
インライン展開でコンパイラが...
-
エクセルに入力した数値を出力...
-
graph.hがincludeできない
-
__extension__
-
変数(関数)名の頭に_
-
volatile修飾について
-
コンパイラについて
-
あるプログラムのコマンドライ...
-
正しい五十音順について
-
65536は2の何乗なのでしょうか?
-
変数の値が勝手に変化する原因
-
VBAで関数をつくる
-
COBOLの連絡領域について
-
VBAで仕様書は書きますか?
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
0除算して、落ちるプログラムと...
-
io.hをincludeするとそのような...
-
C++ で、「)」が必要 というエ...
-
C++でアボート(Abort)で処理が...
-
Visual C++とVisual C++.NETの違い
-
変数(関数)名の頭に_
-
fortranでのNaNについて
-
コンパイルできない
-
C++の Unhandled Exceptionにつ...
-
コンパイラの制限 : ヒープの領...
-
PICマイコンによる乱数の表示に...
-
CPUが16bitでも32bitOSでコンパ...
-
関数の戻り値による変数の初期化
-
Delphiの逆コンパイル
-
どのプログラミング言語ででき...
-
コンパイラフラグ(compiler fla...
-
コンパイラについて
-
FORTRAN→Cに翻訳
-
Eclipseの環境設定について
-
バイナリファイルとソースコー...
おすすめ情報