ROOTでバグ?

ROOTをつかっていろいろやっているのだけれど、よくわからない現象がおきたのでメモ。

最近になってc++11や14に少しづつ馴染んできている。他人が残していったコードを整理しながらすすめているとこれまで知らなかった利点なども見えてくるわけで、自分なりに工夫しながらつかってみようかしら、と試してきた。

今回の問題は std::shared_ptr 。shared pointer 自体に問題があるわけでもなく、適当なメソッドで std::shared_ptr< TGraph > オブジェクトを返すようにしておいて処理をすすめておけば、delete の問題を自然に回避できて良いですね、ということで使う訳。

今回のケースは、返り値として得たstd::shared_ptr<TGraph>をつかって作図したいという話。作図するのだけど、ROOTの良いところというか面倒な所は、作図はCanvas上のイメージを更新するだけではないというところ。Canvas 上には作図対象のオブジェクトが連結されていて、そのオブジェクトに変更が加えられると自動的に図も更新される。あるデーターを持つグラフオブジェクトがあって、その内容をキャンバス上にグラフ化しましょう、と例えば TGraph::Draw() メソッドを呼ぶ場合、内部的にはTGraphオブジェクトを連結、そのオブジェクトを利用して更新がおこなわれる。オブジェクトに変更を加えると、Canvasに再描写命令を与えなくても勝手に図は更新。

便利なんだけど、寿命をもつオブジェクトを作図するといろいろ問題が。ヒープ領域に new で確保するのじゃなくて、適当なスコープ内でオブジェクトを普通に生成しDrawしても、スコープ終了とともに作図結果もろとも消滅。Canvasは白紙に!回避する手段は、

  • 永続的なオブジェクトとして new する
  • TObject::DrawClone() メソッドを利用して、自身のクローンをCanvasに与えてしまう

後の方法は 元々のオブジェクトに変更を加えてもCanvas内容は更新されなくなり、ROOTのメリットを捨てているようにも感じられます。

さて、今回は std::shared_ptr 。使われなくなると自動的に delete されるもの。TCanvas の方ではそれが shared_ptr なのか知らないわけで、単にDrawをしてもその結果はオブジェクトの寿命とともに海の藻屑と。じゃあ DrawClone でよいかしら、というわけなんだけど・・・・・

普通はこれで上手く行くのだけど、今回はなんだかおかしなことに。Canvasを分割して、複数のプロットを並べて描写していました。分割した領域をPad と呼ぶのですが、PadにはIDがあるので、順に一つづつすすめながら、別の std::shared_ptr< TGraph > をつかって DrawClone。

ところが、結果を見てみると2番目以降のPadでおこなったDrawClone処理は、該当Padに描写するのではなくて、なぜか一つまえのPadに結果を描写しているではないですか。????

なんとなく、DrawCloneした時に、一個前のPadに紐付けされていたObjectと入れ替わってしまう様子。なんじゃこりゃ?ROOTにはクローンを作る TObject::Clone というメソッドがあるので、自分でクローンをつくっておいて、それからDrawしてみるとこれはOK。

TObject::DrawClone のリファレンスマニュアル  ROOT: core/base/src/TObject.cxx Source File を見てみても、結局やっているのは Cloneしてから Draw なわけで、うーんなんだかほんとうによくわからない。

std::shared_ptr< TGraph > をつくっているのは std::make_shared< TGraph > を活用しているので、なにか関係するかもとぐぐってみると

cflat-inc.hatenablog.com

なんていうものもあったり。独自の new、 delete が無視されるというのはもしかしたら問題かしら?なんか昔その関係でいろいろ困った事があったような・・・と思い、 make_shared なしで試してみても問題は解消されない。きっと、 TCanvas 側の方の理由だろうなぁと思うのと、なんとなくいやなんだけど解決策が見つかったのでこれはこれで良しとする。

 

Nintendo Switch (+マリオカート8DX) をゲットしたので、所感等

紆余曲折あって、マリオカート8DX同袍版 Switch の購入に踏み切った。店舗にもオンラインストアにも在庫がない中、2ch(笑)の「楽天ブックスにあるよ」の書き込みから、ラッキーにも入手に成功。正直あまり遊んでいる訳でもないけど、とりあえず感じた事をつらつらと。

ちなみに、据え置き型(Switchは据え置き型なのか?という疑問もあるが、今のところTVモードで遊んでいるのでそういう事ですすめる)の家庭用コンソールの購入はセガサターン以来という状況。時々、出先等で他の機種を触った事はある程度。

マリオカートも名前は知っているけど、触った事なし。そういう状況でSwitchでプレイしてみると

  • 絵は綺麗。47インチのVIERAに出力しているけど、まったく不満なし。アナ雪のBDとDVDを入手した時に、BDの綺麗さに驚いたのだけど、ゲームもFull HDですごいですねぇ、といういつの時代?という感想で、自分が情けない。が、綺麗。
  • DEGA - シアターバー - VIERA の接続で、シアターバーを導入しているのだけど、VIERA の 別のHDMI入力にSwitch を繋いでみた所、ちゃんとシアターバーから音が出る。テレビのスピーカーと比べれば、音もしっかり出ていて楽しい。さすがに、うわぁFM音源でプレイすると迫力違うねぇというそれこそ30年前の感想にはならないのですが、音も満足。マリカじゃなくて、ゼルダやりたいなぁ、とおもったり。
  • マリカ: ハンドルアシストというのがデフォルトでON。これを知らずに遊んでいたのですが、「最近のレースゲームはなんだかいきなり簡単に曲がれて、楽しいような楽しくないような」という間違った感想を持ってしまった。OFFにする方法が分かったのでOFFにしてみると、コースを曲がる難しさというか楽しさが復活!やっぱりレースゲームはこうでなくっちゃ、とおもう反面。いつもレースではビリケツに。家族とのバトルでも負け続け。でもね、上手くなったらすごいんだぞ、きっと。

さて、本体についての感想ももうすこし残しておこう。

  • マリカを4人で遊ぶために、Joy-Conをもう一セット購入してみた。購入してから気付いたのだけど、これどうやって充電するの?ということで、充電用パッドも購入。うーん、ここらへんの「商売」的な感じはなんかちょっといやかも。全部まとめて、高額になるのもいやだけど、後から必要なものに気づいて購入するのは、購入意欲が減退する。2セットまとめて充電できる充電台が出ているようなので、そちらの方がよかったかなぁ、とおもったり思わなかったり。TVモードで、左右のJoy-Conをくっつけて遊ぶためのパッドもないので、結局充電用パッドの購入が正解だとはおもうのだけど。
  • まだ追加のマイクロSDカードは入れていない。ダウンロード購入も今のところする予定はないし、たとえばマリカのようなゲームの必要容量を考えると、128GBぐらいないと、複数ゲームを入れて切り替えながら遊ぶってのはあまり現実的ではないような気がする。携帯モードよりもむしろTVモードの問題だと思うのだけど、ゲームを切り替えようとすると、一度ドックから外して、ゲームメディアの交換が必要なのはちょっと問題では?それにあの小さなメディアは、抜き差しには適していないような気も。できれば、TVモード用のドック、もしくはそのUSB端子を利用して、複数のメディアに対応したメディアリーダーが欲しい所。購入したゲームは、3個位は刺したままで切り替えて遊びたいような気がする。Switchのスタイルならば。携帯モードの時は1スロットで交換してもいいとおもうのだけどねぇ。ドックに1口、本体に1口でもかなり快適になるような気がするなぁ。

 

まだ日が浅いのだけど、Switchについては

  1. Joy-Conの充電問題(追加購入した時は特に)※充電スタンドが出ているのは良い
  2. ゲームメディアを複数入れたい、TVモードのドックには用意できたんじゃ?
  3. マイクロSDカードスロットも、本体とドックの両方にあっても良い気がする。
  4. ほとんどタブレットなんだから、ブラウザ(YouTube再生)もあっても良かったんじゃ?

ということをのぞけば、なかなか楽しいコンソールだなぁという印象。

2度あることは3度あるかもしれないので

LibreOffice でつくったImpressファイル(プレゼンファイル)を編集しようと開いてみると、なぜか数式のフォントがおかしくなってしまっている。数式は基本 Times New Roman なのだけど、SanSerif系の文字になっている。数式入力モードでフォントの選択をすればとりあえずは修復できるのだけど、すべての数式について同じ事をするのは考えたくない作業。さらにギリシャ文字は、いくら設定してもまったく駄目。SanSerif系の文字から変化なし。

いろいろ調べて、設定ファイルの中身をいじってみたりしたのだけど、どうしようもない。

よくよく思い起こしてみると、同じような症状はかつても経験した事があって、その時の処方箋は「アンインストール&インストール」。

結局今回も、一度LibreOfficeをアンインストールし、再インストール。そしたら、ちゃんと数式が表示されるようになりました。設定がどこかの段階で壊れてしまったのだろうか?クリーンインストールで治るのはいいのだけど、いやな感じ。

Qt のビルド

Qtをビルドしないといけなくなった。その前に他の理由から OpenSSL 1.1.0 をインストールしていた。

Qt は OpenSSL 1.0.1 までしか正式対応しておらず、ここで一つの壁にぶち当たる。特になにも指定せず、configure & make をすると、OpenSSL に関する所でコンパイルエラー。OpenSSL のバージョンアップに伴う変更で、後方互換がとれていないのが原因。しかたがないので、1.0.1 を 個別にインストールして使う事にするのだけど、どうやって指定すればよいのかよくわからない。

Secure Sockets Layer (SSL) Classes | Qt Network 5.8 に指定の仕方が書いてある。試しに、

$ OPENSSL_DIR=[OpenSSLインストール先] OPENSSL_LIB="-L[インストール先]/lib -lssl -lcrypto" ./configure --ssl-runtime 

で試してみる。が、コンパイルでエラー。

 qtbase/src/netowork でこけるので、 qtbase/src/network/Makefile 中の INCDIR に -I${openssl インストーディレクトリ}/include を指定すれば、一応OK。このMakefileは qmake で生成されるようなので、 qmake をもうすこし調べれば良いと思うのだけど・・・

 上記編集さえしてしまえば、一応ビルドは問題なく進んでいるようす。

Qt 5.8.0 with gcc 6.3.0 での問題

具体的にはQt5でもgccでもなくて、多分OSの事情による問題が起きたと思われる。きっと今時のKernelなら問題なくコンパイルも通ったはず。

問題1

qtserialbus/src/plugins/canbus/socketcan/socketcanbackend.cpp

コンパイルに失敗。sa_family_t に関しては linux/netlink.h を include する事で回避。でも AF_CAN、PC_CANが未定義と怒られる。linux/socket.h で定義されているので、正しくインクルードすれば良いようなきがするのだが、上手くいかない。なので、直接該当ファイル中で定義。これでよいのか?

問題2

qtgamepad/src/plugins/gamepads/evdev/qevdevgamepadbackend.cpp

コンパイルに失敗。BTN_TRIGGER_HAPPY{1,2,3,4} が未定義との事。普通は linux/input.h やら linux/input-event-codes.h やらで定義されている様子。件のシステムにはちょっと古めのKernelがインストールされていて、該当の定義がない。そもそもゲームパッドを使うような事はないので、こちらもソースに直接定義を追加して回避。

Qt 4.8.6 with gcc 6.3.0 での問題

Qt 5.8.0 では問題ないようなので、4系のみの問題?c++11への対応が不十分な所があり、ところどころでコンパイルエラーが発生する。-std=gnu++98 を指定して回避できる所は回避する。

ポインターを返すべき所で false を返す箇所がある。きっと NULL で良いのだと推測し、NULLポインタを返すように回避。これでよいのか?

 

 

独自にインストールした gcc と libtool を利用した場合のトラブル

ちょっと古いOSにいくつかツール&ライブラリを構築する必要が出てきた。だいたいこういうケースは色々な問題が生じるのだけど、今回は管理者権限がない+αの理由で、すべてユーザ権限のもとビルドしないといけない。

gcc からはじまって、 X11 までビルド。dev パッケージをいれてもらえればそこまでする必要はないはずなのに、いろいろなパッケージが足りない事から、こういう状況に。

いくつか問題はあったのだけど、だいたい目的を果たせそうになってきた所で、

  • Xserces
  • Mesa

のビルドで問題発生。どちらも autotools + libtool でビルド環境が整備されるのだけど、デフォルトの gcc ではない別バージョンの gcc を利用すると、 libtool でリンク時に 32bit バージョンと 64bit バージョンの libstdc++.so をリンクしようとする。結構古い問題で、10年前くらいからいろいろポストされているようなのだけど、きまった解決策がないような感じ。

いろいろいじってみた結果、

  • 64 bit のものをつくりたいのであれば
  • 32 bit 版の libstdc++.la を編集し、ライブラリディレクトリを 64bit の方にしておく

ことで解決できそうになった。 libtool の出力には二つ libstdc++.so が並ぶのかもしれないけど、多分大丈夫。 

 

ROOT 実行時のエラー

Fedora 25でビルドした ROOT 6.08.06 頃から、実行時にエラーがでるようになった。

エラー内容は

ERROR in cling::CIFactory::createCI(): cannot extract standard library include paths!
Invoking:
LC_ALL=C ccache -O2 -DNDEBUG -xc++ -E -v /dev/null 2>&1 >/dev/null | awk '/^#include </,/^End of search/{if (!/^#include </ && !/^End of search/){ print }}' | GREP_OPTIONS= grep -E "(c|g)\+\+"
Results was:
With exit code 256

というようなもの。ROOTのエラーといえばエラーなんだろうけれど、 ccache の man を見てみると、 ccache の後ろにコンパイラを指定する必要がある。コンパイラ指定の後にコンパイラオプション。多分ビルド時に

  1. コンパイラが ccache になっている
  2. ccache を使うのだけど、コンパイラを指定する変数が未定義

のどちらかなのだろうと推測。確かに ccache の後にコンパイラを指定して Invoking 下のコマンドを直接入れてみると、目的の結果が得られている様子。

ccmake で ビルド時の変数を確認してみると、CやCXXコンパイラに /usr/lib64/ccache/cc 等が指定されている。これが問題?

同じバージョンのROOTをBuildした他の環境では上記エラーがでておらず、そちらはそもそも ccache が入っていない。

コンパイラを直接指定しながら、もういちどROOTをビルドしてみる。エラーが出なくなった。

※ ROOTのビルドオプションに ccache を有効にするものがあった。有効にしてからビルドしたらどうなるのだろうか?

 

ROOT, Pythia6, cmake

ROOTのビルド時にPythia6 を有効にしたい。cmake でビルドしたいのだけど、ROOTにはいっている Pythia6.cmake で find_packageしたい。

cmake -Dpythia6=ON 

で良いはずなのだが、適切に PYTHIA6 変数を設定しても Pythia6.cmake中の get_filename_component でエラー。

PYTHIA6_LIBRARYを直接していすれば良いのだけど。

 

cmake -DPYTHIA6_LIBRARY=... -Dpythia6=ON