npm install iconvでnode-gypのrebuildが失敗した時

# はじめに

日経競馬のページをダウンロードしようとしたら、文字コードがEUC-JPで文字化けするので、npmからiconvをインストールしてUTF-8に変換しようとすると、node-gypのrebuildで失敗。ログなどを調べると、pythonの2.7.xとMicrosoftのVisual StdioのC++のコンパイラーMSBuild.exeが必要らしいことが判明。その時の備忘録です。

# 前提
* OS : Windows7以上
* PoweShellのターミナルで実行
* VSCodeでコード編集
* node.js環境構築済み
* Visual Studio 2017導入済みでVC++をコンパイル可能

# ログを見てみる

## iconvインストール

```Shell
npm install iconv --save
```

## npmのログの出力先

```Shell
C:\Users\ユーザ\AppData\Roaming\npm-cache\_logs
```

## エラーログ
```Shell
0 info it worked if it ends with ok
1 verbose cli [ 'C:\\Program Files\\nodejs\\node.exe',
1 verbose cli   'C:\\Program Files (x86)\\Nodist\\bin\\node_modules\\npm\\bin\\npm-cli.js',
1 verbose cli   'install',
1 verbose cli   'iconv' ]
2 info using npm@6.6.0-next.0
3 info using node@v8.9.4
4 verbose npm-session 988987ee13c43a94
5 silly install loadCurrentTree
6 silly install readLocalPackageData
7 http fetch GET 304 https://registry.npmjs.org/iconv 172ms (from cache)
8 silly pacote tag manifest for iconv@latest fetched in 207ms
9 timing stage:loadCurrentTree Completed in 317ms

~　中略

129 verbose stack Error: iconv@2.3.4 install: `node-gyp rebuild`
129 verbose stack Exit status 1
129 verbose stack     at EventEmitter.<anonymous> (C:\Program Files (x86)\Nodist\bin\node_modules\npm\node_modules\npm-lifecycle\index.js:301:16)
129 verbose stack     at emitTwo (events.js:126:13)
129 verbose stack     at EventEmitter.emit (events.js:214:7)
129 verbose stack     at ChildProcess.<anonymous> (C:\Program Files (x86)\Nodist\bin\node_modules\npm\node_modules\npm-lifecycle\lib\spawn.js:55:14)
129 verbose stack     at emitTwo (events.js:126:13)
129 verbose stack     at ChildProcess.emit (events.js:214:7)
129 verbose stack     at maybeClose (internal/child_process.js:925:16)
129 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:209:5)
130 verbose pkgid iconv@2.3.4
131 verbose cwd C:\Users\kousei00\Desktop\MPD\Tomorrow\Google\Google Trends\webdav
132 verbose Windows_NT 6.1.7601
133 verbose argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files (x86)\\Nodist\\bin\\node_modules\\npm\\bin\\npm-cli.js" "install" "iconv"
134 verbose node v8.9.4
135 verbose npm  v6.6.0-next.0
136 error code ELIFECYCLE
137 error errno 1
138 error iconv@2.3.4 install: `node-gyp rebuild`
138 error Exit status 1
139 error Failed at the iconv@2.3.4 install script.
139 error This is probably not a problem with npm. There is likely additional logging output above.
140 verbose exit [ 1, true ]

```

行番138 「error iconv@2.3.4 install: `node-gyp rebuild`」とnode-gypのrebuildでエラーとなっているのがわかります。

[**node-gypとは**](https://githubja.com/nodejs/node-gyp)
>
Node.jsネイティブアドオンビルドツール node-gyp は、Node.jsのネイティブアドオンモジュールをコンパイルするために、Node.jsで書かれたクロスプラットフォームのコマンドラインツールです。
>

つまり、**iconvのモジュールコンパイルで失敗**しているということが判明。

## ダウンロード済のファイルを見てみる

たぶん、ローカルにダウンロードしたファイルにヒントがあるはず。

```Shell
C:..\node_modules\iconv
│  binding.gyp
│  LICENSE
│  package.json
│  README.md
│
├─build
│  │  binding.sln
│  │  config.gypi
│  │  iconv.vcxproj
│  │  iconv.vcxproj.filte
│  │
│  └─Release
│      │  iconv.exp
│      │  iconv.lib
│      │  iconv.map
│      │  iconv.node
│      │  iconv.pdb
│      │
│      └─obj
│          └─iconv
│              │  binding
│              │  iconv.o
│              │  localch
│              │  vc141.p
│              │  win_del
│              │
│              └─iconv.t
│                      CL.
│                      CL.
│                      CL.
│                      ico
│                      ico
│                      lin
│                      lin
│                      lin
│
├─deps
│  └─libiconv
│      └─lib
│              aliases.h
│              aliases2.h
│              aliases_aix
│              aliases_aix
│              aliases_dos
│              aliases_ext
│              aliases_osf
│              aliases_osf
│              aliases_sys
│              aliases_sys
│              aliases_sys
│              aliases_sys
│              armscii_8.h
│              ascii.h
│              atarist.h
│              big5.h
│              big5hkscs19
│              big5hkscs20
│              big5hkscs20
│              big5hkscs20
│              big5_2003.h
│              c99.h
│              canonical.h
│              canonical_a
│              canonical_a
│              canonical_d
│              canonical_e
│              canonical_l
│              canonical_l
│              canonical_l
│              canonical_l
│              canonical_l
│              canonical_o
│              canonical_o
│              canonical_s
│              canonical_s
│              canonical_s
│              canonical_s
│              ces_big5.h
│              ces_gbk.h
│              cjk_variant
│              cns11643.h
│              cns11643_1.
│              cns11643_15
│              cns11643_2.
│              cns11643_3.
│              cns11643_4.
│              cns11643_4a
│              cns11643_4b
│              cns11643_5.
│              cns11643_6.
│              cns11643_7.
│              cns11643_in
│              converters.
│              cp1046.h
│              cp1124.h
│              cp1125.h
│              cp1129.h
│              cp1131.h
│              cp1133.h
│              cp1161.h
│              cp1162.h
│              cp1163.h
│              cp1250.h
│              cp1251.h
│              cp1252.h
│              cp1253.h
│              cp1254.h
│              cp1255.h
│              cp1256.h
│              cp1257.h
│              cp1258.h
│              cp437.h
│              cp50221_020
│              cp50221_021
│              cp737.h
│              cp775.h
│              cp850.h
│              cp852.h
│              cp853.h
│              cp855.h
│              cp856.h
│              cp857.h
│              cp858.h
│              cp860.h
│              cp861.h
│              cp862.h
│              cp863.h
│              cp864.h
│              cp865.h
│              cp866.h
│              cp869.h
│              cp874.h
│              cp922.h
│              cp932.h
│              cp932ext.h
│              cp936.h
│              cp936ext.h
│              cp943.h
│              cp949.h
│              cp950.h
│              cp950ext.h
│              dec_hanyu.h
│              dec_kanji.h
│              encodings.d
│              encodings_a
│              encodings_d
│              encodings_e
│              encodings_l
│              encodings_o
│              euc_cn.h
│              euc_jisx021
│              euc_jp.h
│              euc_kr.h
│              euc_tw.h
│              flags.h
│              flushwc.h
│              gb12345.h
│              gb12345ext.
│              gb18030.h
│              gb18030ext.
│              gb18030uni.
│              gb2312.h
│              gbk.h
│              gbkext1.h
│              gbkext2.h
│              gbkext_inv.
│              georgian_ac
│              georgian_ps
│              hkscs1999.h
│              hkscs2001.h
│              hkscs2004.h
│              hkscs2008.h
│              hp_roman8.h
│              hz.h
│              iconv.c
│              iconv_open1
│              iconv_open2
│              iso2022_cn.
│              iso2022_cne
│              iso2022_jp.
│              iso2022_jp1
│              iso2022_jp2
│              iso2022_jp3
│              iso2022_jpm
│              iso2022_kr.
│              iso646_cn.h
│              iso646_jp.h
│              iso8859_1.h
│              iso8859_10.
│              iso8859_11.
│              iso8859_13.
│              iso8859_14.
│              iso8859_15.
│              iso8859_16.
│              iso8859_2.h
│              iso8859_3.h
│              iso8859_4.h
│              iso8859_5.h
│              iso8859_6.h
│              iso8859_7.h
│              iso8859_8.h
│              iso8859_9.h
│              isoir165.h
│              isoir165ext
│              java.h
│              jisx0201.h
│              jisx0208.h
│              jisx0212.h
│              jisx0213.h
│              johab.h
│              johab_hangu
│              koi8_r.h
│              koi8_ru.h
│              koi8_t.h
│              koi8_u.h
│              ksc5601.h
│              loops.h
│              loop_unicod
│              loop_wchar.
│              mac_arabic.
│              mac_central
│              mac_croatia
│              mac_cyrilli
│              mac_greek.h
│              mac_hebrew.
│              mac_iceland
│              mac_roman.h
│              mac_romania
│              mac_thai.h
│              mac_turkish
│              mac_ukraine
│              mulelao.h
│              nextstep.h
│              pt154.h
│              riscos1.h
│              rk1048.h
│              shift_jisx0
│              sjis.h
│              tcvn.h
│              tds565.h
│              tis620.h
│              translit.h
│              ucs2.h
│              ucs2be.h
│              ucs2interna
│              ucs2le.h
│              ucs2swapped
│              ucs4.h
│              ucs4be.h
│              ucs4interna
│              ucs4le.h
│              ucs4swapped
│              uhc_1.h
│              uhc_2.h
│              utf16.h
│              utf16be.h
│              utf16le.h
│              utf32.h
│              utf32be.h
│              utf32le.h
│              utf7.h
│              utf8.h
│              vietcomb.h
│              viscii.h
│
├─lib
│      iconv.js
│
├─src
│      binding.cc
│
├─support
│      config.h
│      iconv.h
│      localcharset.c
│      localcharset.h
│
└─test
    │  run-tests.js
    │  test-basic.js
    │  test-big-buffer.js
    │  test-stream.js
    │
    └─fixtures
            lorem-ipsum.txt
```

* buildディレクトリの「iconv.vcxproj」はC++のプロジェクトファイルです。
  これをもとにC++をコンパイルしようよしていることがわかります。
* buildディレクトリの「config.gypi」はnode-gypのインストール設定です。
  いくつか設定のポイントがあります。

  - **msbuild_path**  
    Visual StudioのMSBuild.exeを設定します。

  ```Shell
   "msbuild_path": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\MSBuild\\15.0\\Bin\\MSBuild.exe",
  ```
  - **node_gyp**  
    node_gyp.jsのパスです。

  ```Shell
  "node_gyp": "C:\\Program Files (x86)\\Nodist\\bin\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js",
  ```
  - gyp\pylib\gypディレクトリ  
  VC++をコンパイルするためのpythonのスクリプトが定義されています。

  ```Shell
  "C:\\Program Files (x86)\\Nodist\\bin\\node_modules\\npm\\node_modules\\node-gyp\\gyp\\pylib\\gyp 
  ```

 ```Shell
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        2019/08/07     16:15            generator
-a---        1985/10/26     17:15      20139 common.py
-a---        1985/10/26     17:15       1970 common_test.py
-a---        1985/10/26     17:15       5014 easy_xml.py
-a---        1985/10/26     17:15       3270 easy_xml_test.py
-a---        1985/10/26     17:15       1749 flock_tool.py
-a---        1985/10/26     17:15     116306 input.py
-a---        1985/10/26     17:15       3187 input_test.py
-a---        1985/10/26     17:15      23379 mac_tool.py
-a---        1985/10/26     17:15      11855 MSVSNew.py
-a---        1985/10/26     17:15       6387 MSVSProject.py
-a---        1985/10/26     17:15      45234 MSVSSettings.py
-a---        1985/10/26     17:15      65937 MSVSSettings_test.py
-a---        1985/10/26     17:15       1804 MSVSToolFile.py
-a---        1985/10/26     17:15       5086 MSVSUserFile.py
-a---        1985/10/26     17:15       9533 MSVSUtil.py
-a---        1985/10/26     17:15      17325 MSVSVersion.py
-a---        1985/10/26     17:15      48034 msvs_emulation.py
-a---        1985/10/26     17:15       5536 ninja_syntax.py
-a---        1985/10/26     17:15      10358 ordered_dict.py
-a---        1985/10/26     17:15       1333 simple_copy.py
-a---        1985/10/26     17:15      12791 win_tool.py
-a---        1985/10/26     17:15     120483 xcodeproj_file.py
-a---        1985/10/26     17:15      66049 xcode_emulation.py
-a---        1985/10/26     17:15      10579 xcode_ninja.py
-a---        1985/10/26     17:15       2174 xml_fix.py
-a---        1985/10/26     17:15      22395 __init__.py
```
**おっと古いスクリプトだ!**  
ちなみに現在のpythonのバージョンは？

```Shell
python --version
Python 3.7.4
```

**これじゃ動かない**  
というわけで、2.7.x系の最終 [python 2.7.15](https://www.python.org/downloads/release/python-2715/) をインストールすることに、ダウンロードしてインストール。

```Shell
python --version
Python 2.7.15
```
無事ダウングレード。

# npm のコンフィグも設定

下記のサイトを参照して、
[「Windowsでnpm installしてnode-gypでつまずいた時対処方法」](https://qiita.com/AkihiroTakamura/items/25ba516f8ec624e66ee7)

```Shell
npm config set msvs_version 2017
npm config set python C:\Users\~\python27\python.exe
```
これで、iconvの再インストール。無事node-gypのrebuildが成功。  
VC++のコンパイルログが出力されます。  


## 日経競馬ページダウンロード
下記のコード（リーディング騎手ダウンロードスクリプト）を実行します。

### jockey_leading.js

```JavaScript
var request = require('request');
var Iconv = require('iconv').Iconv;
var fs = require('fs');
const file = ".\\jockey_leading.html";

var options = {
    url: 'https://db.netkeiba.com/?pid=jockey_leading',
    encoding: null,
    method: 'GET'
}

/**
 *  AppendFile
 * @param {*} path 
 * @param {*} data 
 */
function AppendFile(path, data) {
    fs.appendFile(path, data, function (err) {
      if (err) {
          throw err;
      }
    })
}

request(options, function (error, response, body) {
    if (!error && response.statusCode == 200) {
        var iconv = new Iconv('EUC-JP', 'UTF-8//TRANSLIT//IGNORE');
        body = iconv.convert(body).toString();
        AppendFile(file,body);
    }
})



```

```Shell
node jockey_leading.js
```


### jockey_leading.html(先頭抜粋)
無事文字化けが解消しました。

![2019-08-09-11-32-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239597/34ee7ff5-68d3-f6d3-9a65-64ef8c17cbed.png)

![2019-08-09-11-35-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239597/1d1ef07c-b5a1-ed23-d924-558be2ccc666.png)

今年は、今のところルメールが２位だね。

# まとめ
node.jsはnpmで色々なライブラリーを簡単にダウンロードできるところがいいです。今回のiconvはVC++のモジュールをコンパイルするため、結構ハードルが高いと思います。このようにインストールが失敗する時は、最初にインストールログを見ることです。何が起こってエラーになったのか、唯一の手ががりがきっとあるはずです。
さて、**夏休みまっさかり**、がんがん「jockey_leading.js」を改造して、**競馬データを作りましょう！！**