Xamarin.Macで作ったアプリに自作のDLLを読み込む

自作のダイナミックリンクライブラリをXamarin.Macで作成したアプリから読み込む方法です。

Xamarin.Macで作ったアプリでDLLを読み込めず、System.DllNotFoundExceptionがスローされる問題がなかなか解決できませんでした。

以下の方法で、正しく読み込みができるようになりました。

解決前の状況

Xamarin.Macのプロジェクトに自作のダイナミックリンクライブラリ(libSample.dylib)を追加し、ビルド時に出力ディレクトリにコピーする設定にしていました。

C#のコードで、ファイル名を「libSample.dylib」にすると正しく読み込めます。

[DllImport("libSample.dylib", CallingConvention = CallingConvention.Cdecl)]
internal static extern int MyFunc();

しかし、WindowsとMacでソースコードを共有したいため、ファイル名は「Sample.dll」にして読み込みたい。

[DllImport("Sample.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int MyFunc();

ですが、ファイル名を「Sample.dll」にすると読み込むことができませんでした。

解決策

自作のダイナミックリンクライブラリは、WindowsとMacでソースコードを共有するため、ファイル名は「Sample.dll」とします。

ダイナミックリンクライブラリを使用するC#のソースコードは次のようになっています。

internal static class NativeMethods
{
    [DllImport("Sample.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int MyFunc();
}

Xamarin.Macのプロジェクトにダイナミックリンクライブラリを追加する

Xamarin.Macのプロジェクトにダイナミックリンクライブラリ(libSample.dylib)を追加します。

今回はプロジェクトの直下に配置しました。

Xamarin.Macのプロジェクトに「CustomBuildActions.targets」を追加する

Xamarin.Macのプロジェクトを右クリック→追加→Misc→空のテキストファイルを選択して、ファイル名「CustomBuildActions.targets」を新規に作成します。

「CustomBuildActions.targets」を開き、次のように記述します。

<?xml version="1.0" encoding="UTF-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <CreateAppBundleDependsOn>$(CreateAppBundleDependsOn);CopyOurFiles</CreateAppBundleDependsOn>
    </PropertyGroup>
    <Target Name="CopyOurFiles">
        <Message Text="This is us copying a file into resources!" />
        <Copy SourceFiles="libSample.dylib" DestinationFiles="$(AppBundleDir)/Contents/MonoBundle/libSample.dll" />
    </Target>
</Project>

これは、ビルド時に「libSample.dylib」を「$(AppBundleDir)/Contents/MonoBundle/libSample.dll”」にコピーする設定です。

次にプロジェクトファイル(csproj)を編集します。

テキストエディタでcsprojファイルを開くか、VisualStudio For Macからプロジェクトを右クリック→ツール→ファイルの編集を選択します。

Project閉じタグの直前に次の行を追加します。

<Import Project="CustomBuildActions.targets" />

プロジェクトファイル(csproj)の末尾は次のようになります。

    <Import Project="$(MSBuildExtensionsPath)\Xamarin\Mac\Xamarin.Mac.CSharp.targets" />
    <Import Project="CustomBuildActions.targets" />
</Project>

これでビルド時に「CustomBuildActions.targets」の設定が実行されます。

以上で設定は完了しました。

リビルドを実行すると、DLLを正しく読み込むことができるようになりました。

「__declspec’ attributes are not enabled」のエラーメッセージが表示されるとき

XcodeでC++のダイナミックリンクライブラリを作成しているとき、

'__declspec' attributes are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for __declspec attributes

のエラーメッセージが表示された。

対策は、プロジェクトの以下の設定を行う。

  1. 「PROJECT」を選択する
  2. 「Build Settings」を選択する。
  3. 「ALL」を選択する。
  4. 「Apple LLVM 9.0 – Custom Compiler Flags」の「Other C++ Flags」に「-fdeclspec」を追加する。

Pythonで数値を範囲ごとにグループ化するには

やりたいこと

10未満は「0」、
10以上20未満は「1」、
20以上は「2」
のように、
値がどの範囲に入るかを知りたい。

方法

numpyのdigitize()関数を使います。

import numpy as np

範囲を作ります。
10未満、10以上20未満、20以上のグループに分けます。

bins = np.array([10, 20])

数値「0」はどのグループに入るか調べます。

inds = np.digitize(0, bins)
print(inds)
# => 0

数値「15」はどのグループに入るか調べます。

inds = np.digitize(15, bins)
print(inds)
# => 1

数値「25」はどのグループに入るか調べます。

inds = np.digitize(25, bins)
print(inds)
# => 25

数値の配列を渡して、複数の値をまとめて判定します。

x = np.array([0, 15, 25])
inds = np.digitize(x, bins)
print(inds)
# => [0 1 2]

今回のソースコードは次のようになります。

import numpy as np

bins = np.array([10, 20])

inds = np.digitize(0, bins)
print(inds)
# => 0

inds = np.digitize(15, bins)
print(inds)
# => 1

inds = np.digitize(25, bins)
print(inds)
# => 2

x = np.array([0, 15, 25])
inds = np.digitize(x, bins)
print(inds)
# => [0 1 2]

Pythonで区間を等間隔で分割するには

Pythonで区間を等間隔で分割するには

やりたいこと

startからstopまでの区間をnum等分したい。

たとえば、10から50までを5等分したい。

方法

numpyのlinspace()関数を使います。

startからstopまでの区間をnum等分します。

import numpy as np

start = 10
stop = 50
num = 5
lins = np.linspace(start, stop, num)
print(lins)
# => [10. 20. 30. 40. 50.]