こんにちはー!ニアです。
今回は、C++プロジェクトでNuGetを使ってみようよ!(Vol. 1:パッケージ導入編) の続編で、C++用のNuGetパッケージを作成する基本的な方法について紹介していきます。
#1. C++用のNuGetパッケージを作成するために必要なもの
C++向けのNuGetパッケージに必要なものは以下の4点です。但し、プロパティシートは必要に応じて用意します。
- NuGetパッケージに入れたいライブラリ
- Nuspecファイル
- プロパティシート
- nuget.exe
- Nuspecファイルとは、パッケージの情報やパッケージに含めるファイルの場所などが定義されたXMLファイルで、拡張子は「.nuspec」です。
- プロパティシートとは、C++のプロジェクトの設定するためのXMLファイルで、拡張子は「.props」または「.targets」です。
- nuget.exeはNuGetパッケージを作成するために必要な実行ファイルです。Installing NuGet の「Installing and Updating NuGet Client」→「4. Command-Line Utility」のところにあるリンク「Direct Download」からダウンロードすることができます。
#2. NuGetパッケージを作ってみよう
NuGetパッケージに入れたいライブラリを作成したら、NuGetパッケージに必要なファイルを作成していきましょう。
※この記事ではサンプルとして、以下のソースコードで作成したライブラリをNuGetパッケージにしていきます。
◆ ライブラリのソースコード
#pragma once
#include <string>
class Person {
private:
// 名前
std::string name;
// 年齢
int age;
public:
// コンストラクター
Person( std::string n, int a ) : name( n ), age( a ) {}
// 名前、年齢の取得
std::string Name() const { return name; }
int Age() const { return age; }
// 文字情報の取得
std::string ToString() const;
};
#include "Person.h"
#include <sstream>
using namespace std;
string Person::ToString() const {
ostringstream oss;
oss << "Name : " << this->Name() << endl;
oss << "Age : " << this->Age();
return oss.str();
}
◆ 作成するライブラリ
Person_d.lib
Person.lib
◆ ライブラリとリンクするためのヘッダーファイル
#pragma once
#include "Person.h"
// ライブラリ
#if _DEBUG // デバッグモードの時
#pragma comment( lib, "../lib/Person_d.lib" )
#else // リリースモードの時
#pragma comment( lib, "../lib/Person.lib" )
#endif
##2.1. NuGetパッケージを作成するためのフォルダーを構成する
まずは、以下のような構成を持つフォルダーを作成します。
- ルートとなるフォルダーの中にnuget.exeを入れ、「build」(または「lib」)と名付けたフォルダーを作成します。
- buildフォルダーの中に「native」と名付けたフォルダーを作成します。
- nativeフォルダーの中にライブラリをいれます。
この記事のサンプルでは、nativeフォルダー中に「include」フォルダーと「lib」をフォルダーを作成し、includeフォルダーの中に「NuGetTrial.h」と「Persion.h」を入れ、libフォルダーに「Person_d.lib」と「Person.lib」を入れます。
##2.2. Nuspecファイルを作成する
次に、Nuspecファイルを作成します。中身はXMLなので1から作ることもできますが、nuget.exeを使ってひな形を作成することができます。
コマンドプロンプトを起動し、ルートとなるフォルダーに移動して、以下のコマンドを実行します。
nuget spec [Nuspecのファイル名]
※[Nuspecのファイル名]には、拡張子を除いたファイル名を入力します。省略した場合、「Package」という名前になります。
<?xml version="1.0"?>
<package >
<metadata>
<id>[Nuspecのファイル名]</id>
<version>1.0.0</version>
<authors>[ユーザー名]</authors>
<owners>[ユーザー名]</owners>
<licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
<projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
<iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Package description</description>
<releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
<copyright>Copyright 2015</copyright>
<tags>Tag1 Tag2</tags>
<dependencies>
<dependency id="SampleDependency" version="1.0" />
</dependencies>
</metadata>
</package>
Nuspecで使用できる主な要素とその概要
参考:Nuspec Reference | nuget
https://docs.nuget.org/create/nuspec-reference
※太字のノード名は必須の要素です。
ノード名 | 概要 |
---|---|
package | Nuspecファイルのルートノードです。 |
metadata | このノードの中にNuGetパッケージの情報を入れます。 |
- metadataノード内
ノード名 | 概要 |
---|---|
id | NuGetパッケージを識別するたの一意的な名前を入力します。(注:パッケージのURLにも使用されるので、半角スペースやURLで使用不可能な文字を含めることはできません。)(例:Abc.Def) |
version | バージョンを入力します。(例:1.2.3) |
title | パッケージのタイトル名を入力します。省略した場合、idに入力した値を使用します。 |
author | パッケージに入れたライブラリの作者名をカンマで区切って入力します。(例:Alice, bob) |
owner | NuGetパッケージの作成者名をカンマで区切って入力します。 |
description | パッケージの詳細な説明を入力します。 |
releaseNotes | リリースノート(改訂履歴)を入力します。 |
summary | パッケージの概要を入力します。省略した場合、descriptionに入力した値を使用します。 |
language | 言語(ロケール)を入力します。(例:ja-jp) |
projectUrl | パッケージのプロジェクトのURLを入力します。 |
iconUrl | パッケージマネージャーに表示させるアイコンのURLを入力します。 |
licenseUrl | ライセンス文のURLを入力します。(注:requireLicenseAcceptanceの値をtrueに設定した場合、この要素は必須です。) |
copyright | パッケージのコピーライトを入力します。(例:Copyright (C) 2014-2015 Chronoir.net) |
requireLicenseAcceptance | パッケージのインストール前に、利用者にライセンスの同意をさせたい場合、trueに設定します。省略した場合、falseとなります。 |
dependencies | このノードの中に依存関係となるパッケージのノード(dependency)を入れます。dependencyノードのid属性にそのパッケージのid、version属性にそのパッケージの最小バージョンを入力します。(例:<dependency id="dpd_id" version="1.0.1">) |
tags | パッケージのタグを半角スペースで区切って入力します。パッケージマネージャーの検索などで、そのタグを使って絞り込むことができます。(例:C++ Test Lib) |
作成したNuspecファイルを以下のように編集します。
<?xml version="1.0"?>
<package>
<metadata>
<id>NuGetTrial</id>
<title>NuGetのテスト</title>
<version>1.0.0</version>
<authors>Nia Tomonaka</authors>
<owners>Nia Tomonaka</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<summary>NuGetのテスト(※ここには概要が入ります)</summary>
<description>NuGetのテスト(※ここには詳細な説明が入ります)</description>
<releaseNotes>Ver. 1.00: 初版リリース</releaseNotes>
<copyright>Copyright(C) 2014-2015 Chronoir.net</copyright>
<tags>C++ NuGetTest</tags>
<language>ja-JP</language>
</metadata>
</package>
##2.3. プロパティシートを作成する
C++用のNuGetパッケージをインストールすると、「[ソリューションのフォルダー]/packages/[NuGetパッケージ名]」のフォルダーにパッケージが展開されるので、ヘッダーをインクルードする時はそのフォルダーを経由する必要があります。
そこで、プロパティシートを使い、「追加のインクルードディレクトリ」や「追加のライブラリディレクトリ」にそのフォルダーを追加することで、ヘッダーファイルをインクルードしやすくなります。
// 「[ソリューションのフォルダー]/[プロジェクトのフォルダー]」にあるソースファイルで、
// 「[ソリューションのフォルダー]/packages/NuGetTrial.1.0.0/build/native」フォルダーにある
// NuGetTrial.h をインクルードします。
#include "../packages/NuGetTrial.1.0.0/build/native/NuGetTrial.h"
↓
// 「[ソリューションのフォルダー]/packages/[NuGetパッケージ名]/build/native」フォルダーを
// 追加のインクルードディレクトリに追加します。
#include "NuGetTrial.h"
まず、プロパティーシート(.props)ファイルを作成します。
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets"/>
<PropertyGroup>
</PropertyGroup>
</Project>
次に、プロパティーシート(.targets)ファイルを作成します。
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets"/>
<PropertyGroup>
</PropertyGroup>
<ItemDefinitionGroup>
<!-- プロジェクトファイルの「構成プロパティ」→「C++」に該当します。 -->
<ClCompile>
<!-- マクロを「HAS_NUGETTRIAL」を定義します。 -->
<PreprocessorDefinitions>HAS_NUGETTRIAL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<!-- 追加のインクルードディレクトリに追加するフォルダーを指定します。 -->
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<!-- プロジェクトファイルの「構成プロパティ」→「リンカー」に該当します。 -->
<Link>
<!-- 追加のライブラリディレクトリに追加するフォルダーを指定します。 -->
<AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)../../build/native/lib/;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
</Project>
「$(MSBuildThisFileDirectory)」は、それを書いたファイルのディレクトリを表します。
参考 : MSBuild の予約済みおよび既知のプロパティ | MSDN ライブラリ
https://msdn.microsoft.com/ja-jp/library/ms164309.aspx
.propsのファイルと.targetsのファイルの違いは、プロジェクトファイル(.vcxproj)にインポートするタイミングが異なることです。
参考 : Deep Dive into NuGet Native (Part One) | Past We Saw
http://blog.tnzk.org/post/60429873815/deep-dive-into-nuget-native-part-one
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- プロパティシート( .props )はプロジェクトファイルの最上部にインポートされます。 -->
<Import Project="..\packages\NuGetTrial.1.0.0\build\native\NuGetTrial.props" Condition="Exists('..\packages\NuGetTrial.1.0.0\build\native\NuGetTrial.props')" />
<!-- 中略(プロジェクトの設定) -->
<!-- プロパティシート( .targets )はプロジェクトファイルの最下部にインポートされます。 -->
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\NuGetTrial.1.0.0\build\native\NuGetTrial.targets" Condition="Exists('..\packages\NuGetTrial.1.0.0\build\native\NuGetTrial.targets')" />
</ImportGroup>
</Project>
プロパティシートを作成したら、nativeフォルダーの中に入れます。
##2.4. パッケージを作成する
パッケージに必要なファイルが揃ったら、いよいよパッケージを作成していきます。
コマンドプロンプトを起動し、ルートとなるフォルダーに移動して、以下のコマンドを実行します。
nuget pack [Nuspecのファイル名].nuspec
※[Nuspecのファイル名]には、作成したNuspecファイルの名前を入れます。
パッケージ作成に成功すると、[id].[version].nupkg という名前のファイルができます。
※[id]はNuspecファイルで設定したid、[version]はNuspecファイルで設定したversionです。
nuget pack NuGetTrial.nuspec
'NuGetTrial.nuspec' からパッケージをビルドしています。
パッケージ 'D:\Visual Studio\NuGet\Test\NuGetTest.1.0.0.nupkg' が正常に作成されました。
ちなみに、作成したNuGetパッケージはZIPファイル形式であり、中身はNuspecファイルのあるフォルダーの中身すべてとパッケージを展開するためのファイルが入っています。
#3. 作成したNuGetパッケージでテストしてみよう
作成したNuGetパッケージはNuGetギャラリーや社内サーバーなどへ自由にアップロードできますが、その前にローカル環境でテストしてみましょう。
次に、Visual Studioのパッケージマネージャーの設定を開き、先ほどのフォルダーをNuGetのパッケージリソースに追加します。
参考 : ローカルフォルダをnugetのリポジトリにする | by Temarin_PITA
http://qiita.com/Temarin_PITA/items/293780adf571b802795c
C++プロジェクトを作成し、NuGetパッケージマネージャーで、パッケージリソースを先ほど追加したリポジトリを選択し、作成したパッケージをインストールします(インストールの仕方は、C++プロジェクトでNuGetを使ってみようよ!(Vol. 1:パッケージ導入編) を参照)。
パッケージをインストールしたら、ライブラリが正しく動作するかテストしてみましょう。
#include <iostream>
#include "NuGetTrial.h" // 作成したNuGetパッケージにあるヘッダーファイル
using namespace std;
int main( int argc, char* argv[] ) {
Person nia( "Nia", 22 );
cout << nia.ToString() << endl;
return 0;
}
◆ 実行結果
Name : Nia
Age : 22
#4. おわりに
今回は、C++用のNuGetパッケージを作る基本的な方法を紹介しました。ぜひ、手元にある自作のライブラリのNuGetパッケージを作ってみてはいかがでしょう。
それでは、See you next!
C++プロジェクトでNuGetを使ってみようよシリーズ一覧
- Vol. 1 : パッケージ導入編
- Vol. 2 : パッケージ作成編