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 source/*.c, ...) failed.

====

ルールによるビルドのために、ソースディレクトリ以下の *.c ファイルを探させます。Makefileを書くなら、大抵はこれをやらせます。
このとき、Make組み込みの wildcard 関数でなく、 shell ls や shell find のように外部コマンドを呼び出していると、コマンドの無い環境でエラーが起こります。

wildcard()は子ディレクトリを再帰的に探索してはくれません。なので、以下のようなサブディレクトリのあるソースディレクトリ構成に対応できない問題が有ります。
src/
         + engine/
         + enemy/
サブディレクトリがそうそう増えないもので、階層も深く掘らないならば、サブディレクトリごとにwildcardを書いて、結果を加算していく



『 $(wildcard **.c) などとやると、子ディレクトリ内以下へ再帰的にマッチできるよ』
というStackOverflowに書いてあった小技。これの投稿の下に付いているコメント欄でも出来ない報告が書き込まれていましたが、わたしの環境ではUbuntu LinuxのGNU Make4.1でも使えなかったです。いったい何処由来のネタなのだろう。

閑話休題。



 # 出力先ディレクトリの生成に失敗したことにより起こるエラー


====
process_begin: CreateProcess(NULL, object, ...) failed.
make (e=2): wウスt@CェゥツゥワケB
Makefile:41: recipe for target 'object/pv_color.o' failed
mingw32-make: [object/pv_color.o] Error 2 (ignored)
 source/pv_color.c:130:1: fatal error: opening dependency file object/pv_color.d:
 No such file or directory
 }
 ^
compilation terminated.
Makefile:41: recipe for target 'object/pv_color.o' failed
mingw32-make: *** [object/pv_color.o] Error 1
====


出力先として想定ているobjectディレクトリが作れず、書き出し先が存在しないため、ファイルを作れなくて起こるエラーです。
mkdir -pが無いことが原因です。
GitHubに公開しているmkwin_mnでは、mkdir -p相当の機能を用意することで対処しています。
他に、objectなど、必要なディレクトリがあらかじめわかっているなら、object/.gitkeepなどを置いておいて、書き出し先ディレクトリを予めプロジェクトリポジトリに含めておくという手もあります。
その場合は誤って削除してしまわないよう注意。

以上です。

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->combo_linejoin), column, TRUE);
        gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(self->combo_linejoin), column,
                    "text", 0, NULL);
        gtk_combo_box_set_active(GTK_COMBO_BOX(self->combo_linejoin), 0);
        gtk_box_pack_start(GTK_BOX(self->box_linejoin), self->combo_linejoin, false, true, 3);
    }


====

ついでに使っている独自型などは以下。

====
 /*! @brief StrokeLinejoin */
typedef enum{
    PvStrokeLinejoin_Miter,
    PvStrokeLinejoin_Round,
    PvStrokeLinejoin_Bevel,
}PvStrokeLinejoin;

typedef struct{
    PvStrokeLinejoin linejoin;
    const char *name;
    int cairo_value;
}PvStrokeLinejoinInfo;

int get_num_stroke_linejoin_infos();
const PvStrokeLinejoinInfo *get_stroke_linejoin_info_from_id(PvStrokeLinejoin linejoin);


====

ドロップダウンリストの内容をGtkListStoreで作ります。それをGTK_TREE_MODEL形式でcombo_box_new_*()関数に流しこめば完了です。
一番重要なのはGtkListStoreがGtkTreeModelに変換できること、そしてそれがComboBoxに流し込めることです。

Python版コードなどを見てみると、GTK_TREE_MODELのところはタプルとか作ってそのまま流し込んでいて、確かに動的言語なら辞書配列が簡単に作れるし、それがコンボボックスの材料になるのも納得ですが、C言語だとこのなんだかしっくり来ない謎型変換をするコードになっています。

参考にしたのはこちら。
http://stackoverflow.com/questions/16630528/trying-to-populate-a-gtkcombobox-with-model-in-c
参考コードのほうが綺麗で完結していて読みやすいですね。
参考コードはコンボボックスの選択肢に色を付けるという愉快なサンプルコードになっていますが、これもしかしてここからオブジェクト取り出して選択した要素を一意に特定してコールバック処理の際に処理を分岐するとかの用途を想定しているんじゃないかな、私はコールバックの中でアクティブな選択肢の昇順を取ってきて、キャストなどもせず乱暴に元データのIndexに置き換えています。いずれはgpointer *data に選択肢のポインタそのまま投げ込んで判定するつもりだけれど、といった感じです。

====
g_signal_connect(self->combo_linecap, "changed",
            G_CALLBACK(_cb_changed_linecap_with_combo), NULL);


static void _cb_changed_linecap_with_combo(GtkComboBox *widget, gpointer user_data)
{
    EtStrokePanel *self = stroke_panel;
    assert(self);

    self->stroke.linecap = gtk_combo_box_get_active(GTK_COMBO_BOX(self->combo_linecap));

    _update_focus_elements_from_local();
}

====

以上です。

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 切って無効化しました。


 # SVG画像ファイルを読もうとすると失敗する。

実行時、それもSVG画像を読もうとしてはじめて発生するので、ちょっと厄介。
文字化けはGtk3の出力で別問題、今回は無視しています。
====
C:\Users\nuka\Documents\etaion_20160920_22h17m\etaion>make run
./build/etaion_vector.exe
debug: et_tool_init()[59]: 4
error: et_tool_init()[71]: 'サュシサ「ク・シォェュソセシセ: Z:/srv/win32builder/fixed_364/build
/win32/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.dll: `Z:/srv/win32b
uilder/fixed_364/build/win32/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-s
vg.dll': ョ「ク・シォヲ、セ€'
BUG: main()[81]:
Makefile:50: recipe for target 'run' failed
mingw32-make: *** [run] Error -1

C:\Users\nuka\Documents\etaion_20160920_22h17m\etaion>
 、
 'Unable to load image-loading module:
 ./build/etaion_vector.exe
debug: et_tool_init()[59]: 4
error: et_tool_init()[71]: 'Unable to load image-loading module: Z:/srv/win32bui
lder/fixed_364/build/win32/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg
.dll: `Z:/srv/win32builder/fixed_364/build/win32/lib/gdk-pixbuf-2.0/2.10.0/loade
rs/libpixbufloader-svg.dll': 指定されたモジãƒÂ
¥Ã£Æ’¼ãƒ«ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。'
BUG: main()[81]:
Makefile:50: recipe for target 'run' failed
mingw32-make: *** [run] Error -1
====

libpixbufloader-svg.dll が見つからないことが原因、とのことです。

gtk+-bundle_3.6.4-20130921_win32\lib\gdk-pixbuf-2.0\2.10.0\loaders.cacheを見ると、
====
 "Z:/srv/win32builder/fixed_364/build/win32/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.dll"
====
などと書いてあるので、相対パスなどで *svg.dll のロードをするよう書き換え。

====
C:\Users\nuka\Documents\etaion_20160920_22h17m\etaion>
 "library/gtk+-bundle_3.6.4-20130921_win32/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.dll"
====

以上です。

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はそれなりに黒魔術だと思うので、より良くサポートされた汎用ビルドツールがあるなら、積極的に切り替えたいです。

しかし、次世代ビルドツールはどれも普及度がイマイチで、Web上にエラー解決の情報が不足しています。文法エラーなどで詰まると、そのまま死ぬ。
その点、Makeは優秀です。ほかの追随を許しません。実環境で30年近く叩かれまくっているので、ワークアラウンドとナレッジが溜まっています。大抵の問題は、検索してStackOveflowなどを読めば解決します。


Windows環境に足りないもの(MKDIR_P, RM)を足してやる、というのがmkwin_mnのアプローチです。
既存のMakefileに(ほとんど)手を加えません。
GNU Makeのエコシステムに乗ったままでいられる、という他にはないメリットがあります。

## 実装の詳細

ざっくり実装について。ここから下は適当に流し書きしています。

win:MKDIRはUnixセパレータ'/'を指定しても大丈夫。
win:RMとwin:RMDIRは'\'で渡してやらないと駄目。
というわけで、文字列置換。
bat変数でも、bash変数やMakefile変数と似たような置換の文法が使えた。
ただし、batで変数を扱うには魔法が必要だった。
この魔法が何という文法なのかわからない。検索しようが無い。

今回batファイルを書きましたが、Windowsバッチはよくわかりません。
C++における江添氏のような文法解説がほしい。MSのエバンジェリストの方々はきっとAzureでPowerShellでMSSQLをどうこうするのが忙しいでしょうから期待できないですが。

!cons.batは私のバイブル「30日でできる OS自作入門」由来。
MinGWのmakeにエイリアスをかける拡張をしています。



『Makefileのコマンド変数をWindows用に置き換えて、バッチを呼び出す』
という大枠にしました。
『Unix CLIと同じexeファイルを用意する』
というアプローチは、いろいろ面倒であることが予想されたので、早々に諦めました。

バッチはbatとvbsで少し悩みました。多少は早くて軽くていろいろな環境で動くだろうと思って、batにしました。
vbsのほうが複雑な機能を書きやすいはずなので、もっと複雑な処理が必要になったら、その時はvbsで書き直すかもしれません。
どちらにしろ速度は大して出ないでしょうし、速度を求めるようなモノでもないと思います。

今後について

開発動機は現状で満たしてしまったので、今後の機能追加は無いかもしれません。

リポジトリのTODOにTestと書いてある通り、とりあえず作って、開発中のGtk3アプリケーションのプロジェクトには十分使えることを確認しただけです。
そういう物だとわかった上でお使いください。プルリクエスト、利用報告があれば嬉しいです。

組み込み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により、あなたのC/C++プログラムへ、スクリプティング機能を簡単に拡張することができます。あなたはEcmascriptの中へ、プログラムの中心的な制御フローを作ることができ、同時に高速動作するC関数を使い、重い処理を取り扱うことができます。

(訳注:適当訳)EcmascriptとJavascriptは、大まかに等価ですが、ブラウザ向け拡張などが付いている場合もあって等しくはありません。Duktapeも例外ではなく、よく使われるprint(),alart()を持っています。なので、我々はEcmascriptの全体を実装したと言い表しています。

## Conformance
 (略)
## Features
 (略)
## Goals
 (略)

## ドキュメント構成

<a href>Getting started</a>は、あなたがダウンロード、コンパイル、そしてDuktapeをあなたのプログラムに導入するまでを取り扱っています。これの内容は確固とした例によって、あなたがどのようにあなたのプログラムにスクリプティング機能を導入するかを含んでいます。
<Programming Model><Stack types><C types>で語られているのは、Duktapeヒープのコアコンセプト, context, value stacks, Duktape API, Duktape C関数 です。Dukatapeのスタック構造とC型システムのラッパーについて概要を語っています。

Duktapeが実装しているEcmascript機能についていくつかのセクションで語っています: Type algorithms (for custom types), Duktape built-ins (additional built-ins), Ecmascript E6 features (features borrowed from ES6), Custom behavior (behavior differing from standard), Custom JSON formats, Custom directives, Buffer objects, Error objects (properties and traceback support), Function objects (properties), Debugger, Modules, Logging, Finalization, Coroutines, Virtual properties, Internal properties, Bytecode dump/load, Threading, Sandboxing.

<Performance>では(略)

<Comparison to Lua>では(略)

## Getting started
(略)
## Downloading
(略)
## Command line tool
(略)

## Integrating Duktape into your program

コマンドラインツールは、簡単なサンプルプログラムでDuktapeの組み込み方法を示しています。
組み込んでDuktapeをあなたのプログラムで使う方法はシンプルです:duktape.c, duktape.h, and duk_config.hを追加してビルドし、Duktape APIをあなたのプログラムのどこかから呼ぶ。

Duktapeの配布物に含まれるとても単純なサンプルプログラムの、hello.cがそれを示します。コンパイルとテストをこのプログラムで試すには():

The distributable contains a very simple example program, hello.c, which illustrates this process. Compile the test program e.g. as (<Compiling>の compiler optionも参照してください):
(サンプル略)
テストプログラムは、Duktape contextを作り、任意のEcmascriptコードを実行します:
(サンプル略)

Duktapeは組み込み可能なエンジンであるため、あなたのプログラムの基本のコントロールフローを変更する必要はありません。一般的な使い方は:
・プログラムを起動した際に、Duktape contextを作る(または、スクリプティングが必要となったタイミングで作る)。(訳注:適当訳)通常は、あなたのスクリプトがロードされる間に初期化が終わり、必要なタイミングでそれを実行することができます。
・一意な箇所があなたのプログラムの中にあり、そこでscriptを実行する、またscript内の関数をそこに挿入して呼ぶ。
・script内関数を呼ぶ。最初にpushして呼び出した引数はDuktapeコンテキストのvalue stacksに入れられてDuktape APIから使われる。これは、Duktape APIが実際に呼び出された際に使われる。
・ひとつのscriptを最後まで実行する。戻り値を渡す方法を制御でき、あなたのプログラムへ(Duktape API呼び出しの)戻り値として渡すか、Duktapeコンテキストのvalue stackに置くことができる。Cコードはこれらの戻り値をDuktape APIを通して使うことができる。

単純なサンプルプログラムを見てみましょう。プログラムはstdinを使った行の読み込みをCのmainloop内で行い、呼び出したEcmascriptの助けにより行文字列を変換して、結果を出力します。

スクリプトコードは"process.js"です。サンプルの文字列変換関数は、プレーンテキストの行文字列をHTMLに変換し、アスタリスク'*'で囲まれた文字を太字(bold)にします。
(サンプルコード略)
Cコードは"processlines.c"で、Duktapeコンテキストを初期化し、scriptを実行し、スクリプトが変換する処理対象の行文字列をstdinから読み込み、processLine()関数を行文字列ごとに実行します。
(サンプルコード略)

サンプルコード内のDuktape機能呼び出し箇所を、部分ごとに見て行きましょう。(適当訳)さらなる情報が欲しいならば、<Programming model>に書いてあります。
(サンプルコード略)
まずDuktapeコンテキストを生成します。コンテキストはEcmascriptの変数を変換し、value staskに入出力(pushing,popping)します。以降のDuktapeAPI動作の呼び出しではvalue stackが付き、入出力(pushing,popping)と実行がスタック上で行われます。製品コードには、望むならば、duk_create_heap()によってfatal error handlerをセットすることができます。<Error handling>を参照することで、エラーハンドリングのベストプラクティスについての議論を見ることができます。
(サンプルコード略)
評価(eval)呼び出しで"process.js"ファイルを読み込み、それがスクリプトをコンパイルし実行します。scriptに登録されているprocessLine()関数はEcmascriptグローバルオブジェクトへ、後で使うために格納されます。実行の際、スクリプトエラー・シンタックスエラーはハンドリングされ、fatal errorはハンドリングされません。もしエラーが起これば、エラーメッセージは強制的に安全に使うduk_safe_to_string()を通して提供され、それ以上に深刻なエラーにはなりません。実行結果の文字列は強制的にconst char * (ポインタ)に変換されるためリードオンリで、NULL終端のUTF-8エンコーディング文字列であるため、printfで直接使うことができます。
(サンプルコード略)
1行目は、Ecmascriptグローバルオブジェクトをvalue staskにpushしています。2行目はグローバルオブジェクトからprocessLineプロパティを探索しています("process.js"スクリプトファイル内に定義されている)。引数の-1はvalue stackのインデックスで、マイナス値はスタックを先頭から始め、よって-1はグローバルオブジェクトを一番先頭にスタックします。
(サンプルコード略)
Pushして行文字列が入っている文字列ポインタをvalue stackに入れます。文字列長は自動で、NULL終端で測られます(strlen()のように)。Duktapeは文字列のコピーを作成してstackにpushしますので、この関数の呼び出し後に文字列バッファを開放・書き込みしても構いません。
(サンプルコード略)
ここでvalue stackに入っているものは:グローバルオブジェクト,processLine関数,行文字列。
duk_pcall()メソッドは関数を実行し、指定された数の引数をvalue stack上から与え、それらを関数,引数,戻り値に置き換えます。ここで実行後のvalue stackに入っているものは:グローバルオブジェクト,実行結果 です。実行時のエラーは保護されており、取得してprint出力できます。duk_safe_to_string() APIを呼び出して安全エラーを表示することができます。最終的に、結果(またはエラー)がvalue stackからpopされます。
(サンプルコード略)
Duktapeコンテキストを破棄し、コンテキストのすべてのリソースを開放します。この呼び出しはvalue stackとその上の参照をすべて開放します。このサンプルではvalue stackの左端にglobal objectが入っているというくわだてです。これは問題ありません:メモリリークは起こりません、もしheapを破棄する際にvalue stackが空でも。

コンパイルは次のように。
(サンプルコード略)
テスト実行(process.jsがカレントディレクトリに必要)
(サンプルコード略)

## EcmascriptからCコードを呼び出す(Duktape/C bindings)

この導入サンプルでは、どのようにEcmascriptからCコードを呼び出して実行するか、難しくないCコードをEcmascriptから簡単に呼び出す方法を示します。

Ecmascriptは例にもれずしばしば、逆のシチュエーションとして中からCコードを呼び出したくなります。事例としては、スクリプト内で何らかの処理をとても多く実行する場合や、最適化されない低レベルbyte操作や文字列操作です。最適化されたCヘルパが呼び出し可能であり、あなたはすばらしいEcmascript言語の中で、あなたのスクリプトのロジックを記述して、その中で性能要求がクリティカルな部分をCコード呼び出しにすることができます。別の推測では、ネイティブなライブラリへのアクセスに使われるでしょう。

あなたが書くネイティブC関数の実装は標準的なC関数を、特殊な呼び出し規約の Duktape/C バインディングに適合させたものです。Duktape/C 関数は1つの引数を持ち、Duktapeコンテキストと1つの戻り値としてエラーまたは数値戻り値を持ちます。関数が呼び出し時の引数を得たり戻り値をセットする際にはDuktapeコンテキストのvalue stackに対して、Duktape APIを用いてそれを操作します。我々がさらに深くDuktape/CバインディングとDuktapeAPIを見るのはもう少し後にしましょう。サンプルは:
(サンプルコード略)
行ごとに見ていきます:
(サンプルコード略)
value stackのインデックス0番(スタックの先頭から、関数呼び出し時に指定された最初の引数)の内容が数値(number)であるか確認しています、この場合はこれは数値(number)です;もしそうでなかったなら、errorを投げて、値を返しません。もし内容が数値(number)であるならば、その数値をdouble型で返します。
(サンプルコード略)
引数を2乗して、value stackにプッシュします。
(サンプルコード略)
関数呼び出しからreturnして、これ(訳注:return 1)が指し示すものは(1つの)戻り値がvalue stackの先頭に存在することです。あなたはreturn 0を返すこともでき、これは戻り値が無いことを示します(DuktapeのデフォルトではEcmascriptのundefinedを返す)。負の値の戻り値は、errorが発生し、自動的に投げられたことを示す:これはエラーの投げ方としては単純なものです。なお、あなたがstackから値をポップして返すことを必要としないならば、Duktapeはあなたに関数からのreturnを自動で提供することができます。Programming modelにて詳細を参照ください。

我々の素数判定コードはネイティブコードによりEcmascriptで記述してあるアルゴリズムを高速化することができます。さらにテストプログラム側では1000000以下から素数を探すことに加えて値の下位が'9999'で終わる数値を探します。Ecmascript版プログラムは以下の通り:
(サンプルコード略)
雑記として、このプログラムはネイティブ関数を呼びますが、もしそれが使えない場合にはEcmascript版にフォールバックします。これにより、Ecmascriptコードは(訳注:今回のサンプルプログラム以外の)他のプログラムからも使用可能になります。一方で、もしこの素数判定プログラムを他のプラットフォームへ移植する場合でもネイティブコードは再コンパイル以外の変更は必要なく、ヘルパ関数を移植するまで遅いだけです。このプログラムの場合、ネイティブなヘルパ関数を検出するのはスクリプトを読み込む際です。あなたは一方でヘルパ関数の検出を任意のタイミングにフレキシブルに変更することができます。

ネイティブヘルパ関数には機能としてprimeCheckEcmascriptと等価なものを素直に実装しました。そこにmainを追加した"primecheck.c"は以下の通りです:
(サンプルコード略)
新しい関数呼び出しがあるので、行毎に見ていきます:
(サンプルコード略)
この2行の呼び出しは2引数をネイティブヘルパ関数が要求するためです。もし値がEcmascriptの数値型ではなかった場合、エラーを投げます。もしこれらが数値であった場合、数値を整数に変換し、それぞれローカル変数のval,limに格納します。index 0が第一引数でindex 1が第二引数です。

技術的には、duk_require_int()が返すのはduk_int_t型です;これは間接的にintへ変換されますがそれはintの長さが16bitまでしかない環境では問題が発生します。一般的なアプリケーションであれば、あなたはこれを心配する必要はありません。さらなる詳細はC typesを参照ください。
(サンプルコード略)
value stackにEcmascript falseをプッシュします。Cコードからreturn 1した場合、呼び出し元のEcmascript側ではこれを戻り値falseが返されたと解釈します。
(サンプルコード略)
1行目は、この後に、Ecmascriptグローバルオブジェクトをvalue stackにpushしています。2行目は、Ecmascript関数オブジェクトを作成し、それをvalue stackにpushしています。関数オブジェクトは、Duktype/C関数であるnative_prime_checkをバインドしてます:この時にEcmascript関数を、Ecmascript側から呼ぶために作成することで、C関数を呼び出せるようになります。第二引数の(2)は、このC関数が呼び出される際にvalue stackに必要な引数の数を示しています。もし呼び出し元がこれより少ない引数で関数を呼び出した場合、足りない引数はundefinedで埋められます; もし呼び出し元がこれより多い引数で関数を呼び出した場合、余った引数は自動で無視されます。最後の3行目で実行されていることは、関数オブジェクトをグローバルオブジェクトに格納しつつ、"primeCheckNative"という名前を付けながら関数オブジェクトをスタックからpopして取り出しています。
(サンプルコード略)
このときvalue stackにはすでにglobal objectがスタックの先頭に格納されています。1行目はprimeTest関数をglobal objectから探索しています(ロード済みのスクリプト内で定義されています)。2-4行目は、primeTest関数を引数無しで呼び出し、保護されたエラーが起こっていないかチェックしています。5行目は、実行結果をpopしてスタックから取り除いています; ここで戻り値は必要でないため。

コンパイル方法は以下:
(サンプルコード略)
実行します("prime.js"がカレントディレクトリに必要です):
(サンプルコード略)
さらに素数チェックに必要な時間を測って、スピードアップがEcmascriptと比べてどの程度有効か見てみましょう。あなたがこれを試すには"prime.js"を編集してネイティブヘルパ関数を無効にします。
(サンプルコード略)
再コンパイルして再実行すると:
(サンプルコード略)

## プログラミング・モデル

## 概観

Duktapeによるプログラミングは直裁的には以下の通りです。
・Duktapeソースコード(duktape.c)とヘッダ(duktape.hとduk_config.h)をあなたのビルドに追加
・Duktapeのheap(ガベージコレクション領域)を作成し、context(スレッドハンドラ的なもの)を初期化することを、あなたのプログラム内で行う
・必要なEcmascriptスクリプトファイルを読み込み、Duktape/C関数を準備しておく。Duktape/C関数はC関数をEcmascriptコード側から呼び出すことで、妥当な性能を出すことやネイティブライブラリへのアクセスを提供する。
・Duktape APIを用いて、Ecmasccript関数を妥当なタイミングで呼び出す。Duktape APIは関数と変数へのアクセスを提供する。変数はC変数型とDuktape内部形式(Ecmascript互換)を相互変換することができる。
・Duktape APIは一方で、Duktape/C関数(をEcmascriptから呼び出した)から、関数呼び出し時の引数および、戻り値へアクセスする方法を提供する。

これらすべてのステップを見ることが、我々の提供するさらなる情報にアクセスするのに必要です。

Heapとコンテキスト
Duktape heapは、ガベージコレクションを提供する単一の領域です。heapは文字列のために確保される領域、Ecmascriptオブジェクトやその他の変数に必要な領域、ガベージコレクション情報などに使われます。heap上のオブジェクトは、heapの先頭に持っている管理に必要な情報により、リファレンスカウント、mark-and-sweepガベージコレクション、オブジェクトのfinalizationなどを行います。Heapオブジェクトはリファレンスなどにより、ガーベージコレクションから見た到達可能性グラフ(reachability graph from a garbace collection perspective)を作ります。インスタンスに対しては、Ecmascriptオブジェクトへの参照を、キーと値によるオブジェクトとプロパティのセットにより提供します。あなたは複数のheapを持つことができ、オブジェクトは異なるheap上に直接存在することができません; (適当訳)あなたは異なるheap間では値をserializationしなければなりません。

Duktapeコンテキストは、Ecmascriptの"実行スレッド"としてDuktape heap内に生成されます。コンテキストはduk_context *によりDuktape APIから参照可能で、Duktape内部のコルーチン(a form of a co-operation thread)により組織化されます。いくつかのコンテキストを、共通のglobal objectを(訳注:ベースの?)環境として組織化することができます; コンテキストは任意のglobal objectを共有することができる一方で、異なる環境を持つことができます。コンテキストハンドルはほとんどのDuktape API呼び出しが要求し、そこからDuktapeコルーチンでvalue stackへアクセスします: 値の挿入と探索、関数の呼び出し、など。

コルーチンたちはcall stackにより実行を制御され、関数呼び出しの追跡、ネイティブまたはEcmascriptの分類、などをEcmascriptエンジン内で行います。(適当訳)コルーチンたちは一方でvalue stackを持ち、すべてのコルーチンのアクティブなコールスタックをstoreします。


== 以下、翻訳未終了 ==


テザリング状態の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/ 以下など)をクリアすれば解決することを知っていたからですが、余計な寄り道になってしまいました。

=====
Your mobile broadband provider is running a faulty transparent proxy. The URL http://extras.ubuntu.com/ubuntu/dists/trusty/InRelease should return "404 Not Found". Instead it returns "200 OK" but sends 404 content. Since the URL is "OK",
(以下略)
=====

とのことでしたので、仮想マシン(VirtualBox)のNAT経由ではなく、ゲストへのUSBブリッジ接続により、直接ゲストからUSBテザリングしました。
これで、aptが使えるようになったことを確認しました。

また、これも経験的にそうだろうと思ってアタリだったのですが、Ubuntuゲスト側でNAT接続を切らないとネットに繋がらないようです。
また、繋がらない場合にpingを打つと(ex. ping www.google.com など)繋がりはじめる場合がある気がします。こちらは検証していませんが。

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



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

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

SpinButtonを追加したGtkDialog

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 *spin_w = gtk_spin_button_new_with_range(0, 20000, 100);
 
GtkWidget *spin_h = gtk_spin_button_new_with_range(0, 20000, 100);
 
GtkWidget *label_w = gtk_label_new_with_mnemonic("width ");
 
GtkWidget *label_h = gtk_label_new_with_mnemonic("height");
 
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_w), 1200);
 
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_h), 600);
 
GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
 
gtk_box_pack_start(GTK_BOX(hbox_w), label_w, true, true, 0);
 
gtk_box_pack_start(GTK_BOX(hbox_h), label_h, true, true, 1);
 
gtk_box_pack_end(GTK_BOX(hbox_w), spin_w, true, true, 0);
 
gtk_box_pack_end(GTK_BOX(hbox_h), spin_h, true, true, 1);
 
gtk_box_pack_start(GTK_BOX(content), hbox_w, true, true, 0);
 
gtk_box_pack_start(GTK_BOX(content), hbox_h, true, true, 1);
 
gtk_widget_show_all(dialog);

 
gint result = gtk_dialog_run (GTK_DIALOG (dialog));
 
switch (result)
 
{
 
 
case GTK_RESPONSE_ACCEPT:
 
 
 
{
 
 
 
 
vg->rect.w = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin_w));
 
 
 
 
vg->rect.h = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin_h));
 
 
 
 
et_debug("size:%f,%f,%f,%f\n",
 
 
 
 
 
vg->rect.x, vg->rect.y, vg->rect.w, vg->rect.h);
 
 
 
}
 
 
 
break;
 
 
default:
 
 
 
et_debug("Cancel\n");
 
 
 
break;
 
}
 
gtk_widget_destroy (dialog);

 
return false;


以上です。

ComfyUIでXYZ-PlotするワークフローのサンプルとTips(ComfyUI-XYZ-Stitch)

 ComfyUIでAutomatic1111的なXY-Plotをしたいのだが、ComfyUIデフォルト機能には用意されていない。     カスタムノードが必要となるのだが、Webには古いとか何故か動かないとかなXY-Plotパッケージの使ってみた系記事か、githubに上げられた...