Visual Studio Code で CMake Tools の MSBuild 出力が文字化けする対策

CMakePresets.json の configurePresets で環境変数 DOTNET_CLI_UI_LANGUAGE と VSLANG を指定すると msbuild.exe の出力を英語に設定できる。両方とも指定しないとなぜか変わらない(💢)。

設定例:

{
    "version": 8,
    "configurePresets": [
        {
            "name": "x64",
            "generator": "Visual Studio 17 2022",
            "toolset": "host=x64",
            "architecture": "x64",
            "binaryDir": "${sourceDir}/build/${presetName}",
            "cacheVariables": {
                "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install/${presetName}",
                "CMAKE_C_COMPILER": "cl.exe",
                "CMAKE_CXX_COMPILER": "cl.exe"
            },
            "environment": {
                "DOTNET_CLI_UI_LANGUAGE": "en-US",
                "VSLANG": "1033"
            }
        }
    ],
    "buildPresets": [
        {
            "name": "x64-debug",
            "configurePreset": "x64",
            "configuration": "Debug"
        }
    ]
}

ほんとうは日本語で文字化けせずに出せればそれがいいのだがわからなかった。エクステンションのロード時にどこかでコードページが指定されているようなのだが……。

ウェブアプリ開発をローカルでやるかコンテナでやるか

VSCode で Python ウェブアプリケーションを開発するとき、コンテナの活用という視点で見るとつぎのように分類できる。

ローカルで開発、デバッグ

古典的なやりかた。プロジェクトをチェックアウトして、venv を作ってコードを書く。デバッグ(実行)するときもローカルのマシンで venv の Python で動かして確認する。いちばんなじみがある。

ローカルで開発、コンテナでデバッグ

VSCode ではデバッグ時にコンテナでプロジェクトを走らせることができる。ウェブアプリなんて作ったらどうせ(?) Dockerfile 書いてコンテナで動かすんだからはじめからコンテナで動作確認したほうがいい。後述の Dev Container が出るまでは有力な選択肢だった。

コンテナで開発、デバッグ

Dev Container ができて、最初から実行環境に近いコンテナでぜんぶ開発できるようになった。コンテナの中でローカルのように開発、デバッグできる。VSCode すごい。

Dev Container 開発の利点は、“What’s a devContainer and what is it good for?” (2023) という記事で次のような点が挙げられている。

  • 必要な開発環境をすぐに用意できる(依存ライブラリのインストールなどをあらかじめ揃えておける)。
  • 開発環境のバージョンを固定化できる。手元のマシンでは最新版にアップデートしたランタイムが後方互換性を失っているときなどでも以前のバージョンで開発を再開できる。
  • データベースなど連携するコンポーネントもコンテナに含めてしまうことで、実環境の変更の影響が開発環境に及ばないようにできる。開発者は各自自分のコンテナでの DB との接続性を保ったまま開発に集中できる。

で、ここではじつは開発環境が実行環境に近いということはとくに謳っていないのだが、たとえばプロジェクトで利用しているあるライブラリが Linux のみ対応だったり、Windows / macOS では挙動が違ったり、ディレクトリ構成が異なることで面倒な対応が必要だったりというのはありがちな話なので、そういうことから解放されるのはけっこう大きいメリットではないかと思う。

ひみつメモ帳を現行の macOS に対応させたい

ひみつメモ帳で使っていた OpenSSL ライブラリは、現行の macOS (Mojave) だと標準装備されなくなっている。したがって自分で openssl ライブラリをビルドして同梱する必要がある。ソースをダウンロードして自分でビルドしてもいいが、Homebrew か MacPorts を使うと楽そう。あまり考えずみんな大好き Homebrew にしてみる。

Homebrew でインストールしたライブラリとリンクしてビルドするところまでは簡単。しかしここで問題が出る。できたバイナリは openssl ライブラリを Homebrew でインストールしている環境でしか動かない。ユーザーに Homebrew で手作業で入れてもらうわけにもいかないし。バイナリがどこのライブラリを見にいくかは otool -L でわかる。

こういうときの定石としては、アプリのパッケージ内にライブラリをコピーしてそれを使うようにすればいいらしい。Xcode のビルド設定でできる。しかしコピーするだけで実行ファイルがそのライブラリを探すようになるわけではないので動かない。そこでビルド後の Run Script フェーズで install_name_tool を使ってバイナリのライブラリ参照先を書き替える。

これで .app 単体でどの環境でも起動するようになった。Parallels で作った新規インストールの macOS で確認。いまの macOS は開発、テスト用に仮想環境に2つまでコピーをインストールできることが使用許諾に含まれている。

しかしこのプロジェクトをアーカイブしてストア用に validate すると通らない。

OpenSSL の .dylib バイナリに LC_VERSION_MIN_MACOSX ロードコマンドが含まれていないのがエラーのひとつ。このライブラリは Homebrew で入れたものなので、brew install のビルド設定を変えないとだめそう。

ここでものすごく時間を費やす。

けっきょく、Homebrew では LC_VERSION_MIN_MACOSX を付けるビルドにカスタマイズすることはできないというのを発見する。Homebrew は捨てて MacPorts を使え。

MacPorts でもそのまま欲しいパッケージを入れると LC_VERSION_MIN_MACOSX は付かない。ちなみにこの確認は otool -l でできる。そこで /opt/local/etc/macports/macports.conf を編集して設定を変更する。

末尾に

macosx_deployment_target 10.12

の設定を追加。ちなみにこのオプションは文書化されていない(ファッ○)。

また、~/.bash_profile に export MACOSX_DEPLOYMENT_TARGET=10.12 を追加してみたが、これははなくても LC_VERSION_MIN_MACOSX が付いたので消した。参考にしたサイトには universal_target と macosx_sdk_version も指定するよう書いてあったが、universal_target オプションはいまの MacPorts では廃止されたのでもう存在せず、macos_sdk_version はおそらくビルドに使う SDK のバージョンなので、対象となる OS のバージョンの設定とは無関係とみて設定しなかった。

上記の作業をやったうえで、インストール時に、

sudo port install -s openssl

と -s オプション付きで導入すればよい。このオプションを付けるのは、そのままだとパッケージによってはビルド済みバイナリを取ってきて導入してしまうからで、それだともちろんビルド設定は反映されていない。ソースからちゃんとビルドするように指定するオプション。ただし当然ながら導入までの時間は長くかかる。

(2020-04-07追記) /opt/local/etc/macports/macports.conf の buildfromsource オプションを always にすると毎回 -s オプションを付けなくてもソースからビルドしてくれる。

これでアプリの validation における .dylib の問題は解決。その後 App ID が登録されてないとかカテゴリが一致してないとかあったがそれはアップルの開発者サイトで登録したり Xcode で設定を合わせたりすればよい。

アプリのサンドボックス関連の検証エラーで、.entitlements ファイルの com.apple.security.app-sandbox の値が真になってないとか言ってくることがあるが、.entitlements ファイルを見てもちゃんと設定されている。これはターゲットの設定の Capabilities にある App Sandbox 設定を on にすればよい。

アプリの登録ページで、ひみつメモ帳は暗号関係ライブラリを使ってるので、米国の輸出規制対象となるのでコンプライアンス書類を提出する必要がある。いまここ。めんどくさそう。

Vcpkg

Vcpkg は、Visual C++ でオープンソースのライブラリをパッケージとして簡単に管理できるツールとして Microsoft がさいきん公開したツール。GitHub で公開されている。

有名どころのライブラリはほとんどがすでにポートとして網羅されていて、boost、curl、gettext、gtk などを vcpkg コマンドを使って VC++ で使うためにビルドできる。個人的に気になるのは freetype, icu, opencv, openssl, python3, wxwidgets あたりかな。これまで NuGet にもあった WTL はこっちにもある。

オープンソースのライブラリはメインターゲットがほとんど Linux なので Windows で使おうとすると README 読んで自分でがんばるしかないという状況だったので、MS 謹製でこういうものを用意してくれるとありがたい。Visual Studio でこれらを扱う標準的なやりかたが出たのも大きい。

たとえば、ひみつメモ帳は OpenSSL と(現在公開しているバージョンでは)wxWidgets を使っているのだけど、それぞれ自力でビルドしてプロジェクトの設定にマニュアルでパスを追加している。これが、コマンドラインで vcpkg install openssl wxwidgets とだけ叩けば、プロジェクトのソースで #include <openssl/crypto.h> といきなり書けるようになる。ビルドの設定じゃなくてコードに集中できてよい。

気になるのは、OSS のライブラリに交じって、ATL とか MFC とかのポートが含まれているところ。あんまり使う機会はなさそうだけど、やるとどうなるのだろう。

Visual Studio Code

WZ を離れて以来テキストエディタ難民状態だったけど、さいきんは VS Code に落ちついてきた。Sublime Text は開発ペースが遅すぎるし Atom は動作が遅すぎた。Code は Windows と Mac で動くし開発も盛んだし VCS 連携で Mercurial のプラグインがあるのもよい。

ためしてないけど Arduino のエディタとしても使えるらしい。

個人的には優先事項ではないけれどメニューが日本語化されているので会社でほかの人に勧めやすいのもある。