Introduction

前々回は、GLibc内の関数をP/Invokeで呼び出してみました。

また、CMakeでビルドしたC++のライブラリで関数を公開してみました。

これを利用して、.NET CoreでビルドしたC#のアプリケーションから、自作のC++ライブラリの関数を呼びだしてみます。

Preparation

C#とC++の簡単なプロジェクトを用意します。
今回のサンプルは

になります。

サンプルは下記の構成になります。

  • C++ 2つのint型の引数の和を返すAdd関数を備えたSharedライブラリ
  • C# コマンドラインの2つの引数を整数に変換し、その引数をAdd関数に渡した結果を標準出力に表示する実行アプリ

C#

Program.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using System.Runtime.InteropServices;

namespace CsharpApp
{
class Program
{
[DllImport("libCppLib.so")]
private static extern int Add(int x, int y);

static void Main(string[] args)
{
var x = int.Parse(args[0]);
var y = int.Parse(args[1]);
var sum = Add(x, y);
Console.WriteLine($"{x} + {y} = {sum}");
}
}
}

C++

libCppLib.cpp

1
2
3
#include <iostream>

extern "C" int Add(int x, int y){ return x + y; }

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
cmake_minimum_required(VERSION 3.0.0)
project(CppLib VERSION 0.0.0)

include(CTest)
enable_testing()

add_library(CppLib SHARED CppLib.cpp)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

Try

C++側は、Visual Studio Codeで、CMakeを使ってビルドします。
ビルド完了後、buildフォルダ配下に libCppLib.so が生成されます。
このファイルをシステムの共有フォルダに移動します。
FHS (Filesystem Hierarchy Standard) のルールに従って適切なフォルダにSharedライブラリをコピーします。
今回は、**/usr/local/lib64**にコピーします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ file cp CppLib/build/libCppLib.so
CppLib/build/libCppLib.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically
linked, BuildID[sha1]=73b7791b3eeb907e40dadcfbac6ec14df4da8eef, not stripped
$ nm -D CppLib/build/libCppLib.so
0000000000000760 T Add
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
0000000000201028 B __bss_start
U __cxa_atexit
w __cxa_finalize
w __gmon_start__
0000000000201028 D _edata
0000000000201030 B _end
0000000000000764 T _fini
00000000000005f8 T _init
$ sudo cp CppLib/build/libCppLib.so /usr/local/lib64

きちんと、Sharedライブラリがx64形式になっていることと、Add関数が公開されていることを確認し、フォルダにコピーしています。

C#側もビルドしますが、ビルド完了後、環境変数LD_LIBRARY_PATH/usr/local/lib64 を追加します。
そうしないと、C#のアプリがライブラリを見つけることができません。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ cd CsharpApp
$ dotnet restore
$ dotnet build
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

CsharpApp -> /home/xxxxxx/Work/Demo/DotNetCoreLinux6/CsharpApp/bin/Debug/netcoreapp2.0/CsharpApp.dll

Build succeeded.
0 Warning(s)
0 Error(s)

Time Elapsed 00:00:10.24
$ export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH
$ dotnet run 2 4
2 + 4 = 6
$ dotnet run 12 664
12 + 664 = 676

期待通りの結果になりました。
環境変数LD_LIBRARY_PATHへの追加は一時的なものですので、別のシェルを立ち上げたりすると、そのシェルでは認識しないので、再度追加するか永続的に認識するよう別途対応しましょう。

Conclusion

自作ライブラリを使えるようになりました。
これによりLinuxでやれることが広がりました。

Source Code

https://github.com/takuya-takeuchi/Demo/tree/master/DotNetCoreLinux/DotNetCoreLinux6