- 投稿日:2020-01-01T23:37:01+09:00
RuboCopはじめました
Railチュートリアルをカンニングしながらインスタクローンを作っているのですが、RuboCopを導入してみました
初期設定で色々と戸惑ってしまったので、対処方法を自分用にまとめます
RuboCopとは
Ruby Style Guideに則ってコードを自動修正してくれたり、誤った書き方を指摘してくれるgemです
公式ドキュメント
https://docs.rubocop.org/en/stable/GitHub
https://github.com/rubocop-hq/rubocopインストール方法
直接インストール
$ gem install rubocopGemfileからインストール
Gemfilegem 'rubocop', require: falseドキュメントによると、RuboCopはアップデートによって過去のバージョンと互換性のない変化を起こすことがあるらしいので、不測のアップデートを避けたい方はこちらの方法でとのこと
Gemfilegem 'rubocop', '~> 0.78.0', require: false基本的な使用方法
以下のコマンドを実行するだけ。
$rubocopこのままだとどこが規約違反なのか指摘してくれるだけなので、自動で直して欲しい時は-aを付け加える
$rubocop -aこうするとインデントなどの小さな規約違反を自動で直してくれます
自動で直してくれない部分は自分で直す必要あり
ただデフォルトの設定は少し厳しすぎるので、自分で設定を変更してみます
設定を変える
設定を変える方法はルートディレクトリに.rubocop.ymlというファイルを作り、そこに設定を書き込んでいくだけでオーケーです
以下は自分が最初に行っておくべきと感じた設定です
.rubocop.ymlLineLength: Max: 100 Documentation: Enabled: false AsciiComments: Enabled: false MixinUsage: Enabled: false ClassAndModuleChildren: Enabled: falseRails newした直後にrubocop -aを実行してもかなりの数の規約違反が出てきてびっくりすると思いますが、とりあえずこの設定にしておけばRails newの直後からrubocop先生に怒られることはないと思います
またどんな設定があるのかは、ググるよりもGitHubのソースコードを見た方が早いです
rubocop -aを実行して怒られた箇所をGitHubのソースコードから探してみましょう
最後に
自分用なのでかなり雑に書いています。申し訳ないです。
また、おかしい部分がありましたらご指摘ください
- 投稿日:2020-01-01T13:07:04+09:00
[Ruby on Rails] ERB�.Haml.Slimの書き方別
お疲れ様です!Rails書籍を読んでいると
ERBよりも、HamlやSlimがテンプレートエンジンとして現場で採用されているらしい?です。
今回は、備忘録も兼ねてそれぞれの記述方法を書いていきまーす。
<html> <body> <h1><%= @title %></h1> </body> </html>↑ERB
%html %body %h1= @title↑Haml
html body h1= @title↑Slim
こう見ると、Slimが断然効率よくかけそうですね。
どのパターンでもかけるようにして行きたいです。不備がありましたら、コメントいただけたら幸いです!
ありがとうございました!参考書籍
現場で使える Ruby on Rails 5速習実践ガイド
- 投稿日:2020-01-01T11:14:46+09:00
ruby2.7に更新するとbootsnapで例外が発生する
bootsnapを使っているRailsアプリケーションでRuby2.6から2.7に更新すると以下の様なエラーが発生するようになった。
require 'bootsnap/setup'
している箇所で例外が発生する。$ bundle exec rails s Traceback (most recent call last): 24: from bin/rails:3:in `<main>' 23: from bin/rails:3:in `require_relative' 22: from /Users/murase/work/oacis/config/boot.rb:4:in `<top (required)>' 21: from /Users/murase/work/oacis/config/boot.rb:4:in `require' 20: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/setup.rb:30:in `<top (required)>' 19: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap.rb:30:in `setup' 18: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/compile_cache.rb:9:in `setup' 17: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:48:in `require_relative' 16: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-5.2.3/lib/active_support/dependencies.rb:291:in `require' 15: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-5.2.3/lib/active_support/dependencies.rb:257:in `load_dependency' 14: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-5.2.3/lib/active_support/dependencies.rb:291:in `block in require' 13: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' 12: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' 11: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' 10: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `bloc k in require_with_bootsnap_lfi' 9: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' 8: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/compile_cache/iseq.rb:1:in `<top (required)>' 7: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-5.2.3/lib/active_support/dependencies.rb:291:in `require' 6: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-5.2.3/lib/active_support/dependencies.rb:257:in `load_dependency' 5: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-5.2.3/lib/active_support/dependencies.rb:291:in `block in require' 4: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' 3: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' 2: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' 1: from /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' /Users/murase/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require': no implicit conversion of String into Integer (TypeError)bootsnapの方でもissueとして上がっている。https://github.com/Shopify/bootsnap/issues/258
すでに修正が入っている。
1.4.4以前のバージョンだと発生するが、2020年1月時点の最新版1.4.5に更新することで解決する。
- 投稿日:2020-01-01T10:25:48+09:00
えっ? Ruby で 0 / 0 == 0 + 0 ?
さて問題です。Ruby で以下の結果になるようにするには,どうすればいいでしょう。
puts "えっ? Ruby で #{x} / #{x} == #{x} + #{x} ?" # => えっ? Ruby で 0 / 0 == 0 + 0 ? puts x / x == x + x # => trueただし,
x
はローカル変数です。
外部ライブラリーは使いません。つまり,x
の値は〈組込みクラスもしくは標準添付ライブラリーのクラス〉のインスタンスです。
クラスやモジュールに手は加えません。
メソッドの定義・再定義も行いません。
答えはここをめくってね
require "pathname"; x = Pathname("0")
- 投稿日:2020-01-01T00:23:51+09:00
macにleveldb-nativeをgemでインストールする
GoogleのBigTableの概念を参考に作られたKeyValue型データストアであるLevelDBを、macのruby環境にインストールする方法について説明します。この記事では、leveldb-rubyではなく、leveldb-native(C++実装)について触れています。
いつもながら素人記事ですので、コメントありましたらぜひお寄せください!実行環境
- 実行日: 2019-12-25
- OS version: MacOS Mojave 10.14.6
- Ruby version: 2.6.3
- leveldb version: 0.6
事象
上記実行環境でleveldb-nativeをgemでインストールしようとすると、次のようなコンパイルエラーが出て、インストールできません。
[ 19-12-24 19:34 ] ~/workspace/bitcoinrb osada@mbp17e% gem install leveldb-native Building native extensions. This could take a while... ERROR: Error installing leveldb-native: ERROR: Failed to build gem native extension. current directory: /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/gems/leveldb-native-0.6/ext/leveldb-native /Users/osada/.rvm/rubies/ruby-2.6.3/bin/ruby -I /Users/osada/.rvm/rubies/ruby-2.6.3/lib/ruby/site_ruby/2.6.0 -r ./siteconf20191224-34602-37ap6f.rb extconf.rb checking for -lleveldb... yes creating Makefile current directory: /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/gems/leveldb-native-0.6/ext/leveldb-native make "DESTDIR=" clean current directory: /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/gems/leveldb-native-0.6/ext/leveldb-native make "DESTDIR=" compiling leveldb-native.cc In file included from leveldb-native.cc:4: In file included from /usr/local/include/leveldb/db.h:12: In file included from /usr/local/include/leveldb/iterator.h:19: /usr/local/include/leveldb/slice.h:43:25: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] Slice(const Slice&) = default; ^ /usr/local/include/leveldb/slice.h:44:36: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] Slice& operator=(const Slice&) = default; ^ In file included from leveldb-native.cc:4: In file included from /usr/local/include/leveldb/db.h:12: In file included from /usr/local/include/leveldb/iterator.h:20: /usr/local/include/leveldb/status.h:27:11: error: expected ';' at end of declaration list Status() noexcept : state_(nullptr) {} ^ ; /usr/local/include/leveldb/status.h:33:16: warning: rvalue references are a C++11 extension [-Wc++11-extensions] Status(Status&& rhs) noexcept : state_(rhs.state_) { rhs.state_ = nullptr; } ^ /usr/local/include/leveldb/status.h:33:23: error: expected ';' at end of declaration list Status(Status&& rhs) noexcept : state_(rhs.state_) { rhs.state_ = nullptr; } ^ ; /usr/local/include/leveldb/status.h:103:16: error: 'Status' is missing exception specification 'throw()' inline Status::Status(const Status& rhs) { ^ throw() /usr/local/include/leveldb/status.h:24:22: note: previous declaration is here class LEVELDB_EXPORT Status { ^ /usr/local/include/leveldb/status.h:115:40: warning: rvalue references are a C++11 extension [-Wc++11-extensions] inline Status& Status::operator=(Status&& rhs) noexcept { ^ /usr/local/include/leveldb/status.h:115:48: error: expected function body after function declarator inline Status& Status::operator=(Status&& rhs) noexcept { ^ In file included from leveldb-native.cc:4: In file included from /usr/local/include/leveldb/db.h:12: /usr/local/include/leveldb/iterator.h:28:31: warning: deleted function definitions are a C++11 extension [-Wc++11-extensions] Iterator(const Iterator&) = delete; ^ /usr/local/include/leveldb/iterator.h:29:42: warning: deleted function definitions are a C++11 extension [-Wc++11-extensions] Iterator& operator=(const Iterator&) = delete; ^ /usr/local/include/leveldb/iterator.h:80:27: warning: alias declarations are a C++11 extension [-Wc++11-extensions] using CleanupFunction = void (*)(void* arg1, void* arg2); ^ In file included from leveldb-native.cc:4: In file included from /usr/local/include/leveldb/db.h:13: /usr/local/include/leveldb/options.h:49:26: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] bool create_if_missing = false; ^ /usr/local/include/leveldb/options.h:52:24: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] bool error_if_exists = false; ^ /usr/local/include/leveldb/options.h:59:24: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] bool paranoid_checks = false; ^ /usr/local/include/leveldb/options.h:69:20: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] Logger* info_log = nullptr; ^ /usr/local/include/leveldb/options.h:82:28: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] size_t write_buffer_size = 4 * 1024 * 1024; ^ /usr/local/include/leveldb/options.h:87:22: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] int max_open_files = 1000; ^ /usr/local/include/leveldb/options.h:94:22: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] Cache* block_cache = nullptr; ^ /usr/local/include/leveldb/options.h:100:21: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] size_t block_size = 4 * 1024; ^ /usr/local/include/leveldb/options.h:105:30: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] int block_restart_interval = 16; ^ /usr/local/include/leveldb/options.h:115:24: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] size_t max_file_size = 2 * 1024 * 1024; ^ /usr/local/include/leveldb/options.h:131:31: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] CompressionType compression = kSnappyCompression; ^ /usr/local/include/leveldb/options.h:137:19: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] bool reuse_logs = false; ^ /usr/local/include/leveldb/options.h:142:37: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] const FilterPolicy* filter_policy = nullptr; ^ /usr/local/include/leveldb/options.h:147:19: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] ReadOptions() = default; ^ /usr/local/include/leveldb/options.h:151:25: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] bool verify_checksums = false; ^ /usr/local/include/leveldb/options.h:155:19: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] bool fill_cache = true; ^ /usr/local/include/leveldb/options.h:161:28: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] const Snapshot* snapshot = nullptr; ^ /usr/local/include/leveldb/options.h:166:20: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] WriteOptions() = default; ^ /usr/local/include/leveldb/options.h:182:13: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions] bool sync = false; ^ In file included from leveldb-native.cc:4: /usr/local/include/leveldb/db.h:56:10: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] DB() = default; ^ /usr/local/include/leveldb/db.h:58:19: warning: deleted function definitions are a C++11 extension [-Wc++11-extensions] DB(const DB&) = delete; ^ /usr/local/include/leveldb/db.h:59:30: warning: deleted function definitions are a C++11 extension [-Wc++11-extensions] DB& operator=(const DB&) = delete; ^ In file included from leveldb-native.cc:5: /usr/local/include/leveldb/cache.h:36:13: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] Cache() = default; ^ /usr/local/include/leveldb/cache.h:38:25: warning: deleted function definitions are a C++11 extension [-Wc++11-extensions] Cache(const Cache&) = delete; ^ /usr/local/include/leveldb/cache.h:39:36: warning: deleted function definitions are a C++11 extension [-Wc++11-extensions] Cache& operator=(const Cache&) = delete; ^ In file included from leveldb-native.cc:6: /usr/local/include/leveldb/write_batch.h:45:35: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] WriteBatch(const WriteBatch&) = default; ^ /usr/local/include/leveldb/write_batch.h:46:46: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] WriteBatch& operator=(const WriteBatch&) = default; ^ 34 warnings and 4 errors generated. make: *** [leveldb-native.o] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/gems/leveldb-native-0.6 for inspection. Results logged to /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/extensions/x86_64-darwin-18/2.6.0/leveldb-native-0.6/gem_make.out当然、irbからleveldb-nativeを使おうとするとエラーになります。
[ 19-12-24 19:43 ] ~/workspace/bitcoinrb osada@mbp17e% irb 2.6.3 :001 > require 'leveldb-native' Traceback (most recent call last): 8: from /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/bin/ruby_executable_hooks:24:in `<main>' 7: from /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/bin/ruby_executable_hooks:24:in `eval' 6: from /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/bin/irb:23:in `<main>' 5: from /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/bin/irb:23:in `load' 4: from /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/gems/irb-1.2.1/exe/irb:11:in `<top (required)>' 3: from (irb):2 2: from /Users/osada/.rvm/rubies/ruby-2.6.3/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require' 1: from /Users/osada/.rvm/rubies/ruby-2.6.3/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require' LoadError (cannot load such file -- leveldb-native)解決策
事象の34個のwarningを見ると、「C++11 extension」で定義された関数が正しく使えていないようなことが見れます。また、4個のerrorを見ると、文法間違い扱いとなっているようで、コンパイルが通らない様になっているようです。
どうやら、私の実行環境はC++標準が古いようで、インストールするためには、コンパイル時のオプションでC++11以降を指定する必要があるようです。そこで、次のようにしてインストールするgemファイルを編集してからインストールすることにします。手順1. ダウンロード
gem fetchで、インストールするgemファイルをダウンロードします。
[ 19-12-25 9:41 ] ~/workspace/bitcoinrb osada@mbp17e% gem fetch leveldb-native Fetching leveldb-native-0.6.gem Downloaded leveldb-native-0.6 [ 19-12-25 9:41 ] ~/workspace/bitcoinrb osada@mbp17e% ls leveldb-native-0.6.gem手順2. 展開
gem unpackで、gemファイルを展開します。
[ 19-12-25 9:41 ] ~/workspace/bitcoinrb osada@mbp17e% gem unpack leveldb-native-0.6.gem Unpacked gem: '/Users/osada/workspace/bitcoinrb/leveldb-native-0.6' [ 19-12-25 9:42 ] ~/workspace/bitcoinrb osada@mbp17e% ls leveldb-native-0.6/ leveldb-native-0.6.gem手順3. extconf.rbの編集
leveldb-native-0.6/ext/leveldb-native/extconf.rbに、コンパイル時に指定するオプションに情報を追記します。
leveldb-native-0.6/ext/leveldb-native/extconf.rbrequire 'mkmf' have_library "leveldb" or abort "Can't find leveldb library." $CXXFLAGS += " -std=c++11 " # <= ココ!!! create_makefile "leveldb-native/leveldb_native"$CXXFLAGSに、-std=c++11を追加するわけです。-stdの前の半角スペースと、11の後ろの半角スペースを忘れずに。
ちなみに、このmkmfというパッケージはMakefileを生成するrubyのモジュールのようです。手順4. gemspecの作成
gem fetch / gem unpackしたファイルには、gemspecがありません。次のように手動で作成します。
[ 19-12-25 14:19 ] ~/workspace/bitcoinrb osada@mbp17e% gem spec --ruby leveldb-native-0.6.gem > leveldb-native-0.6.gemspec [ 19-12-25 14:19 ] ~/workspace/bitcoinrb osada@mbp17e% ls leveldb-native-0.6/ leveldb-native-0.6.gem leveldb-native-0.6.gemspec手順5. buildの実行
手順4.で作成したgemspecファイルを適切な場所に配置して、編集した手順3.を含んだleveldb-nativeをgem buildします。
[ 19-12-25 14:19 ] ~/workspace/bitcoinrb osada@mbp17e% mv leveldb-native-0.6.gemspec leveldb-native-0.6 [ 19-12-25 14:19 ] ~/workspace/bitcoinrb osada@mbp17e% cd leveldb-native-0.6 [ 19-12-25 14:20 ] ~/workspace/bitcoinrb/leveldb-native-0.6 osada@mbp17e% gem build leveldb-native-0.6.gemspec WARNING: open-ended dependency on rake (>= 0.9, development) is not recommended if rake is semantically versioned, use: add_development_dependency 'rake', '~> 0.9' WARNING: See http://guides.rubygems.org/specification-reference/ for help Successfully built RubyGem Name: leveldb-native Version: 0.6 File: leveldb-native-0.6.gem [ 19-12-25 14:20 ] ~/workspace/bitcoinrb/leveldb-native-0.6 osada@mbp17e% ls LICENSE example/ leveldb-native-0.6.gemspec README.md ext/ lib/ Rakefile leveldb-native-0.6.gem test/まあ、なにかwarningが出ますが、無事新しいleveldb-native-0.6.gemが生成されました。
手順6. インストール
新しいgemファイルをinstallします。このとき、"./"を忘れずに。
[ 19-12-25 14:20 ] ~/workspace/bitcoinrb osada@mbp17e% gem install ./leveldb-native-0.6.gem Building native extensions. This could take a while... Successfully installed leveldb-native-0.6 Parsing documentation for leveldb-native-0.6 Installing ri documentation for leveldb-native-0.6 Done installing documentation for leveldb-native after 0 seconds 1 gem installed手順7. 使ってみる
[ 19-12-25 14:20 ] ~/workspace/bitcoinrb osada@mbp17e% irb 2.6.3 :001 > require 'leveldb-native' => true 2.6.3 :002 >できた!
原因調査
環境調査
C++のバージョンやgemの環境変数を確認します。
[ 19-12-24 19:47 ] ~/workspace/bitcoinrb osada@mbp17e% which c++ /usr/bin/c++ [ 19-12-24 19:59 ] ~/workspace/bitcoinrb osada@mbp17e% gem environment RubyGems Environment: - RUBYGEMS VERSION: 3.0.6 - RUBY VERSION: 2.6.3 (2019-04-16 patchlevel 62) [x86_64-darwin18] - INSTALLATION DIRECTORY: /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb - USER INSTALLATION DIRECTORY: /Users/osada/.gem/ruby/2.6.0 - RUBY EXECUTABLE: /Users/osada/.rvm/rubies/ruby-2.6.3/bin/ruby - GIT EXECUTABLE: /usr/bin/git - EXECUTABLE DIRECTORY: /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/bin - SPEC CACHE DIRECTORY: /Users/osada/.gem/specs - SYSTEM CONFIGURATION DIRECTORY: /Users/osada/.rvm/rubies/ruby-2.6.3/etc - RUBYGEMS PLATFORMS: - ruby - x86_64-darwin-18 - GEM PATHS: - /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb - /Users/osada/.rvm/rubies/ruby-2.6.3/lib/ruby/gems/2.6.0 - GEM CONFIGURATION: - :update_sources => true - :verbose => true - :backtrace => false - :bulk_threshold => 1000 - REMOTE SOURCES: - https://rubygems.org/ - SHELL PATH: - /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/bin - /Users/osada/.rvm/gems/ruby-2.6.3@global/bin - /Users/osada/.rvm/rubies/ruby-2.6.3/bin - /Users/osada/.rvm/bin - /usr/local/opt/jpeg-turbo/bin - /Users/osada/.pyenv/shims - /Users/osada/.pyenv/bin - /usr/local/bin - /usr/bin - /bin - /usr/sbin - /sbin - /Applications/VMware Fusion.app/Contents/Public - /Library/TeX/texbin - /usr/local/share/dotnet - /Applications/Wireshark.app/Contents/MacOS - /sbin - /usr/local/bin - /Users/osada/binMakefile/Rakefile/extconf周辺
leveldb-naitiveは、nativeという言葉が意味する通り、C++でコンパイルしたバイナリで動作します。というわけで、Makefileを使う"make"でインストールすることになります。一方で、gemはrubyのパッケージマネージャであって、ここではRakefileを使う"rake"でインストールことになります。
Makefileの中に色々なコンパイルオプションが書かれていますが、ここではCXXFLAGSに注目して書いてみて、makeするとうまくコンパイルが通るようになります。
[ 19-12-25 13:12 ] ~/workspace/bitcoinrb/leveldb-native-0.6/ext/leveldb-native osada@mbp17e% make compiling leveldb-native.cc In file included from leveldb-native.cc:1: In file included from /Users/osada/.rvm/rubies/ruby-2.6.3/include/ruby-2.6.0/ruby.h:33: In file included from /Users/osada/.rvm/rubies/ruby-2.6.3/include/ruby-2.6.0/ruby/ruby.h:2111: /Users/osada/.rvm/rubies/ruby-2.6.3/include/ruby-2.6.0/ruby/intern.h:56:19: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register] void rb_mem_clear(register VALUE*, register long); ^~~~~~~~~ /Users/osada/.rvm/rubies/ruby-2.6.3/include/ruby-2.6.0/ruby/intern.h:56:36: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register] void rb_mem_clear(register VALUE*, register long); ^~~~~~~~~ leveldb-native.cc:205:3: warning: 'auto_ptr<bound_db>' is deprecated [-Wdeprecated-declarations] auto_ptr<bound_db> db(new bound_db); ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:2080:28: note: 'auto_ptr<bound_db>' has been explicitly marked deprecated here class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 auto_ptr ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__config:1101:39: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11' # define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__config:1090:48: note: expanded from macro '_LIBCPP_DEPRECATED' # define _LIBCPP_DEPRECATED __attribute__ ((deprecated)) ^ 3 warnings generated. linking shared-object leveldb-native/leveldb_native.bundleただし、このままだとgemとして使うことができません。そこで、このMakefileを生成するrakeコマンドを見ていくわけです。rakeは、引数を指定して実行する必要があります。ここではextを選びます。
[ 19-12-25 13:11 ] ~/workspace/bitcoinrb/leveldb-native-0.6 osada@mbp17e% rake --task rake clean # Clean compiled files rake dist_clean # Clean compiled files and Makefile rake ext # Build extension rake release # Test, commit, tag, and push repo; build and push gem rake release:diff # Diff to latest release rake release:log # Log to latest release rake test # Run tests for {:test=>:ext} [ 19-12-25 13:11 ] ~/workspace/bitcoinrb/leveldb-native-0.6 osada@mbp17e% rake ext cd ext/leveldb-native && ruby extconf.rb checking for -lleveldb... yes creating Makefile ## <= ココ!!! cd ext/leveldb-native && make compiling leveldb-native.cc In file included from leveldb-native.cc:4: In file included from /usr/local/include/leveldb/db.h:12: In file included from /usr/local/include/leveldb/iterator.h:19: /usr/local/include/leveldb/slice.h:43:25: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] Slice(const Slice&) = default; ^ (略) /usr/local/include/leveldb/write_batch.h:46:46: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions] WriteBatch& operator=(const WriteBatch&) = default; ^ 34 warnings and 4 errors generated. make: *** [leveldb-native.o] Error 1 rake aborted! Command failed with status (2): [cd ext/leveldb-native && make...] /Users/osada/workspace/bitcoinrb/leveldb-native-0.6/Rakefile:28:in `block in <top (required)>' /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/gems/rake-13.0.1/exe/rake:27:in `<top (required)>' /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/bin/ruby_executable_hooks:24:in `eval' /Users/osada/.rvm/gems/ruby-2.6.3@bitcoinrb/bin/ruby_executable_hooks:24:in `<main>' Tasks: TOP => ext => ext/leveldb-native/leveldb_native.so (See full trace by running task with --trace)Makefileを作っていることがわかりますね。rakeが指定するRakefileを見てみましょう。
Rakefiledesc "Build extension" task :ext => File.join(ext_dir, so_name) file File.join(ext_dir, so_name) => FileList[ File.join(ext_dir, "*.{c,cc,h}"), File.join(ext_dir, "Makefile")] do sh "cd #{ext_dir} && make" end file File.join(ext_dir, "Makefile") => File.join(ext_dir, "extconf.rb") do sh "cd #{ext_dir} && ruby extconf.rb" end上記はextタスク部分を取り出したものです。Makefile作成にには、ext_dirにある"extconf.rb"をrubyで実行していることがわかります。
これを見に行くと、手順3に繋がります。
いや〜、C++の標準の違いは利用者も意識する必要があるので、骨が折れますね。c++11なのかc++14なのか、はたまたc++17なのか。コンパイルオプション"-std=xxx"で指定する部分は環境変数でなんとかならないものなんでしょうかね。
参考サイト
- LevelDBとは
- Unsupported leveldb 1.21 on MacOS
- How to add a C++ compiler flag to extconf.rb
- インストールできない gem を修正してインストールする