投稿

2016の投稿を表示しています

Vim x C言語で書くプロジェクトの良さと(私的)つらみについて

イメージ
この記事は Vim Advent Calendar 2016 の16日目の記事です。
15日目の前日は shinespark氏の「Vimでtreeっぽくディレクトリ構成を書きたい、そんなアナタの為のVim Plugin、できてます。」でした。


この前の新Mac騒動でCtrl+]を初めて知った@MNukazawaです。
しかし相変わらずESCを連打しています。


追記 > 投稿してから文字サイズがおかしいことに気づいたのですが、ざっくり対処しておきますので、多少おかしくても勘弁いただければと思います。
まえがき
家でも仕事でも、C言語を書くときは(C言語を書くときに限らず)Vimを使っています。
ライトVimmerにとって、Vimは最高ですが、完璧ではないです。
C言語での開発とVimとの相性は最高ですが、光のあるところには影もあり、以下に書いてあるアレコレのつらみに、私は今も苦しんでいます。

今回挙げた中には、受け入れていかなければならないものや、いかにも井の中の蛙っぽい悩みも含まれており、解決策やベストプラクティスが無いはずがないと思えるものもあります。
「プラグイン忌避を克服しろ」「Vimの基本コマンドくらい覚えろ」等々、厳しくツッコミを入れて頂けると、正直とても嬉しいです。


私は現在、Vecterion(べくてりおん)という名前のベクターグラフィック・エディタを書いています。
今回のVim記事も、VecterionをVimで書いているときの話をするので、Vecterionのスペックをざっくり挙げておきます。
* GUIアプリケーション(ベクターグラフィック・エディタ)
* C言語/GTK3で書いている。
* googletest使用
* GNUMake(生Makefile)でビルド
* 中規模アプリケーション(1人で開発。アプリケーション本体のヘッダとソースが50個ずつ有る)

リリースはまだしていませんが、昨日もリリースブロッカを一つ潰したので、来年のどこかでは...。
Vecterionについては、Vimに関わらない C言語 Advent Calendar 2016 の12日目の記事「Cで書く中規模GUIアプリケーションから得た知見(初稿) 」でざっくり書いたので、よければどうぞ。





つらみ達 # ディレクトリ構成 中規模アプリケーションは、ヘッダと…

Cで書く中規模GUIアプリケーションから得た知見(初稿)

イメージ
この記事は C言語 Advent Calendar 2016 の12日目の記事です。
11日目の前日はegtra氏の「配列でないオブジェクトに対するポインタ演算」でした。


@MNukazawaといいます。今、ベクターグラフィック・エディタをC言語で書いています。
Vecterion(べくてりおん)という名前です。
VecterionはGtk3/C言語で書いています。
現在進行形ですが、今日はVecterion開発の知見というか、Vecterionで使っているちょっと大きめのイディオムを、いくつか紹介したいと思います。

なおこの記事で言っている「中規模」ですが、
* ワンソース(ほぼmain.cだけ)に収まるアプリケーションを小規模
* 多人数で開発しなきゃ作れないアプリケーションを大規模
として、コマンドラインスクリプトよりは高度なことをしているけれど、コード量としては一人で収まる。
小規模と大規模の間くらい、程度の意味です。

小規模は、(語弊があるが)catやechoのような、ワンパスのコマンドラインスクリプト程度の機能。
大規模は、GIMP, LibreOfficeのようなGUIエディタや、Linuxカーネルなど。



なんというか、中規模コードの良い例を見つけることができなかったので書きました。
どなたかオススメのプロジェクトをご存知の方は教えてください。


開発中プロジェクトでまだ悩み中(本当は良くない)なので、まとまりきらない内容になっていますが、あなたが中規模プロジェクトを書く際に、一部でも参考になれば幸いです。

# ソース構成 ## ソース構成 struct型の定義と一緒に、メンバ関数・構造体を操作するUtility関数を同じヘッダに置いている。
CヘッダとCソースは原則的に一対一対応させている。

これらのソース構成は、ビルド速度的には最善ではないが、関数の置き場所がわかりやすく、プロジェクト全体の読みやすさに繋がる。

"#define"でない方法で定数 を定義している。
===
 static const PvPoint PvPoint_Default = {0, 0};¬
===
static const は入れ子に宣言定義(?)できないので、その時は諦めて#defineを使う。


Gtk的な関数名の付け方を、そのままソースの名前…

GdkPixbufを高速にリサイズ(cairo)

イメージ
GdkPixbufのサイズ変更を、元画像500x500px から 出力画像100x100~10x10pxで行うと、どうやらとても遅くなるようです。



GDK_POINTER_MOTION_HINT_MASK を使わずに motion-notify-eventをそのまま再描画に投げている私も悪いのですが。
とはいえ GDK_POINTER_MOTION_HINT_MASK はGtk3で思った通りにならず、アプリケーションがフリーズするようになっていました。

将来的には描画前のレンダリングをマルチスレッド化するつもりではいます。しかしシングルスレッドだと競合などを考えずに済み楽であるため、どうにもならなくなるまではシングルスレッドで行くつもりです。

というわけで、単純にリサイズ機能を高速化して対応。このあたりも、cairo任せにするといろいろオブジェクトを確保するコストを考えてもずっと早いのではないかというカンが当たった感じです。


なお、 gdk_pixbuf_scale_simple()をそのまま、画質を GDK_INTERP_HYPER からバイリニア指定に変えるのは試してみましたが、ほとんど効果なしでした。

なお画質は不明。見た目にわからないですし悪くないですが、アプリケーションが将来的に画質を指定するようになったら、リサイズ機能を見直そうと思います。

呼び出し例は以下。
====
/*

GdkPixbuf *pb = gdk_pixbuf_scale_simple(



pixbuf,

(int)w, (int)h,
GDK_INTERP_HYPER);
*/
GdkPixbuf *pb = _pv_copy_new_pixbuf_scale(
pixbuf,
(int)w, (int)h); ====

実装は以下。
====
static GdkPixbuf *_pv_copy_new_pixbuf_scale(GdkPixbuf *pb_src, double w_dst, double h_dst)
{
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w_dst, h_dst);
pv_assert(surface);
cairo_t *cr = cairo…

BLADE v7 liteについて(スマホ買いました)

イメージ
BLADE v7 liteを買って、半年使ったので、本日レビューを書き散らします。
半分くらいAndroid6.0レビューみたいになるかも。

NTT-Xで2万円弱で買った。


BLADE v7 Liteを選んだ理由は、Android6.0が使える端末で他に手頃なものが無かったから。
同価格のASUSのZenPhoneのほうがCPUが少し良いので、そちらでも良いかと思った。ノートPCはASUSなので揃えてみたかったし。
だが最終的に、ZenPhoneにはGPSに問題があるという話と、やはりAndroid5.xではなく6.0にしたいということでBLADE v7 liteにした。






この端末、届いてから3週間近くSIMを待っていた。SIM契約のアテが外れたから。
初期設定でSIM設定をスキップすると、後が面倒そうだったので、WiFi運用などもせずバッグに放り込んでいた。この間ほぼ無充電だったが、2週間くらい放っておいてもBLADE v7 liteは普通に起動した。電波を掴んでいなかったからかもしれないが。



途中で一度、Y!MobileのSIMが差し込まれた。
(店頭での動作確認。きちんとブラウザでWebサイトが見れることを確認した。通話は未確認)
Y!Mobileはパケット繰越しないと言われたためSIMを買わなかった。
UQMobileのSIMは試していない。店頭で契約しようとしたら、店員に「未対応端末では壊れるかもしれないからやめたほうがいいです」と静止されたから。これについては感謝している。次があればまたUQMobileを検討しよう、と思ったくらい。

閑話休題。

その後、MineoのSIMを契約して家で刺して、動いた。
Mineoの設定はあらかじめ登録されている。ユーザ名とパスワードも共通のものだったようで、デフォルトのままで動いた。SIMのMNP切替中に、何度か"モバイルデータの有効化"だったかを無駄にON/OFFしていたが、ともかく1時間も置いておいたらインターネットも通話もできるようになった。

なお、microSDは、秋葉原で1000円程度で買った32GBのTOSHIBA製を新規購入して入れた。

前の端末は3.5年前のAndroid4.2端末だった。電池がヘタっていたのと、ブラウザ(chromeその他問わず)が3タブほど開くと、タブ切り替え…

Windows環境でMakeする際に起こるエラーと対処

イメージ
Make オルタネイティヴは数あれど、小さな実験プロジェクトを始めるときに、簡単に使えるMakeは未だにビルドツールとして有力な選択肢だと思います。

MakefileはUNIX環境、というかCLIツール群があることを前提にしているところがあります。Windows環境ではUNIXコマンドがそもそも無かったりするため、Makefileが可搬ではないです。



GitHubに公開しているmkwin_mnでは、mkdir -p と rm -f を解決しました。
以下には ls find が無いことにより発生する問題もあり、wildcard関数による解決は満点とは言いがたいので、誰か対処してくれないかなと思っています。
Cygwin入れろと言われると返す言葉がないです。(MinGWといろいろ共存面倒そう、という言い訳がある。きちんと調べて対処すべきなのだろうけれど。)


 # ls, findが無いことにより起こるエラー
====
 process_begin: CreateProcess(NULL, sh C:\Users\nuka\Documents\etaion_20160920_22
h17m\etaion\library\gtk+-bundle_3.6.4-20130921_win32\bin\xml2-config --cflags --
libs, ...) failed.
cc1.exe: error: ./: No such file or directory [-Werror=missing-include-dirs]
source/pv_color.c:130:1: fatal error: opening dependency file object/pv_color.d:
 No such file or directory
 }
 ^
cc1.exe: all warnings being treated as errors
compilation terminated.
Makefile:40: recipe for target 'object/pv_color.o' failed
mingw32-make: *** [object/pv_color.o] Error 1
 process_begin: CreateProcess(NULL, ls sourc…

Gtk3でコンボボックス(ドロップダウン) Widgetを作る

イメージ
Gtk3で、ComboBox(DropDown)を作るサンプルコードです。

これまでGtk3では公式ドキュメントを反面教師として、単体動作するコードをサンプルとして提示してきたつもりなのですが、今回は諦めました。すいません。なんというか、実用を目指すプロジェクトからコードを一部だけ、動く状態に抜き出すって無理ですね。



====
        // self->combo_linejoin = gtk_combo_box_new();
    //    GtkListStore *liststore = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
        GtkListStore *liststore = gtk_list_store_new(1, G_TYPE_STRING);
        int num = get_num_stroke_linejoin_infos();
        for(int i = 0; i < num; i++){
            const PvStrokeLinejoinInfo *info = get_stroke_linejoin_info_from_id(i);
            gtk_list_store_insert_with_values(liststore, NULL, -1,
                            0, info->name,
    //                        1, info->linejoin,
                            -1);
        }
        self->combo_linejoin = gtk_combo_box_new_with_model(GTK_TREE_MODEL(liststore));
        g_object_unref(liststore);
        GtkCellRenderer *column = gtk_cell_renderer_text_new();
        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(self->…

Gtk3アプリケーションをWindows環境でビルドした際に出たエラーと対処

イメージ
ここでは、私の環境とビルド内容で出たGtk3固有のエラーとその対処について。Windows7 x64 と MinGWにて。

最初はビルド環境の構築その他を扱おうかと思ったのですが、他サイトでも少しづつ情報があるのでやめました。なんとなくできると思います。
Gtk2 Windows開発環境キットをGitHubにて公開しているので参考にどうぞ。
https://github.com/MichinariNukazawa?tab=repositories



今回は、gtk+-bundle_3.6.4-20130921_win32を使いましたが、見返してみると、
gtk+-bundle_3.10.4-20131202_win32.zip
とか、それなりに新しいのがありました。が、それでも2013年...。
その他バージョンなどダウンロードはこちらから。
http://win32builder.gnome.org/
この公式Gtk3パッケージ、バージョンを見ればわかるとおり、すでに非常に古いものとなっています。


 #  Gtk3バージョンが古いからか、未実装関数的なものがある? ====
 source/et_layer_view.c: In function 'et_layer_view_init':
source/et_layer_view.c:146:2: error: implicit declaration of function 'gtk_text_
view_set_monospace' [-Werror=implicit-function-declaration]
  gtk_text_view_set_monospace (GTK_TEXT_VIEW(self->text), TRUE);
  ^
cc1.exe: all warnings being treated as errors
Makefile:42: recipe for target 'object/et_layer_view.o' failed
mingw32-make: *** [object/et_layer_view.o] Error 1
====

対処:この関数だけWindows環境を判定してCソースにて #IFDEF 切って無効化しました。


 # …

mkwin_mnを作りました (Makefile in Windows toolkit)

イメージ
mkwin_mnとは 小規模なMakefileを、Windows環境で動作させるための互換用ファイル群です。
主にMakefileの $(MKDIR_P) と $(RM) のWindows版を提供しています。
というかそれだけです。

用途に対して実用的であれば良しとしています。Unix CLIとの互換性は、高くはありません。完全コンパチを目指すつもりもないです。



ダウンロードする GitHubで公開しています。
あなたのプロジェクトの中から git clone などしてください。
$ git clone https://github.com/MichinariNukazawa/mkwin_mn

## 使い方 ダウンロードしてきて、あなたのプロジェクトの Makefile にインクルードするだけです。簡単ですね。
include mkwin_mn.Makefile
非Windows環境との切り分けは、呼び出し側のMakefileでやってもらうようにしました。
そのほうが、環境のフラグに好きな方法を使えるから良いだろうと考えています。

Windows環境のmakeによる Makefile実行で、変数からの機能呼び出しにより mkdir -p と rm -f  (rm -rf) のようなことができるようになります。

具体的な使い方の例は、添付してある example_project を参考にしてください。

## mkwin_mnのターゲット 小規模プロジェクトの手書きのMakefileがターゲットです。

循環定義的ですが、小規模プロジェクトとは、今どきMakefileを手書きしているようなプロジェクトを指します。

## 動機 開発の動機は、現在Ubuntu環境で作成中のGtk3アプリケーションをWindowsでビルドしようとしたら make clean が機能しなかったから、です。

## mkwin_mnのアプローチ 2016年現在、GNU Makeを置き換えうる、次世代ビルドツールは乱立しています。
新言語には新ビルドツールが付いていて当たり前の雰囲気です。
次世代ビルドツールは当然のようにUnix/Windowsコンパチなので、どれかに移行できればWindows非互換問題は片付きます。

私はMakeはそれなりに黒魔術だと思うので、より良くサポートされた汎用ビルドツール…

組み込みJavaScriptエンジン Duktape 非公式日本語訳(途中)

イメージ
Cアプリケーションに組み込める、フリーのJavaScriptエンジンを探していて、Duktapeというプロジェクトが見つかり、興味があったのでドキュメントを読んでいました。
以下は、途中までですが、読みながら翻訳していたものを公開します。



 == 以下、翻訳版注意書き ==





この文章は、アプリケーション組み込み向けEcmascript(Javascrip)エンジンであるDuktapeのドキュメントの非公式日本語訳です。
この翻訳は、自分がDuktapeについて把握することを目的として行ったものです。全体を通して翻訳が雑です。というか誤訳を含みます。翻訳ミスしても実際のサンプルコードと自作コードで確認すれば気づくだろう、だからいいや、というレベルです。訳しづらかったところを飛ばしていたりもします。翻訳ミス前提で読んでください。
日本語としてメチャクチャなので、頭の中で再度訳しながら読むことになるかと思います。
ライセンスは原文に準じます。原文が許す限り、新しい翻訳のベースなど自由に使っていただいて構いません。とはいえ、新規に訳したほうが早いでしょう。
指摘・修正はメール(michinari.nukazawa@gmail.com)またはtwitterに頂けると嬉しく思います。

原文
http://duktape.org/guide.html


== 以下、翻訳文 ==

version 1.4.0 (2016-01-10)

## このドキュメントの範囲 このガイドの内容は、あなたのプログラムでDuktapeを使いはじめるためのイントロダクションです。あなたが基礎知識をすでに持っているならば、わかりやすい<a href>API reference</a>にてAPI構成を一覧できます。<a href>Duktape Wiki</a>の内容は、さらなる概要と使用例、ベストプラクティスです。

このドキュメントはDuktapeの内部構造について扱いません。(もしあなたが我々と共にDuktapeを弄ることに興味があるようならば、Duktape repoをご覧ください。)

## Duktapeとは何か? Duktapeは、移植性とコンパクトなフットプリントに注力した、組み込み可能なEcmascript E5/E5.1エンジンです。Duktapeによ…

テザリング状態のUbuntuでaptできない原因と対処

イメージ
結論としては、『テザリングで使うIPS+Proxy接続(また仮想マシンのNATなど)』の組み合わせにより、Ubuntu環境でaptが使えなくなる場合があるようです。








対処方法としては、Proxy接続を通さないで直接インターネット接続させることで、aptを使えるようになりました。
Ubuntu,aptの設定変更で済ませたかったところですが、仕方ありません。

現象
apt-get update が、以下のエラーメッセージを表示して失敗します。
===
InRelease: クリアサインされたファイルが有効ではなく、'NODATA' を得ました (認証にネットワークが必要?)
===

英語だと以下になります。
===
Get:1 http://extras.ubuntu.com trusty InRelease                               
100% [1 InRelease gpgv 3650 B]Splitting up /var/lib/apt/lists/partial/extras.ubuIgn http://extras.ubuntu.com trusty InReleaseta and signature failed
E: GPG error: http://extras.ubuntu.com trusty InRelease: Clearsigned file isn't valid, got 'NODATA' (does the network require authentication?)
===

fix-missingも何も効かないので焦りました。

対処
ppaリポジトリを追加しようとしてこの現象が起こったので、最初はaptの設定に原因があるかとも考えました。

http://askubuntu.com/questions/474549/got-nodata-issue-nodata-does-the-network-require-authentication

最初は、このページに書かれている、『/var/lib/apt/lists以下を再作成』などの設定作業による回避を模索していました。
過去の経験からaptが壊れた場合、aptの設定(/var/apt/source.list.d/ …

Gtk3でダイアログにWidgetを追加する

イメージ
Gtk3で書いているアプリケーションで、カスタムダイアログが必要となった際の記録です。

最初にGtkDialogを使ったときに、 ダイアログ内に追加したWidgetが表示されなかったため、少し時間を取られたので記事にしています。


Gtk3でダイアログボックスを使用するGtkDialogにWidgetを追加する場合、まずダイアログから、ダイアログ内のコンテナウィジェットへのポインタを取り出します。
GtkWidget *    gtk_dialog_get_content_area ()
によって取得したコンテナにGtkBoxなどのWidgetを追加していくことで、ダイアログをカスタマイズします。

また、
GtkWidget *    gtk_dialog_get_action_area ()
もありますが、こちらはdeprecated (廃止予定に非推奨)となっています。

そして、ダイアログ内へ追加したWidgetを、gtk_dialog_run() したときに表示するには、
gtk_widget_show_all(dialog);
を実行しておきます。
GtkWindowに対して使うことが多いと思いますが、dialogにも有効でした。

ソースコード 作成中のプログラムからそのままコピーしてきたコードなので、オリジナル関数(et_error())などが入っていますが上手くやってください。



GtkWidget *dialog;
GtkDialogFlags flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
dialog = gtk_dialog_new_with_buttons ("New Document",
NULL,
flags,
"_OK",
GTK_RESPONSE_ACCEPT,
"_Cancel",
GTK_RESPONSE_REJECT,
NULL);

GtkWidget *hbox_w = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1);
GtkWidget *hbox_h = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1);
GtkWidget …

JavaScript enginたちのコンパイル(2015)

2015年版の情報ですが、SpiderMonkeyとv8のビルド手順を確認した際のメモです。
勿体無いので一応公開しておきます。


 SpiderMonkeyの取得とビルド

公式の手順にあるビルドシステムのブートストラップを実行します。
wget -O bootstrap.py https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py && python bootstrap.py

下記の返答を 要求されたので「1」を答えました。
その後で依存パッケージ導入のために管理者権限を要求されます。
Please choose the version of Firefox you want to build:
1. Firefox for Desktop
2. Firefox for Android
Your choice:

SpiderMonkeyの環境構築はV8と違って、ブートストラップの最後にgitリポジトリの案内まで表示してくれる親切さです。(公式ダウンロードリポジトリ案内を読むまでもなかった。)


Gitリポジトリ取得は、履歴の長さ故かとても時間がかかります。
git clone https://git.mozilla.org/integration/gecko-dev.git

わたしは一晩放置しました。
最新ソースだけ欲しい場合は、単に最新ソースツリーを指定して取得したほうが良さそうです。
git clone --depth 1 https://github.com/mozilla/gecko-dev.git


ビルドは、思った以上に早く終わりました。8コア指定したからかもしれません。
autoconfは念の為にバージョンを確認しましょう。 ブートストラップが最適バージョンを配置してくれているようですが。
autoconf --version
autoconf
mkdir build_OPT.OBJ
cd build_OPT.OBJ
../configure make -j8

ビルド成功を確認。
dist/bin/js --help

今回は、インストールはしませんでした。




JavaScript v8の取得

V8 JavaScri…