nupkgファイルを作成する C++native版①

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

C++のdllをnupkgにして、C++のexeのコードから使いたい。

実験コード

今回実験で作成したコードは下記。

github.com

やったこと

やったこと概要

  • 指定のフォルダ構成を作成し、
  • その中にpropsファイルとtargetsファイルを作成し、配置する
  • specファイルを作成し、配置する
  • nuget.exe pack <nuspecファイル>コマンドで、nupkgを固める

ということをする。

登場人物

フォルダ構成

下記のような構成のフォルダを作成する。

※「DllTest」というライブラリ名だとする。

DllTest.nuspec
include\DllTest.h
lib\native\DllTest.dll
lib\native\DllTest.lib
build\native\DllTest.props
build\native\DllTest.targets

※.hやdll、libは、必要な数だけ、includeフォルダ、libフォルダに配置する。

今回実験で作成したコードだと、以下のフォルダがそれ。
プロジェクトの中に、そういう階層構造のフォルダを作成した。

https://github.com/tera1707/CppDllTemplate/tree/main/nupkg

ライブラリ名.props

.props ファイルは、
「プロジェクトが参照されたときに適用される初期設定」を追加するファイル。
主に インクルードパスやライブラリパスの追加など、コンパイル前に必要な環境を整える。

C++のライブラリの場合はbuild\native\フォルダに配置する。

→初期設定を注入してくれるファイル。

今回の実験の例

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemDefinitionGroup>
    <ClCompile>
      <!-- include フォルダを自動追加 -->
      <AdditionalIncludeDirectories>
        $(MSBuildThisFileDirectory)..\..\include;%(AdditionalIncludeDirectories)
      </AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
        <!-- lib フォルダをライブラリ検索パスに追加 -->
        <AdditionalLibraryDirectories>
            $(MSBuildThisFileDirectory)..\..\lib\native;%(AdditionalLibraryDirectories)
        </AdditionalLibraryDirectories>
        <!-- 必要な .lib を追加 -->
        <AdditionalDependencies>
            DllTest.lib;%(AdditionalDependencies)
        </AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
</Project>
  • パッケージを使う側のプロジェクトの設定(vcxproj)に対して、
    • パッケージの中にある.hファイルを置いてある場所を「追加のインクルードフォルダ」に登録して、
    • パッケージの中にあるlibファイルが置いてある場所を「追加のlib参照先フォルダ」に登録して、
    • なんのlibを見るか、

の設定をしている。

ライブラリ名.targets

  • .targets ファイルは、
    「ビルドの過程で適用される処理や動作」を追加するファイル。
    主に DLL のコピーや追加ビルド手順など、ビルド後に必要なアクションを実行する。

C++のライブラリの場合は、propsと同じくbuild\native\フォルダに配置する。

→ビルド動作を注入するファイル。

今回の実験の例

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <None Include="$(MSBuildThisFileDirectory)..\..\lib\native\DllTest.dll">
      <Link>DllTest.dll</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

パッケージの中にあるdllファイルを、出力先フォルダにコピーしますよ、という設定。

nuspecファイル

nupkgの情報が詰まったファイル。
「このパッケージはどういうもので、どんなファイルを含んでいて、どう使われるべきか」を宣言するファイル。

  • パッケージのメタ情報(ID、バージョン、作者、説明など)
  • 含めるファイルの一覧(DLL、LIB、ヘッダ、props/targets など)
  • 依存関係の定義(他のパッケージに依存する場合) ※今回の実験では←はやってない

上のフォルダ構成に、propstargetsを配置して、nuspecを書いてフォルダ構成の一番topに置き、 そのnuspecをnuget.exe packコマンドに食わすと、nupkgができる。

今回の実験の例

<?xml version="1.0"?>
<package>
  <metadata>
    <id>DllTest</id>
    <version>1.0.2</version>
    <authors>MyName</authors>
    <owners>MyOrg</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>C++ DLL library package Test</description>
  </metadata>
  <files>
    <file src="include\*.h" target="include" />
    <file src="lib\native\*.dll" target="lib\native" />
    <file src="lib\native\*.lib" target="lib\native" />
    <file src="build\native\*.props" target="build\native" />
    <file src="build\native\*.targets" target="build\native" />
  </files>
</package>

★注意★

nuspecで指定するパッケージのID(上のnuspecでいうところの「<id>DllTest</id>」の部分)に付けるIDと、.propsファイル名、.targetsファイル名は同じでないといけない。

この記事ではやってないのだが、nuget.exe push で、nugetホストにuploadするときに、はじかれたりしたことがある。 地味に注意。

今回の実験コード 参考情報

今回、ソリューションのtopフォルダに、「nupkg」というフォルダを作成し、 その中身を上の「フォルダ構成」に沿うような形にした。

.props、.targetsファイルは、build\native\フォルダの中に置き、gitにも登録するのだが、 lib\native\の中に置く/dllや.libは、DllTestのプロジェクトをビルドしたときの「ビルド後イベント」で、 出力されたdllやlibを、そのフォルダにコピーするようにした。

参考までに、ビルド後イベントに下記のようなコピーのためのバッチを入れている。

xcopy /Y /S /I "$(OutDir)*.dll" "$(SolutionDir)nupkg\lib\native"
xcopy /Y /S /I "$(OutDir)*.lib" "$(SolutionDir)nupkg\lib\native"
xcopy /Y /S /I  "$(ProjectDir)DllTest.h" "$(SolutionDir)nupkg\include"

→このパッケージを利用する側がコードを書く際/ビルドする際に必要になる.hファイルとlibファイル、動くときに必要になるdllファイルを、nupkgのフォルダにコピーしている。

その他 参考情報

今回、x64でのみ動けばよかったので、「フォルダ構成」の中に、x64フォルダなどは出てこなくてよかった。 ただそれをわけたいとき(x64/x86で分けたいとき、Debug/Releaseでわけたいとき)には、またやり方があるっぽい。 (WindowsのCopilotが、そういうやり方がありますよ、試してみますか?と聞かれたが、今回はやらなかった)

下の「参考」のdocにもその内容が書かれているようなので、そこを見るか、copilotに聞くとよいかもしれない。

参考

フォルダ構成をどうすればいいか?

https://learn.microsoft.com/ja-jp/nuget/create-packages/creating-a-package#from-a-convention-based-working-directory

nuspecファイルの書き方

https://learn.microsoft.com/ja-jp/nuget/create-packages/creating-a-package#the-role-and-structure-of-the-nuspec-file

targetsファイル、propsファイルの書き方

https://learn.microsoft.com/ja-jp/nuget/concepts/msbuild-props-and-targets