C++
OpenGL
Makefile
glut

クロスプラットフォームなOpenGL(GLUT)用Makefile

More than 1 year has passed since last update.

前回複数のC、C++のプログラムをコンパイルするための汎用的なMakefileを紹介しました。(wildcardを利用したシンプルな汎用Makefile)
今回はその応用的な記事です。

自分がプログラミングを始めようと思ったきっかけはゲームを作りたかったからです。
初心者にとって最初に学習する言語を選ぶのはかなり大きな問題かもしれません。せっかくなら汎用的な言語を学びたいものです。

自分の場合は最終的にはゲームを作りたかったので高速に動作するC言語から学び始めようと考えました。また、C言語は低級言語と呼ばれており、他の言語を学ぶ際に必要な基礎力が身につくと様々な記事で見かけたことも大きな理由でした。(【入門者必見】2017年最新比較!プログラミング言語ランキングTOP10)

GLUTとは

ゲームを作るのにどれほどの要素があるのか分かりませんが、間違いなく描画をする部分が必要です。
C言語でCGを作成するためのパッケージ(関数群)にOpenGLがあります。OpenGLそのものは低次のライブラリであり、実際にはよりソフトウェアに近いGLUT(OpenGL Utility Toolkit)と呼ばれる高次の補助ライブラリを使います。GLUTはWindows、macOS、LinuxなどのUnix系OSで使用できて、その実態であるglut.hをインクルードする部分以外は全て同じソースコードで動作します。

自分は現在MacBook Air(11-inch, Early 2015)を使用していますが、/usr/X11/include/GLにglut.hが入っていました。デフォルトで入っていたかXQuartzのダウンロード時に入ったものだと思われます。
また、MacBook AirにVirtualBoxを使ってLinux(Cent OS)を仮想マシンとして使っていますが、こちらは標準で入っていました。
もし入ってない場合は公式HPから無料で落とせます。

今回はソースコードを書き換えることなく、2つの異なる環境(OS XとCent OS)でCGを描画するためのMakefileの紹介です。

概要

今回もこんな感じのディレクトリ構造を想定しています。

.
├── GNUmakefile
│
├── src
│   ├── sourceA.cpp  # ***.cでも可
│   ├── sourceB.cpp
│   └── ...
│
├── include
│   ├── header1.hpp  # sourceAやsourceBで呼ばれるヘッダファイル
│   ├── header2.hpp
│   └── ...
│
└── bin
    └──

sourceA.cppやsourceB.cppはそれぞれ別々のプログラム。
MacとLinuxでGLUTを使用するために以下のようにソースコードに記述します。

sourceA.cpp
#ifdef __APPLE__
#include <GLUT/glut.h>
#endif

#ifdef linux
#include <GL/glut.h>
#endif

OS XではGLUT/glut.hが、Cent OSではGL/glut.hがインクルードされます。(どちらもglut.hの内容は同じ)

Makefileの中身

# GNUmakefile
#       (c) S.Suzuki 2017.7.24

SUFFIX   = .cpp

SRCDIR   = ./src
INCLUDE  = ./include
EXEDIR   = ./bin

COMPILER = g++

UNAME   := $(shell uname)
ifeq ($(UNAME), Darwin)
CFLAGS  += -Wall -O2 -mmacosx-version-min=10.8
FRAME    = -framework GLUT -framework OpenGL 
endif
ifeq ($(UNAME), Linux)
CFLAGS  += -w -O2 -I/usr/X11R6/include -L/usr/X11R6/lib -lglut -lGLU -lGL -lXmu -lXi -lXext -lX11 -lm -lpthread
endif

SOURCES  = $(wildcard $(SRCDIR)/*$(SUFFIX))
OBJECTS  = $(notdir $(SOURCES:$(SUFFIX)=.o))
TARGETS  = $(notdir $(basename $(SOURCES)))

define MAKEALL
$(1): $(1).o
    $(COMPILER) -I$(INCLUDE) $(CFLAGS) $(FRAME) -o $(EXEDIR)/$(1) $(1).o
    @$(RM) $(1).o
$(1).o:
    $(COMPILER) -I$(INCLUDE) $(CFLAGS) $(FRAME) -c $(SRCDIR)/$(1)$(SUFFIX)
endef

.PHONY: all
all: $(TARGETS)
$(foreach VAR,$(TARGETS),$(eval $(call MAKEALL,$(VAR))))

#make clean
.PHONY: clean
clean: 
    $(RM) $(OBJECTS) 

解説

前回紹介したwildcard関数を使ったMakefileを核としています。
変更点はCFLAGSとFRAMEを環境に合わせて変化させるために、UNAMEという変数を導入した点です。
UNAMEはshellのunameコマンドによりOSの種類を取得し格納します。unameコマンドの挙動は次の通りです。

$ uname   # macで実行した場合
Darwin
$ uname   # linuxで実行した場合
Linux

Makefileでのif文はifeqで記述します。

ifeq (変数A,変数B)
   #何らかの処理
endif

つまり、UNAME変数がDrawinであればOS XでのCFLAGS、FRAMEの設定が行われ、LinuxならCent OSの設定が行われます。

UNAME   := $(shell uname)
ifeq ($(UNAME), Darwin)
CFLAGS  += -Wall -O2 -mmacosx-version-min=10.8
FRAME    = -framework GLUT -framework OpenGL 
endif
ifeq ($(UNAME), Linux)
CFLAGS  += -w -O2 -I/usr/X11R6/include -L/usr/X11R6/lib -lglut -lGLU -lGL -lXmu -lXi -lXext -lX11 -lm -lpthread
endif

mmacosx-version-min=10.8としているのは、OS Xのバージョンが10.9(Mavericks)以降でGLUTを使用したソースをコンパイルすると, "deplicated" (非推奨)という警告が出るためです。Linuxの方では同じ目的でコンパイラオプション-Wall(全ての警告を出力)の代わりに-w(警告を出力しない)を使用しています。

使用例

最近暇があれば回しているハンドスピナーをCGで再現するプログラムをOS XとCent OSという2つの異なる環境でコンパイルしてみました。(ハンドスピナーシミュレーター)
Linuxの方はポップアップメニューがちょっと古臭いですが、どちらも正常に動作しています。

OS X

ScreenShot 4.png

Cent OS

ScreenShot 2.png

参考

–– C言語でコンピュータグラフィクスを作ろう!!
–– GLUTによる「手抜き」OpenGL入門

GitHubアカウント

OpenGL(GLUT)で色々作っています。