CMake で C++ の DLL を C# から呼び出す VS ソリューションを作ってみた


作ったものはこちらです。

C# の exe ファイルから c++ で書かれた dll 内の helloworld な API を呼び出すだけのシンプルなサンプルです。

備忘録的メモ

環境

  • Windows 7
  • CMake 3.9.3
  • Visual Studio Community 2017

ディレクトリ構成

以下のような構成。

+-build/
| +-CMakeGenerate.bat
| +-project/
|   +-DEBUG/
|   +-RELEASE/
|   +-ソリューションファイルなど
|
+-src/
  +-DllCaller/
  | +-CMakeLists.txt
  | +-main.cs
  |
  +-HelloWorldDll/
  | +-CMakeLists.txt
  | +-helloworld.cpp
  | +-helloworld.h
  |
  +-CMakeLists.txt

build ディレクトリに入って CMakeGenerate.bat を走らせると,projet ディレクトリにソリューションが作成される。 ソリューションをビルドすると,ビルド設定に応じて DEBUG なり RELEASE なりのディレクトリが作られて,exe や dll はその中に配置される作戦。

各ファイルの働き

build/CMakeGenerate.bat

project ディレクトリを作成して,その中で cmake を読んで Visual Studio のソリューションを作る。

src/CMakeLists.txt

set(CMAKE_SUPPRESS_REGENERATION true)

ZERO_CHECK プロジェクトは特に必要ない。 なので CMAKE_SUPPRESS_REGENERATION を true にセットして,このプロジェクトが生成されないようにする。

project(CSharpWithCppDLL)

ソリューション名の定義。 ここでソリューション名の定義と一緒に言語 (C# と C++) を有効化しても良さそう。

set(CMAKE_CONFIGURATION_TYPES Debug Release)

この設定を明示的に与えない場合,MinSizeRel などのビルド設定が追加される。 自分の場合,ビルド設定は Debut と Release があれば十分なので,上の設定をしておく。

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/DEBUG")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/DEBUG")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/RELEASE")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/RELEASE")

EXE から DLL を呼び出す都合上,これらの出力先ディレクトリをまとめておきたい。 というわけで上のような設定をしておく。 CMAKE_RUNTIME_OUTPUT_DIRECTORY は,EXE ファイルの出力先ディレクトリを指定するもの。 同様に,CMAKE_LIBRARY_OUTPUT_DIRECTORY は DLL の出力先を指定する。

これらのプロパティ名の末尾にビルド設定名を付加することで,ビルド設定毎に異なるディレクトリに出力することができる。 これによって,上記のように Debug と Release で出力ディレクトリを分けることができる。

add_subdirectory(DLLCaller)
add_subdirectory(HelloWorldDll)

Dll 呼び出し用の C# の exe と,C# から呼び出される C++ の dll を定義するサブディレクトリをソリューションにに追加する。

set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT DllCaller)

最後に,DllCaller (C# の exe) のプロジェクトを Visual Studio のスタートアッププロジェクトに設定しておく。

src/DllCaller/CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
enable_language(CSharp)
add_executable(DllCaller main.cs)

C# を使えるように enable_language して,ソースファイルを追加しているだけ。

src/HelloWorldDll/CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
enable_language(CXX)
add_library(HelloWorldDll
  SHARED
  helloworld.h
  helloworld.cpp
)
add_definitions(-DDLL_EXPORT)

enable_language で C++ を有効化した後,DLL 生成用のプロジェクトを追加している。 DLL を作成する場合には,add_library の第 2 引数に SHARED を渡す (この引数に STATIC を渡すと,.lib ファイルが作成されるプロジェクトになる)。

最後の add_definitions は,helloworld.h の中でのコンパイルスイッチを操作するためのもの。 この行を追加することで,コンパイル時に DLL_EXPORT が define され,helloworld.h にて __declspec(export) が使われるようになる。