Skip to main content

Mac と Windows 両方で動作させるときの注意点

0. 背景と教訓

背景

  • Mac で開発していたが、Windows でも動作させたくなった
  • そしたらハマった

教訓

  1. スクリプト系は bash や python でなく極力 node.js でやる
  2. markdown のファイル名に日本語を使わない
  3. ファイル open 時の encoding は明示的に指定

特に 1 を守らずハマったのでメモを残しておく。

※ 2 は、濁音/半濁音などで URL encoding や git 周りで苦労するのが想像つくので、避けている (つまりここには解決策は書いてない)

前提

git clone 後にライブラリを入れていること

npm ライブラリ

bash
npm install

Python 関連ライブラリ

venv 作成済であること。

bash
bash
python -m venv .venv
. .venv/Scripts/activate
pip install -r requirements.txt

参考: venvメモ

対応 1. bash にパスが通っていなかった場合、git bash にパスを通す

通常はインストーラで 以下を選んでれば足されるはずなのだが、足されないので手動で足す

  • 画面 : Adjusting your PATH environment
  • 項目 : Git from the command line and also from 3rd-party software

Windows の設定画面からやっても良いが、PowerShell のプロンプトからやる手順はこう。

ps1
$gitBashPath = "C:\Program Files\Git\bin"
$oldPath = [Environment]::GetEnvironmentVariable("Path", "User")
$newPath = "$oldPath;$gitBashPath"

[Environment]::SetEnvironmentVariable("Path", $newPath, "User")

対応 2. package.json で シェルスクリプトを呼んでいた場合、bash を明示

package.json
"scripts": {
"docusaurus": "docusaurus",
"prestart": "tools/preprocess.sh",
"prebuild": "tools/preprocess.sh",

bash から呼ぶ形にする (Windows では shebang は解釈してくれないので。ということだろう)

package.json
"scripts": {
"docusaurus": "docusaurus",
"prestart": "bash tools/preprocess.sh",
"prebuild": "bash tools/preprocess.sh",

対応 3. .venv の activate 時の Path が異なっている(なぜ・・)ので、分岐する

前提

  • Mac : .venv/bin/activate
  • Win : .venv/Scripts/activate (なぜ・・)

こういう差異は venv の利点を損ねていると思うけど・・、まあしょうがないので呼び元のシェルで分岐する

エラーメッセージ

エラーらしいエラーは出ず、以下のように Python とだけ出て、リターンコード 非0 で失敗する。

txt
$ npm run start
Python

なので、venv が正しく呼べてるか確認のために、バージョン番号も、呼び元シェルで出力しておく。

シェル変更点

bash
#!/usr/bin/env bash

set -e
set -o pipefail

if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
# Git Bash / Windows
ACTIVATE=".venv/Scripts/activate"
else
# macOS / Linux
ACTIVATE=".venv/bin/activate"
fi

if [[ -f "$ACTIVATE" ]]; then
. "$ACTIVATE"
else
echo "Error: Cannot find Python virtualenv activate script at $ACTIVATE"
exit 1
fi

# Python 実行確認
echo "Using Python: $(which python)"
python --version

# 以下、もともと呼んでいた Markdown 成形などの前処理 (上のほうが長い・・)
tools/order-dir-category-json.py docs
...

対応 4. shebang に指定するのは python3 でなく python にする

これは venv 使っていれば python で両対応できるはずなので、そうしておく。

py
#!/usr/bin/env python3

py
#!/usr/bin/env python

対応 5. エンコーディングと、改行コードは明示する

前提知識

Python での デフォルト エンコーディング

  • Mac/Linux のデフォルト : UTF-8
  • Windows のデフォルト : cp932 (Shift-JIS の Microsoft 版みたいなもの)

Python での デフォルト 改行コード

  • 読み込み時 : 強制的に '\n' に変換される
  • 書き込み時 : OS によって異なる (Win: '\r\n', Mac/Linux: '\n')

エラーメッセージ

エンコーディングでのエラー

txt
UnicodeDecodeError: 'cp932' codec can't decode byte 0x84 in position 23: illegal multibyte sequence

改行コードでの問題

→ git diff したときに気づくことになる ( 行末に ^M と出る )

修正の例

open 読みモード

py
with open(path) as f:

py
with open(path, encoding='utf-8') as f:

open 書きモード

py
with open(path, 'w') as f:

py
with open(path, 'w', encoding='utf-8', newline='\n') as f:

read, write

open で明示していれば足りてるはずだが、
必要に応じて read(), read_text(), write_text() も同様に。

デフォルトの encoding の全体設定

  • 環境変数で設定できるらしいが、これも環境依存・・・・
  • そして、Terminal の出力も変わる・・? それだけ聞くと文字化けなどの二次被害ありそう・・

というわけで、いったん使わず、open() で指定する方式にする・・。

bash
export PYTHONUTF8=1  # Python 3.7 以降。 入出力と、open() に効く
bash
export PYTHONIOENCODING=utf-8 # Python 3.10 以降。 入出力だけに効く。 open() には効かない

参考:

対応 6. パス区切り文字の吸収

glob でとってきたディレクトリのパスや、os.path.join() で作成したパスを、URL のパスに使おうとしてハマった。

→ ここでやったのは、 \\/ に変換しただけ

bash
for dirname in [os.path.normpath(x).replace('\\', '/') for x in glob.glob('**/*/', recursive=True)]:

Pathlib で .as_posix() を使うと良さそうであるが、試してない

bash
from pathlib import Path
dirs = [p.as_posix() for p in Path(".").rglob("*") if p.is_dir()]