scoop でインストールした plantuml と plantuml-mode on Emacs でプレビューできない件
- Windows
- scoop でインストールした plantuml
- Emacs の plantuml-mode
- http://plantuml.com/ のオンライン変換を使うのではなく、以下のような設定でローカルで変換する
(setq plantuml-executable-path (executable-find "plantuml")) (setq plantuml-default-exec-mode 'executable)
というケースで C-c C-c
とかすると文字化けバッファが表示される。
Warning: -headless flag must be the first one in the command line
ってなのが最初についててその後ろに画像データがくっついているので、 Emacs が画像とみなさないようだ。
本質的には、 「画像も warning も同じ標準出力に出している」 と思われる plantuml に非があると推測するが、 Emacs の設定からどうコマンドラインオプションを指定しても どうしてもこの warning が消せない。
プレビュー機能を諦めて2ヶ月くらい放置してたんだが、 今日たまたま
(executable-path "plantuml")
とかしてて plantuml.cmd の中身を見てて原因がわかった。 scoop が作る plantuml.cmd は graphviz の dot のパスをコマンドラインオプションで plantuml.jar へ渡すようになってて、 plantuml.cmd に対して指定したコマンドラインオプションは必ずその後ろに付加される書き方になってる。 だから、この問題は plantuml.cmd の外側 ≒ Emacs plantuml-mode の設定 では解決できないんだ。
なので、plantuml.cmd でこう↓なっているのを
@java -jar "D:\Users\mino\scoop\apps\plantuml\1.2020.19\plantuml.jar" -graphvizdot "D:\Users\mino\scoop\shims\dot.exe" %*
こうしてしまえば warning は出なくなる。
@java -jar "D:\Users\mino\scoop\apps\plantuml\1.2020.19\plantuml.jar" %* -graphvizdot "D:\Users\mino\scoop\shims\dot.exe"
ひとまず解決したのは良かったけど、まぁ釈然とはしないなぁ…w
あ、一応この plantuml.cmd を生成してる scoop extras bucket の修正 PR は出しておきました。 個人的には解決しちゃったので、マージされなくてもちっとも困らないんですが、 今後ハマる人が少しでも少なくなれば。
emacs --daemon + emacsclient で起動したときも、daemon 使わず起動したときも期待通りの設定で動くようにする (途中)
途中なんだけどメモっておかないと忘れるので。
やりたいことは…
- Emacs の起動高速化したい、
emacs --daemon
が使えそう - 今すでにある「環境によらず同じ初期化ファイル」というのはキープしたい
emacs --daemon
+emacsclient
も、単にemacs
を起動しても動くようにしたい- text terminal で
emacs -nw
で起動した場合も、GUIで起動した場合も動くようにしたいが、それぞれで見た目とか設定を変えたい可能性もある
↑こんな感じ。
で、こんなの↓を作ってみて
それでわかった?ことは…
emacs --daemon
で初期化ファイルを読み込んだときはwindow-system
はnil
なので一部設定ができないemacsclient
で起動したときに設定を遅延すればよくて使えそうな hook がafter-make-frame-hook
- daemon 使用時と非使用時(普通に
emacs
起動したとき)で初期化ファイルを共有するためには…- GUI 設定を関数にまとめとく
- その関数を
after-make-frame-hook
にひっかけておく when (window-system)
のときは hook が呼ばれるのを待たずにその関数を呼んじゃう- これだけだとフレーム作るたびに関数が呼ばれるので、関数の最後で自分自身を
remove-hook
しとく
after-make-frame-hook
は frame 生成後に呼ばれるのでdefault-frame-alist
とかをそこで設定しても frame には反映されない?- とりあえず
(modify-frame-parameters (selected-frame) default-frame-alist)
的なことをすれば解決はできそう
- とりあえず
まぁ、何が言いたいかというと、 emacs --daemon
がもうちょっと使いやすいと嬉しい、と。
emacsclient でファイルを開かずにフレームを開く
Emacs の起動高速化の関連でちょっと調べてた件。
普通に emacsclient
コマンドを使うとファイルを指定しないといけないんだが、
$ emacsclient -c
でフレームだけ開ける。 終了を待ち合わせないで良いなら
$ emacsclient -c -n
で OK。
これを使って
「Ubuntu, macOS, Windows あたりの環境において
アイコンクリックで高速にEmacs起動するようにできないかな…」
とか考えをめぐらし中…。
ログイン時に emacs --daemon
するか、
初回アイコンクリック時だけ emacs --daemon
してから emacsclient
叩くみたいなことしないとダメかなぁ…。
Doxygen で internal な実装群を隠す
隠すやり方がいくつかあるんだけど、 どう隠したいかで使うべきコマンドが違うみたい…。
遭遇したケース
通常、 source file local な class やメソッドに対する Doxygen コメントとかは
Doxygen の設定の EXTRACT_〜
を適切にすれば出力されないはず。
私が今回遭遇したケースは
- constexpr function なのでヘッダーに実装を書いてる
- Google C++ Style Guide に則るとヘッダーファイルでは無名名前空間が使えないので
impl
という名前空間に入れてる - 勢い余ってせっかく書いた doxygen コメントは残しておきたいが、内部実装なので API リファレンスとしての Doxygen の output からは除外したい
- そういった実装が複数連続してる存在してるのでまとめて隠したい
この場合は @cond
, @endcond
を使うとできる。
Doxygen における条件による出力の出し分け方
いくつか方法がある。以下網羅できてるかは知らない。
#ifndef
を使う方法
- 隠したいところを Doxygen 解釈時以外には絶対に定義されないマクロの
#ifndef
で括る
#ifndef DOXYGEN_SHOW_CLASS_FOO /// This class provides so FOO features. class Foo { }; #endif // !defined(DOXYGEN_SHOW_CLASS_FOO)
ENABLE_PREPROCESSING = YES
にする- 出力したいときは
PREDEFINED = DOXYGEN_SHOW_CLASS_FOO
にする
これは @cond
が実装される前に使われてた方法らしい。
- C / C++ として何か作用したいわけではないのに、 C / C++ としてのソースが汚れる
- ソースコードの読み手が慎重になる必要がある
- プリプロセッサマクロを解釈するようなツール群が期待しない動作になる or 期待動作のために追加設定が必要になる、かも
- エディタのコードハイライティング
- lint など静的解析ツール
- ...
あたりが欠点かなぁ…。
@cond
を使う方法
これは上で書いたので簡単に言うと #ifndef
とかの代わりに Doxygen コマンドを使う、と。
/// @cond DOXYGEN_SHOW_CLASS_FOO /// This class provides so FOO features. class Foo { }; /// This class provides so BAR features. class Bar { }; /// @endcond
- 出力したいときは
ENABLED_SECTIONS=DOXYGEN_SHOW_CLASS_FOO
のようにする
これは使いやすいよね。コードハイライティングがおかしくなったりもしないだろうし。
ちなみに常時出力しないのでよければ @cond
のうしろ(「セクションラベル」と呼ぶらしい)は省略できるらしい。
/// @cond /// This class provides so FOO features. class Foo { }; /// This class provides so BAR features. class Bar { }; /// @endcond
まぁ、どういう意図で @cond
で括っているかの表明にもなるから、私だったら省略しないルールにすると思う。
@if
を使う方法
これが紛らわしい。
@cond
がざっくりまとめて出力・非出力を切り替える目的に使えるのに対して、
@if
はコメントブロック内で一部の出力条件を変える目的に使う。
この「コメントブロック内〜」が重要なんだけど私は最初読み飛ばしちゃってて混乱した。
要はクラスなり関数なりの説明のまとまりの中で一部を出力する条件を記述するのに使えるってことらしい。
今回のように目的が「コードを読んだ人には見せるけど Doxygen 出力からは隠す」だと
/// This class provides so FOO features. /// /// @if CLASS_FOO_SECRET /// This is not doxygen-documented secret, Ha ha. /// @endif class Foo { };
みたいなことになる。
ENABLED_SECTIONS=CLASS_FOO_SECRET
としてやれば括ってあるところも出力される。
ただ、コメントブロックをまたげないので、
今回のように複数関数をまとめて出力する・しないを切り替えたいような用途には使えない。
これだけだと私にはあんまりありがたみが感じられなかったんだが、
/// This class provides so FOO features. /// /// @if english /// Details by English. /// @elseif japanese /// 日本語での詳細記述。 /// @endif class Foo { };
こんな感じで言語を切り替えるのに使ってるのは、
そういえば以前に見たような記憶がかすかにある…。
ENABLED_SECTIONS
と出力先を切り替えながら出力すると
複数言語分のドキュメントが生成できる、と。
Dependency Walker のいま
Windows で exe/dll の依存関係を追跡するツール Dependency Walker のいまについて。 ちょっと調べれば情報に行き当たるので、 大して書くこともないんだが…。
- Dependency Walker は Visual Studio の配布物からは独立して、単独ツールになったっぽい
- Windows 10 では Dependency Walker は安定して動かないらしい
- C# で書き直して OSS 化した Dependencies というツールがあるっぽい
- github.com
- scoop の extras bucket を入れてあれば
scoop install dependencies
で一発でインストールできる
ちなみに Dependency Walker が VS の配布物から外れたのは10年以上前らしく、 私が Windows アプリの本格的な開発から外れて長いのが分かりますw
gcovr や Doxygen の HTML を自動的に deploy する
やりたいこと
- GitHub のリポジトリ上のものを種に生成される静的 HTML サイトを自動的に deploy する
- Doxygen で生成した HTML
- gcovr で生成した Coverage report の HTML
- ...
GitHub Actions で actions/upload-artifact
を使えば
ディレクトリ単位の成果物を workflow の実行に紐付けてアップロードするのは簡単にできるのだが、
ディレクトリごとの ZIP ファイルになってしまうので
いちいちダウンロードして解凍しないとブラウザで確認できない。
これはちとめんどくさい。
どこかのサイトに自動的にアップロードされて、 必要に応じて自動的に更新されると嬉しいなー、と。
道具
- GitHub Pages
- deploy 先として使う
- あらかじめ設定しておいたブランチに push さえすれば、その内容を https://username.github.io/repository_name/ というサイトとして見られるように deploy できる仕組み
- GitHub Actions
- GitHub 謹製の CI/CD システム
- 静的 HTML サイトの構成を作って deploy するのに使う
peaceiris/actions-gh-pages
- 「あらかじめ設定しておいたブランチに push」をやってくれる GitHub Actions の action
下準備
- リポジトリの Settings で GitHub Pages の設定を
gh-pages
ブランチを deploy するように設定しておく- あとからやってもいいが、 push 時にしか deploy されないみたいなので、あとから設定した場合は設定後一度 push する必要があるっぽい
解説
- 2020/09/06 時点での GitHub Actions の workflow は https://github.com/MinoruSekine/libfixedpointnumber/blob/9085595bb0848fb1bcb7f634f1af63e8d2383ee6/.github/workflows/deploy_github_pages.yml
- 読んで分かることしかしてないけど、以下パートごとに解説
master
ブランチへpush
時にこの workflow が動くようにする、PRマージ時もこれで動く、ついでにworkflow_dispatch:
を書いておいてデバッグ等で便利なように手動トリガー可能にしておく
on: push: branches: - master workflow_dispatch:
runs-on
は https://github.com/peaceiris/actions-gh-pages にどれをサポートしているか書いてあるのでその中から選ぶ
jobs: deploy: runs-on: ubuntu-18.04
- チェックアウトする
steps: - uses: actions/checkout@v1
- 静的HTMLサイトを生成するのに必要な道具をセットアップする
- ここは Pelican でも何でもお好みのツールをセットアップすればOK
- この例では coverage report のための gcovr と Google Test Framework、Doxygen ドキュメントのために Doxygen と GraphViz をインストールしてる
- 最後の
rm -rf googletest
はmake install
するために checkout してきたソースコードとビルド生成物を消してる- これをやっておかないと
googletest/
以下の Doxygen とか作ろうとしちゃう /tmp/
とかへ checkout するなり、Doxyfile
で exclude するなりすればいいのだが、手を抜いてるだけ
- これをやっておかないと
- name: Install gcovr run: | sudo pip3 install gcovr - name: Install graphviz and doxygen run: | sudo apt update sudo apt install -y --no-install-recommends graphviz doxygen - name: Install googletest run: | git clone https://github.com/google/googletest.git cd googletest cmake -DBUILD_GMOCK=OFF -DCMAKE_CXX_STANDARD=11 . sudo make -k -j all install cd .. rm -rf googletest
- 静的HTMLサイトを生成する、この例では
make site
でout/site/
以下に静的HTMLサイトが生成されるようにしてある ( https://github.com/MinoruSekine/libfixedpointnumber/blob/9085595bb0848fb1bcb7f634f1af63e8d2383ee6/Makefile#L216 )
- name: Build site run: | make BUILD_TYPE=coverage -k -j site
- Deploy する、
publish_dir
以下が deploy される- 実際にはリポジトリの
gh-pages
というブランチに push されるだけ
- 実際にはリポジトリの
- name: Deploy uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./out/site
できあがったサイト
- 以上で、 PR マージなどで
master
ブランチが更新されるたびに静的 HTML サイト(Doxygen ドキュメントと coverage report)が更新される - というわけで出来上がったのが minorusekine.github.io
四捨五入の実装って地味に面倒なんじゃないか? という話
C言語だと round()
とかが整備されたのって C99 からじゃないかと思うんだが、
まぁまぁ詳しい事情は置いておくとして
二十年くらい前までって四捨五入って当たり前に個々に実装してたような記憶がある。
で、その実装もたいてい
「0.5足して切り捨てればいいじゃん」
という実装だったと記憶している。
別に間違ってないんだけど、これってその型が表現できる最大値から 0.5 以内のところって
たぶん正しく動作しないよね??
そのへんはどうしてたんだろうか…
まさに「個々に実装してた」の「個々」の事情で 最大値スレスレにならなきゃ問題にならないからいいってことなんだろうか…。
というのを
GitHub - MinoruSekine/libfixedpointnumber: Library for fixed point number by C++11
の実装を思案してて気になったのでした…。
まぁ「0.5足して切り捨てる」だけだと値が負のときの動作が JIS Z8401 相当になることは諦めてるわけで、 その時点で「個々」の事情で起き得ないところは動作の正しさを諦めてるってことか…。