« ^ »

CMakeとGLEWについて考える

所要時間: 約 10分

CMakeを使っていた所、CMakeのバージョンが原因でGLEWを検索できない問題に出会った。こういう出会いは大切にしたい。そこでCMakeについて考える事にした。

WebでアクセスできるCMakeの情報をざっくりまとめる

CMakeはビルド自動化のためのツールであり、様々な所で使用されている。CMake自体については、公式のWebページ1やWikipedia2を読む方が良いため、ここで詳しくは触れない。ソースコードはGitlabでホスティングされており3、GitHubにミラーされている4

CMakeとHomeBrew

macOSでCMakeを使う場合いくつかの方法があるが、ここではHomeBrewを使ってCMakeをインストールする。HomeBrewとはmacOS用のパッケージマネージャで、様々なツールを brew コマンドでインストールできる。

どのようにインストールするかといった情報は、フォーミュラと呼ばれるRubyスクリプトで記述されていて、通常はhttps://github.com/Homebrew/homebrew-coreで管理されているが、これは自分で作成する事もできる。CMakeのフォーミュラはhttps://github.com/Homebrew/homebrew-core/blob/master/Formula/cmake.rbにある。現在のmasterブランチにあるフォーミュラを確認すると 3.27.0 のバージョンのCMakeがインストールされる事がわかる。

とりあえず雑にCMakeをインストールしておく事にする。

brew install cmake

シンプルなCMakeの構成

CMakeを使ってビルドができるように構成を整えていく。

simpleというディレクトリを作成し、その中に最小の構成を作成する。

mkdir -p simple

このディレクトリの中にプログラムのソースコードとなるファイルを作成する。ここでは便宜上 main.c というファイルを作成し、とりあえずCで実装する。

#include <stdio.h>

int main () {
  printf("Ok\n");
}

次にCMakeの設定を作成する。 CMakeLists.txt という名前でファイルを作成し add_executable コマンドを使い、先程の main.c を登録する。ここでは testing という実行可能ファイルを出力するように設定する。

add_executable (testing main.c)

以下のようなディレクトリの構成となった。

tree simple
simple
|-- CMakeLists.txt
`-- main.c

1 directory, 2 files

これをビルドしていく。CMakeでは2つのコマンドを実行する事でビルドを行う。1つめは cmake -S ディレクトリ で、CMakeの設定を元にビルドに必要なファイルを生成する。

cmake -S simple -B .build
-- The C compiler identification is AppleClang 13.1.6.13160021
-- The CXX compiler identification is AppleClang 13.1.6.13160021
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (0.7s)
-- Generating done (0.0s)
-- Build files have been written to: /opt/ng/symdon/pages/posts/1678518623/.build

-B .build にはファイルを生成するディレクトリを指定するが、これは省略する事もできる。 省略すると現在の作業ディレクトリに生成される。幾つかのディレクトリとファイルが生成され、ビルドのための準備が整えられる。整うと .build ディレクトリは次のような構成となる。

tree .build
.build
|-- CMakeCache.txt
|-- CMakeFiles
|   |-- 3.26.4
|   |   |-- CMakeCCompiler.cmake
|   |   |-- CMakeCXXCompiler.cmake
|   |   |-- CMakeDetermineCompilerABI_C.bin
|   |   |-- CMakeDetermineCompilerABI_CXX.bin
|   |   |-- CMakeSystem.cmake
|   |   |-- CompilerIdC
|   |   |   |-- CMakeCCompilerId.c
|   |   |   |-- CMakeCCompilerId.o
|   |   |   `-- tmp
|   |   `-- CompilerIdCXX
|   |       |-- CMakeCXXCompilerId.cpp
|   |       |-- CMakeCXXCompilerId.o
|   |       `-- tmp
|   |-- CMakeConfigureLog.yaml
|   |-- CMakeDirectoryInformation.cmake
|   |-- CMakeScratch
|   |-- Makefile.cmake
|   |-- Makefile2
|   |-- TargetDirectories.txt
|   |-- cmake.check_cache
|   |-- pkgRedirects
|   |-- progress.marks
|   `-- testing.dir
|       |-- DependInfo.cmake
|       |-- build.make
|       |-- cmake_clean.cmake
|       |-- compiler_depend.make
|       |-- compiler_depend.ts
|       |-- depend.make
|       |-- flags.make
|       |-- link.txt
|       `-- progress.make
|-- Makefile
`-- cmake_install.cmake

10 directories, 28 files

生成したファイルを使い、実行可能ファイルをビルドする。ビルドには cmake -build コマンドを実行する。

cmake --build .build
[100%] Built target testing

正常にビルドされると .build/testing という実行可能ファイルが生成される。

.build/testing
Ok

GLEWを読み込むような構成を作る

この問題に取り組もうと思ったきっかけは Evolution Gym というツールをビルドしようとした時に、GLEWやGLFWを読み込めなくて苦労した事がきっかけだった。その時は pip を使用し Evolution Gym のインストールを試みると、 pip は以下のエラーを出力していた。

Obtaining file:///opt/ng/evogym
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Preparing editable metadata (pyproject.toml) ... done
Building wheels for collected packages: evogym
  Building editable for evogym (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Building editable for evogym (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [136 lines of output]
      running editable_wheel
      creating /private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-wheel-id944k49/.tmp-s0dt4vyl/evogym.egg-info
      writing /private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-wheel-id944k49/.tmp-s0dt4vyl/evogym.egg-info/PKG-INFO
      writing dependency_links to /private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-wheel-id944k49/.tmp-s0dt4vyl/evogym.egg-info/dependency_links.txt
      writing top-level names to /private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-wheel-id944k49/.tmp-s0dt4vyl/evogym.egg-info/top_level.txt
      writing manifest file '/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-wheel-id944k49/.tmp-s0dt4vyl/evogym.egg-info/SOURCES.txt'
      reading manifest file '/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-wheel-id944k49/.tmp-s0dt4vyl/evogym.egg-info/SOURCES.txt'
      adding license file 'LICENSE'
      writing manifest file '/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-wheel-id944k49/.tmp-s0dt4vyl/evogym.egg-info/SOURCES.txt'
      creating '/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-wheel-id944k49/.tmp-s0dt4vyl/evogym-1.0.0.dist-info'
      creating /private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-wheel-id944k49/.tmp-s0dt4vyl/evogym-1.0.0.dist-info/WHEEL
      running build_py
      running build_ext
      -- The C compiler identification is AppleClang 13.1.6.13160021
      -- The CXX compiler identification is AppleClang 13.1.6.13160021
      -- Detecting C compiler ABI info
      -- Detecting C compiler ABI info - done
      -- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc - skipped
      -- Detecting C compile features
      -- Detecting C compile features - done
      -- Detecting CXX compiler ABI info
      -- Detecting CXX compiler ABI info - done
      -- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ - skipped
      -- Detecting CXX compile features
      -- Detecting CXX compile features - done
      -- Found OpenGL: /Library/Developer/CommandLineTools/SDKs/MacOSX12.3.sdk/System/Library/Frameworks/OpenGL.framework
      CMake Error at /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
        Could NOT find GLEW (missing: GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
      Call Stack (most recent call first):
        /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:600 (_FPHSA_FAILURE_MESSAGE)
        /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindGLEW.cmake:238 (find_package_handle_standard_args)
        CMakeLists.txt:22 (find_package)


      -- Configuring incomplete, errors occurred!
      Traceback (most recent call last):
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/command/editable_wheel.py", line 155, in run
          self._create_wheel_file(bdist_wheel)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/command/editable_wheel.py", line 344, in _create_wheel_file
          files, mapping = self._run_build_commands(dist_name, unpacked, lib, tmp)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/command/editable_wheel.py", line 267, in _run_build_commands
          self._run_build_subcommands()
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/command/editable_wheel.py", line 294, in _run_build_subcommands
          self.run_command(name)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/_distutils/cmd.py", line 318, in run_command
          self.distribution.run_command(command)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/dist.py", line 1234, in run_command
          super().run_command(command)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 988, in run_command
          cmd_obj.run()
        File "<string>", line 32, in run
        File "<string>", line 57, in build_extension
        File "/usr/local/Cellar/[email protected]/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/subprocess.py", line 413, in check_call
          raise CalledProcessError(retcode, cmd)
      subprocess.CalledProcessError: Command '['cmake', '/opt/ng/evogym/evogym/simulator', '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/opt/ng/evogym/evogym', '-DPYTHON_EXECUTABLE=/Users/sximada/.venv/py311/bin/python3.11', '-DCMAKE_BUILD_TYPE=Release']' returned non-zero exit status 1.
      /private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/_distutils/dist.py:988: _DebuggingTips: Problem in editable installation.
      !!

              ********************************************************************************
              An error happened while installing `evogym` in editable mode.

              The following steps are recommended to help debug this problem:

              - Try to install the project normally, without using the editable mode.
                Does the error still persist?
                (If it does, try fixing the problem before attempting the editable mode).
              - If you are using binary extensions, make sure you have all OS-level
                dependencies installed (e.g. compilers, toolchains, binary libraries, ...).
              - Try the latest version of setuptools (maybe the error was already fixed).
              - If you (or your project dependencies) are using any setuptools extension
                or customization, make sure they support the editable mode.

              After following the steps above, if the problem still persists and
              you think this is related to how setuptools handles editable installations,
              please submit a reproducible example
              (see https://stackoverflow.com/help/minimal-reproducible-example) to:

                  https://github.com/pypa/setuptools/issues

              See https://setuptools.pypa.io/en/latest/userguide/development_mode.html for details.
              ********************************************************************************

      !!
        cmd_obj.run()
      Traceback (most recent call last):
        File "/Users/sximada/.venv/py311/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 353, in <module>
          main()
        File "/Users/sximada/.venv/py311/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 335, in main
          json_out['return_val'] = hook(**hook_input['kwargs'])
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/Users/sximada/.venv/py311/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 273, in build_editable
          return hook(wheel_directory, config_settings, metadata_directory)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/build_meta.py", line 445, in build_editable
          return self._build_with_temp_dir(
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/build_meta.py", line 401, in _build_with_temp_dir
          self.run_setup()
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/build_meta.py", line 338, in run_setup
          exec(code, locals())
        File "<string>", line 61, in <module>
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/__init__.py", line 107, in setup
          return distutils.core.setup(**attrs)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/_distutils/core.py", line 185, in setup
          return run_commands(dist)
                 ^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/_distutils/core.py", line 201, in run_commands
          dist.run_commands()
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 969, in run_commands
          self.run_command(cmd)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/dist.py", line 1234, in run_command
          super().run_command(command)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 988, in run_command
          cmd_obj.run()
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/command/editable_wheel.py", line 155, in run
          self._create_wheel_file(bdist_wheel)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/command/editable_wheel.py", line 344, in _create_wheel_file
          files, mapping = self._run_build_commands(dist_name, unpacked, lib, tmp)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/command/editable_wheel.py", line 267, in _run_build_commands
          self._run_build_subcommands()
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/command/editable_wheel.py", line 294, in _run_build_subcommands
          self.run_command(name)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/_distutils/cmd.py", line 318, in run_command
          self.distribution.run_command(command)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/dist.py", line 1234, in run_command
          super().run_command(command)
        File "/private/var/folders/0m/47l1rtnx3s9dzk560gpfykh00000gp/T/pip-build-env-v_3va8s2/overlay/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 988, in run_command
          cmd_obj.run()
        File "<string>", line 32, in run
        File "<string>", line 57, in build_extension
        File "/usr/local/Cellar/[email protected]/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/subprocess.py", line 413, in check_call
          raise CalledProcessError(retcode, cmd)
      subprocess.CalledProcessError: Command '['cmake', '/opt/ng/evogym/evogym/simulator', '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/opt/ng/evogym/evogym', '-DPYTHON_EXECUTABLE=/Users/sximada/.venv/py311/bin/python3.11', '-DCMAKE_BUILD_TYPE=Release']' returned non-zero exit status 1.
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building editable for evogym
Failed to build evogym
ERROR: Could not build wheels for evogym, which is required to install pyproject.toml-based projects

[notice] A new release of pip is available: 23.1.2 -> 23.2.1
[notice] To update, run: pip install --upgrade pip

もう、この時点でいろんな事を諦めてしまいそうだが、エラーメッセージの最後の方をよく見ると次の出力がある。

      subprocess.CalledProcessError: Command '['cmake', '/opt/ng/evogym/evogym/simulator', '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/opt/ng/evogym/evogym', '-DPYTHON_EXECUTABLE=/Users/sximada/.venv/py311/bin/python3.11', '-DCMAKE_BUILD_TYPE=Release']' returned non-zero exit status 1.

このログからcmakeコマンドを使ってシミュレータをビルドしようとして、失敗している事が何となくわかる。このコマンドは手でも実行できそうであるため、実行する事にした。実行するのは以下のようなコマンドだ。

cmake /opt/ng/evogym/evogym/simulator -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/opt/ng/evogym/evogym -DPYTHON_EXECUTABLE=/Users/sximada/.venv/py311/bin/python3.11 -DCMAKE_BUILD_TYPE=Release

これは当然失敗するのだが、エラーメッセージからヒントを得られる。

bash-5.2$ cmake /opt/ng/evogym/evogym/simulator -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/opt/ng/evogym/evogy
CMake Error at /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake
  Could NOT find GLEW (missing: GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
Call Stack (most recent call first):
  /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:600 (_FPHSA_
  /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindGLEW.cmake:238 (find_package_handle_standard
  CMakeLists.txt:22 (find_package)

-- Configuring incomplete, errors occurred!

ここまで来るとようやく FindGLEW.cmake でGLEWが見つけられていないという想像が付く。環境変数が足りていないようにも思える。そこで、それなりの値を設定して再度実行する事にした。

bash-5.2$ export GLEW_INCLUDE_DIRS=/opt/ng/evogym/evogym/simulator/externals/glew/include
bash-5.2$ export GLEW_LIBRARIES=/opt/ng/evogym/evogym/simulator/externals/glew/lib/libGLEW.2.2.0.dylib
bash-5.2$ cmake /opt/ng/evogym/evogym/simulator -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/opt/ng/evogym/evogym -DPYTHON_EXECUTABLE=/Users/sximada/.venv/py311/bin/python3.11 -DCMAKE_BUILD_TYPE=Release
CMake Error at /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find GLEW (missing: GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
Call Stack (most recent call first):
  /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:600 (_FPHSA_FAILURE_MESSAGE)
  /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindGLEW.cmake:238 (find_package_handle_standard_args)
  CMakeLists.txt:22 (find_package)


-- Configuring incomplete, errors occurred!

これでも特に変化はない。本当にやりたい事は、この問題を解消する事だけれど、ここまでやってみて、それはちょっと込み入っているように思えた。だから、もっと小さな構成を作って調査を進めたい。ここでは、先程の simple 配下のファイルををベースにして、 use-glew ディレクトリを作り、GLEWを利用するようなコードを実装する事で、ビルド時に Evolution Gym と同じようなエラーを発生させられるような構成を作る。通常ではGLEWは別途インストールする必要があるのだが Evolution Gym はGLEW自体を git submodule に登録し内包しているため、外部からそのソースコードツリーの位置を指定する事で、探索する方法を探す。

ソースコードの構成は次のよにした。

tree use-glew
use-glew
|-- CMakeLists-static.txt
|-- CMakeLists.txt
|-- FindGLEW.cmake
|-- a.out
`-- main.c

1 directory, 5 files

main.c はGLEWのヘッダファイルをインクルードしている。当然このままではエラーが発生するが、本当にエラーが発生するかを確認する。

cmake -S use-glew -B .build-glew
cmake --build .build-glew
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /opt/ng/symdon/pages/posts/1678518623/.build-glew
[ 50%] Building C object CMakeFiles/testing.dir/main.c.o

途中まで実行されるが、ビルド時にエラーが発生し、以下のエラーメッセージが出力される。

/opt/ng/symdon/pages/posts/1678518623/use-glew/main.c:2:10: fatal error: 'GL/glew.h' file not found
#include "GL/glew.h"
         ^~~~~~~~~~~
1 error generated.
make[2]: *** [CMakeFiles/testing.dir/main.c.o] Error 1
make[1]: *** [CMakeFiles/testing.dir/all] Error 2
make: *** [all] Error 2

これは当然の結果で GL/glew.h を探せていないからだ。CMakeでこれを探し出し、ビルドファイル内に構成する方法が知りたいのだが、まずは Evolution Gym のビルド時に発生したものと同じ状況を作成したい。 CMake では find_package コマンドを使う事で依存ライブラリを探せるようになっている。そこで find_packageGLEW を指定する事にした。 CMakeLists.txt は以下のような定義となった。

cmake_minimum_required(VERSION 3.0)
project(test_glew)
find_package(GLEW REQUIRED)
add_executable (testing main.c)

この状態で再度ビルドする。

cmake -S use-glew -B .build-glew
-- Configuring incomplete, errors occurred!

これはビルドまで行かずに失敗する。

CMake Error at /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find GLEW (missing: GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
Call Stack (most recent call first):
  /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:600 (_FPHSA_FAILURE_MESSAGE)
  /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindGLEW.cmake:238 (find_package_handle_standard_args)
  CMakeLists.txt:3 (find_package)


[ Babel evaluation exited with code 1 ]

エラーメッセージは Evolution Gym のインストール時に見かけたものと同じだ。これを解消したい。find_packageでGLEWの探索パスを変数として読み込ませる方法を調べる事ができなかった。そこで FindGLEW.cmake を自作する事にした。

use-glew/FindGLEW.cmake

# FindGLEW.cmake
# Search for GLEW library and include directories

find_path(GLEW_INCLUDE_DIR GL/glew.h)
find_library(GLEW_LIBRARY NAMES GLEW GLEW32)

if (GLEW_INCLUDE_DIR AND GLEW_LIBRARY)
    set(GLEW_FOUND TRUE)
else()
    set(GLEW_FOUND FALSE)
endif()

if (GLEW_FOUND)
    if (NOT GLEW_FIND_QUIETLY)
        message(STATUS "Found GLEW: ${GLEW_LIBRARY}")
    endif ()
else()
    if (GLEW_FIND_REQUIRED)
        message(FATAL_ERROR "Could NOT find GLEW")
    endif ()
endif()

mark_as_advanced(GLEW_INCLUDE_DIR GLEW_LIBRARY)

そして、このFindGLEW.cmakeを読み込んで利用するように CMakeLists.txt を変更した。

use-glew/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(test_glew)

set(CMAKE_MODULE_PATH "/opt/ng/symdon/pages/posts/1678518623/use-glew")  # 自前のFindGLEW.cmakeを使用する
set(GLEW_INCLUDE_DIR "/opt/ng/evogym/evogym/simulator/externals/glew/include")
set(GLEW_LIBRARY "/opt/ng/evogym/build/temp.macosx-10.9-x86_64-cpython-37/externals/libglew.a")
find_package(GLEW REQUIRED)  # 自前のFindGLEW.cmakeを使用してGLEWを見つける

add_executable(testing main.c)
target_include_directories(testing PRIVATE ${GLEW_INCLUDE_DIR})
target_link_libraries(testing PRIVATE ${GLEW_LIBRARY})

この状態で構成ファイルの生成を行う。

cmake -S use-glew -B .build-glew
-- Found GLEW: /opt/ng/evogym/evogym/simulator/externals/glew/lib/libGLEW.2.2.0.dylib
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /opt/ng/symdon/pages/posts/1678518623/.build-glew

成功した。次にビルドを試みる。

cmake --build .build-glew
[100%] Built target testing

成功した。実行してみる。

./.build-glew/testing
dyld[38598]: Library not loaded: '/usr/local/lib/libGLEW.2.2.0.dylib'
  Referenced from: '/opt/ng/symdon/pages/posts/1678518623/.build-glew/testing'
  Reason: tried: '/usr/local/lib/libGLEW.2.2.0.dylib' (no such file), '/usr/lib/libGLEW.2.2.0.dylib' (no such file)
bash: line 1: 38598 Abort trap: 6           ./.build-glew/testing
[ Babel evaluation exited with code 134 ]

リンクに失敗しているようだった。この理由を調査する必要がある。この /usr/local/lib/libGLEW.2.2.0.dylib は存在しているかといえば、HomeBrew等を使ってGLEWをインストールしていないから、このファイルは存在しない。では libGLEW.2.2.0.dylib はどこにあるのかというと、 /opt/ng/evogym/evogym/simulator/externals/glew/lib/libGLEW.2.2.0.dylib にあり、これは環境変数 GLEW_LIBRARIES に指定したものだ。dylibにリンクする際のパスに正しいものが設定されていない事により、ライブラリが読み込めないでいた。

実際、DYLD_LIBRARY_PATHを指定すると先程ビルドしたバイナリでも実行できる。

DYLD_LIBRARY_PATH=/opt/ng/evogym/evogym/simulator/externals/glew/lib ./.build-glew/testing
Ok

この環境変数を指定しても良いが、できれば静的リンクさせたい。少し別の作業をしていたら lib ディレクトリにライブラリファイルが無くなっていた。どこにビルドされているのか確認すると、 /opt/ng/evogym/build/temp.macosx-10.9-x86_64-cpython-37/externals 配下に作られていた。今回確認したいのはGLEWのビルド方法ではない。だから、もう何も考えずこのファイルを使う事にした。要点としては GLEW_LIBRARY に静的リンクファイルを指定する事だ。

このファイルを使うため、シンボリックリンクとして CMakeLists.txt を置き換える。

ln -sf CMakeLists-static.txt use-glew/CMakeLists.txt

構成ファイルを生成する。

cmake -S use-glew -B .build-glew
-- The C compiler identification is AppleClang 13.1.6.13160021
-- The CXX compiler identification is AppleClang 13.1.6.13160021
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found GLEW: /opt/ng/evogym/build/temp.macosx-10.9-x86_64-cpython-37/externals/libglew.a
-- Configuring done (0.8s)
-- Generating done (0.0s)
-- Build files have been written to: /opt/ng/symdon/pages/posts/1678518623/.build-glew

成功した。次にビルドを試みる。

cmake --build .build-glew
[ 50%] Building C object CMakeFiles/testing.dir/main.c.o
[100%] Linking C executable testing
[100%] Built target testing

実行する。

./.build-glew/testing
Ok

成功した。ライブラリを正しく探したり、指定したりする方法を試した。CMakeについて少し詳しくなれた気がする。

古いCMakeをHomeBrewでインストールする

以前、動作確認を行っていた時は 3.25 だった。その時は、

インストールが必要になったバージョンは3.22系と3.24系だった。そこで、それらのフォーミュラを個人用のHomebrew Tapに追加する。

古いバージョンは現在のmacOS用のバイナリが提供されていない。その場合はソースコードからビルドする --build-from-source オプションを指定する。

CMake 3.22用ののフォーミュラには Modules/Internal/CPack/CPack.OSXScriptLauncher.in のリンクを削除するワークアラウンドと思われるコードがある。

    # Remove deprecated and unusable binary
    # https://gitlab.kitware.com/cmake/cmake/-/issues/20235
    (pkgshare/"Modules/Internal/CPack/CPack.OSXScriptLauncher.in").unlink
修正前の[email protected]

しかし私の環境では、このコードはエラーしてしまい、正常にインストールできなかった。そのため、このコードはコメントアウトした。

インストールはこのようにする。

brew install takesxisximada/tap/[email protected]  -s
[email protected]のインストール

3.24系は上記のようなコメントアウトは必要なかった。ただし、やはりバイナリは無いのでソースコードからビルドする。

brew install takesxisximada/tap/[email protected]  -s
[email protected]のインストール

リポジトリに置いておく。

https://github.com/TakesxiSximada/homebrew-tap