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にするのはやめたほうがいいと思います。

2016年6月10日金曜日

Ubuntu14のGUIをリモートコントロールしたいならX2Goだ!

自分は、最近Ubuntuを気に入って使ってるんだけど、リモートでGUIを動かす機会が多い。

いままで、vncserverかNoMachineを使ってたんだけど、最近見つけたX2Goがよくて、激しくおすすめしたいので、記事にしてみた。

普通、第一選択肢になることが多いのがvncserverを立てての接続なんだけど、これだと結構、日本語入力でハマることが多い。
自分の場合、Ubuntuが何台かあって(違う人がセッティングしてたりする)、自分が作業するときは、いつもこの設定をするんだけど、なぜか毎回違うところでハマる。

うまくいってるマシンから ~/.vnc/xstartup をコピッて来ても、他のマシンでは動かなかったり(足りないmoduleが無いわけじゃなくても動かん)、fcitxを使ってると日本語入力できないことが多かったり(動くマシンもある)。さっぱりわからん。

NoMachineの場合、日本語入力の問題は出ないのだけど、無料版だとディスプレイに表示されている画面のコントロールになってしまい、やってることが丸見えなだけでなく、そこに誰かいたら簡単に乗っ取られてしまうので危なっかしい。

で、今回もvncserverの設定をしてて、うまくいかなかくてキレてたところたまたまみつけたのが、X2Go
親切な解説はココ。とくに設定しなくても、あっさり日本語入力できて感激。

UbuntuのリモートGUI操作で、日本語入力に困ってる方は一度使ってみるといいと思います。

xfce4のターミナルでtabキーでコマンド補完が効かない時の対処

xfce4を使ったら、ターミナル内でコマンド補完が効かなくて困った。
shift+tabやctrl+iでは、コマンド補完が効く状態。

対処方法は、
https://www.starnet.com/xwin32kb/tab-key-not-working-when-using-xfce-desktop/にあったんだけど、日本語化してる場合の設定箇所をメモ。

アプリケーションメニュー -> 設定 -> ウィンドウマネージャー -> keyboardタブ -> 同じアプリケーションのウィンドウの切り替え 設定をクリア
で、tab補完復活しました。

2016年5月19日木曜日

Ubuntu14.04で、extra-cmake-modulesを使いたい & apt-getできないパッケージの探し方

Ubuntu14.04を使ってて、githubからfcitx-qt5を落として使おうと思ったんだけど、cmakeをかけると、こんなエラーが出た。
CMake Error at CMakeLists.txt:8 (find_package):
  Could not find a package configuration file provided by "ECM" (requested
  version 1.4.0) with any of the following names:

    ECMConfig.cmake
    ecm-config.cmake
{なんじゃ、このECMってのは? しゃーない入れるか。}
と調べると、 extra-cmake-modules というもののよう。
これを使うと、どうも CMakeLists.txt が書きやすくなるものらしく、最近cmakeの際に、ECMを必要とするプロジェクトが増えている様子。 例によって、
sudo apt-get install extra-cmake-modules
してみたが、
E: パッケージ extra-cmake-modules が見つかりません
と怒られた。
{えーっ。ないのかー。探すか・・・}
Ubuntuだと、このECMっちゅうのは、14.10からの導入らしく14.04の標準リポジトリには、存在しない。 しかも、Ubuntu14.04 extra-cmake-modules ECM apt-get とかのキーワードをいろいろ組み合わせてググってもパッとしない。
結局、見つかったんだけど、それがここ。一見、14.04用ないじゃん・・・ ってなるけど、わかりにくく下の方に、
Other versions of ‘extra-cmake-modules’ in untrusted archives.
てあるので、そこ開いてTrusty(14.04のこと。わかりにくいから数字にしてくれ・・・)を叩くと、非公式リポジトリの説明ページに飛ぶから、そこの情報に従い、
sudo add-apt-repository ppa:ubuntu-sdk-team/staging
で、リポジトリ追加して後は、お決まりの
sudo apt-get update
sudo apt-get install extra-cmake-modules
で、無事ECM追加できて、cmakeもあっさり通った。
今回お世話になった、パッケージ情報がたくさんある launchpad.net なんだけど、Ubuntuのパッケージを探すときには、注意点があって、トップページにある検索窓に、パッケージ名(例:extra-cmake-modules)を打ち込んでも、結果のExact matchesには、ソースパッケージの情報しかでてこない。(お目当てのモノは、下のずらーーーっの中に埋没している。)
なので、Ubuntuパッケージのページの検索窓を使う。こっちは、Exact matchesにちゃんと実行できるパッケージが出るので、そのから探すと速いです。

2016年4月26日火曜日

Django (1.9) で、PyMySqlのDictCursorを使う方法。

対象

Djangoから、DBに接続してデータをごにょごにょやりたいんだけど、ORMが嫌いで
「Viva! SQL」 な人。

やりたいこと

Djangoのconnectionsを使うと、SELECT文の結果カーソルがtupleになってしまいフィールド順序でのアクセスになってしまうので、こんな風に
{'name': 'Taro Yamada', 'age': 25}
Dictionaryで結果がほしい。

やったこと (簡潔編)

ORM使わないなら、Djangoのconnectionsいらないから、自分でconnectする。
参考URL: YoheiM.NET

やったこと (だらだら編)

Djangoで、settings.pyにDBを以下のusersのように追加して、(docs.djangoproject.jpより引用)
DATABASES = {
    'default': {
        'NAME': 'app_data',
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit'
    },
    'users': {
        'NAME': 'user_data',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'priv4te'
    }
}
で、データがほしいところで
from django.db import connections

conn = connections["users"]
cur = conn.cursor()
cur.execute("SELECT * FROM persons WHERE id = %s", 100)
row = cur.fetchone()
print(row)
てな感じで、書くとprintされるのが、以下みたいな感じ
(100, "Taro Yamada", 25, 1, True)
{えーっ。tupleですかー? これじゃ、templateにrowを渡した時に、{{ row.1 }} な感じで読み取らないといけないから、わけわかめじゃんよー・・・。俺は、class Person を作りたくないんだってば }
どうやら調べると、DictCursorなるものを使えば、rowがtupleでなく
{'id': 100, 'name': 'Taro Yamada', 'age': 25, 以下略}
のようにdictionaryで取れるらしい。(参照: stackoverflow) 押忍。じゃあ、そこに
connection.cursor(pymysql.cursors.DictCursor)
なんて記述が、あったからさっきの上のコードをこんなふうに変更してみたところ
--- cur = con.cursor()
+++ cur = con.cursor(pymysql.cursors.DictCursor)
こんなエラーが
    cur = connections['users'].cursor(pymysql.cursors.DictCursor)
TypeError: cursor() takes 1 positional argument but 2 were given
{むきーっ!! }
どうやら、connections[‘users’]でとれるconnectionと、上記stackoverflowサンプルのconnectionは、別物らしい。
そりゃそうじゃよな。
具体的には、前者が ‘django.db.backends.mysql.base.DatabaseWrapper’
で、後者が ‘pymysql.connections.Connection’
さらに調べると、別のstackoverflowで、
「djangoに、DictCursorなんて、なぁぃですね~↑」(No there is no such support for DictCursor in django.)
{なにーっ!! }
さらに、その回答の解決案がびみょ~~な感じ。
でも、考えてみるとDictCursorを使いたいって時点で、djangoのORM無視してSQL投げたいってことなんだから、自分でconnectすればいいじゃんか。 ← 早く気がつけ。
幸い、親切な人が素晴らしい解説を書いている(YoheiM.NET)ように、使い方は簡単。
ただ、DB接続設定は、settings.pyに残しておきたいのと、データを使う側でのコードを簡潔にしたいので、最終的に以下のようになった。
まず、settings.py に、connectionまで定義してしまってアプリ全体で使い回す。
import pymysql.cursors

USERS_DB = pymysql.connect(
    host='localhost',
    user='db_user',
    password='db_pass',
    db='users',
    charset='utf8',
    cursorclass=pymysql.cursors.DictCursor)
最後の一行が、ポイント。 settings.pyってpythonファイルだから、こんなものも置けるんだ・・・
DBにアクセスしたい方では、
from django.conf import settings

conn = settings.USERS_DB  # ←これ便利
cur = con.cursor()
cur.execute("SELECT * FROM persons WHERE id = %s", 100)
row = cur.fetchone()
print(row)
これで、 {'id': 100, 'name': 'Taro Yamada', 'age': 25, 以下略} が、めでたくprintされる。
ついでに書くと、templateに渡すところでは、↑のrowを利用して、views.py で
render(request, 'users.html', {'person': row})
なふうに、簡単に渡して、template側では、
{{ person.name }}
とか
{{ person.age }}
みたいに、見てすぐにわかるように呼び出せるようになった。

でも、django.db.backends.mysql.base.DatabaseWrapperと pymysql.connections.Connectionのようにオブジェクト自体が異なっていても、executeの書き方やfetchoneで呼ぶところなど、共通だからほとんどコード変更の必要が無いのって、pythonからのDBアクセス方法がPEP 249で規定されてるからなんだよね。
pythonって文法が好きになれないんだけど(俺が好きなのはscala)、取り巻く環境がいろいろと整ってるから結局使っちゃうのよ。

長いところ、最後までお読みいただきありがとうございました。