e-tipsmemo

ごった煮

Visual Studio 2017 boost xml serialization

Nuget パッケージマネージャーでboostと検索して
プロジェクトのプラットフォームツールセットのバージョンにあったBoostをインストールする

f:id:katakanan:20180630112732p:plain
今回はv140を入れた。

準備

シリアライズしたいクラスに追加する。

#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/string.hpp>

class hoge
{
public:
	int a;
	std::string b;

private:
	friend class boost::serialization::access;
	template <class Archive>
	void serialize(Archive& archive, unsigned int version) 
	{
		archive& boost::serialization::make_nvp("a", a);
		archive& boost::serialization::make_nvp("b", b);
	}
};

メンバに自作の別のクラスがある場合は、そのクラスにも似たようにserialize関数を実装すると
再帰的にシリアライズされてくれる。

STLのクラスには自分で実装できないので
~~~.hppをincludeするとできる(例: boost/serialization/string.hpp )

利用

#include <boost/archive/xml_oarchive.hpp>//書き出し
#include <boost/archive/xml_iarchive.hpp>//読み込み

書き出し

hoge h;
//hに値をセットする
std::ofstream ofs(TEXT("test.xml"), std::ios::trunc);
{
	boost::archive::xml_oarchive oarchive(ofs);
	oarchive << boost::serialization::make_nvp("Root", h);
} //ファイルを閉じる前にスコープを区切る
ofs.close();

スコープを切らないと、多分oarchiveのデストラクタが呼ばれなくて(?)、xmlタグが正しく閉じられない。
間違った形のxmlをiarchiveで読もうとすると、
input stream errorでプログラムが止まる。

読み込み

std::ifstream ifs(TEXT("test.xml"));
if (ifs.fail())
{
	return false;
}
hoge h;
{
	boost::archive::xml_iarchive iarchive(ifs);
	iarchive >> boost::serialization::make_nvp("Root", h);
}
//hが読めているはず

Visual Studio 2017 C++ Rest SDK static library build

Visual Studio 2017でcpprestsdkの静的リンクライブラリを作成したときにでてきたエラーの解決方法(2018/06/19)

Cannot fimd Build/Release.Tests.settings

github.com
からリポジトリをクローンするのだが、

WSLからgitコマンドを利用したところ、一部のファイルがうまく引っ張ってこれなくて、
Visual Studioでプロジェクトファイルが開けなかった。

解決策

zipでダウンロードした。
f:id:katakanan:20180619234850p:plain

Can't find v140 in Visual Studio 2017

Nugetからcpprestsdkを利用するときも書いたが、
build set が v140でないとコンパイルが通らない。

CL.exe not found

普通はvcvarsall.batがいつの時点でかで実行されてパスが通っているはずなのだが、
通っていない。

解決策

(install dir) : ~~ \2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx86\x86
環境変数のPathに追加する。

Can not open include file: 'vcruntime.h': No such file or directory

cpprestsdk.sinはVisual Studio 2015を想定しているから見つからないのだろうか。。。

解決策

cpprestsdk.static をクリックしてプロパティから
VC++ディレクトリの
インクルードディレクトリに
D:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\include
などを
追加する。

これでビルド通った。

C++のコンパクトなハッシュライブラリ

HMAC-SHA1を計算したかった。
win32にはcrypt32とかあるけどよくわからなかったので

github.com

便利

#include "../sha1.h"
#include "../hmac.h"

#include <string>
#include <vector>
#include <iostream>

int main()
{
    std::string input= "what do ya want for nothing?";
    std::string key = "Jefe";
    std::string hash = hmac<SHA1>(&input[0], input.size(), &key[0], key.size());
    std::cout << hash << std::endl;
    return 0;
}

f:id:katakanan:20180616111719p:plain

Test Cases for HMAC-MD5 and HMAC-SHA-1

ただし出力が16進数のstringなので、一旦char arrayなどにして解釈し直さないと、間違えることがある。

バイト列でほしいなら

std::string hash = hmac<SHA1>(&input[0], input.size(), &key[0], key.size());
std::vector<unsigned char> v(hash.length() / 2, 0);

for (size_t i = 0; i < hash.length() / 2; i++)
{
	std::string b = hash.substr(i * 2, 2);
	v[i] = std::stoi(b, NULL, 16);
}

こんな感じにする必要がある。

stringとwstringとtstring

Visual Studioで文字列を扱うとき、
以下の設定の違いで

f:id:katakanan:20180616104252p:plain
f:id:katakanan:20180616104219p:plain

TCHARの定義がかわる。
f:id:katakanan:20180616104721p:plain
参考
Tchar.h における汎用テキストのマッピング

typedef std::basic_string<TCHAR> tstring;
typedef std::basic_stringstream<TCHAR> tstringstream;
typedef std::basic_ostringstream<TCHAR> tostringstream;
typedef std::basic_istringstream<TCHAR> tistringstream;

どこかのサイトで見たが、こうしておけばどちらにでも対応できる。
(本当は最初から std::wstring で良かった)

Unicode文字セットのときの、
上の定義でのtstringはstd::wstringと同じであり、
std::stringとの相互変換方法を調べた。

見つかったサイト。
kryozahiro.hateblo.jp

このサイトではwcstombsという関数を使っているが、これはもう古くてでVisual Studio 2017ではエラーがでてしまうので
微修正した。

//std::wstring -> std::string
void narrow(const std::wstring &src, std::string &dest) {
	char *mbs = new char[src.length() * MB_CUR_MAX + 1];
	size_t i;
	wcstombs_s(&i, mbs, src.length() * MB_CUR_MAX + 1, src.c_str(), src.length() * MB_CUR_MAX + 1);

	dest = mbs;
	delete[] mbs;
}
//std::string -> std::wstring
void widen(const std::string &src, std::wstring &dest) {
	wchar_t *wcs = new wchar_t[src.length() + 1];
	size_t i;
	mbstowcs_s(&i, wcs, src.length() + 1, src.c_str(), src.length() + 1);
	dest = wcs;
	delete[] wcs;
}

多分これで良いんじゃないかとおもう。

C++ Rest SDK Visual Studio 2017 E0427 Error

WindowsでWin32のアプリを作っていたとき
http requestとかするときいいライブラリないなみたいな記憶があって
わざわざC++/CLIで、C#のHttpRequestクラスみたいなものをつかてたけども、

MicrosoftのメンテしているC++ Rest SDKという物があったらしい。
(いつのまにか?)
github.com

Visual StudioだとNuget経由で簡単にパッケージの追加と削除が可能になっていてとても良いけども
なぜかメニューバーのツールメニューからNugetの項目が消える。
意味不明だ・・・

なんとかNuget経由で、cpprestsdkをインストールする

そうしたところ、以下のようなエラーがでた。
f:id:katakanan:20180614030219p:plain

調べたところプラットフォームツールセットが新しいのがいけない?

そこで、以下を追加インストールする。
f:id:katakanan:20180614030624p:plain

そしてプロジェクトのプロパティで Visual Studio 2015 (v140)を選択する。

f:id:katakanan:20180614030957p:plain

これでビルドできた。
v141とv140で何が違うんだろうか。

Vivado fsbl build batchmode③

http://e-tipsmemo.hatenablog.com/entry/2018/06/11/000000e-tipsmemo.hatenablog.com

の続きでfsblと言っているが、
device-treeをhsiから作る。

これはそこまで苦労しなかった。

前提

WSLが入っている。とか
WSLが入っているならdevice-tree-compilerが入っているか、とか
hsiへのパスが通っているとか

tcl script


xilinxのdevice-tree-generatorのリポジトリをクローンした場所

このあとにdtcを使えば終了

dts:
	cmd.exe /c 'hsi -mode tcl -source .\dts.tcl'

dtb: dts
	$(shell dtc -I dts -O dtb -o $(dt_dir)/devicetree.dtb $(dt_dir)/system-top.dts)
	$(shell dtc -I dtb -O dts -o $(dt_dir)/devicetree.dts $(dt_dir)/devicetree.dtb)

makeの書き方・・?

Vivado fsbl build batchmode②

前回
e-tipsmemo.hatenablog.com

まだ稚拙だがとりあえず自動化できた
依存の書き方がちょっとよくわからないので、本当は更新していないのに毎回ビルドされる。
それでもSDKをいちいち立ち上げるよりは早い。
いつか直す。

構造
f:id:katakanan:20180606234510p:plain
hsi**はログファイル

makeファイルの書き方がよくわからないけどこんな感じだろうか

$(eval current_dir_name := $(notdir $(shell pwd)))
sdk_dir := "./"$(current_dir_name)".sdk"
fsbl_dir := $(sdk_dir)"/fsbl"
lib_dir := $(fsbl_dir)"/zynq_fsbl_bsp"
release_dir := $(fsbl_dir)"/Release"
USER_SRCS := $(wildcard ../src/*.c) $(wildcard ../src/*.h)
FSBL_SRCS := $(wildcard $(sdk_dir)/*.c) $(wildcard $(sdk_dir)/*.h)

.PHONY: all
all: BOOT.bin

fsbl_project: fsbl.tcl
	cmd.exe /c 'hsi -mode tcl -source .\fsbl.tcl'

libs: fsbl_project
	make -C $(lib_dir) all

executable.elf: libs $(USER_SRCS)
	$(shell cp $(USER_SRCS) ./$(fsbl_dir))
	make -C ./$(fsbl_dir) all

BOOT.bin: executable.elf
	$(shell cp ./$(fsbl_dir)/executable.elf $(release_dir)/fsbl.elf)
	$(shell cp ../bifs/* $(release_dir)/)
	$(shell sh $(release_dir)/bootgen.sh)

clean:
	rm -f $(release_dir)/*
	make -C $(lib_dir) clean
	make -C $(fsbl_dir) clean

また
bootgen,batは考えるのを諦めたので
bootgen.shを別に作ってRelease下で実行させるようにした。

#!/bin/sh
cd `dirname $0`
cmd.exe /c "bootgen.bat -image ./bootbin.bif -arch zynq -o BOOT.bin"

①tclでfsbl. fsbl_bspが生成されて、
②libsをビルドしてから
ソースコードをコピーして
④fsbl自体をビルドして、
⑤Releaseフォルダにいろんな物をコピーして
⑥bootgenでBOOT.binを生成する。

という流れ。