monaをmacで掘る

$kotoに続いて、monaのCPUマイナーのformulaも作ってしまおうと思います。 (koto minerについては記事書き途中です)
そのため、まずは手動でビルドしてみます。

公式: [monacoinproject/cpuminer-multi](https://github.com/monacoinproject/cpuminer-multi)

# TL;DR

  * macでのビルドはちょっくらめんどくさいぜ
  * もしよかったら `$ brew install cj-bc/miners/monacoin-cpuminer-multi`でインストールできるはずなので使ってみてください

# 手動でmonaのCPUマイナーをビルドする

## 依存パッケージの確認

  公式に書かれている依存パッケージは以下の通りです:

  ```
  libcurl http://curl.haxx.se/libcurl/
  jansson http://www.digip.org/jansson/ (jansson source is included in-tree)
  openssl libcrypto https://www.openssl.org/
  pthreads
  zlib (for curl/ssl)
  ```

  このうち、`jansson`は含まれているとのことなので入れる必要はなく、他はhomebrewを使うと以下で良いようでした:

  ```
  $ brew install curl
  $ brew install openssl
  $ brew install zlib
  ```

  `pthreads`については、元々`homebrew`にあったものの`homebrew/php`に分けられたようです。
  しかし**homebrew/phpがdeprecatedとなり使えない**ので、現状どうしようもありません(困ってる)

## ビルドしてみる


  公式のREADMEにある以下の手順では、うまくいきませんでした:

  ```bash
  $ ./autogen.sh
  $ ./nomacro.pl
  $ ./configure CFLAGS='-march=native' --with-crypto --with-curl
  $ make
  /Applications/Xcode.app/Contents/Developer/usr/bin/make  all-recursive
  Making all in compat
  make[3]: Nothing to be done for `all-am'.
  gcc -DHAVE_CONFIG_H -I.  -Iyes/include -I/usr/local/opt/openssl/bin/openssl/include -fno-strict-aliasing  -I. -Iyes/include -I/usr/local/opt/openssl/bin/openssl/include -Wno-pointer-sign -Wno-pointer-to-int-cast   -march=native  -Iyes/include -I/usr/local/opt/openssl/bin/openssl/include -MT cpuminer-cpu-miner.o -MD -MP -MF .deps/cpuminer-cpu-miner.Tpo -c -o cpuminer-cpu-miner.o `test -f 'cpu-miner.c' || echo './'`cpu-miner.c
  cpu-miner.c:28:10: fatal error: 'openssl/sha.h' file not found
  #include <openssl/sha.h>
           ^~~~~~~~~~~~~~~
  1 error generated.
  make[2]: *** [cpuminer-cpu-miner.o] Error 1
  make[1]: *** [all-recursive] Error 1
  make: *** [all] Error 2
  ```

  opensslが見つかってない...??
  色々と試してみてうまく行ったものを先に挙げ、失敗例を後ろに残しておきます。

## 自分の環境で成功した改善案(2019/01/12現在)

  * `configure`で`--with-crypto=/usr/local/opt/openssl`とする
  * その後、makeする直前に`perl -p -i -e "s/#if \(WINDOWS\)/#define ASM 0\n#if (WINDOWS)/g" algo/neoscrypt.c`を実行して置換を行う

  これらを行うことで、いくつかwarningは出るにせよ取り急ぎビルドできました。

  ビルドするために行なった過程(git clone済みとする):

  ```bash
  $ ./autogen.sh
  $ ./nomacro.pl
  $ ./configure CFLAGS='-march=native' --with-crypto=/usr/local/opt/openssl --with-curl
  $ perl -p -i -e "s/#if \(WINDOWS\)/#define ASM 0\n#if (WINDOWS)/g" algo/neoscrypt.c
  $ make
  ```

  これでも残ったwarning:

  ```
  algo/neoscrypt.c:55:9: warning: 'ASM' macro redefined [-Wmacro-redefined]
  #define ASM 0
          ^
  algo/neoscrypt.c:51:9: note: previous definition is here
  #define ASM 1
          ^
  ld: warning: directory not found for option '-Lyes/lib'
  ld: warning: directory not found for option '-Lyes/lib'
  ```

  これのうち上記は`perl`の部分で行なった処理のせいなので問題ないと思います。
  下のwarningについては、`yescrypt`アルゴリズムに影響しそう...?
  あまりわからないですが、`yescrypt`ディレクトリがあるのでそこなのかなぁと思いつつ今はスルーしました。

## 失敗例集

### ダメだった改善案1: ASMのコードを抜く

  * 参考: https://qiita.com/asymme/items/7c6aa8d9b59dd560b701

  まぁエラーの内容から確実に違うことはわかるのですが...
  `./configure`の後に以下のスクリプトを実行し、ASMのコードを消してもうまくいきませんでした。

  ```
  $ perl -p -i -e "s/#if \(WINDOWS\)/#define ASM 0\n#if (WINDOWS)/g" algo/neoscrypt.c
  ```

### ダメだった改善案2: configureのオプション調整(1)

  * 参考: http://www.kyulene.com/2017/09/03/post-885_2/

  これは理解してないけどとりあえず試してみました。が、依然同じエラー...

  ```bash
  $ sed -i -e "s/INCLUDES/AM_CPPFLAGS/g" Makefile.am
  $ ./autogen.sh
  $ ./nomacro.pl
  $ ./configure --disable-assembly CFLAGS="-Ofast -march=native" --with-crypto --with-curl
  $ make
  ```

### ダメだった改善案3: with-cryptoにbin指定してみる

  なんかどこかでみたので、`with-crypto`に指定してみる。
  ただしうろ覚えだったので間違ってる

  ```bash
  $ ./configure CFLAGS='-march=native' --with-crypto= /usr/local/opt/openssl/bin/openssl --with-curl
  ```

### ダメだった改善案4: CPPFLAGSを指定する

  あんまり知らないのですが、`./configure -h`をみていて気になったので、`CPPFLAGS`にインクルードパスを追加してみます。

  ```bash
  $ ./configure CPPFLAGS='-I/usr/local/Cellar/openssl/1.0.2p/include/openssl/' CFLAGS='-march=native' --with-crypto --with-curl
  ```

  ちなみに`/usr/local/Cellar/openssl/1.0.2p/include/openssl/`以下はこんな感じです:

  ````bash
  $ ls /usr/local/Cellar/openssl/1.0.2p/include/openssl/
  aes.h         crypto.h      hmac.h        pem.h         ssl.h
  asn1.h        des.h         idea.h        pem2.h        ssl2.h
  asn1_mac.h    des_old.h     krb5_asn.h    pkcs12.h      ssl23.h
  asn1t.h       dh.h          kssl.h        pkcs7.h       ssl3.h
  bio.h         dsa.h         lhash.h       pqueue.h      stack.h
  blowfish.h    dso.h         md4.h         rand.h        symhacks.h
  bn.h          dtls1.h       md5.h         rc2.h         tls1.h
  buffer.h      e_os2.h       mdc2.h        rc4.h         ts.h
  camellia.h    ebcdic.h      modes.h       ripemd.h      txt_db.h
  cast.h        ec.h          obj_mac.h     rsa.h         ui.h
  cmac.h        ecdh.h        objects.h     safestack.h   ui_compat.h
  cms.h         ecdsa.h       ocsp.h        seed.h        whrlpool.h
  comp.h        engine.h      opensslconf.h sha.h         x509.h
  conf.h        err.h         opensslv.h    srp.h         x509_vfy.h
  conf_api.h    evp.h         ossl_typ.h    srtp.h        x509v3.h
  ```
  単純に考えすぎたのだろうか...

### ダメだった改善案5: CFLAGSを指定する

  CPPFLAGSがダメならということでCFLAGSに指定を増やす。
  が、変わらずでした...

  ```bash
  $ ./configure CFLAGS='-march=native -I/usr/local/Cellar/openssl/1.0.2p/include/openssl/' --with-crypto --with-curl
  ```

### ダメだった改善案6: opensslのパスを通す

  至る所で書かれているのですが、標準ではopensslへのパスがhomebrewのものになっていないのでPATHをいじります。
  ただし、愚直に書き換えると何が影響するかわからなかったので一時的に変更させています。

  ```bash
  $ PATH="/usr/local/Cellar/openssl/1.0.2q/bin:$PATH" ./configure CFLAGS='-march=native' --with-crypto --with-curl
  ```

### ダメだった改善案7: with-cryptoを指定する2

  * 参考: https://gist.github.com/quagliero/90f493f123c7b1ddba5428ba0146329a

  `改善案3`で、指定が間違っていたようなのでもう一度やってみる
  binを指定するのではなく、その上のディレクトリを指定するべきだったようです。

  ```bash
  $ ./configure CFLAGS='-march=native' --with-crypto=/usr/local/opt/openssl --with-curl
  ```

  これによって元のエラーは解消されましたが、他のエラーが出るようになりました

  ```
  g++  -g -O2 -L/usr/local/opt/openssl/lib -Lyes/lib  -L/usr/local/opt/openssl/lib -Lyes/lib  -o cpuminer cpuminer-cpu-miner.o cpuminer-util.o cpuminer-api.o cpuminer-sysinfos.o cpuminer-uint256.o sha3/cpuminer-sph_keccak.o sha3/cpuminer-sph_hefty1.o sha3/cpuminer-sph_groestl.o sha3/cpuminer-sph_skein.o sha3/cpuminer-sph_bmw.o sha3/cpuminer-sph_jh.o sha3/cpuminer-sph_shavite.o sha3/cpuminer-sph_blake.o sha3/cpuminer-mod_blakecoin.o sha3/cpuminer-sph_luffa.o sha3/cpuminer-sph_cubehash.o sha3/cpuminer-sph_simd.o sha3/cpuminer-sph_echo.o sha3/cpuminer-sph_hamsi.o sha3/cpuminer-sph_fugue.o sha3/cpuminer-sph_gost.o sha3/cpuminer-sph_sha2.o sha3/cpuminer-sph_sha2big.o sha3/cpuminer-sph_shabal.o sha3/cpuminer-sph_whirlpool.o crypto/cpuminer-blake2s.o crypto/cpuminer-oaes_lib.o crypto/cpuminer-c_keccak.o crypto/cpuminer-c_groestl.o crypto/cpuminer-c_blake256.o crypto/cpuminer-c_jh.o crypto/cpuminer-c_skein.o crypto/cpuminer-hash.o crypto/cpuminer-aesb.o lyra2/cpuminer-Lyra2.o lyra2/cpuminer-Sponge.o yescrypt/cpuminer-yescrypt-common.o yescrypt/cpuminer-yescrypt-best.o yescrypt/cpuminer-sha256_Y.o algo/cpuminer-axiom.o algo/cpuminer-bastion.o algo/cpuminer-blake.o algo/cpuminer-blakecoin.o algo/cpuminer-blake2.o algo/cpuminer-bmw256.o algo/cpuminer-c11.o
  algo/cpuminer-cryptonight.o algo/cpuminer-cryptolight.o algo/cpuminer-decred.o algo/cpuminer-drop.o algo/cpuminer-fresh.o algo/cpuminer-groestl.o algo/cpuminer-heavy.o algo/cpuminer-ink.o algo/cpuminer-luffa.o algo/cpuminer-lyra2re.o algo/cpuminer-lyra2rev2.o algo/cpuminer-myr-groestl.o algo/cpuminer-keccak.o algo/cpuminer-pentablake.o algo/cpuminer-quark.o algo/cpuminer-neoscrypt.o algo/cpuminer-nist5.o algo/cpuminer-pluck.o algo/cpuminer-qubit.o algo/cpuminer-scrypt.o algo/cpuminer-scrypt-jane.o algo/cpuminer-sha2.o algo/cpuminer-sibcoin.o algo/cpuminer-skein.o algo/cpuminer-skein2.o algo/cpuminer-s3.o algo/cpuminer-x11.o
  algo/cpuminer-x13.o algo/cpuminer-x14.o algo/cpuminer-x15.o algo/cpuminer-yescrypt.o algo/cpuminer-zr5.o asm/cpuminer-neoscrypt_asm.o  asm/cpuminer-sha2-x64.o asm/cpuminer-scrypt-x64.o asm/cpuminer-aesb-x64.o   -lcurl -lz -lssl -lcrypto -ljansson -lpthread                                                           
  ld: warning: directory not found for option '-Lyes/lib'
  ld: warning: directory not found for option '-Lyes/lib'
  Undefined symbols for architecture x86_64:
    "_neoscrypt_blkcpy", referenced from:
        _neoscrypt in cpuminer-neoscrypt.o
        _neoscrypt_blkmix in cpuminer-neoscrypt.o
    "_neoscrypt_blkswp", referenced from:
        _neoscrypt_blkmix in cpuminer-neoscrypt.o
    "_neoscrypt_blkxor", referenced from:
        _neoscrypt in cpuminer-neoscrypt.o
        _neoscrypt_blkmix in cpuminer-neoscrypt.o
    "_neoscrypt_chacha", referenced from:
        _neoscrypt_blkmix in cpuminer-neoscrypt.o
    "_neoscrypt_salsa", referenced from:
        _neoscrypt_blkmix in cpuminer-neoscrypt.o
    "_neoscrypt_salsa_tangle", referenced from:
        _neoscrypt in cpuminer-neoscrypt.o
  ld: symbol(s) not found for architecture x86_64
  clang: error: linker command failed with exit code 1 (use -v to see invocation)
  make[2]: *** [cpuminer] Error 1
  make[1]: *** [all-recursive] Error 1
  make: *** [all] Error 2
  ```

# homebrew用のformulaを作る

  ここまででビルド手順はわかったので、今度はformulaに落としていきます。
  ...とはいえここはあまり書くことがない...
  ついでなのでformula書く手順も書いておきます。
  homebrewのformulaはrubyで書かれています。が、自分はformula作成以外にruby経験がないのでおかしなところあったら指摘願います...
  本来はテスト等も書く方が良いのですが、書けないので省略...

  ちなみに英語が読める人はこれを読めば良い話: [formula-cookbook](https://docs.brew.sh/Formula-Cookbook)
  ちょっと古いけどformula例(公式なのかは不明): [example-formula.rb](https://github.com/syhw/homebrew/blob/master/Library/Contributions/example-formula.rb)


## 1. クラスを作る

  ```ruby
  require "formula"

  class MonacoinCpuminerMulti < Formula
  end
  ```

  - クラスは必ず*`Formula`を継承する*必要があります。
  - クラス名はパッケージ名からとる
    - 初めは大文字(これはrubyの規則？)で
    - 単語が区切れるなら次の単語の初めを大文字にして繋げる

  今回の場合:
    - パッケージ名: monacoin-cpuminer-multi
    - 初めを大文字に: Monacoin-cpuminer-multi
    - 残りの単語の初めを大文字にし繋げる: MonacoinCpuminerMulti

## 2. 諸々の説明を追加

  ```ruby
  require "formula"

  class MonacoinCpuminerMulti < Formula
    desc "crypto cpuminer (linux + windows)"
    homepage "https://github.com/monacoinproject/cpuminer-multi"
    version "1.2"
    url "https://github.com/monacoinproject/cpuminer-multi/archive/v#{version}-multi.tar.gz"
    sha256 "da2e9a50cc728c5cdc55e4a4de4d609ff1ca2f636a61b19d08afc124b0829f5f"
  end
   ```

  | プロパティ(?) | 説明 |
  |:-:|:-:|
  | `desc`      | このformulaでインストールできるものの説明。 |
  | `homepage`  | このformulaでインストールできるもののHP     |
  | `version`   | インストールするバージョン                  |
  | `url`       | tarファイルへのURL                          |
  | `sha256`    | tar.gzファイルのsha256ハッシュ              |

  sha256を求めるツールを書いているのでこれを使うと素早く(?)求めることができます

  ```bash
  $ check256 monacoinproject/cpuminer-multi v1.2-multi
  SHA256(v1.2-multi.tar.gz)= da2e9a50cc728c5cdc55e4a4de4d609ff1ca2f636a61b19d08afc124b0829f5f)
  ```

  ツールはこちら: [Cj-bc/check256](https://github.com/Cj-bc/check256)

  ちなみにこのツールもhomebrewでインストールできます:

  ```bash
  $ brew tap Cj-bc/check256
  $ brew install check256
  # or
  $ brew install Cj-bc/check256/check256
  ```

## 3. 依存パッケージを表記

  ```ruby
  require "formula"

  class MonacoinCpuminerMulti < Formula
    desc "crypto cpuminer (linux + windows)"
    homepage "https://github.com/monacoinproject/cpuminer-multi"
    version "1.2"
    url "https://github.com/monacoinproject/cpuminer-multi/archive/v#{version}-multi.tar.gz"
    sha256 "da2e9a50cc728c5cdc55e4a4de4d609ff1ca2f636a61b19d08afc124b0829f5f"

    depends_on "curl" => :build
    depends_on "openssl" => :build
    depends_on "automake" => :build
    depends_on "autoconf" => :build

 ```

  `=> :build`とすることで、ビルド時に必要であると明記しています。

## 4. インストール処理を書く

  ここからが本番
  インストール処理は、`install`内に記述します。

  ```ruby
  require "formula"

  class MonacoinCpuminerMulti < Formula
    desc "crypto cpuminer (linux + windows)"
    homepage "https://github.com/monacoinproject/cpuminer-multi"
    version "1.2"
    url "https://github.com/monacoinproject/cpuminer-multi/archive/v#{version}-multi.tar.gz"
    sha256 "da2e9a50cc728c5cdc55e4a4de4d609ff1ca2f636a61b19d08afc124b0829f5f"

    depends_on "curl" => :build
    depends_on "openssl" => :build
    depends_on "automake" => :build
    depends_on "autoconf" => :build

    def install
      system "./autogen.sh"
      system "./nomacro.pl"
      system "./configure CFLAGS='-march=native' --with-crypto=/usr/local/opt/openssl --with-curl"
      inreplace "algo/neoscrypt.c", "#if \(WINDOWS\)", "#define ASM 0\n#if (WINDOWS)"
      system "make"

      system "mv", "cpuminer", "mona-cpuminer"
      bin.install "mona-cpuminer"
    end
  end
  ```

  シェルコマンドは`system "<command>"`の形で書くことができます。
  標準のRubyだと`system('<command>')`があるらしいですがhomebrew formulaではこの形の方が使われています。
  尚、`perl`で書かれていた文字列置換の処理はRubyで書き直しています(なるべく依存パッケージを減らすため)
  初めsedで書こうとしたけどGNU sedとBSD sedの切り替えがめんどいのでやめた経緯があります。
  `inreplace path, before, after`で path のファイルの before を after で置換しています。

  **これで完成**!!! やったね


# SUMMARY

  * **まだ掘ってないよ** (とりあえず報告だけ先にしに来たので)
  * monacoinのCPUマイナーをhomebrewから入れられるようにしたよ
  * ビルド意外とめんどいので使いたかったら使ってね
  * でも非公式なので責任は持てないよ(主はこれで入れている)
  * 投げ銭歓迎でs(

mona: MBdCkYyfTsCxtm1wZ1XyKWNLFLYj8zMK3V
koto: k1LR5z3PSHnm9mN9KmmHSfF1zc2GhsAZRKn

[2019-01-11 18:31]