Qt は全く使ったことがなかったが,ここまでできれば簡単なことはリファレンスだけで できそう。
.ui ファイルでレイアウトを作る方法や QtCreator を使う方法(まあこれも間接的に .ui を使う 方法だといえると思うが)ではなく,とりあえずコードでレイアウト組む方法でやってみた。 ちょっとした GUI を作るのに別ファイルが必要だったりテキストファイルを埋め込んだり (バッファから読ませることができるのかは調べてないので分からない)というのは 面倒臭いと思ったので。
というわけで Hello world。
#include <QApplication> #include <QLabel> int main(int argc, char **argv) { /* Widget を作る前に QApplication を作っておく必要あり */ QApplication app(argc, argv); QLabel l("Hello"); l.setWindowTitle("Hello world!"); l.show(); return app.exec(); } コンパイルは:
$ g++ -fPIC $(pkg-config --cflags --libs Qt5Widgets) foo.cc これで Hello と書かれた Hello world というタイトルのウィンドウが出てくる。 まともにレイアウトを作るならばなんとか Layout とかに addWidget したりしていき, 最後にルートの Widget に setLayout していくことになる。
UNIX のコマンドで(本来の)機能が誤解されがちなコマンドとして cat や touch が有名な 気がするが,env もそのひとつだと思う。env の使われ方としては,単独で実行して設定されている 環境変数を見たり,shebang で bash (やその他 executable)のパスをハードコードするのを避けるために
#!/usr/bin/env bash といった感じで使われるのが多分ほとんどのような気がする。
env の本来(?)の機能は環境変数をいじってからコマンドを実行するといったところだ。 なので Bash から実行するときは env なしで
FOO=bar command といった感じで実行しているのをこういった書き方が使えない環境で実現したいと思ったときに
env FOO=bar command というコマンドで実行すると等価なことができるということだ。
NMake は並列でビルドできないという問題があるので,JOM という NMake のクローンを使う。 これは Qt の開発元が作っているらしい。
ビルドするのは面倒なので適当に公式からバイナリ配布を拾ってくる(ソースコードかと思ってダウンロードしてみたらバイナリだった)。 で,面倒なので PATH を通す。こういう具合でどんどん PATH を通していくと膨大な PATH になってしまう訳ですね。
で,CMake で JOM 用の Makefile を生成する。
$ cmake -G"NMake Makefiles JOM" .. これで
$ jom /J 8 とかすると 8 並列でビルドされる。おしまい。
ちょっと前に .bashrc に追加したやつの紹介。
既に(別の terminal で)動いているプロセスの stdin, stdout, stderr を乗っ取って自分の terminal に 無理矢理つなぐ。
(適当に dotfiles から抜粋)
if [ "$#" -ne 1 ]; then echo 'usage: hijack PID' >&2 return 1 fi local tty="$(readlink /proc/self/fd/0)" echo "Info: Connect to $tty" local run_as_root= if command -v sudo &>/dev/null && [ "_$(whoami)" != '_root' ]; then run_as_root=sudo fi local pid="$1" $run_as_root gdb -p "$pid" <<EOF compile code \ unsigned char attrs[3][1024]; \ for (int fd = 0; fd < 3; ++fd) { \ tcgetattr(fd, (struct termios *)attrs[fd]); \ } \ dup2(open("$tty", 0 /* O_RDONLY */), 0); \ dup2(open("$tty", 1 /* O_WRONLY */), 1); \ dup2(open("$tty", 1 /* O_WRONLY */), 2); \ for (int fd = 0; fd < 3; ++fd) { \ tcsetattr(fd, 0 /* TCSADRAIN */, (struct termios *)attrs[fd]); \ } EOF # If this is TUI app, let it redraw. kill -WINCH "$pid" tail -f /dev/null --pid "$pid" やっていることは基本的に単純で,gdb でプロセスを attach して file descriptor の 0 から 2 までを書き換えています。compile ってのは gdb のコマンドで,渡したコード をコンパイルして,そのプロセスで実行してくれる。このときに #include すると いろいろ問題が起きたりしたので O_RDONLY とか O_RWONLY とかは数字をそのまま書いてある。 あといろんなヘッダファイルに書いてある情報が使えないがために struct termios の 大きさが 1024 byte 以下という仮定をしていたりする。1 KiB 超えの構造体ってなんやねん なので大丈夫やろ。
深さNのところをi, ii, iii,… というふうにしたいならば,
\renewcommand{\labelnumN}{\roman{enumN}} \romanの部分は選べる。
なまえ すたいる \alph a, b, c,… \Alph A, B, C,… \arabic 1, 2, 3,… \roman i, ii, iii,… \Roman I, II, III,… プリアンブルに書くと文書全体これになるので,一箇所だけに適用したければ enumerate 環境の中で \renewcommand する。おわり。
UNIX で Makefile 生成してビルドしていたような CMake のプロジェクトを Windows に移植する。
ここでは Visual Studio について言及するとき Visual Studio 2019 を前提とする (というか試せる環境がそれしかない)が多分そこにはそんなに依存していないはず。
とりあえず言えることは,CMake で Visual Studio のプロジェクトを生成する方法は Make を使ったプロジェクトとビルドシステムの設計というか思想が違いすぎてその差異を CMakeLists.txt で吸収するのは無理だと思う(たぶん単純なプロジェクトだと大丈夫だけど凝ったことをしようとすると すぐ詰む)。書くの面倒臭いので飛ばすけど Visual Studio は CMake では Multi-config という扱いになって Makefile とはちょっと違う環境になるので。 というわけで,NMake の Makefile を生成するのが簡単な方法だと思う。 この方法だと最小限のプラットフォーム固有の(cmake の)コードでビルドが通るようにできる。
全ファイルコミットできる単位でコミットしろよ←わかる
全ファイルをコミットする 一番簡単。だいたいこれでやってる気がする。
$ git add -A 一部のファイルだけコミットする 普通。
$ git add foo.c bar.c baz.c 一部の hunk だけコミットする $ git add -p ってやると hunk を stage するか聞かれるので stage したい hunk で y と答える。
hunk の一部だけコミットする 変更がくっついていると違う内容の変更が 1 個の hunk に入ってしまったりする。
$ git add -p した後に追加したい変更が入っている hunk で e と答える(え?) するとテキストエディタが起動して,diff を編集しろと言ってくる。 で,これは編集しろと言ってくるファイルにも書いてあるが,
- で始まる行(削除した行)をなかったことにしたかったら - を (スペース)で置き換える + で始まる行(追加した行)をなかったことにしたかったらその行自体を削除する という感じで編集すると望んだ部分だけを stage することができる。 間違っても死ぬわけじゃないのでそんなに恐れずやっていいと思う。
小数単位でのスケーリングをしていたら XWayland のアプリケーションは ぼやけているので自明な感じはあるが,面白い(かつ見た目が良い?)見分け方を 見つけたので。
xeyes を起動する。 マウスを動かしてみる。 簡単ですね!
マウスをいろんなウィンドウの上に動かしてみて目が動くウィンドウは XWayland, 目が動かないウィンドウは Wayland で動いている。
参考 https://medium.com/@bugaevc/how-to-easily-determine-if-an-app-runs-on-xwayland-or-on-wayland-natively-8191b506ab9a xeyes のソースコード: https://gitlab.freedesktop.org/xorg/app/xeyes
XWayland だとスケーリングしたときにぼやける問題があるので,Wayland を使うようにする。
今の段階だと MOZ_ENABLE_WAYLAND=1 という環境変数があった場合は Wayland を使う ようになっている。毎回端末から実行すれば当然できるが,それは面倒なのでアイコンをクリックしたときでも Wayland を使う設定で普通に起動するようにしたい。
同じ方法で Thunderbird にも Wayland を使わせることができる。
方法1: .bashrc とかに書く 一番簡単。でも僕はむやみに環境変数足したくない派(全然関係ないプロセスからアプリケーション固有の 設定が見えるのが無駄な感じがする)なのでこの方法はあまり好きじゃない。
方法2: デスクトップエントリーをいじる /usr/share/applications/firefox.desktop を ~/.local/share/applications/ に コピーしてきて Exec の行のコマンドの先頭に env MOZ_ENABLE_WAYLAND=1 を追加する。 本当は差分だけ編集したい(systemd のユニットファイルみたく)けどそういう方法では動かなかった。
一応型ごとの大きさは規格では決まってない(最小限のビット数はあるけどこれを書いても意味がない) けど x86_64 だったら普通同じになるはず。
Type Bits Min Max signed char 8 -128 127 unsigned char 8 0 255 signed short 16 -32768 32767 unsigned short 16 0 65535 signed int 32 -2147483648 2147483647 unsigned int 32 0 4294967295 signed long int 64 -9223372036854775808 9223372036854775807 unsigned long int 64 0 18446744073709551615 signed long long int 64 -9223372036854775808 9223372036854775807 unsigned long long int 64 0 18446744073709551615 コード
#include <iostream> #include <limits> using namespace std; #define LIMIT(type) cout << "`" #type "` | " \ << sizeof(type) * numeric_limits<unsigned char>::digits << " | " \ << +numeric_limits<type>::min() << " | " \ << +numeric_limits<type>::max() << endl; int main() { cout << "Type | Bits | Min | Max" << endl; cout << "-----|------|-----|----" << endl; LIMIT(signed char); LIMIT(unsigned char); LIMIT(signed short); LIMIT(unsigned short); LIMIT(signed int); LIMIT(unsigned int); LIMIT(signed long int); LIMIT(unsigned long int); LIMIT(signed long long int); LIMIT(unsigned long long int); } 浮動小数点数 10進での桁数
type num float 6 double 15 long double 18