Tips
Qt を使った macOS アプリで "cocoa" が見つからないというエラーが出る
Qt を同梱する macOS アプリで、下記の「"cocoa" が見つからない」というエラーが出る時の対応方法。
qt.qpa.plugin: Could not find the Qt platform plugin "cocoa" in ""
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
QtCore, QtGui, QtPrintSupport, QtWidgets の Frameworks に加えて、 qt.conf と libqcocoa.dylib を Resources に配置する必要がある。
- MyApp.app/Contents/
- Frameworks/
- QtCore.framework/
- QtGui.framework/
- QtPrintSupport.framework/
- QtWidgets.framework/
- Resources/
- plugins/platforms/libqcocoa.dylib
- qt.conf
- Frameworks/
[Paths]
Plugins = Resources/plugins
C++ で桁数以上のビットシフトの返り値は、ゼロではなく不定
static_cast<uint32_t>(1) << 31; // 0b1000...0000 (0 が 31 個) 期待通り
static_cast<uint32_t>(1) << 32; // 0 にならない。不定
static_cast<uint32_t>(1) << 33; // 0 にならない。不定
static_cast<uint64_t>(1) << 63; // 0b1000...0000 (0 が 63個) 期待通り
static_cast<uint64_t>(1) << 64; // 0 にならない。不定
static_cast<uint64_t>(1) << 65; // 0 にならない。不定
Colab の clang で試してみると不定の方は実行のたびに値が変わる。
そのため下記のコードは期待通りに動かない。
// index よりも小さい桁にあるビット数を数える意図の関数だが、
// index = 0 の時の返り値が不定になるバグがある
int PopCountRhs(uint64_t bitmap, int index) {
return popcount(bitmap << (64 - index)); // INVALID CODE
}
Python で入出力を継続するコマンドをラップする方法
シェルのような入力と出力を交互に繰り返すコマンドを、Python から制御するためのサンプルコード。
Stack overflow の Timeout on subprocess readline in Python を参考にした。
import asyncio
import sys
from asyncio.subprocess import PIPE
async def run_shell():
process = await asyncio.create_subprocess_exec(
'/bin/sh', stdin=PIPE, stdout=PIPE)
while process.returncode is None:
command = input('> ')
process.stdin.write(command.encode('utf-8') + b'\n')
while True:
try:
line = await asyncio.wait_for(process.stdout.readline(), timeout=0.1)
except asyncio.TimeoutError:
break
if not line:
break
print(line.decode('utf-8'), end='')
return await process.wait()
if sys.platform == 'win32':
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
returncode = loop.run_until_complete(run_shell())
loop.close()
0.1 秒間出力がない場合に、入力を受け取るようにしている。
もっと正しい方法があるとは思う。
Python でコマンドの出力を取得しつつ、エンターキーで終了する方法
上記 Python で入出力を継続するコマンドをラップする方法 から、非同期で標準入力を受け取れるように変更。
import asyncio
import concurrent.futures
import subprocess
import sys
import threading
from asyncio.subprocess import PIPE
is_terminate = threading.Event()
async def check_interuption(loop):
reader = asyncio.StreamReader()
protocol = asyncio.StreamReaderProtocol(reader)
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
line = await reader.readline()
print('read:' + line.decode('utf-8'))
is_terminate.set()
async def run_command(args):
process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)
output = []
while not is_terminate.is_set():
try:
line = await asyncio.wait_for(process.stdout.readline(), timeout=0.1)
except asyncio.TimeoutError:
continue
line = line.decode('utf-8')
output.append(line)
print(line, end='')
return ''.join(output)
def get_event_loop():
if sys.platform == 'win32':
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
return loop
loop = get_event_loop()
args = ['/usr/local/bin/adb', 'shell', 'getevent', '/dev/input/event1']
futures = asyncio.gather(run_command(args), check_interuption(loop))
output = loop.run_until_complete(futures)[0]
print(output)
loop.close()
参考: python - Listen to keypress with asyncio - Stack Overflow
Android の adb でスクリーンキャプチャ
adb exec-out screencap -p > image.png
参照: android - Read binary stdout data from adb shell? - Stack Overflow
Qt で最前面でフォーカスを取らない枠なしウインドウを作成する
QWidget window;
window.setWindowFlags(Qt::ToolTip |
Qt::FramelessWindowHint |
Qt::WindowStaysOnTopHint);
Git で改行コードを変更せずに clone する
Windows でも改行コードを CRLF (\r\n) に変更しない方法
git clone -c core.autocrlf=false https://github.com/<REPOSITORY>
参照: git - Trying to clone a repository but the line endings are wrong - Stack Overflow
MSVC で "cannot subtract incompatible string_view iterators." というエラーが出る
string_view
の begin()
や end()
で引き算をしているのが原因。 data()
および data() + size()
を使う。
std::string_view sv1(char_pointer);
std::string_view sv2(char_pointer + 5);
// BAD
// int offset = sv2.begin() - sv1.begin();
// GOOD
int offset = sv2.data() - sv1.data();
Git のサブモジュールを特定のタグに更新する
cd <submodule_dir>
git fetch --tags
git checkout tags/<tag_name>
git submodule update
cd <main_dir>
git add <submodule_dir>
git commit
サブモジュールが更新された remote_repo を local_repo へ pull したら、local_repo のサブモジュールをアップデートする必要がある。
git submodule update
サブモジュール内で使用しているサブモジュールを更新するために、
サブモジュール内で git checkout tags/<tag_name>
のあとに
git submodule update
をする必要がある。
Mac の Android Studio でエミュレーターが Not responding で起動しない。
データ消去 & 再インストールが確実らしい。…なるほど?
- AVD Manager から Virtual Devices をすべて消す
- [Android Studio] > [Preference...] > [Appearance & Behavior] > [System Settings] > [Android SDK] を選ぶ
- [SDK Tools] > [Android Emulator] の項目を外してアンインストールする
- Android Studio の再起動
- [SDK Tools] > [Android Emulator] の項目を加えて再インストールする
- AVD Manager に Virtual Devices を追加する
Qt でスレッド間通信 (QThread + connect)
#include <QtWidgets/QtWidgets>
class Receiver : public QObject {
Q_OBJECT
public:
void HandleValue(int i);
};
class Sender : public QObject {
Q_OBJECT
public:
Sender(Receiver *receiver);
void RunLoop(int times);
void SetValue(int i);
signals:
void EmitRunLoop(int times);
void EmitValue(int i);
};
#include "my_qt_thread.h"
#include <unistd.h>
#include <iostream>
Sender::Sender(Receiver *receiver) {
connect(this, &Sender::EmitValue, receiver, &Receiver::HandleValue);
connect(this, &Sender::EmitRunLoop, this, &Sender::RunLoop);
}
void Sender::RunLoop(int times) {
for (int i = 0; i < times; ++i) {
sleep(1);
SetValue(i);
}
}
void Sender::SetValue(int i) {
std::cout << "Sender::SetValue: " << i << std::endl;
emit EmitValue(i);
}
void Receiver::HandleValue(int i) {
std::cout << "Receiver::HandleValue: " << i << std::endl;
}
int main(int argc, char **argv) {
QApplication app(argc, argv);
Receiver receiver;
Sender sender1(&receiver);
QThread thread1;
sender1.moveToThread(&thread1);
thread1.start();
emit sender1.EmitRunLoop(10);
Sender sender2(&receiver);
QThread thread2;
sender2.moveToThread(&thread2);
thread2.start();
emit sender2.EmitRunLoop(3);
const int result = app.exec();
thread1.wait();
thread2.wait();
return result;
}
Astro A50 がファームウェアの更新に失敗する
問題
- ヘッドセットの電源が入らず、ハードリセット (Dolby + Game 長押し) をしても、ファームウェアの更新に失敗する
- ベースステーションに置くように指示されるが、置いても反応しない
解決方法
- Microsoft Store から Windows10 用の ASTRO COMMAND CENTER をインストールする
- ヘッドセットをハードリセットする (Dolby + Game 長押し)
- Windows10 用の ASTRO COMMAND CENTER から、ヘッドセットのファームウェアを最新版に自動更新する。
サポートページから直接ダウンロードできる macOS 版や Windows 版の ASTRO COMMAND CENTER では解決しない。
Android エミュレーターから、開発マシン上のサーバーへのアクセス
10.0.2.2
を使えばよい。
エミュレーター上のウェブブラウザから、開発マシン上のウェブサーバーへアクセスするなら、https://10.0.2.2/
でアクセス可能
ファイルを改行単位で 10 分割するコマンドライン
下記のコマンドラインで data.txt
を data00.txt
から data09.txt
に分割できる
split -n l/10 -d --additional-suffix=.txt data.txt data
-
-n l/10
: 改行単位で 10 分割 -
-d
: 分割後のファイルに数字をつける (00
から09
の部分) -
--additional-suffix=.txt
分割後ファイルの接尾辞 -
data.txt
分割したいファイル -
data
分割後ファイルの接頭辞
-n 10
とするとサイズが均等になるように (改行によらず) 10 分割される
-n l/10
なら、サイズをできるだけ均等にしたうえで改行単位で分割する
Git で特定のコミットメッセージを変更する
以下は abcd123
のコミットメッセージを変更する方法
-
git rebase -i abcd123^
でエディタが開く (最後に^
が必要) -
pick abcd123
とある行をr abcd123
に変更して保存 (r
はreword
でもよい) - コミットメッセージの編集画面が開くので、変更して保存
abcd123 を含む以降のコミット ID はすべて変更される
疑問
- 2 の工程を飛ばして、1 から 3 に直接行く方法はないのだろうか?
参考
Git で特定のコミットで変更されたファイルを表示する
以下は abcd123
のコミットで変更されたファイルを確認する方法
git diff-tree --name-only --no-commit-id -r abcd123
次の方法でもだいたい大丈夫
git diff-tree -r abcd123
git diff abcd123 abcd123~
参考
Git で特定のコミットからファイルを分離する
以下は abcd123
のコミットに含まれる file.txt
を分離する方法。
git rebase -i abcd123^
-
pick abcd123
をe abcd123
に変更 git reset HEAD^ -- file.txt
-
git commit --amend
(file.txt 以外の変更がコミットされる。コミットメッセージは保持される) git add file.txt
git commit
git rebase --continue
参考
version control - How to split last commit into two in Git - Stack Overflow
Wikipedia で XML データの書き出し
special:export/
もしくは 特別:データ書き出し/
を URL の wiki/
のあとに付与する。
https://ja.wikipedia.org/wiki/メインページ
なら、
https://ja.wikipedia.org/wiki/special:export/メインページ
とする。
2 つのファイルを横に結合するコマンドライン
paste
を使う。
% cat a.txt
a
b
c
% cat b.txt
0
1
2
% paste a.txt b.txt
a 0
b 1
c 2
macOS の pkg ファイルの展開
pkgutil
に --expand-full
というオプションがある。
pkgutil --expand-full Application.pkg /tmp/extracted
参考:
Python でシンボリックリンクに対応した zip ファイルの作成
shutil.make_archive
を素直に使うとシンボリックリンクは実ファイルに置き換えられてしまう。
zipfile.ZipFile
を ZipInfo
と組み合わせて使えば、シンボリックリンクへの対応は可能。
参考:
とはいえ、 zip コマンドを Python 内で呼び出すほうが分かりやすい気がする。
cd <base_dir>
zip -ry archive.zip <target>
macOS で PrintScreen を「形式なしのペースト」に割り当てる
Karabiner-Elements の設定ファイルを書いて実現する。
~/.config/karabiner/assets/complex_modifications ディレクトリに json 形式の設定ファイルを書く。
ファイル名は自由。
下記のファイルでは Right-Option もコピーに割り当てている。
{
"title": "Right-Option/PrintScreen to copy/paste w/o format (Shift + Command + v)",
"rules": [
{
"description": "Right-Option/PrintScreen to copy/paste w/o format (Shift + Command + v).",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "right_option"
},
"to": [
{
"key_code": "c",
"modifiers": [
"left_command"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "print_screen"
},
"to": [
{
"key_code": "v",
"modifiers": [
"left_command",
"left_shift"
]
}
]
}
]
}
]
}
macOS の .dmg ファイルのフォーマットを確認する
hdiutil
の imageinfo
オプションを使う
% hdiutil imageinfo myimage.dmg
Google Spreadsheets で配列
INDEX
と {}
を使う。1-origin なので、下記の場合は 100 が返り値になる
=INDEX({100, 200, 300}, 1)
Git で管理されているファイルの編集を無視する方法
git update-index --assume-unchanged src/config.txt
もとに戻すには --no-assume-unchanged を使う
git update-index --no-assume-unchanged src/config.txt
参考:
Google Spreadsheet で GAS を使って、カタカナをひらがなに変換
セルをまとめて変換する方が早くなる?
function toHiragana(args) {
if (Array.isArray(args)) {
let output = [];
for (let arg of args) {
output.push(toHiragana(arg));
}
return output;
}
if (typeof args != "string") {
return "";
}
let codes = [];
for (let chr of args) {
const offset = ('ァ' <= chr && chr <= 'ヶ') ? -0x0060 : 0;
codes.push(chr.charCodeAt() + offset);
}
return String.fromCharCode(...codes);
}
2 つのファイルで共通する行を出力するコマンドライン
comm -12 sorted_lines1.txt sorted_lines2.txt > common_lines.txt
sorted_lines1.txt
と sorted_lines2.txt
はソートされている前提
参照:
ファイルの各行に文字列を追加するコマンドライン
sed -e 's/^/prefix/' file.txt > prefixed_file.txt
そりゃまあ sed
を使えばできるけど…それ以外にはないのかな?
参照:
VSCode で .tsv ファイルではタブが入力できるようにする
keybindings.json に次のように設定する。
[
{
"key": "tab",
"command": "type",
"args": {"text": "\t"},
"when": "editorTextFocus && editorLangId == plaintext"
}
]
.tsv ファイルは plaintext として認識されるので、plaintext 全体が適用範囲にはなってしまう。 .tsv ファイルに限定するのは宿題。
参照
git でタグをつけて公開する
% git tag -a {tag} {commit-id}
% git push -u origin master {tag}
具体例
% git tag -a 2.26.4660.102 063c41f1d7c1a877f44c1f8caad6be1897350336
% git push -u origin master 2.26.4660.102
svg から ico ファイルを作成するコマンドライン
ImageMagick の convert
と Icoutils の icotool
を使う
convert -background none -density 1024 -resize 16x16 -extent 16x16 -gravity Center icon.svg icon_16.png
convert -background none -density 1024 -resize 24x24 -extent 24x24 -gravity Center icon.svg icon_24.png
convert -background none -density 1024 -resize 32x32 -extent 32x32 -gravity Center icon.svg icon_32.png
icotool -c icon_16.png icon_24.png icon_32.png > icon.ico
シェルスクリプトでまとめての実行
for n in icon1 icon2 icon3; do
PNGS=()
for s in 16 20 24 32 48 64 128 256; do
convert -background none -density 1024 -resize ${s}x${s} -extent ${s}x${s} -gravity Center ${n}.svg ${n}_${s}.png
PNGS+=${n}_${s}.png
done
icotool -c $PNGS[@] > ${n}.ico
done
macOS で CPU 温度を取得するコマンドライン
sudo powermetrics --samplers smc -n 1
一般ユーザーでは実行できないので、sudo
が必要
macOS でインストールされたパッケージの一覧を取得するコマンドライン
pkgutil --pkgs
インストールされたファイルの一覧
pkgutil --files [package_name]
インストールの記録を削除
sudo pkgutil --forget [package_name]
macOS でアプリケーションのウインドウを移動するコマンドライン
osascript \
-e 'tell application "Terminal"' \
-e 'set position of front window to {1, 1}' \
-e 'end tell'
デスクトップの指定方法と複数ウインドウがある場合の指定方法も確認したい
参照
macOS で pkg ファイルをインストールするコマンドライン
sudo installer -pkg MyApp.pkg -target /
adb でデバイス内のファイルにアクセス
adb pull /data/data/com.example.package/databases/data.db .
"permission denied" の場合
adb shell "su -c cat /data/data/com.example.package/databases/data.db" > data.db
or
adb shell "run-as com.example.package cat /data/data/com.example.package/databases/data.db" > data.db
"run-as package: not debuggable" の場合
adb backup -noapk com.example.package
参考
adb でインストール済みパッケージ一覧を取得
adb shell pm list packages
Git: サブディレクトリを新規リポジトリにする
SOURCE_REPO/PROJECT を NEW_REPO として登録する
curl "https://raw.githubusercontent.com/newren/git-filter-repo/main/git-filter-repo" > ~/git-filter-repo
git clone https://github.com/USER/SOURCE_REPO.git
cd SOURCE_REPO
python3 ~/git-filter-repo --path PROJECT
python3 ~/git-filter-repo --subdirectory-filter PROJECT
git remote add origin https://github.com/USER/NEW_REPO.git
git push -u origin main
macOS の codesign で特定の証明書を使わずに擬似的に署名をする
--sign
の引数に -
を渡すと、擬似的な証明書 (pseudo identity) で署名ができる
codesign --sign - /path/to/Product.app
参考
Bazel でビルドに必要なファイルをあらかじめダウンロードする
--repository_cache
オプションと --registry
オプションを使う
Bzlmod の場合
ファイルの準備
bazel fetch --repository_cache="/path/to/repository_cache"
git clone https://github.com/bazelbuild/bazel-central-registry.git /path/to/bcr
使用方法
bazel build --repository_cache="/path/to/repository_cache" --registry=file:///path/to/bcr ...
WORKSPACE の場合
ファイルの準備
bazel sync --repository_cache="/path/to/repository_cache"
使用方法
bazel build --repository_cache="/path/to/repository_cache" ...
参考
Bazel でサブプロセスが Operation not permitted というエラーで失敗する
--spawn_strategy=local
をオプションで指定すると回避できることがある。
bazel build ... --spawn_strategy=local
macOS の /usr/bin/hdiutil
を実行する genrule
が上記のエラーで失敗したが、 --spawn_strategy=local
で問題は回避できた。
参考
Bazel の Abseil が absolute paths をインクルードしているというエラーで失敗する
開発環境が更新されると、下記のようなエラーで失敗することがある。
ERROR: .../.cache/bazel/.../external/abseil-cpp~/absl/debugging/BUILD.bazel:335:11: Compiling absl/debugging/internal/utf8_for_code_point.cc failed: absolute path inclusion(s) found in rule '@@abseil-cpp~//absl/debugging:utf8_for_code_point':
the source file 'absl/debugging/internal/utf8_for_code_point.cc' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain):
'/usr/lib/gcc/x86_64-linux-gnu/14/include/stdint.h'
'/usr/lib/gcc/x86_64-linux-gnu/14/include/limits.h'
'/usr/lib/gcc/x86_64-linux-gnu/14/include/syslimits.h'
'/usr/lib/gcc/x86_64-linux-gnu/14/include/stddef.h'
Target //:package failed to build
bazel clean --expunge
でキャッシュを削除すると解決した。