CMake + OpenCL


CMake 3.1 より、OpenCL の include path 及び library path を探索してくれる FindOpenCL.cmake が追加されました。
今回は CMake を使って Makefile を生成し OpenCL プログラムを作成してみます。

環境

OS Windows 7 64bit
GPU nVidia GeForce 750Ti
CMake 3.2.2
コンパイラ Visual Studio 2013

FindOpenCL.cmake について

OpenCL のライブラリを探すにあたって、何かしら環境変数などで探索先を指定していると予想できます。とりあえず FindOpenCL.cmake を読んでみましょう。

find_path(OpenCL_INCLUDE_DIR
  NAMES
    CL/cl.h OpenCL/cl.h
  PATHS
    ENV "PROGRAMFILES(X86)"
    ENV AMDAPPSDKROOT
    ENV INTELOCLSDKROOT
    ENV NVSDKCOMPUTE_ROOT
    ENV CUDA_PATH
    ENV ATISTREAMSDKROOT
  PATH_SUFFIXES
    include
    OpenCL/common/inc
    "AMD APP/include")

上記のようにベンダー別の環境変数を参照しているようです。今回は nVidia 環境ですので NVSDKCOMPUTE_ROOT もしくはCUDA_PATH を設定すれば良いことが判ります。
FindOpenCL.cmake は結果として

  • OpenCL_FOUND
  • OpenCL_INCLUDE_DIRS
  • OpenCL_LIBRARIES
  • OpenCL_VERSION_STRING
  • OpenCL_VERSION_MAJOR
  • OpenCL_VERSION_MINOR

を定義します。よって CMakeLists.txt 以下のように利用すれば OK です。

find_package(OpenCL REQUIRED)
include_directories(${OpenCL_INCLUDE_DIRS})
add_executable(opencl_app src.cpp)
target_link_libraries(opencl_app ${OpenCL_LIBRARIES})

実際にアプリケーションを作る

使用したコードは次のような単に platform と device を取得するだけのものです。

main.cpp
#include <CL/cl.h>
#include <iostream>

int main(){
    cl_uint num_platforms;
    cl_platform_id platforms;
    cl_int ret = clGetPlatformIDs(1, &platforms, &num_platforms);
    if (ret != CL_SUCCESS){
    std::cerr << "Error: Can't get platform ids" << std::endl;
    return -1;
    }

    cl_device_id dev;
    cl_uint num_devices;
    ret = clGetDeviceIDs(platforms, CL_DEVICE_TYPE_GPU, 1, &dev, &num_devices);
    if (ret != CL_SUCCESS){
    std::cerr << "Error: Can't get device ids" << std::endl;
    return -1;
    }
    return 0;
}

そして次の CMakeLists.txt を利用して Visual Studio の sln を生成します。

cmake_minimum_required(VERSION 3.1)

find_package(OpenCL REQUIRED)

include_directories(${OpenCL_INCLUDE_DIRS})
add_executable(opencl_test main.cpp)
target_link_libraries(opencl_test ${OpenCL_LIBRARIES})

後は GUI なり コンソールから CMake を実行すれば OK です。

まとめ

CMake を使って OpenCL を用いたアプリケーションをビルドしてみました。今回は特に GPU を用いた演算などは行いませんでしたが、OpenCL_VERSION_STRING を用いることで、環境に応じて用いる kernel のソースコード を変更するなど、より柔軟にアプリケーションの開発が可能と考えられます。
個人的には、見つかったライブラリのベンダーなども定義して返してくれると、環境依存のコードを #ifdef で分けるなどしやすいかなと思います。
(OpenCL_LIBRARIES から類推することは可能ですが)