読者です 読者をやめる 読者になる 読者になる

今日も窓辺でプログラム

外資系企業勤めのエンジニアが勉強した内容をまとめておくブログ

Windows 10 + bash + Atom + scriptパッケージでC++をお手軽コンパイルしたかった…

Windows 10のAnniversary Updateで追加された Bash on Windows を使ったら、Atomのscriptパッケージ でC++をお手軽コンパイルできるんじゃないかと思ったけど、結局できなかった作業ログです。

文字化け

まずは Atom、Scriptパッケージ、そしてBash on Windowsが入った状態で適当なcppファイルを用意して、Ctrl+Shift+Bを押してみます。
f:id:kanohk:20160801225414p:plain

なんかエラー吐いてるっぽいけど、文字化けして読めず。。
文字化けを解消する方法を少し調べてみたけど、それっぽいものが見つからず。

ソースコードを見てみる

ファイルの種類からそれぞれコマンドを投げる部分のコードはこちらで読むことができます。
atom-script/grammars.coffee at master · rgbkrk/atom-script · GitHub

WindowsでC++をコンパイルする部分はこの通り。特に変なことはしていません。

    else if GrammarUtils.OperatingSystem.isWindows() and GrammarUtils.OperatingSystem.release().split(".").slice -1 >= '14399'
      "File Based":
        command: "bash"
        args: (context) -> ["-c", "g++ -Wall -include stdio.h -include iostream '/mnt/" + path.posix.join.apply(path.posix, [].concat([context.filepath.split(path.win32.sep)[0].toLowerCase()], context.filepath.split(path.win32.sep).slice(1))).replace(":", "") + "' -o /tmp/cpp.out && /tmp/cpp.out"]

実際に実行されているコマンドは?

実際にログを確認してみても、期待通りの引数でbashが実行されています。
[Command: bash -c 'g++ -Wall -include stdio.h -include iostream '/mnt/c/Users//test.cpp' -o /tmp/cpp.out && /tmp/cpp.out']

このコマンドをbashから実行してみると、問題なく動く。

$ bash -c 'g++ -Wall -include stdio.h -include iostream '/mnt/c/Users/<hogehoge>/test.cpp' -o /tmp/cpp.out && /tmp/cpp.out'
hello world

ではコマンドプロンプトから実行するとどうでしょう。
f:id:kanohk:20160801233421p:plain

お?これか?

シングルクォートが犯人?

下のように、g++コマンドをかこっているシングルクオーテーションをダブルクオーテーションに変えてあげたら、コマンドプロンプトでもコンパイルを実行できました。

bash -c "g++ -Wall -include stdio.h -include iostream '/mnt/c/Users/<hogehoge>/test.cpp' -o /tmp/cpp.out && /tmp/cpp.out'

つまり、こういうことです。
bashにはシングルクォートで囲った部分全部が引数として送られて欲しかったのですが、コマンドプロンプトは&&の前後の文字列を別々のコマンドとして認識してしまって

bash -c "g++ -Wall -include stdio.h -include iostream '/mnt/c/Users//test.cpp' -o /tmp/cpp.out

/tmp/cpp.out'
という2つのコマンドとして認識してしまったわけです。
(参考:Download Windows Server 2003/2003 R2 の削除されたコンテンツ from Official Microsoft Download Center

というわけで、scriptパッケージのコードを書き換えて再度試してみましたが、結局同じエラーメッセージが表示されてコンパイルできませんでした。

英語環境を用意してみる

やっぱりあの文字化けしているエラーメッセージが何言ってるのかわからないとどうにもならない、ということで英語環境を用意しました。
すると、こんなことを言っていました。

'bash' is not recognized as an internal or external command,
operable program or batch file.

なんと。bashが見えてない?

Atomが32bitだったことが原因

いろいろ原因を調べてみたのですが、結局原因はAtomが32ビットのバイナリなのに対し、bashが64ビットのバイナリだったことでした。
パッケージ中のrunner.coffeeというコードを読むと分かりますが、実際にコンパイルを実行するプロセスはBufferedProcessというNode.jsのchild_processのラッパーを使って実装されています。
なので、当然コンパイルも32ビットのプロセス内で走っているわけです。

原因はわかった、だけど、、、

これで原因はわかりました。Atomとbashを64ビットか32ビットに統一してあげればよさそうです。

というわけで、64bitのAtomをインストールしてみようとそましたが、ざっと公式ページを見てみても、Windowsの64ビットバイナリは見つかりません。
Issueを検索してみると、まだ64bitのバイナリはリリースできる状態にないようです。
Windows 64bit release · Issue #4881 · atom/atom · GitHub

あまり乗り気はしませんが、32bitのbash on windowsは存在するのでしょうか。軽く探してみた限り、なさそうに見えます…。

というわけで、現時点では、Bash on Windowsを使ってScriptでC++をコンパイルはできなさそうです。。