Debian busterにmxeをインストールしてQtCreatorで使う
Mastering Qt 5 の Chapter 2 で、いきなり windows.h が要求されて詰まった。ハードル高くない?スルーしてLinuxのコードの部分だけやればいいのかもしれないけど、もやもやする。
そもそもQtを使う人は様々なOSで使いたいわけだから、最初の方のchapterに複数OSの対応を書いておくのが良いということかな。
あまり詳しい説明はないままWindows、Linux、Mac用のコードが書いてある。それぞれのPCで各自環境構築はやってねということか。OSはあることはあるけど、いちいちソースを移動するのは面倒だよね。それぞれに開発環境を入れないといけないし。
仕方がないのでwindowsバイナリをコンパイルできるように設定する。
まず、mxeを取ってきておもむろにmxeをmakeする。
git clone https://github.com/mxe/mxe.git cd mxe make qt5
missing ... と表示された場合は、足りないものを https://mxe.cc/#requirements を見ながらインストールする。
(aptコマンドをコピペしても良いが、一応一つ一つ確認しながらインストールしたいので)
今の自分の環境だと以下のパッケージが必要だった。
apt install bison flex gperf intltool-bin libtool lzip
あとは
make -j10 MXE_TARGETS='x86_64-w64-mingw32.static' qt5
してしばらく待つ。
結構時間がかかる。(-j オプションと64bitターゲット指定を忘れないように)
# 4/27 追記
身内だけで使うならこれでもいいけど、公開するなら
make -j10 MXE_TARGETS='x86_64-w64-mingw32.shared' qt5
shared の方が良いかも。
まあ配布するなら、配布用バイナリはWindowsでコンパイルする方が良いのかもしれないが。
あと、そもそもqtcreatorをwineで入れる方法があるようだ。
Cross compiling Qt application for Windows on Linux with dynamic linking - Stack Overflow
こっちはちょっと面倒かな。それなら仮想マシンのWindowsにqtcreatorを入れる方が楽な気がする。
# 4/28 追記
mxe で sharedのバイナリは起動できなかった。
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Unhandled exception: unimplemented function KERNEL32.dll.RaiseFailFastException called in 64-bit code (0x000000007bc5d60c). Register dump:
というエラーが出て、ログには
wine: Call from 0x7bc5d60c to unimplemented function KERNEL32.dll.RaiseFailFastException, aborting wine: Unimplemented function KERNEL32.dll.RaiseFailFastException called at address 0x7bc5d60c (thread 0009), starting debugger...
というエラーが出ている。他にも
0025:err:winediag:xrandr12_init_modes Broken NVIDIA RandR detected, falling back to RandR 1.0. Please consider using the Nouveau driver instead. 002b:fixme:dbghelp:elf_search_auxv can't find symbol in module
のエラーが出ていた。NVIDIAのエラーは、正常に動く場合でも出てる。
仕方がないので普通にWindowsにVisual Studio 2019 と Qt を入れた。
# 追記ここまで
コンパイルが終われば、QtCreatorの「オプション」「Kits」の設定で
コンパイラ
Cコンパイラ:mxe/usr/bin/x86_64-w64-mingw32.static-gcc
C++コンパイラ:mxe/usr/bin/x86_64-w64-mingw32.static-g++
CMake
mxe/usr/bin/x86_64-w64-mingw32.static-cmake
Qtバージョン
mxe/usr/x86_64-w64-mingw32.static/qt5/bin/qmake
キット
上記設定したものを指定
適当にMinGWとでも名前を付けてPATHを手動追加する。
コンパイラのABIは x86 windows msys pe 64bit にする。
chapter 02 をある程度進めて、Windows版はビルドしてから wine64で立ち上げる。
これでいいのかな?とりあえずCPU Widgetは Linux版もWindows版もDebian上で確認できた。
Qtをやってみてる
Qt Creatorをインストールする。
apt install qtcreator
他にも何か入れたかもしれない。Qt Creatorを使わずに qmake だけ入れたこともあって、そのときのライブラリが残っているのかもしれない。忘れた。
デバッグでエラーが出るのでpython で gdbが使えるようにしておく?
The selected build of GDB does not support python scripting. It cannot be used in Qt Creator.
デバッグ実行するとこのエラーが出る。
gdbは入っているのになと思っていたら、gdb-minimalではダメで
apt install gdb
する必要があったようだ。
Debugger does not start. GDB not support Python scripting. | Qt Forum
python-dbg は要らなかった。
そうすると起動はしたけどwarningが出る。
&"warning: GDB: Failed to set controlling terminal: \343\203\207\343\203\220\343\202\244\343\202\271\343\201\253\345\257\276\343\201\231\343\202\213\344\270\215\351\201\251\345\210\207\343\201\252ioctl\343\201\247\343\201\231\n"
printf "warning: GDB: Failed to set controlling terminal: \343\203\207\343\203\220\343\202\244\343\202\271\343\201\253\345\257\276\343\201\231\343\202\213\344\270\215\351\201\251\345\210\207\343\201\252ioctl\343\201\247\343\201\231\n" | nkf warning: GDB: Failed to set controlling terminal: デバイスに対する不適切なioctlです
c++ - Setup GDB with QtCreator - Stack Overflow
ターミナルで実行すれば解決するみたいだけど、いちいちターミナルを開くのは見づらいかもしれない。
とりあえずスルーで。
これでMastering Qt 5を写経してみている。
英語だけれど意外と読める。
英語の児童小説は1ページも読めなかったけれど、プログラムの本なら読めるというのが新感覚。
時々英語のAPIドキュメントとかチュートリアルとか見てるおかげ?文章の意味が分からなくてもプログラムの意味は分かるのが大きいのかも。Dockerのセットアップとかが英語で書かれていても、読むというよりはざっと眺める感じだし、この本もそれに近い。重要な概念の説明っぽい箇所は意味を調べつつ読んでるけれども。
Google翻訳アプリのカメラでリアルタイム翻訳が、ちょっと惜しい感じ。文章を上書きしないで単語の説明を出してほしいところだけど、カメラが揺れるし使いやすくするのは難しいのかも。
今はChapter 01 をやったところ。
Googleの検索順位を手軽に数えるブックマークレット
普段ブラウザのブックマークレットとして登録しているけれど、他のPCで使いたくなったとき用にメモ。
まず、Googleの検索オプションで100件表示にする。
シークレットウィンドウでも使うために、規定の検索エンジンのURLに「&num=100」を付け足すのでも良い。
その後、検索結果ページ(SERP)のHTMLをJavaScriptで調べる。
javascript:s = prompt('url'); document.querySelectorAll('#search a h3').forEach((v, i) => {if (v.parentNode.href && v.parentNode.href.match(s)) alert(v.parentNode.href +': ' + (i+1) + '位')})
alertしているけれど、コピペするならconsole.logで表示または画面に独自ダイアログを表示しても良いかも。
HTMLに影響されるのでSERPのHTMLに変更があったらその都度対応していく必要があるかもしれない。
PHPでDDDのようなClean Architectureのような単純なLayeredとIoC
DDDやクリーンアーキテクチャの記事や
5年間 Laravel を使って辿り着いた,全然頑張らない「なんちゃってクリーンアーキテクチャ」という落としどころ
この辺の記事を読んだりして、自分なりの最適解を探している。
まだやり始めたところだけど、現状をメモしておく。
まず、PHPで今書いているコードは基本的にUIに関連する処理が最も多く、ドメインロジック的なものよりプレゼンテーションロジックが多いということをふまえて。
src/ └── Ddd ├── Application │ ├── UseCase │ │ └── Cart │ └── ViewUseCase │ ├── Cart │ └── Product ├── Domain │ ├── Cart │ └── Product └── Io └── Infrastructure ├── Cart ├── Order └── Product
アプリケーション層のユースケースと同じ階層に表示のためのユースケースを入れる。
これは、表示のための文字列を整形する処理が結構な分量あり、それをテストしたいため。CQRS(というかCQS)のクエリ結果を整形して、それが正しく整形されたかチェックしたい。なので複雑なクエリもアプリケーション層に入れる。
ViewUseCaseではデータの保存は無し。
「保存 => 結果を取得して表示」の場合はまずUseCaseで保存して ViewUseCase のクエリで表示用のデータを取得する。
また、リポジトリはアプリケーション層に所属する。ドメインはリポジトリを扱わない。
他のDDDなどの解説で、ドメインロジックがfindやstoreを実行しているけど、それってユースケースでは?という単純な疑問がある。あとユースケースに沿ったSQLを書きたくて、ドメイン用の全部入りSQLは発行したくないので。
それにstrict layeredとの相性も悪そうだった。
ドメインロジックは、ロジックというか型変換に徹する。DomainではなくてType というネームスペースにしようか迷ったぐらい。基本的にはユースケースのコードが膨らむことになる。
そこは諦めてテストを書く。
そうすると結局、昔ながらのレイヤー構造+IoCでリポジトリだけ依存関係を逆転させた普通の構造になったかもしれない。
テストはユースケースに対して行う。ドメイン(というかここでは細かい型用のクラス)はリファクタリングしたいのでテストを細かく書かない。
ユースケースにプレゼンテーションを含めたことにより、ブラウザが表示するUIと直結しているので、UIのテストも多少は兼ねることになっている。
PHPのファイルも込みで並べると
└── src ├── Controller │ ├── Cart │ │ └── IndexPage.php │ └── Product │ ├── DetailPage.php │ └── IndexPage.php └── Ddd ├── Application │ ├── UseCase │ │ └── Cart │ │ ├── AddCartUseCase.php │ │ ├── CartItemRow.php │ │ ├── CartRepository.php │ │ └── CartRow.php │ └── ViewUseCase │ ├── Cart │ │ ├── CartDto.php │ │ ├── CartItemDto.php │ │ ├── CartQuery.php │ │ ├── GetCartPageUseCase.php │ │ └── RowDtoConverter.php │ └── Product ├── Domain │ ├── Cart │ │ ├── Cart.php │ │ └── CartItem.php │ └── Product └── Io └── Infrastructure ├── Cart │ ├── CartQueryImpl.php │ └── CartRepositoryImpl.php ├── Order └── Product
こんな感じになっている。
UseCaseからViewUseCaseへの参照は無し。逆はあり。
Row はリポジトリからのマッピングクラス、Dto はUIへのマッピングクラスになっている。
本当はここもインターフェースと実装クラスを分ける方が綺麗だけど、大量にあるカラムのgetterを用意するのが面倒なので、オブジェクトのpublicプロパティにした。そうするとユースケースがDBのカラムを少し知っていることになるけれど、これは妥協で。インフラ層で詰め替えてもいいけど、インフラは基本的にコードを少なくしたくて、何の加工もせずにそのまま返したい。加工はアプリケーション層でやって、それはテスト対象になる。本気で切り離してもあまりメリットはなく、変更を追いやすく修正しやすければ良いので。
基本的にstrict layered、つまり階層を飛び越えて参照しない。
コントローラーからはドメインを参照しない。ここを甘くするとテンプレートでメソッドを呼び出したりしてしまうので。
テンプレートエンジンに渡すのは、ユースケースから返ってきたDtoをそのまま渡す。
コントローラーでフォームの処理とエラーチェックをしているけど、本当は Io\Form 等に入れたい。まだそこまで行ってない。
とりあえず今はこんな感じ。
GnuPG を使えるメーラーを探す
Thunderbird 78 で OpenPGP が組み込み機能になった代わりに Enigmail プラグインが使えなくなって GnuPG と連携ができなくなったらしい。
Thunderbird 78 系で GnuPG を使う【ただし不完全】 | text.Baldanders.info
インポートしたら使えたけど、鍵の管理が別々になってしまう。
プラグインの方が使いやすかった。
他のメーラーを探すと Sylpheed というものがあるらしい。軽さがウリでデフォルトでGnuPGが使えるらしい。
これは機能がシンプルすぎるので、SylpheedからフォークしたClaws Mailをインストールした。
apt install claws-mail claws-mail-tools
でもGmailでIMAPログインできず…。セキュリティを下げてパスワード認証に対応する設定が必要になるみたい。
あとClaws Mailのアカウント設定画面を開こうとすると segmentation fault で落ちる。
今すぐ必要というわけでもないのでThunderbirdの更新を待つか…。
その他。
GnuPGP で利用法(Usage、暗号化とか署名とか)を変更する。
security.stackexchange.com
change-usage という隠しコマンドがあるようだ。
これで [SC] になっているものを [C] だけに変更したりできる。隠しコマンドというかhelpに追記忘れ?とりあえず実行してみたら問題なく使えてるっぽい。
# 2021/03/26 追記
ひとまず前のバージョンのThunderbird をDLしてきてインストールした。
オプションで自動更新をオフにしておく。
やっぱりこっちの方が使いやすい。
macOS Big Sur に更新すると VMware Fusion 10 が動かなくなった
修理の前にMacを更新して、そのあとあまり動作確認していなかった。
どうやらVMware Fusionが動かなくなっていた模様。
構成した設定でこの仮想マシンをパワーオンするには物理メモリが不足しています
というエラーだったのでメモリやディスクが原因かと思って遠回りしてしまった。
元々使っていた VMware Fusion 10 はBig Surに対応していないらしい。
他にも色々問題があったようだ。
VMware Fusion 12.1公開 - ゲスト内仮想環境機能復活、macOS Big Sur対応 | TECH+
macOS のバージョンを上げるたびにVMwareのアップグレード版を買うのはつらい。
仕方がないので VMware Fusion Player 12.1 をインストールした。
古いVMware Fusion はそのまま Player をインストールすると自動的に上書きされる?
特に問題なく起動した。
仮想マシンの複数起動もできるし、特に違いは無いっぽい?
技術駆動パッケージングとstrict layered
一般的な用語かどうか分からないけど、DDDなどの構造に関する方式メモ。
「技術駆動パッケージング」
DDDをいざやろうとして、実際にファイルをどこに置くの?どういうカテゴリーでディレクトリにまとめるの?という疑問への回答。
これはアンチパターン派が多そう。
右(2枚目)は「技術駆動パッケージング」というアンチパターン。設計パターンごとにまとめるのは一見綺麗に整頓されているように見えるが、ドメインの関心事が設計パターンで分断されてしまい、業務概念ごとにまとまるべきものが低凝集になってしまう。特にマイクロサービス化を試みる場合非常に困る。 https://t.co/ixXh8X0DB1
— ミノ駆動 (@MinoDriven) 2019年7月10日
ただ、この図を見ると、コントローラーも同じディレクトリにまとめてしまった方が分かりやすくない?と思うのだけれど。
コントローラーやDBアクセス(リポジトリの実装クラス)ごと一つの機能の構成単位としてディレクトリにまとめてしまっても良いような。設計が綺麗じゃない感じがするけど、フレームワークもDBも変更しない前提なら特にデメリットは無いような気がする。
「strict layered と relaxed layered」
レイヤーを飛び越えてアクセスしても良いかどうか。
これはそれぞれ自分で選んでねということらしい。
詰め替えのコードが少ない手間で書けるのなら全部詰め替えた方が良いんだろうけど、増えてくると結構な手間がかかりそう。言語による?