実施したいこと
- LinuxとWindowsで共通のMakefileを使用し、C++のソースをコンパイルしたいです。
- コンパイラは、ARMクロスコンパイラを使用しています。ビルドファイルを、ARMコア搭載のRaspberry Pi等で使用します。
前提
- Makefileを使ってC++のソースをコンパイルする。
- コンパイルしたいディレクトリの構成は以下の通り。
txt
1. 2├── Makefile 3├── include 4│ ├── subdir 5│ │ │── subheader1.h 6│ │ │── subheader2.h 7│ │ └── ... 8│ │── header1.h 9│ │── header2.h 10│ └── ... 11| 12└── source 13 ├── subdir 14 │ ├── subsource1.cpp 15 │ ├── subsource2.cpp 16 │ └── ... 17 │── source1.cpp 18 │── source2.cpp 19 └── ...
- ソースファイルのルートディレクトリは、
source
である。source
は任意のサブディレクトリおよびソースを含む。 - ヘッダーファイルのルートディレクトリは、
include
である。include
は任意のサブディレクトリおよびヘッダーを含む。 - Makefile によるコンパイル後のディレクトリ構成は以下の通り。
txt
1. 2├── Makefile 3├── example.exe 4├── include 5│ ├── subheader 6│ │ │── subheader1.h 7│ │ │── subheader2.h 8│ │ └── ... 9│ │── header1.h 10│ │── header2.h 11│ └── ... 12| 13|── source 14| ├── subsource 15| │ ├── subsource1.cpp 16| │ ├── subsource2.cpp 17| │ └── ... 18| │── source1.cpp 19| │── source2.cpp 20| └── ... 21| 22└── object 23 ├── subsource 24 │ ├── subsource1.o 25 │ ├── subsource2.o 26 │ └── ... 27 │── source1.o 28 │── source2.o 29 └── ...
- オブジェクトファイルのルートディレクトリは、
object
である。object
は、source
と同じディレクトリ構造を持つ。
該当のソースコード
リンク先のサイトを参考にさせていただきました。
makefile
1# コンパイラの指定 2CXX := arm-linux-gnueabihf-g++ 3 4# コンパイラオプションの指定 5CXXFLAGS := -g -O1 -Wall -Wextra -Wuninitialized -std=c++11 6 7# インクルードディレクトリの指定 8INCDIR := -I./include -I./include/% 9 10# ライブラリへのリンクの指定 11LIBS := -lm 12 13# コンパイルするソースの拡張子の指定 14EXTENSION := cpp 15 16# 生成するターゲット名 17TARGET := ./example.exe 18 19# ソースファイルのルートディレクトリ 20SRCROOT := ./source 21 22# ソースルートディレクトリの中を(shellの)findコマンドで、サブディレクトリを含めてリスト化する 23SRCDIRS := $(shell find $(SRCROOT) -type d) 24 25# ソースディレクトリを元にforeach命令で全ファイルをリスト化する 26SRCS := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.$(EXTENSION))) 27 28# 中間バイナリファイルの出力ルートディレクトリ 29OBJROOT := ./object 30 31# ソースディレクトリと同じ構造でオブジェクトファイル名を指定 32OBJS := $(patsubst $(SRCROOT)/%.o, $(OBJROOT)/%.o, $(patsubst %.$(EXTENSION), %.o, $(SRCS)) ) 33 34# クリーン用コマンド 35RM := rm -rf 36 37# Windows用コマンド 38ifeq ($(OS),Windows_NT) 39 RM := cmd.exe /C del /q 40endif 41 42$(TARGET): $(OBJS) 43 $(CXX) $(CXXFLAGS) -o $@ $^ 44 45$(OBJROOT)/%.o: $(SRCROOT)/%.$(EXTENSION) 46 @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi 47 $(CXX) $(CXXFLAGS) $(LIBS) $(INCDIR) -o $@ -c $< 48 49.PHONY: all clean 50 51all: $(TARGET) 52 53clean: 54 $(RM) $(TARGET) $(OBJROOT)
発生している問題
- Linuxでは問題なく実行できるのですが、Windowsでは実行できずにエラーとなります。
- エラーメッセージは文字化けしていて内容が不明ですが、おそらく
SRCDIRS
および`$(OBJROOT)/%.o: $(SRCROOT)/%.$(EXTENSION)
`のレシピでシェルのコマンドを使用しているので、Windowsではオブジェクトファイル用のサブディレクトリを生成できないことが、エラーの原因と思われます。
RM
のコマンドのように、上記のオブジェクト用ディレクトリ生成コマンドも、Linux用とWindows用で自動で切り替わるようにしたいです。Windowsコマンドのいい書き方が分からなかったので、ご教示いただきたいです。- そのほか加筆修正事項がありましたら、ご指摘お願いいたします。
補足情報(FW/ツールのバージョンなど)
- PC OS:Windows10バージョン2004
- CPU:Intel Core i5
- 使用しているLinux OS:WSL(Windows Subsystem for Linux)Ubuntu 20.04.1 LTS
- コンパイラ:arm-linux-gnueabihf-g++(ARMクロスコンパイラ) 4.8.3
とりあえず気になったこととして、Intel x86(i386)/AMD64(x86-x64)のLinux UbuntuでC++コンパイラがarm-linux-gnueabihf-g++ と言うのはちょっとあり得ないのですが。それはARM用のクロスコンパイラのはずです。CPUがARMの、Raspberry Piなどで動かしていませんか。Windows用ではMinGWのg++になるはずです。
エラーメッセージが文字化けしてしまうのであれば、makeを実行する前に
$ export LANG=C
などと実行してからmakeを実行してみてください。
ご指摘ありがとうございます。補足情報を修正いたしました。
ARMクロスコンパイラを使用してビルドしています。ビルドは、Intel CoreのWindowsまたはLinuxで行い、ビルドファイルをARMコア搭載のRaspberry Pi等で使用するイメージです。
Windows側の make がどのようなものか使ったこともないのでわかりませんが、そもそも wildcard 関数などは GNU Make 固有のものではなかったかな(?) 汎用性を(今後のことも含めて)考えるなら、あまりそれらを多用しない方がよいようにも感じます。SRCS の定義にて foreach を用いていますが、ここはサブディレクトリごとに、それぞれ Makefile を作れば解決しそうに思います(その手法はここでは説明しきれませんが)。
たしかに、リンク先(https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html)を見るとGNU Make用でした。アドバイスをありがとうございます。
回答2件
あなたの回答
tips
プレビュー