2017年11月15日水曜日

Ubuntu16でnouveauドライバをアンインストールする。

Ubuntu16のマシンからnouveauドライバをアンインストールしたときの記録です。
 Ubuntu16のマシンにNVidiaのグラボを挿してNVidiaのドライバを入れたのですが、少し動作が不安定なので、nouveauドライバを抜いて様子を見ようとしたのが動機です。
なお作業は、sshでコンソールログインして行っいました。
 
NVidiaのドライバを入れた後に、lsmodをすると、
mxm_wmi                16384  1 nouveau
video                  40960  1 nouveau
i2c_algo_bit           16384  1 nouveau
ttm                    98304  1 nouveau
drm_kms_helper        155648  2 nouveau,nvidia_drm
な感じで、 nouveauドライバが入りまくっている。こいつらを消したい。
cudaは動くので、NVidiaのドライバが入っていることは確実。

まず、/etc/modprobe.d/blacklist-nouveau.conf を作成し中身を
blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off 
としました。次に、dpkg -l | grep nouveau で見つけたあやしいやつを削除
sudo apt purge xserver-xorg-video-nouveau
 その後、
update-initramfs -u
これで再起動したら、lsmodしても綺麗サッパリnouveauが見えなくなりました。

2017年11月10日金曜日

ラズパイ3&バスパワースピーカーのノイズ退治(3.5mmジャック使用)

Raspberry pi3とバスパワースピーカーと3.5mmオーディオジャックの組み合わせで「強烈な」バックグラウンドノイズがのっていたのを解決した一例としてアップしておきます。

高音質にする、とかいう話ではなく、連続的な耐えられないノイズが発生していたのでそれを取った話です。

3.5mmオーディオジャック関連のノイズでは、ネットで
いろいろあったけど、ググっても見ないパターンでハマりました。

自分の場合↓の図のように接続していました。
これで、「ズビズビズビ、ピキーピピ、ズズビビ」のような、いかれたノイズが鳴り続けていました。どうやらこれは、電源系のノイズだったらしく次のようにつなぎ替えたらノイズが治まりました。
 バスパワースピーカーの電源を、別のACアダプタから取るのがポイントで、「ラズパイから電源を取らなきゃいんじゃね」と2個口以上あるUSBポートから、ラズパイとスピーカーの電源をとってしまうとノイズは消えませんでした。
 自分の場合は、ACアダプタ2つだとかさばるので、コイツを使って省スペースにしました。
この場合、一つの機器からラズパイとスピーカーの電源をとっていますが、片方がUSBポートで、もう片方が100Vに別のACアダプタをつないだものなのでOKでした。
つまり、ラズパイのオーディオジャックととバスパワーのスピーカーを使う場合、両方の機器の電源が一つの5Vの系にあるとノイズが発生するようです。

2017年11月9日木曜日

javascriptで簡単なカリー化関数を作った(ES6版)

最近、scalaからjavascriptに不本意ながら引っ越してきました。初めは嫌々ながらだったんですけど、ES6になってめっちゃ書きやすくなってるんですね。知りませんでした。
そんなわけで今回は、カリー化の仕組みがjavascriptの標準になさそうだったので、簡単にカリー化したいと思って調べてみると。 結構良さそうなのが、ありました。(Qiita: JavaScript でカリー化)
そのまま使っても良かったんですけど、僕はjavascriptでは、できるだけthisを使わないようにしているので、リンクの記事のcontextがいらないのと、その場合の空の括弧()がいらないので、上の記事のコードを参考に改造しました。
あと、他の言語から来ると、関数宣言の括弧の中にない引数をargumentsを使って取るのは気持ち悪いので、ES6の可変長引数を使ってこんな風にしてみました。
Function.prototype.curry = function (...args) {
  let func = this;
  function partial(...args) {
    return (args.length >= func.length)
      ? func.apply(null, args)
      : function(...ret_args) {
          return partial.apply(null, [...args, ...ret_args]);
        }
  }
  return partial.apply(this, args);
};
とりあえず、こんな感じにして動作確認
function sum1(a, b, c) {
  return a + b + c;
}
let sum2 = ((a, b, c) => a + b + c).curry()

console.log(sum1.curry(4, 5, 6))  // <- 6
console.log(sum1.curry(4)(5)(6))  // <- 15
console.log(sum2(10)(11)(12))  // <- 33
これでいいんだけど、あまりビルトインのprototypeを勝手に拡張すんな!としつこくMDN(ココココ)に書いてあるので、僕は潔癖でないのでそういうの嫌なんだけど、まあ後でcurryメソッドとか正式に追加されたらそれはそれで嫌なので、ただの関数版も作ってみた。
scalaのimplicit conversionが懐かしいぜ・・・
function curry(fn) {
  return function partial(...args) {
    return (args.length >= fn.length)
      ? fn.apply(null, args)
      : function(...ret_args) {
          return partial.apply(null, [...args, ...ret_args]);
        }
  }
};
こっちの使い方はこんな感じ
let sum3 = curry((a, b, c) => a + b + c)

// sum1は、上のを使いまわし
console.log(curry(sum1)(4, 5)(6))  // <- 15
console.log(curry(sum1)(1)(2)(3))  // <- 6
console.log(sum3(20)(21)(22))  // <- 63
console.log(sum3(2)(4, 6))  // <- 12
まあ、難しいこと考えなければこれで良いような気がします。
関数版は、憎たらしいthisも使わないですんでるし。
昔、10年くらい前には、
{javascriptって何でもfunctionで出来てて意味わかんねー} 
とかって思ってたんすけど、その基本設計と最近のES5,ES6と続く言語の拡張により俄然、モダンな書き方ができる言語に変化してきてるんですね。

2017年2月27日月曜日

Ubuntu Classic Server 16.04 on Raspberry Pi3 で固定IPに変更

タイトル通りの単純な話のはずだったんだけど、なかなかうまくいかなかったので、エントリアップ。
最初に、ありがちな/etc/network/interfacesの最後に
    # eth0設定
    auto eth0
    iface eth0 inet static
      address 172.20.XX.XX
      network 172.20.0.0
      netmask 255.255.0.0
      broadcast 172.20.255.255
      gateway 172.20.YY.YY
な感じで、追加したんだけど、起動してみたら確かに、指定したアドレスのIPを持ってたんだけど、それとは「別に」DHCPでもアドレスを取得していてそっちでもアクセスできちゃう。

さらに気持ち悪いことに、ifconfigをやってみると、なぜかDHCPで取ってきたアドレスだけ表示されて、↑で指定したアドレスが見えない。
{なんじゃろなー・・・}
と思い /etc/network/interfaces を見てみると、
    source /etc/network/interfaces.d/*.cfg
てな行があったので、
{こいつか}
と探すと、/etc/network/interfaces.d/50-cloud-init.cfgがいた、このページを見た感じ、これ変えりゃ行けるっぽかったので、このファイルに設定を移して、rebootすると、指定アドレスでなくDHCPになっている。

{オレなんかミスったか?} 
/etc/network/interfaces.d/50-cloud-init.cfg を見ると編集前の状態に戻っている。
{はっーー!? なんじゃそりゃ?} 
もう一回やったが、全く同じ現象・・・
どうやら、cloud-initさんとやらが起動時に勝手に書き換えちゃってくれているらしい。

ちょっと調べると、ビンゴなタイトル「how to set static ip in ubuntu 16.04 on raspberry pi 3 (cloud-init)?」のページがあったんだけど、回答はついてなくて、コメントで
「sudo apt remove cloud-init やったら動いたょ」
「えーっ。cloud-init使う方法ないの?」
みたいなやりとりがあって微妙。

他にもIP変えようとして、苦労して解決したけどcloud-initへの怒り丸出しなページ も発見、しかし、うちのケースには役に立たずがっかり。

{うー。ちゃんとしたドキュメント見つからないなーー。}
とさまよっていると、RedHatのユーザー向けページに「cloud-init に関する FAQ」 なんてやつを発見。結構丁寧に書いてあるが、↑で最初に書いたような設定を、meta-data ファイルに書けとの司令。

{うーむ、meta-data ファイルって何・・? っていうか、どこ・・?}
公式 見ても、ググっても何か埒あかないので、頭来て、
sudo find / 2>/dev/null | grep meta-data
で、ルートから探してやったら、
    /var/lib/cloud/seed/nocloud-net/meta-data 
{なんすかそこは? 見つかんないよそれは・・・}
で、その見つけたファイルに
network-interfaces: |
  auto lo
  iface lo inet loopback

  auto eth0
    iface eth0 inet static
    address 172.20.XX.XX
    network 172.20.0.0
    netmask 255.255.0.0
    broadcast 172.20.255.255
    gateway 172.20.YY.YY
bootcmd:
  - ifdown eth0
  - ifup eth0
って追加したらやっとまともに動きました。

動きはしたんですが、 /etc/network/interfaces.d/50-cloud-init.cfg はdhcpのままなんすよね。/etcをgrepしても、↑で指定したアドレスを含むファイルは無いようだし、cloud-init 全然理解してないです。

2017年1月18日水曜日

c++で、scala風ifをやりたい

scalaをしばらくやっていると、c++を書いた時にifが値を返さないのでトサカにくることがある。

三項演算子とラムダ式を使えばもちろんできるんだけど、超絶汚くなる。けど、マクロにしたら案外すっきりしたので、記事アップ。
// scala風if
#define IF(COND) (COND)?[&](){
#define ELSE ;}():[&](){
#define ENDIF ;}()
#define IFRES return
こんな感じ。c++11以降ね。使うときは、
// scala風if sample1
    const int i = 5;
    const auto s = IF(i == 4) {
        cout << "case true" << endl;
        IFRES "if true!";
    } ELSE {
        cout << "case false" << endl;
        IFRES "if false!";
    } ENDIF;

    cout << s << endl;
そこそこ見やすい。ENDIFが必要なのは勘弁してね。
c++は、中括弧の最後の値が中括弧全体の値にならないので、IFの戻り値にしたい値にIFRESを付けてね。
IFRESは、ただのreturnなんだけど、直にreturnって書くと関数全体のreturnに見えてしまい、わけわからなくなるので、このキーワードを使います。
逆に言うと、IFやELSEの中から関数の外へ直接return出来ないので、あしからず。returnしたい人は、別にifの戻り値が欲しいわけじゃないので普通のifを使ってください。

あと、ENDIFマクロの最後にセミコロンをあえて含めずに、使うときにセミコロンをつけるようにしたのは、コンストラクタの初期化子でも使いやすくしたかったから。

IFとかELSEの後がブロックでなくてもOK。
// scala風if sample2
    const int i = 5;
    const auto s = IF(i == 4) IFRES "if true!"
                   ELSE IFRES "if false!"
                   ENDIF;
    cout << s << endl;

2016年10月20日木曜日

opencv2系をgcc6でコンパイルしたらエラーになった

opencv2.4.13をubuntu16.10環境(gcc6)でコンパイルしたらこんなエラーが出て止まった。
In file included from /usr/include/c++/6/bits/stl_algo.h:59:0,
                 from /usr/include/c++/6/algorithm:62,
                 from /opencv-3.1.0/modules/core/include/opencv2/core/base.hpp:53,
                 from /opencv-3.1.0/modules/core/include/opencv2/core.hpp:54,
                 from /opencv-3.1.0/modules/core/include/opencv2/core/utility.hpp:52,
                 from /opencv-3.1.0/build/modules/core/precomp.hpp:49:
/usr/include/c++/6/cstdlib:75:25: fatal error: stdlib.h: そのようなファイルやディレクトリはありません
 #include_next <stdlib.h>
{stdlib.hがありませんって、そんなわけねーだろ!}
一瞬、あせったけど、cmakeで
-D ENABLE_PRECOMPILED_HEADERS=OFF
付けとけば、とりあえずOKっぽい。
opencvの方がおいおいgcc6対応すると思うけど、今のところこれで切り抜けられそうです。

2016年10月6日木曜日

docker buildしたときに、Dockerfileがシンボリックリンクだと失敗する。

タイトルのまんまなんだけど、docker buildしたときに、Dockerfileがシンボリックリンクだと失敗する。こんなエラーね。
% docker build -t image-name:tag-name .

unable to prepare context: The Dockerfile () must be within the build context (.)
そんなときは、リダイレクトでぶち込むととりあえず動きます。
% docker build -t image-name:tag-name - < Dockerfile
pathのところがハイフンになっている所に注意です。

追記
しかし、上の方法だとADDやCOPYでのファイルのコピーができません。
{ムキーッ。動かないし、あわてて上のエントリだしちまって、アホ丸出しだぜ。}
でこんなふうにやってみた。
# -f で相対パス指定 -> ダメ
%  docker build -t image-name:tag-name -f ../another-dir/Dockerfile .
unable to prepare context: The Dockerfile ({.の絶対パス/Dockerfile}) must be within the build context (.)

# -f で絶対パス指定 -> ダメ
%  docker build -t image-name:tag-name -f /xxx/another-dir/Dockerfile .
unable to prepare context: The Dockerfile ({.の絶対パス/Dockerfile}) must be within the build context (.)

# zsh使ってるのでプロセス置換 -> ダメ
% docker build -t image-name:tag-name -f <(cat Dockerfile) .
unable to prepare context: unable to evaluate symlinks in Dockerfile path: lstat /proc/29179/fd/pipe:[1290842]: no such file or directory   
{う~む。かなり、頑固だなあ。}
dockerは、どうしてもcontext dirにDockerfileの実体がないと動いてくれないらしい。
しかたないので、簡単な build.shを↓のように書いてみた。
#!/bin/bash

if [ $# -ne 1 ]; then
  echo "usage: build.sh tag_name" 1>&2
  exit 1
fi

rsync symlinkしてたDir/Dockerfile Dockerfile
docker build -t image-name:$1 .
動いたよ。

しかし、ここでもしやと思い、build context dirの外を向いているsymlinkをDockerfileのCOPYで、コピーしようとしてみたら、こんなエラーが
lstat symlinkの名前: no such file or directory
{docker buildは、徹底的にsymlinkが嫌いなようだ。今回は敗北感が大きいな・・・}
とにかく、dockerさんは、dockerfileやCOPYしたいファイルの「実体」があるところでbuildしてくださいといいたいのだろう。

そして、dockerfileの変更はsymlinkで同期させるのでなく、build可能な、contextディレクトリをgit等で管理するのが作法だぞということなのかもしれない。

仕方ない、従いますよdockerさん。ここまで、読んでくれた方、もしいらしたらごめんなさい。dockerfileをsymlinkにするのはやめたほうがいいと思います。