はじめに
OpenGLを勉強してドローンのシミュレーションの可視化に挑戦しようと思って、 Web上でOpenGLのサンプルプログラムなどを見つけてビルドしてみました。
すると・・・・
ビルド失敗!!!
こんな事で、1日悪戦苦闘し、ようやくできたので、忘れない様に ここにまとめておきたいと思います。
免責事項など
アップルシリコンのM1 Mac Book Proを購入した時に、以前持っていた、インテルMacの環境を引き継いでいるので ソフトの開発環境がぐちゃぐちゃになっている様な気がしてます。
そのため、ここに書かれていることを、そのままやっても同じ様に上手くいかない人が いるかもしれないと思っております。
万一、上手くいかない場合はご容赦願いたいと思います。
目指すところ
以下のサイト様のサンプルプログラムをビルドして実行できることを目指します。
xcodeのGUIの統合開発環境は使いません。
ビルドはgccで行うものとし、端末にgccコマンドを省略なしに、
全て打ち込んで行います。
(実際は当記事の記載をコピペすればOK)
本記事のやり方がわかってしまえば、独自にmakefileを書いて
makeを使う等の応用ができる様になると思います。
また他のgccが使える環境ならば
同じ様な考え方でビルドができると思います。
準備
以下のライブラリやソフトウエア準備します
- OpenGL
- xcode(CLI)
- homebrew
- git
- VSCode
- GLFW
- GLEW
- GLM
- GCC
OpenGLは最初から入っているので何もしません。
xcodeのインストール
念の為、コマンドライン用のxcodeをインストールします。 もう既に入っているかも知れません。入っていればそういったメッセージが出ます。
以下をコピペして端末に貼り付けて実行してください。
xcode-select --install
homebrewのインストール
Macを使ってプログラミングやロボット開発している人なら既に入っていると思いますが、 homebrewを使うと使いたいソフトのインストールが簡単になるので、まず初めに homebrewをインストールします。
以下をコピペして端末に貼り付けて実行してください。
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
パスを/opt/homebrew/bin
に通しておかないと
homebrewでインストールしたソフトは使えないので通します。
Macのデフォルトのシェルはzshに変わっています。
シェルがzshの場合はホームディレクトリにある.zshrcファイルの末尾に以下を
シェルがbashの場合はホームディレクトリにある.bashrcファイルの末尾に以下を
export PATH="/opt/homebrew/bin/:$PATH"
追加して、保存してください。
これが終わったら端末を一度閉じて開き直すか
zshならば
source .zshrc
bashならば
source .bashrc
を実行してください。
こうするとhomebrewでインストールしたソフトが使える様になります。
gitのインストール
バージョン管理ソフトgitのインストールです。 サンプルソースなどをgithubから持ってくるのに超便利です。
使わない手はありません。
インストールはhomebrewで以下を端末にコピペして実行するだけです
brew install git
VSCodeのインストール
エディタとしても、開発環境としても便利に使えるVisual Studio Codeをインストールします。
- ここからVSCodeをダウンロードします。
- ダウンロードされたZipファイルをFinderで探します。
- zipファイルをダブルクリックして解凍します。
- 解凍されたファイルの中にVSCodeのアイコンのVisualStudioCode.appファイルをApplication folderにドラッグして入れます
- Launchpadで確認できる様になるので起動します
また、homebrewを使ってもインストール可能です
brew install --cask visual-studio-code
--cask
はhomebrewでGUIアプリをインストールするときのオプションです。
GLFWのインストール
OpenGLをそれぞれの環境で使うために自前でコードを書くのは大変と言われています。 私もそこはできないので、そこを肩代わりしてくれるツールキットと呼ばれるものに 依存しなければなりません。
昔から有名なツールキットはglutなのですが、GLSL時代には少々古いかも知れないということで glutに代わるマルチプラットフォームなツールキットとしてGLFWを使いたいと思います。
インストールはhomebrewで以下を端末にコピペして実行するだけです
brew install glfw3
GLEWのインストール
GLEWはOpenGL Extension Wrangler Libraryのことだそうです。
OpenGL拡張機能を使うために必要なライブラリです。 GLSLを使うためには必要です。
インストールはhomebrewで以下を端末にコピペして実行するだけです
brew install glew
日進月歩の世の中でglewに代わり
gladと言うライブラリに移行しつつある様です
今回の記事では、ネット上に使用例が多く存在するglewを使いますが
最新の記事などgladを使ってる場合があり、以下のままではビルドできないです。
gladについては以下を参考にしてみてください。
GLMのインストール
行列計算などのライブラリです。 汎用の数学ライブラリがあれば自分で書いても良い気がしますが GLMを使うと少し楽ができます。 その代わり使い方を覚える必要があります。
インストールはhomebrewで以下を端末にコピペして実行するだけです
brew install glm
GCCのインストール
Mac標準のclangでもビルドはできます。
デフォルトのMacではgccと打つとclangが使われます。
端末で以下のgccを実行すると、clangなのかgccなのかわかります。
gcc -v
私の環境は既にGCCが走る様になっているので以下の様に結果が出ます
Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/opt/homebrew/Cellar/gcc/11.3.0_2/bin/../libexec/gcc/aarch64-apple-darwin21/11/lto-wrapper Target: aarch64-apple-darwin21 Configured with: ../configure --prefix=/opt/homebrew/opt/gcc --libdir=/opt/homebrew/opt/gcc/lib/gcc/11 --disable-nls --enable-checking=release --with-gcc-major-version-only --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-11 --with-gmp=/opt/homebrew/opt/gmp --with-mpfr=/opt/homebrew/opt/mpfr --with-mpc=/opt/homebrew/opt/libmpc --with-isl=/opt/homebrew/opt/isl --with-zstd=/opt/homebrew/opt/zstd --with-pkgversion='Homebrew GCC 11.3.0_2' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --build=aarch64-apple-darwin21 --with-system-zlib --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 11.3.0 (Homebrew GCC 11.3.0_2)
gcc入っていないと、以下な感じ
Apple clang version 13.1.6 (clang-1316.0.21.2.5) Target: arm64-apple-darwin21.5.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
インストールはhomebrewで以下を端末にコピペして実行するだけです
brew install gcc
ここまでしたら、念の為端末を閉じて、再度開いてください。 私の場合は、こうしないとgccをインストールした後に確認してもclangのままでした。
OpenGLのサンプルプログラムのビルド
サンプルソースのクローン
いよいよビルドしていきます。
サンプルは以下ものを使用させていただきました。
適当なディレクトリを作成してそこに移動して
端末を開いて適当なディレクトリhoge
を作ってそこに移動するならば
以下の様にコマンドを実行します。
mkdir hoge cd hoge
mkdir
がディレクトリを作るコマンド、
cd
がディレクトリに移動するコマンドです。
以下を実行してgithubからクローンしてください。 クローンというのは自分のディレクトリにサンプルの ソースコードをディレクトリ構造ごとコピーしてくることを言います。
git clone https://github.com/opengl-tutorials/ogl
これで、なにやらダウンロードが始まるので、しばし待ちます。
完了すると'ogl'ディレクトリが出来上がっています。
以下の様に、'ls'コマンドを打ち込むと、ogl
ディレクトリが出来上がっているのが確認できます。
ls
VSCode 起動してフォルダを開く
VSCodeを起動して
ファイル
->フォルダを開く
を選択し
先ほどクローンしてきたogl
フォルダ(以下ディレクトリをフォルダと呼びます)の下の
tutorial08_basic_shading
を選びます。
その後tutorial08.cpp
を開くと、次の図の様になります。
なにやら所々の行に赤い波線がでていますが、今は無視します。
端末(ターミナル)起動
VSCodeは内部で端末を開けるので便利です。
ターミナル
->新しいターミナル
を選びます
すると、次の図の様に下部にターミナルが開きます。
依存関係の解決とローカルへのコピー
インクリュードファイルとライブラリファイルの場所が特定されていないとコンパイルができないので 場所を探し、今回は今現在作業しているフォルダにコピーしてしまおうと思います。
GLFWの実態をローカルにコピー
開いたターミナルで
brew info glfw
と打つと、glfwのインストールされている場所がわかります。 以下が、その出力です。
MacBook-Pro-4:tutorial08_basic_shading itoukouhei$ brew info glfw glfw: stable 3.3.7 (bottled), HEAD Multi-platform library for OpenGL applications https://www.glfw.org/ /opt/homebrew/Cellar/glfw/3.3.7 (14 files, 495.5KB) * Poured from bottle on 2022-07-02 at 21:37:16 From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/glfw.rb License: Zlib ==> Dependencies Build: cmake ✔ ==> Options --HEAD Install HEAD version ==> Analytics install: 3,894 (30 days), 13,391 (90 days), 50,938 (365 days) install-on-request: 3,356 (30 days), 11,602 (90 days), 45,413 (365 days) build-error: 0 (30 days)
よく見ると
/opt/homebrew/Cellar/glfw/3.3.7
にGLFWの実態があることがわかりました。
ここにあるinclude
フォルダと、lib
の中にあるライブラリファイルを
dependencies
以下の'include'と'library'にコピーします。
Finderの移動でそのフォルダに移動します。
表示されたフォルダの位置をコピペして移動します。
この様に、include
フォルダとlib
フォルダがあることがわかります。
Finder
でCommand+t
でタブを一つ増やします。
そして、新しいタブでtutorial08_basic_shading
フォルダを開きます。
こちらのフォルダへ依存するインクリュードファイルとライブラリファイルをコピーしてくるdependencies
フォルダを作ります。
フォルダができました。
さらにdependencies
フォルダを開いておきます。
glfwのinclude
フォルダをコピーします。
そしてdependencies
フォルダにペーストします。
新たにdependencies
以下にlibrary
フォルダを作ります。
glfwのlib
フォルダ以下にあるlibglfw.3.3.dylib
をコピーして
library
フォルダ以下にペーストします。
このlibglfw.3.3.dylib
がglfwとしてリンクされるライブラリファイルです。
GLEWの実態をローカルにコピー
開いたターミナルで
brew info glew
と打つと、glewのインストールされている場所がわかります。 以下が、その出力です。
MacBook-Pro-4:tutorial08_basic_shading itoukouhei$ brew info glew glew: stable 2.2.0 (bottled), HEAD OpenGL Extension Wrangler Library https://glew.sourceforge.io/ /opt/homebrew/Cellar/glew/2.2.0_1 (38 files, 3.7MB) * Poured from bottle on 2022-07-03 at 12:01:22 From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/glew.rb License: BSD-3-Clause ==> Dependencies Build: cmake ✔ ==> Options --HEAD Install HEAD version ==> Analytics install: 7,184 (30 days), 22,204 (90 days), 101,874 (365 days) install-on-request: 1,416 (30 days), 4,360 (90 days), 21,236 (365 days) build-error: 0 (30 days)
よく見ると
glewの実態が/opt/homebrew/Cellar/glew/2.2.0_1
にあることがわかります。
glfwと同様にfinderでそのフォルダを開くと以下の様に見えます。
glfwと同様に、include
フォルダをローカルのdependencies
フォルダにコピぺします。
ローカルのinclude
フォルダ内は以下の様になります。
glewのlib
フォルダの中はこの様になっています。
これらのライブラリファイル二つを先ほど作成したローカルのlibrary
フォルダ以下にコピペします。
GLMの実態をローカルにコピー
GLMも全く同じ手順でローカルにインクリュードファイルとライブラリファイルを持ってきます。
実態の場所を調べる
brew info glm
調べた結果は以下
glm: stable 0.9.9.8 (bottled), HEAD C++ mathematics library for graphics software https://glm.g-truc.net/ /opt/homebrew/Cellar/glm/0.9.9.8 (1,341 files, 18.8MB) * Poured from bottle on 2022-07-03 at 13:03:37 From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/glm.rb License: MIT ==> Dependencies Build: cmake ✔, doxygen ✘ ==> Options --HEAD Install HEAD version ==> Analytics install: 983 (30 days), 3,145 (90 days), 13,464 (365 days) install-on-request: 530 (30 days), 1,689 (90 days), 8,421 (365 days) build-error: 0 (30 days)
これも、よく見ると
GLMの実態は/opt/homebrew/Cellar/glm/0.9.9.8
にあることがわかりました。
Finderで開くと
これまでと同様に、include
フォルダをローカルのdependencies
にコピペします。
コピペした後のローカルのinclude
フォルダの中身
実は、GLMはlib
以下にライブラリファイルは存在せず、インクリュードするだけで使用できるライブラリとなっています。
commonをコピー
以下はこのサンプルプログラム特有の操作です。
サンプルのソースを見るとcommon
ファイル以下にも依存することが見えます。
このcommon
はtutorial08_basic_shading
の親フォルダ内にあります。ここにあっても、工夫すればビルドできますが、今回はローカルのinclude
内に丸ごとコピペします。
サンプルの親フォルダ内のcommon
はこんな感じで格納されています。
common
フォルダをローカルのinclude
以下にコピペします。
コピペした後
これで、必要なファイルはローカルのフォルダ内にすべて存在していることになります。
ここまでするとVSCodeで開いているサンプルのソースファイルに赤い波線があったものが消えていることがわかります。
ビルド
g++コンパイラ
ビルドするコンパイラは今回のサンプルはC++ソースなので
g++を使います。
g++はgccをインストールした時に同時に入っています。
以下の様にして確認してみましょう。
g++ -v
すると
Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/opt/homebrew/Cellar/gcc/11.3.0_2/bin/../libexec/gcc/aarch64-apple-darwin21/11/lto-wrapper Target: aarch64-apple-darwin21 Configured with: ../configure --prefix=/opt/homebrew/opt/gcc --libdir=/opt/homebrew/opt/gcc/lib/gcc/11 --disable-nls --enable-checking=release --with-gcc-major-version-only --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-11 --with-gmp=/opt/homebrew/opt/gmp --with-mpfr=/opt/homebrew/opt/mpfr --with-mpc=/opt/homebrew/opt/libmpc --with-isl=/opt/homebrew/opt/isl --with-zstd=/opt/homebrew/opt/zstd --with-pkgversion='Homebrew GCC 11.3.0_2' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --build=aarch64-apple-darwin21 --with-system-zlib --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 11.3.0 (Homebrew GCC 11.3.0_2)
となります。
ビルドとは
ビルドとは
必要なソースファイルをコンパイルしてオブジェクトファイル(.oファイル)を作り
出来上がったオブジェクトファイルとライブラリ(.aファイルや.dylibファイル)を合わせてリンクすると 実行ファイルが出来上がるということでした。
2段階にしなくても、ソース、オブジェクトファイル、ライブラリをパスを含めていっぺんに指定してやるとg++は 自動的に実行ファイル生成してくれます。
現在tutorial08_basic_shading
フォルダにいます。この場所をカレントフォルダと言います。
これまで用いてきたパスという用語は、ファイルがどこあるかを表す用語です。
ターミナルで
pwd
と打ち込むとカレントフォルダのパスが表示されます。
ここで表示されるのはPCの一番上のフォルダからのパスが示されるので長いです。
例えば以下の様な感じです。
/Users/pc_user_name/tmp/hoge/ogl/tutorial08_basic_shading
長いので、
カレントフォルダは簡単に./
と表記することが可能です。
今回のビルドに必要なファイルをパスを含めて書くと以下となります。
./tutorial08.cpp ./dependencies/include/common/shader.cpp ./dependencies/include/common/texture.cpp ./dependencies/include/common/controls.cpp ./dependencies/include/common/objloader.cpp ./dependencies/include/common/vboindexer.cpp
ソースファイルは以上の6つです。
試しに、上記パス付きのファイル名を全部g++に与えたらどうなるかやってみます。
端末で全部横に並べると長くなるので\
を使って適宜改行して書いていきます。
適当なところで\
を書いて改行すると、次の行でもコマンド入力が継続できます。
ファイルの区切りはスペースなので忘れない様にしてください。
g++ ./tutorial08.cpp \ ./dependencies/include/common/shader.cpp \ ./dependencies/include/common/texture.cpp \ ./dependencies/include/common/controls.cpp \ ./dependencies/include/common/objloader.cpp \ ./dependencies/include/common/vboindexer.cpp
すると、こんなエラーが出ます
エラーの一部を見てみると
fatal error: GL/glew.h: No such file or directory
これはGL/glew.h
と言うヘッダファイルが見つからないと言うものです。
コンパイルオプション:ヘッダフィルのパスの指定
実はビルドする時はg++にヘッダファイル(.hファイル)がどこにあるのか教えてやらなければなりません。
今回はこれまでの操作で./dependencies/include
以下に必要な全てのヘッダファイルがありますので、そこを教えてやります。
コンパイルオプションとして指定してやりますが、ハイフンと大文字のI(アイ)を使って以下の様に書きます。
-I./dependencies/include
ヘッダファイルの位置はインクリュードパスと言いますが、インクリュードパスの指定を含めた コンパイルのための記述をあらためて書きます。以下を端末に打ち込んでください。
g++ -I./dependencies/include \ ./tutorial08.cpp \ ./dependencies/include/common/shader.cpp \ ./dependencies/include/common/texture.cpp \ ./dependencies/include/common/controls.cpp \ ./dependencies/include/common/objloader.cpp \ ./dependencies/include/common/vboindexer.cpp
とすると、今度はUndefined symbols for architecture arm64:
に続いて
たくさんのエラーが出ます。
これはライブラリから必要なファイルがリンクできないと言うものです。
ライブラリの指定
ライブラリをリンクするためにはコンパイルオプションでライブラリの場所(ライブラリパス)を教えていやることと どのライブラリかを指定する必要があります。
ライブラリパスの指定は以下のオプションです
-L./dependencies/library
そして、ライブラリの指定はlibrary
フォルダ以下には次の様なファイルがあると思いますが
libGLEW.2.2.0.dylib libGLEW.a libglfw.3.3.dylib
これらのファイルがライブラリファイルです。
これらのファイル名の頭のlib
を取り除き、末尾の拡張子を取り除いた名前を使ってライブラリを指定します。
GLEWのライブラリは2種類あります。
.a
は静的ライブラリ、.dylib
は動的ライブラリです。
今回は動的ライブラリに統一したいので、動的ライブラリを使います。
ライブラリの指定の書式はハイフンと小文字のl(エル)を用いて以下です。 複数ある場合はスペースで区切ります。
-lGLEW.2.2.0 -lglfw.3.3
では、あらためてライブラリ関連を含めた、コンパイルコマンド全文は以下となります。
g++ -I./dependencies/include \ -L./dependencies/library \ -lGLEW.2.2.0 -lglfw.3.3 \ ./tutorial08.cpp \ ./dependencies/include/common/shader.cpp \ ./dependencies/include/common/texture.cpp \ ./dependencies/include/common/controls.cpp \ ./dependencies/include/common/objloader.cpp \ ./dependencies/include/common/vboindexer.cpp
これでもまだたくさんのエラーが出ます。
fremeworkオプション
実は肝心のOpenGLやMacのウインドウを表示する関連や、 キーボードやマウスを扱う機能を実現するPCの根本にかかわるライブラリを指定する必要があります。 それらは単にライブラリと呼ばずにフレームワークと呼ばれています。
フレームワークを指定する書式は以下の様になります.複数のフレームワークはスペースで区切ります。
-framework OpenGL -framework Cocoa -framework IOKit -framework Corevideo
ここでは、一つ一つのフレームワークの説明は割愛しますが、OpenGLのプログラムのビルドには以上が必要です。
では、あらためてフレームワーク関連を含めた、コンパイルコマンド全文は以下となります。
g++ \ -I./dependencies/include \ -L./dependencies/library \ -lGLEW.2.2.0 -lglfw.3.3 \ -framework OpenGL \ -framework Cocoa \ -framework IOKit \ -framework Corevideo \ ./tutorial08.cpp \ ./dependencies/include/common/shader.cpp \ ./dependencies/include/common/texture.cpp \ ./dependencies/include/common/controls.cpp \ ./dependencies/include/common/objloader.cpp \ ./dependencies/include/common/vboindexer.cpp
お!
ビルド成功しましたね!
実行ファイル名を指定する
以上でビルドは成功しました。
実行ファイル名はデフォルトでa.out
というものになってしまうので
好きなファイル名'monky'にするには、以下の小文字のo(オー)のコンパイルオプションを追加します。
-o monky
では、あらためて 最終的なコンパイルコマンド全文は以下となります。
g++ \ -o monkey \ -I./dependencies/include \ -L./dependencies/library \ -lGLEW.2.2.0 -lglfw.3.3 \ -framework OpenGL \ -framework Cocoa \ -framework IOKit \ -framework Corevideo \ ./tutorial08.cpp \ ./dependencies/include/common/shader.cpp \ ./dependencies/include/common/texture.cpp \ ./dependencies/include/common/controls.cpp \ ./dependencies/include/common/objloader.cpp \ ./dependencies/include/common/vboindexer.cpp
カレントフォルダにmonkey
と言うファイルができています。
端末に
./monkey
と打ち込むと実行されます。
カーソルキーとマウスに反応します。
終了はESCキーを押します。
clang++でビルド
clang++でビルドするには次のコンパイルオプションを追加しなければなりません。
実は私のハマりポイントはこれでした。
-arch arm64
コマンド全文は
clang++ \ -o monkey \ -arch arm64 \ -I./dependencies/include \ -L./dependencies/library \ -lGLEW.2.2.0 -lglfw.3.3 \ -framework OpenGL \ -framework Cocoa \ -framework IOKit \ -framework Corevideo \ ./tutorial08.cpp \ ./dependencies/include/common/shader.cpp \ ./dependencies/include/common/texture.cpp \ ./dependencies/include/common/controls.cpp \ ./dependencies/include/common/objloader.cpp \ ./dependencies/include/common/vboindexer.cpp
おわりに
長い文章にお付き合いいただきまして、ありがとうございます。
ヘタクソな解説でごめんなさい。
もし、ビルドに失敗したら、既に入っていると思われるソフトや
ライブラリをインストールし直すことをお勧めします。
あと、冒頭でも述べましたが、私の環境は
これまで色々重ねてきたカオスなものなので
たまたまビルドが通ってしまうのかもしれません。
今回は
MacでOpenGLのプログラムを初めてビルド失敗して
心が折れそうになったので初心に帰って、
一つ一つ積み上げてビルドを成功させました。
プログラム初心者は、たった一つの
hello.c
みたいなソースファイルを
コンパイルすることから初めて、
そこから上級には行かない場合が多々あると思います。
強いて言えば、数学ライブラリを使うために-lm
オプションを
つけてねと言われ意味もわからずやっていたかもしれません。
今回はOpenGLをMacでコンパイルすると言う話題でしたが
プログラムをビルドする場合の
基本的な知識をおさらいした形になっています。
依存関係がより複雑になると、
依存するライブラリを全てローカルに
コピーすることなんかできません。
従ってインクリュードパスやライブラリパスを
自分で調べてフルパス (PCの一番上のフォルダからパスを記述すること)
で指定してやらなければなりません。
描くのが大変でビルドコマンド書くだけでするだけで心が折れます。
しかも、ビルドに謎のエラーが出て失敗してしまうと、
もう何もしたくなくなります。
少しでもビルド作業を楽にするには
makeやcmakeを学んだりします。
インクリュードパスやライブラリパスを
自動的に知る方法もあったりします。
私も勉強しないと、全部できませんが
日々これ勉強です。
と言うことで、楽しく計算したり
ロボットや回路を動かすための
プログラミングをやっていきましょう!
ではまた!