Author Archives: admin

Slim Reader Writer ロック

WindowsのWin32APIの話、実験してないので予想で記述。

Vistaから使える

Vistaから使える。

クリティカルセクションに比べて早い

クリティカルセクションはリーダーとかライターの区別がないので、リーダーがたくさん動いていると大変になる場合がある。

ShareモードとExclusiveモードがある

同じロックに対してSharedモードで取得するかExclusiveモードで取得するか選択できる。Shareモードをロックした場合は次のShareモードロックも取得できるはず。Exclusiveはロックが全くない場合だけ取得できるはず。Exclusiveがロックされているときはどっちも取得できない。

再取得できない

クリティカルセクションは取得後に再取得できたがこれはできないらしい。小さなコードブロックで使いデッドロックしないように注意。

使い方

  • InitializeSRWLockで初期化、またはSRWLOCK_INITを直接設定
  • AcquireSRWLockSharedでShareモードロックを取得、ReleaseSRWLockSharedで開放
  • AcquireSRWLockExclusiveでExclusiveモードロックを取得、ReleaseSRWLockExclusiveで開放

 

 

 

wordpressの固定ページで最近の投稿を表示する

サイドバーに追加するにはwidgetを使えばいいのだがメインのページに表示する方法。

Display Posts Shortcodeをインストール

プラグインのDisplay Posts Shortcodeをインストールする。

ページにショートコードを追加

以下のようなコードをページ追加する。

使えるショートコードの一覧はここ

WindowsのPHPのCurlで”SSL certificate problem: unable to get local issuer certificate”

理由はよくわからないが解決法

https://raw.githubusercontent.com/bagder/ca-bundle/e9175fec5d0c4d42de24ed6d84a06d504d5e5a09/ca-bundle.crt

をダウンロードして何処かに置く。

php.iniを編集して以下を追加。

Google Testを使う

GoogleのC++用のテストフレームワーク。これを使うと何が嬉しいのか
・出力がきれい
・デフォルトでいろんなコマンドラインをつけてくれる
・コマンドラインでテストの制御ができる
・パラレルで実行できる(多分)
・繰り返し実行して簡易計測ができる
・デステストができる

しかしGUIアプリの場合はテストは難しいのでここではスルー。テストはあくまで機能として分離がし易いものをテストする段階。付属のGoogleMockなどをつかって、Mockオブジェクトを作り分離させるために頑張る方法もあるのだろうがここではスルー。

実験

ここでは既存の自作テストプロジェクトをGoogleTestに置き換えていくことを想定。別に新規に追加しても良い。Windows, VS2013, C++/CLIプロジェクト

git submoduleで追加

ソリューションのフォルダで以下を実行して、googletestを持ってくる。べつにダウンロードしてもいい。

テストプロジェクトの設定

テストプロジェクトにgoogletestのソースコードを追加する。テストプロジェクトがなければコンソールアプリで作る。

まず、googletest\googletest\src\gtest-all.ccをプロジェクトのソースコードに追加。このファイルは必要なソースをincludeしてこのファイルだけで全部ビルドできる。

次にプロジェクトのインクルードパスに以下の2つを追加

これで準備が整ったのでmain.cpp(自分のファイル)にテストコードを書く。

InitGoogleTestは最初に書いたようにコマンドラインを処理してくれる。RUN_ALL_TESTSはこちらが定義したテストを実行する。今はまだ何も定義してない。

テストの定義

以下のように書く。

TESTマクロは2つの引数を取る。最初の引数はテストケースと呼ばれていて、テストを大きくカテゴライズしたもの、次の引数はそのカテゴリー内のテスト。1つのクラスをテストケースと考えてその中のメンバ関数をテスト名と考えてもいいかもしれない。

テストコード内でマクロを書く

テストコード内でテスト用のマクロを書く。これに引っかかるとテストに失敗するが、いろんな失敗のさせ方があるらしい。EXPECTは失敗しても続行の失敗(のはず)。ASSERTは失敗すると止める。

コマンドラインのチェック

ここで一旦コーディングをやめて、コマンドラインを試してみる。-hでヘルプを見れる。

–gtest_list_tests

オプション無しでテスト実行

GoogleTestをプロジェクトに追加しておくと、自分がテストするだけでなく、他人がプロジェクトの内容を知ることもできるし、実行ファイルを生成するので、どのように動くのかもわかって便利。

このようにテストをどんどん追加していくと、持つべきデータや初期化作業が共通化してくるので、これをFixtureと読んでおく。このFixture付きのテストがTEST_F。

TEST_F

以下の普通のTESTがあるとする。

これをTEST_Fに置き換えたのが以下。

TEST_Fの中でclassのインスタンスにアクセスできる。このクラスの初期化と終了処理はSetUpとTearDownのオーバーライドで行う。ちなみにこのクラスはテストごとに作られて、インスタンスは共通ではない。

フィルター

-gtest_filterでテストをフィルタできる。テストケースとテスト名は’.’ピリオドで区切る。ワイルドカードも使える。

powershellとリピートでトータル時間を計算する

フィルターでテストを指定し、リピートで繰り返し実行し、powershellのMeasure-Commandで時間を計算すれば、指定されたテストのみの実行時間を計算できるので、コードを変えたときの変化を見ることができる

パラレルで実行する

gtest-parallel(python2スクリプト)でパラレル実行ができるみたいなので試してみる。git submoduleや単にダウンロードしてインストールされたものとする。

デステスト

デステストとはアプリがちゃんと終了するか(クラッシュするか)をテストするツールである。

こられのマクロのMyExitはこのプロセスでは実行されない。同じ実行ファイルを内部引数で起動し(InitGoogleTestで処理される)そのプロセスで実行される。実行された結果の出力と最後に指定された正規表現を比較してテストし、EXPECT_EXITの場合は二番目にに指定された述語(関数オブジェクト)をExitCodeを引数に呼ぶ。これがfalseを返したり、MyExitが実際に終了しなかったりするとテストはエラーを報告する。

gitのsubmoduleでの変更を無視する

gitにsubmoduleを追加してそのサブモジュール内でファイルの変更や追加をすると親でstatusした時になんか出る。(下のfile)

これはgitlinkといって特別な扱いらしい。.gitignoreに追加しても無視できなかった。これを無視するには親ディレクトリの.gitmodulesを開いてignore = dirtyを追加する。

参照:
https://stackoverflow.com/questions/7912022/do-you-ignore-a-git-submodule-in-your-gitignore-or-commit-it-to-your-repo

https://stackoverflow.com/questions/3240881/git-can-i-suppress-listing-of-modified-content-dirty-submodule-entries-in-sta

AnyCPUのアセンブリから自動でx86かx64のアセンブリをロードする

普通にC#でアプリケーションを作るとAnyCPUのアセンブリができる。これは64ビット環境では64ビットで動作し、32ビットの場合は32ビットで動作する。

C++やC++/CLIで作ったライブラリはAnyCPUにすることができない。そしてWindowsでは64ビットアプリは64ビットのライブラリしかロードできない。32ビットも同じ。

AnyCPUのアプリをつくるときにこの問題をどう解決するかのはなし。ここではC++/CLIでライブラリをつくり、それをC#から利用することを考える。

C++/CLIで32ビットと64ビットのライブラリをつくる

作り方は省略。MyLib.x86.dllとMyLib.x64.dllができたとする。

C#でMyLib.x86.dllを参照する

参照するときに、プロジェクトの参照をするのではなく、ファイルを直接参照する。参照のプロパティのCopy LocalをFalseにする。こうすることでビルド時にライブラリがコピーされない。

C#のビルドイベントでMyLib.*をターゲットディレクトリにコピーする

この時のコピー先のパスはランタイムが自動で見つけられない場所にする。自動で見つけると違うdllをロードして例外が発生する。

以下はビルド後のコマンドの例、アプリのフォルダ配下のplatformにコピーしている。

この状態でアプリを起動してもライブラリが見つからない、のエラーが出る。

staticコンストラクタでカスタムローダを設定する

staticコンストラクタはstatic main()よりも早く動く。ここでライブラリが見つからないときのイベントハンドラを設定し、ハンドラで適切なライブラリを読み込む。以下はC#でデフォルトでできるクラスProgramに記述する例。

もともとx86の方を参照しているので、ランタイムはこのファイルがないと通知してくる。ここで環境(Environment.Is64BitProcess)に合わせてライブラリを読み込む。

参照

Using Side-by-Side assemblies to load the x64 or x32 version of a DLL

Msys2 and ming-w64

msys2とming-w64が分かりづらいので少し調べた。

MSYS2

msys2はCygwinをベースにしていてmsys-2.0.dllがパスの切り替えやforkなど(多分)を行う。cygwinにはコマンドラインパッケージマネージャがないので、pacmanを有するmsys2の方がインストールがしやすい。

msys-2.0.dllに依存しない通常のexeをmsys2から起動するとパスの変換が行われる(コマンドラインの)。cygwinではこういうことは行われないようだ。

MINGW

Mingw-w64で一つの名前。Mingwの64ビットバージョンの意味ではない。これらはmsys2.0.dllに依存していないツールでWindows向けにビルドされたもの。
msys2でgccをインストールしようとすると以下の2つがある。

mingw-w64-i686-gcc
mingw-w64-x86_64-gcc

mingw-w64で一つの名前なのでi686が32bitでx86_64が64bitのgcc、これらをインストールするとそれぞれ/mingw32/binと/mingw64/binに置かれる。msys2をインストールすると、mingw32.exeとmingw64.exeができるが、この違いはパスの違いである。

これとは別のgccもあってそれはmsys2で動く実行ファイルを作るためのgcc。これはmsys2-develに含まれる。msys2.exeを起動すると上記パスに/mingw32などが含まれない。

/MD と /MTの話

上のようなエラーがどうして起こるのかの話。ただしどこからはじめても要素が絡み合ってまとまらないので適当に書く。

コンパイルフェーズ

ソースコードからどのように最終成果物のexeやdllが生成されるか?libは最終成果物というよりも開発途上物と呼ぶべきもの(一般ユーザに配布するわけじゃないから)。

1、ソースファイルから*.objをつくる。
clコマンドでつくる。/cをつくるとコンパイルだけしてリンクしない。ここで/MDや/MTの指定ができる。デフォルトは/MT。デバッグの話を混ぜるとさらに複雑になるので省略。マルチスレッドも省略(今はほとんどマルチスレッド)。

/MTや/MDはCRT(Cランタイムライブラリ(printf()とか))の扱いを決める。ほとんどのプログラムがCRTをつかう。CRTはmain()を呼んだり、__argcをつくったりするのでないと大変。

/MTを指定すると、スタティックライブラリのCRTを使うことを指定する。これは最終成果物のexeやdllにCRTの実装が入ることを意味する。clで*.objをつくった際、このobjにはリンカーへの指示としてLIBCMT.libとともにリンクするよう伝えるように書き込まれる。libコマンドで*.libをつくる際にも同じ情報が書き込まれる。後々linkで最終成果物を作るときにLIBCMT.libがコピー(みたいに)される。

プロジェクトがいくつものライブラリをリンクする際(外部ライブラリも含めて)すべて/MTで統一されていれば、リンクエラーは起きない(VCのバージョンが違う場合はどうなるか知らない)。すべての*.objや*.libがLIBCMT.libとリンクしてほしいと指示しているので。

/MDを使ってobjをつくるとCRTのダイナミックライブラリとリンクしたいことを指示する。objやlibにはmsvcrt.libとリンクするように指示される。msvcrt.libはインポートライブラリで実装はmsvcrtXXX.dllにある。

link時に/MTと/MDが混在しているとLIBCMT.libとmsvcrt.libが両方指定されて、この2つは元は同じもののはずだから(ソースコードレベルでは)同じシンボルを持ち、上記のようなエラーが発生する。よって上記のようなエラーが出た場合には、/MTや/MDを直すべきのはず。

シナリオ

ただ難しいのはあるソースから作られるものはexeとdllとlibがあって、dllをつくるときもlibができて、dllをつくるときの/MTや/MDをどうするのがいいのかということになると思う。

自分が作るのがexeで使うスタティックライブラリが/MTで作られていたなら自分も/MTにするしかない(はず)。しかしちなみにC++/CLIでは/MDしか許されないのでこれができない。

自分が作るのがスタティックライブラリのときはどうなるだろうか。/MTを指定すると、自分を使う人にも/MTを使ってほしいことになる。/MDを指定すると自分を使う人にも/MDを使ってほしいことになる?(はず)

さらに難しいのがdllをつくるときに外部ライブラリも必要な場合どうなるのかということだ。MSのドキュメントにはit is not recommended to link statically to the CRT in a DLL unless the consequences of this are specifically desired and understoodと書かれているので/MDを使うことになるが、その外部ライブラリが/MTなら自分も/MTにするしかなくそうなった場合いったい何が起こるのか。簡単に言うとMSが推奨してない/MTでdllをつくってそのdllつかうexeをコンパイルしたり実行したときどうなるのかの問題。

よくわからないが結論

スタティックライブラリを作るときは/MTを使う。DLLをつくるときは/MDをつかう。

しかしこうなると2つのライブラリを自分のexeに取り込みたいとき、そしてその2つがスタティックライブラリとDLLしか提供していない場合に、どちらも取り込むということができなくなるのではないか?

よってライブラリ作成者はスタティックバージョンとDLLバージョンの両方を用意するのが普通ということになるのだろうか。

LoadLibraryはどうなる

LoadLibraryが失敗するとき、シンボルが見つからないからとか言うエラーはよく見るが、シンボルが重複しているからというのは見たことがない。もしかして2重に持つのだろうか?(上記のような矛盾の場合)もしそうなら上で書いたできないの内いくつかは解決するはず。

落としたrubyが走り出さない

落としたruby2.4.2がWindowsXPで動かない。

仕方ないのでビルドしたついでにアップロード。vc9,32bit。XP以上で動くはず。2000でもvc9ランタイムがあれば動くはず。vc6ではビルドできなかった。

https://onedrive.live.com/?id=F0D9DDC561F5CF32%212276&cid=F0D9DDC561F5CF32