Posted at

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

More than 1 year has passed since last update.

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

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) が使われるようになる。