2019年4月から「Rust By Example(実例で学ぶRust)」というサイトを利用して、新たなプログラミング言語としてRustを学んでいる。
現在写経中の15章はRustのメモリ管理をテーマにしており、いよいよRustの大事な部分に入りつつあるが、初っ端から未解決問題につまづいてしまったのでメモしておく。
- [Rust By ExampleでValgrindを使う]
- [HomebrewでValgrindをインストール(失敗)]
- [パッチ適用済ブランチを利用(失敗)]
- [symbol(s) not found]
- [まとめ]
[Rust By ExampleでValgrindを使う]
1ヶ月以上に渡り、ほぼ毎日ちまちまとRust By Exampleの写経を続けている。
おかげで何となくRustの特徴的な文法にも多少は慣れてきた。リターンするときはセミコロン不要というのは最初は戸惑ったが、for文を書く際にカッコがいらないあたりはGo言語にも似ていて、見知った言語のようにも思える。
今週取り組み始めた15章の最初のテーマは、RAII(Resource Acquisition Is Initialization)だった。
いつも通り、章タイトルをファイル名にして写経をしていく。
すると、以下のような指示が出ていた。
Of course, we can double check for memory errors using
valgrind
Valgrindというツールを使い、メモリーに関するエラーをチェックする必要があるようだ。Wikipediaの記載によれば、Valgrindを利用すると、メモリデバッグ、メモリリークの検出、スレッドエラーの検出、プロファイリングなどを行うことができるらしい。
[HomebrewでValgrindをインストール(失敗)]
早速Rust By Example15章をやっつけてRustの真髄に触れるべく、Valgrindをインストールすることにした。
利用しているOSはmacOS Mojave(バージョン 10.14.4)である。
まずはhomebrewでのインストールを試してみる。と、以下のようなエラーが出てうまくいかない。
brew install valgrind Updating Homebrew... ==> Auto-updated Homebrew! Updated 1 tap (homebrew/core). ==> New Formulae (中略) ==> Updated Formulae (中略) ==> Deleted Formulae (中略) valgrind: This formula either does not compile or function as expected on macOS versions newer than High Sierra due to an upstream incompatibility. Error: An unsatisfied requirement failed this build.
慌てて公式サイトをよく読むと、次のようにmacOS Mojave(バージョン 10.14.4)は未対応である旨が書かれていた。
It runs on the following platforms: X86/Linux, AMD64/Linux,(中略), X86/Darwin and AMD64/Darwin (Mac OS X 10.12).
[パッチ適用済ブランチを利用(失敗)]
何とかならないかと思い、「mojave valgrind」でググると、次のページにたどり着くことができた。rather painfulと書かれており、手順はやや面倒そうだが、一応MojaveにもValgrindをインストールできそうに見える。
回答の指示に従って手を動かしていく。まずはフォークされたリポジトリをクローンする。
git clone https://github.com/Echelon9/valgrind.git Cloning into 'valgrind'... remote: Enumerating objects: 495, done. remote: Counting objects: 100% (495/495), done. remote: Compressing objects: 100% (280/280), done. remote: Total 124654 (delta 268), reused 329 (delta 213), pack-reused 124159 Receiving objects: 100% (124654/124654), 44.01 MiB | 3.44 MiB/s, done. Resolving deltas: 100% (94992/94992), done. Checking out files: 100% (5962/5962), done.
次に、パッチが適用されているブランチをチェックアウトする。
$ cd valgrind $ git checkout feature/v3.14/macos-mojave-support-v2 Branch 'feature/v3.14/macos-mojave-support-v2' set up to track remote branch 'feature/v3.14/macos-mojave-support-v2' from 'origin'. Switched to a new branch 'feature/v3.14/macos-mojave-support-v2'
./autogen.sh
を実行する。
$ ./autogen.sh running: aclocal running: autoheader running: automake -a configure.ac:30: installing './compile' configure.ac:201: installing './config.guess' configure.ac:201: installing './config.sub' configure.ac:14: installing './install-sh' configure.ac:14: installing './missing' Makefile.vex.am: installing './depcomp' running: autoconf
configure
コマンドを実行する。
$ ./configure --prefix=/where/you/want/it/installed --enable-only64bit checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... ./install-sh -c -d checking for gawk... no checking for mawk... no checking for nawk... no (中略) config.status: creating coregrind/link_tool_exe_darwin config.status: creating coregrind/link_tool_exe_solaris config.status: creating config.h config.status: executing depfiles commands Maximum build arch: amd64 Primary build arch: amd64 Secondary build arch: Build OS: darwin Link Time Optimisation: no Primary build target: AMD64_DARWIN Secondary build target: Platform variant: vanilla Primary -DVGPV string: -DVGPV_amd64_darwin_vanilla=1 Default supp files: exp-sgcheck.supp xfree-3.supp xfree-4.supp darwin10-drd.supp darwin18.supp
そしてmakeコマンドを実行したら終わり、のはずだが……エラーが出る。
$ make echo "# This is a generated file, composed of the following suppression rules:" > default.supp (中略) /usr/bin/ar cru libvexmultiarch-amd64-darwin.a priv/libvexmultiarch_amd64_darwin_a-multiarch_main_main.o ranlib libvexmultiarch-amd64-darwin.a Making all in coregrind make[2]: *** No rule to make target `/usr/include/mach/mach_vm.defs', needed by `m_mach/mach_vmUser.c'. Stop. make[1]: *** [all-recursive] Error 1 make: *** [all] Error 2
このエラーについてはStackOverflowの回答にも予想されているので、さらに指示に従って修正を加えていく。
まずはxcode-select --install
を実行してxcode-selectをインストールする。
xcode-select --install
をコマンドを実行すると次のようなダイアログが開く。
Xcode本体はインストールされているので、青の「インストール」ボタンをクリックすると、以下のように使用許諾契約のダイアログが表示される。
大人しく読んで「同意する」をクリックすると、インストールが開始される。
日頃の行いが悪いのか、ネットワークの調子が悪いのか、「残り9秒」->「残り10秒」->「残り11秒」と何故かカウントアップが始まってしまったが、数分待つと無事インストールが完了した。
xcode-selectのインストール完了後は、coregrind/Makefile
ファイルのam__append_19
の箇所を以下のように修正する。
am__append_19 = \ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/mach/mach_vm.defs \ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/mach/task.defs \ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/mach/thread_act.defs \ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/mach/vm_map.defs
ここでもう一度makeコマンドを実行するとvg_preloaded.c:136:19: error: expected ';' before 'const'
というエラーが出るはずなのだが、以下のようなエラーが表示されてしまった。
$ make ./auxprogs/make_or_upd_vgversion_h . /Applications/Xcode.app/Contents/Developer/usr/bin/make all-recursive Making all in include (中略) link_tool_exe_darwin: /usr/bin/ld -static -arch x86_64 -macosx_version_min 10.6 -o memcheck-amd64-darwin -u __start -e __start -image_base 0x158000000 -stack_addr 0x154000000 -stack_size 0x800000 memcheck_amd64_darwin-mc_leakcheck.o memcheck_amd64_darwin-mc_malloc_wrappers.o memcheck_amd64_darwin-mc_main.o memcheck_amd64_darwin-mc_main_asm.o memcheck_amd64_darwin-mc_translate.o memcheck_amd64_darwin-mc_machine.o memcheck_amd64_darwin-mc_errors.o ../coregrind/libcoregrind-amd64-darwin.a ../VEX/libvex-amd64-darwin.a Undefined symbols for architecture x86_64: "_mach_msg_destroy", referenced from: __kernelrpc_mach_vm_allocate in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o) __kernelrpc_mach_vm_deallocate in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o) __kernelrpc_mach_vm_protect in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o) _mach_vm_inherit in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o) __kernelrpc_mach_vm_read in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o) _mach_vm_read_list in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o) _mach_vm_write in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o) ... ld: symbol(s) not found for architecture x86_64 make[3]: *** [memcheck-amd64-darwin] Error 1 make[2]: *** [all-recursive] Error 1 make[1]: *** [all-recursive] Error 1 make: *** [all] Error 2
StackOverflowの回答欄をよく読むと、同じように「"_mach_msg_destroy"」関連のエラーメッセージが表示され、結局インストールできないという反応が寄せられている。
どうやら2019年5月現在では、macOS MojaveにValgrindを簡単にインストールする方法は無いようだ。
[symbol(s) not found]
ld: symbol(s) not found for architecture x86_64
それにしても、どこかで見覚えのあるエラーメッセージである。
以前、React Nativeアプリ開発の際に、Realmというデータベースを利用していたのだが、バージョンアップ時に何かを間違えたのか、起動しなくなってしまった。
このRealmのエラーについて困っているとTwitterに書いたところ、StackOverflowで聞いてみろとアドバイスを頂いたので質問をしてみたものの、未だに返答がない。
前回のRealmの場合も今回のValgrindの場合も、C言語で実装されている部分で別のモジュールをインクルードしようとして失敗しているらしい、ということはエラーメッセージから何となく読み取ることができる。
何となく読み取ることはできるのだが、それをどう直せばいいのか、検討がつかない。見つからないと言われているシンボルでディレクトリ内を探してみても、それらしい内容のファイルが見当たらないのだ。きっと、バイナリで提供されているなどして、テキスト検索では検索できないようになっているのだろう、と推測している。
C言語については、去年軽くチュートリアルを触った程度でしかなく、初心者同然のレベルである。もう少し実戦経験を積んで、問題解決能力を身に付けていかねばと考えている(いつになることやら……)。
[まとめ]
- Rust By Exampleでは実コードを元にRustを学べる
- Valgrindを使うとメモリリークなどを検出することができる
- ただし、2019年5月時点のValgrind(3.15.0)はmacOS Mojave(バージョン 10.14.4)に対応していない
- C言語関連(と思われる)エラーの対応は難しい