C言語からXXを使う

ダーク・マターなら、宇宙に存在する暗黒物質って事で、現在宇宙物理学者達が血眼になって 探してるものだ。人間の知りたい欲望の極みになるかな。夢が有る話。

じゃ、『ダーク・マネー』はどうだ? 暗い金。それってマネロンの類の話? 俄かに 競馬で当てる方法やら株で儲ける方法を、この間からやってる機械学習の成果として 見出した。それで、先回りして、金隠しの方法でも勉強しようっての?

そういう誤解を招くような事を書くと、酷税庁に目を付けられますって。ましてやこの本の 出版社が、東洋経済新報社となると尚更です。

だから違うって。コーク兄弟と言う富豪が居て、そいつの音頭で、政府をわが物にしようって いう陰謀が企てられているのを暴いた本。

コークと言うと、あの砂糖水(を売ってて面白いかねとジョブズに言われた)の会社ではない。 第二次世界大戦前、石油精製の方法を発明したけど、政府と取り巻きの石油のメジャー会社に 発明を潰され、その技術を旧ソ連やヒトラー帝国に捧げ、大儲けしてのし上がってきた、コーク 一族。

2009年、民主党の小浜が就任式をやってる時、カリフォルニアの某高級リゾート地に、密に 大富豪達が集まってきた。どうやって、小浜に対抗しようかの相談。

富豪は持ってる金を有効に使って、金が金を生むようにしたい。それには、ごちゃごちゃ言う 政府を黙らせたい。ひそかに進む計画。

600ページ近い大著で、読み始めたばかりだけど、面白そう。 あれ、トランプって共和党だよな。おまけに大富豪。これって、陰謀が成功したって事かな。 富豪が儲かり、平民が搾取される国に作り替えられるのかな。

とんでもない失態

前回、自前でRndを書いた。その時シャッフルも含めたけど、それに文字列を渡すと エラーになった。その時は軽く考えていたけど、もう一度考えを整理しとく。

>>> s = "abcdefghijk"
>>> s[3] = "D"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> t = s[:]
>>> t[3] = "D"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> u = list(s)
>>> u[3] = "D"

文字列は書き換え不能。だから、定義したsの一部を変更しようとすると、そんな事は サポートしてないと窘められる。ならば、コピーを取ればってんで、スライスtを作ってみた。 それでも、元が文字列なんで、やはりエラー。

ならば、文字列を分解しちゃえってんで、listにする。これでようやくOKになった。 listを思い出す前に、splitだろうとあたりを付けたけど、この場合には使えない。

>>> hex(id(s))
'0x7fe06b5c59e0'
>>> hex(id(t))
'0x7fe06b5c59e0'
>>> hex(id(u))
'0x7fe06ac46598'

スライスを作っても、同じ所を指しているのね。なお、部分的にスライスしてくると、そのidは 変わるけど、文字列って いう属性は継承されるので、やはり書き換え不可でした。(当たり前な事が理解出来たな)

>>> z = s[2:4]
>>> hex(id(z))
'0x7fe06ac3cda8'
>>> z
'cd'
>>> z[1] = "D"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

簡易クラスブラウザー

を一行コマンドで作ってみた。最初、pythonの事はpythonに任せよう。良いreの勉強になるかと 思っていたんだけど、そんなの一行野郎で十分だろうと思って、下記に落ち着いた。志有る人は こんなに怠けていないで、ちゃんとしたのを作ってください。

[cent Lib]$ egrep '(^class|^ *def)' random.py
class Random(_random.Random):
    def __init__(self, x=None):
    def seed(self, a=None, version=2):
    def getstate(self):
    def setstate(self, state):
     :
class SystemRandom(Random):
    def random(self):
    def getrandbits(self, k):
    def seed(self, *args, **kwds):
    def _notimplemented(self, *args, **kwds):
def _test_generator(n, func, args):
def _test(N=2000):

idleに付いてたパイソン・クラス・ブラウザーと結果を比較してみたら、同じだった。こんな 簡単なのでOKなのね。さすがパイソン。偏な書き方が出来ないように工夫されてるな。

気を良くしたオイラーはエイリアスに登録しとこうと思った。名前どうしよう。そのまま頭文字を 拾うと、pcbか。これだとプリント板とか昔出てきたプロセス・コントロール・ブロックと被るな。それと、pdbとも似てるし。。。

alias cb="egrep '(^class|^ *def)'"

結局、cbなんていう無難な名前で登録したよ。(cdと良く似てるじゃんてのは、却下です。)一応、どういう風に登録されたか確認。

[ob: ~]$ alias
alias cb='egrep '\''(^class|^ *def)'\'''
 :

なんか、大変苦労されてました。

gaucheの場合

とあるページを見ていたら、 C言語からGaucheを使おう! (10) まとめなんてのに出会った。昔々に来た事が有った ような気がするけど、検証してみる。gaucheを入れてるのは、CentOSとFreeBSDだったりする ので、まずはCentOSで実験。

[cent tmp]$ make
gcc -std=gnu99 -Ofast -Wall -Werror -o a.out `gauche-config -I` main.c `gauche-config -L` `gauche-config -l`
[cent tmp]$ ./a.out
./a.out: error while loading shared libraries: libgauche-0.9.so.0.5: cannot open shared object file: No such file or directory

あれ、失敗したぞ。そんな馬鹿な! 気を取り直して、どんなになってるか確認。

[cent tmp]$ ldd ./a.out
        linux-vdso.so.1 =>  (0x00007ffe1342d000)
        libgauche-0.9.so.0.5 => not found
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f0046bbf000)
        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f0046988000)
        libutil.so.1 => /lib64/libutil.so.1 (0x00007f0046785000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f004657c000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f004627a000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f004605e000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f0045c9c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0046dd0000)
        libfreebl3.so => /lib64/libfreebl3.so (0x00007f0045a99000)

やっぱり無いと言ってる。でもgoshを入れた時はちゃんと動いていたぞ。

[cent tmp]$ ldd /usr/local/bin/gosh
        linux-vdso.so.1 =>  (0x00007ffcc7ef3000)
        libgauche-0.9.so.0.5 => /usr/local/lib/libgauche-0.9.so.0.5 (0x00007f4cb83cc000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f4cb81bc000)
        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f4cb7f85000)
        libutil.so.1 => /lib64/libutil.so.1 (0x00007f4cb7d82000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f4cb7b79000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f4cb7877000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f4cb765b000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f4cb7299000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f4cb8b11000)
        libfreebl3.so => /lib64/libfreebl3.so (0x00007f4cb7096000)

こちらはちゃんと見つけているな。えーーーーと、長い経験で、こういう時は、

[cent tmp]$ export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
[cent tmp]$ ./a.out
100

lddで確認しても、ちゃんと今度は見つけてくれている。もう一つ方法が有った事を思い出した。 /etc/ld.so.conf.d/の下に、適当なファイルを置き、その内容を/usr/local/libに設定。 それから、ldconfig -v とかやる方法。こちらの方がお勧めだったはず。

でも、goshの場合はちゃんとライブラリィーを見つけていたな。コンパイル時に魔法を かけていたのだろう。調べてみると、

Shared Object 入門

とか

LD_RUN_PATH と LD_LIBRARY_PATH

が、出てきた。そうか、調べてみる。

[cent tmp]$ readelf -a /usr/local/bin/gosh | grep /usr/local/lib
 0x000000000000000f (RPATH)              Library rpath: [/usr/local/lib]
[cent tmp]$ readelf -a ./a.out | grep /usr/local/lib

そして、こちらは、gaucheをconfigureした時の、Makefile内容

[cent Gauche-0.9.5]$ find . -name Makefile | xargs grep rpath
./Makefile:# depend on gosh's rpath to point a valid version of libgauche.so.
./src/Makefile:RPATH_TMP  = -Wl,--rpath=`pwd`
./src/Makefile:RPATH_REAL = -Wl,--rpath=$(LIB_INSTALL_DIR)

確かにrpathが埋め込まれているな。納得しましたよ。

今度は、FreeBSDでやってみる。

[fb11: gauche-c]$ make
cc -std=gnu99 -Ofast -Wall -Werror -o a.out `gauche-config -I`  `gauche-config -L` `gauche-config -l`
/usr/lib/crt1.o: In function `_start':
/usr/src/lib/csu/amd64/crt1.c:(.text+0x17b): undefined reference to `main'
cc: error: linker command failed with exit code 1 (use -v to see invocation)
*** Error code 1

Stop.
make: stopped in /usr/home/sakae/src/gauche-c

ここにたどり着く前に、FreeBSDにはgccなんてのは無いと言われ、clangに切り替えたんですが まだ、何か有るようですよ。で、困った時には、gmakeってのを思い出したぞ。

[fb11: gauche-c]$ gmake
cc -std=gnu99 -Ofast -Wall -Werror -o a.out `gauche-config -I` main.c `gauche-config -L` `gauche-config -l`
[fb11: gauche-c]$ ./a.out
100

ちゃんと動いた。これは、makeの非互換性に入れておけば良いのかしらね? 分類に困る エラーだな。一見、リンカーのエラーのようにも見えるんだもん。

何にせよ、BSDは見捨てられる方向に動いているのかな。

[fb11: bin]$ readelf -a gosh | grep /usr/local
 0x000000000000000f RPATH                Library rpath: [/usr/local/lib]
 0x000000000000001d RUNPATH              Library runpath: [/usr/local/lib]

これも互換性の確保の為? 誰かに聞いてみたいぞ。

pythonの場合

gaucheだけでは片手落ちだと思うので、今度はC語からpythonを呼び出してみる。こういう 無駄?な事も、きちんと解説ページが用意されてるのが、おもてなしのpython流。

他のアプリケーションへの Python の埋め込み

これだけではあれなので、市中に例を求めてみる。

C言語からpython3呼び出してHello Worldしてみた

Makefileは、上のgaucheのものを流用。こういうのをMakefileの継承とか言うんでしょうか? そして、ターゲットを、まだ登場してないDebian様と世間から忘れ去られそうなOpenBSDに してみます。

アラブの男性は、妻を4人まで娶ることが出来るそうです。但し、平等に扱わなければなりません。体力と資金力が無いと無理。オイラーには無理、せめて出来るのは4種のOSを操るぐらいです。平等にね。

[debian tmp]$ cat Makefile
SRC = main.c
OUT = a.out
INCLUDE_DIR = `python3.6-config --cflags`
LIBRARY_DIR = `python3.6-config --ldflags`

$(OUT): $(SRC)
        cc -std=gnu99 -o $(OUT) $(INCLUDE_DIR) $^ $(LIBRARY_DIR)

run: $(OUT)
        @./$(OUT)

clean:
        rm -f $(OUT)

これは有り難くコピペしました。記して感謝致します。

[debian tmp]$ cat main.c
#include <stdio.h>
#include "Python.h"
int main() {
        printf("C: Hello World!\n");
        Py_Initialize();
        PyRun_SimpleString("print('Python: Hello World!!')");
        return 0;
}
[debian tmp]$ make
cc -std=gnu99 -o a.out `python3.6-config --cflags` main.c `python3.6-config --ldflags`
main.c:3:5: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
 int main() {
     ^
[debian tmp]$ ./a.out
./a.out: error while loading shared libraries: libpython3.6m.so.1.0: cannot open shared object file: No such file or directory

出ました! エラーが。軽くエラー除けしましょ。何が欲しいか、聞いてみる。

[debian tmp]$ python3.6-config --ldflags
 -L/home/sakae/conda3/lib -lpython3.6m -lpthread -ldl  -lutil -lrt -lm  -Xlinker -export-dynamic
[debian tmp]$ export LD_LIBRARY_PATH=/home/sakae/conda3/lib:$LD_LIBRARY_PATH
[debian tmp]$ ./a.out
C: Hello World!
Python: Hello World!!

手抜きの方法で、取り合えず動かした。で、python本体は、魔法がかかって、RPATHでも 設定してあるのかな?

[debian tmp]$ which python3.6
/home/sakae/conda3/bin/python3.6
[debian tmp]$ readelf -a /home/sakae/conda3/bin/python3.6 | grep home/sakae

そんなものは埋め込まれていませんねぇ。そもそも、anaconda提供なんで、本体が何処に 置かれるなんて分かりませんから、埋め込みは無理な相談。

分かるのは、起動したpythonの絶対PATH。このbinの所から、../lib を見つけ出して いるんだろうね。ちょいと調べてみる。

[debian tmp]$ ldd /home/sakae/conda3/bin/python3.6
        linux-vdso.so.1 (0x00007ffe317ae000)
        libpython3.6m.so.1.0 => /home/sakae/conda3/bin/../lib/libpython3.6m.so.1.0 (0x00007fd8e59eb000)
          :

やっぱりね。そうだと思った。

なお、出来上がった a.outのファイルサイズは、約11kぐらい。やはり、libpythonはリンク されてた。だから小さい容量で済むんだな。

[debian tmp]$ ldd a.out
        linux-vdso.so.1 (0x00007ffceb385000)
        libpython3.6m.so.1.0 => /home/sakae/conda3/lib/libpython3.6m.so.1.0 (0x00007faac8a7e000)
          :

本体のpythonと、派生品のa.outで、libpythonの指示方法が微妙に違ってて面白いな。

debianにも自前でコンパイルしたdebug付きの pythonが入っている。それでコンパイルすると、libpythonは自前で抱えこんだものになった。 おかげで、出来上がったa.outは11Mを越えていたぞ。(多分、デバッグシンボルが大量に 入っているんでしょうけどね。)

そんじゃ、4人目の妻、じゃなかった、OpenBSDの元を訪れて機嫌を伺ってみます。

[ob: c-py]$ make
cc  -o a.out `python3.6-config --cflags`  `python3.6-config --ldflags`
/usr/lib/crt0.o: In function `_start':
(.text+0x5e): undefined reference to `main'
collect2: ld returned 1 exit status
*** Error 1 in /home/sakae/c-py (Makefile:7 'a.out')

FreeBSDと同じエラーになった。これぞBSDグループ。GNUに頑なに抵抗していますよ。

[ob: c-py]$ gmake
cc  -o a.out `python3.6-config --cflags` main.c `python3.6-config --ldflags`
main.c:3: warning: function declaration isn't a prototype
/home/sakae/MINE/lib/python3.6/config-3.6dm/libpython3.6dm.a(bytesobject.o): In function `PyBytes_FromFormatV':
../Objects/bytesobject.c:271: warning: warning: sprintf() is often misused, please use snprintf()
/home/sakae/MINE/lib/python3.6/config-3.6dm/libpython3.6dm.a(traceback.o): In function `_Py_FindSourceFile':
../Python/traceback.c:238: warning: warning: strcpy() is almost always misused, please use strlcpy()
/home/sakae/MINE/lib/python3.6/config-3.6dm/libpython3.6dm.a(getpath.o): In function `ismodule':
../Modules/getpath.c:163: warning: warning: wcscat() is almost always misused, please use wcslcat()
/home/sakae/MINE/lib/python3.6/config-3.6dm/libpython3.6dm.a(getpath.o): In function `copy_absolute':
../Modules/getpath.c:232: warning: warning: wcscpy() is almost always misused, please use wcslcpy()

gnuのmakeを使うと無事にコンパイル出来た。非互換性は、オイラーの知らないものかと思って、 "$^" を、"$(SRC)" に変更したら、互換になった。これって依存ファイルのリストを意味する らしいぞ。

[ob: c-py]$ ./a.out
C: Hello World!
Python: Hello World!!
[ob: c-py]$ file a.out
a.out: ELF 64-bit LSB shared object, x86-64, version 1
[ob: c-py]$ ls -l a.out
-rwxr-xr-x  1 sakae  sakae  7767564 Apr 10 07:48 a.out*

コードサイズがやけに大きいな。ひょっとしてpythonなんとかを抱え込んでいないかな?

[ob: c-py]$ ldd ./a.out
./a.out:
        Start            End              Type Open Ref GrpRef Name
        0000030cb6300000 0000030cb6b32000 exe  2    0   0      ./a.out
        0000030f04361000 0000030f0476f000 rlib 0    1   0      /usr/lib/libpthread.so.22.0
        0000030fa207b000 0000030fa2487000 rlib 0    1   0      /usr/lib/libutil.so.12.1
        0000030ede664000 0000030edea8c000 rlib 0    1   0      /usr/lib/libm.so.9.0
        0000030f6ac31000 0000030f6b0fb000 rlib 0    1   0      /usr/lib/libc.so.88.0
        0000030f81300000 0000030f81300000 rtld 0    1   0      /usr/libexec/ld.so

やっぱりリンクしてないね。

[ob: c-py]$ python3.6-config --ldflags
-L/home/sakae/MINE/lib/python3.6/config-3.6dm -L/home/sakae/MINE/lib -lpython3.6dm -lpthread  -lutil -lm  -Wl,--export-dynamic

で、--export-dynamicの用法を調べてみると、全てのシンボルを動的シンボルテーブルに加えるものらしい。これは、dlopenする時に必要になるとな。

じゃ、証拠を掴みましょう。リナだとstraceとかするんだろうけど、BSDしかもOpenBSDでは

[ob: c-py]$ ktrace ./a.out
C: Hello World!
Python: Hello World!!

どんなファイルの名前解決を欲してるか、心のうちを推し量ってみます。これは、まあ、ほのかな期待なんでしょうかね。(そんなの、システムコールのopenなりを見ろってのが、リナ陣営の 言い分でしょうが、OpenBSDのopenは、セキュリティ上の理由からか、単なる数値データしか 返ってきません)

[ob: c-py]$ kdump | grep NAMI
 13389 ktrace   NAMI  "./a.out"
 13389 a.out    NAMI  "/usr/libexec/ld.so"
 13389 a.out    NAMI  "/var/run/ld.so.hints"
 13389 a.out    NAMI  "/usr/lib/libc.so.88.0"
  :
 13389 a.out    NAMI  "/home/sakae/MINE/bin/python3.6"
  :
 13389 a.out    NAMI  "/home/sakae/MINE/lib/python3.6/lib-dynload"
  :

gdbでdlopenに網を張ってみたけど、引っかからず。素直にopenを見ていく。

(gdb) b open
Breakpoint 1 at 0x53310
(gdb) r
Starting program: /home/sakae/c-py/a.out
C: Hello World!

Breakpoint 1, *_libc_open_cancel (
    path=0x7f7ffffee590 "/usr/share/locale/UTF-8/LC_CTYPE", flags=65536)
    at /usr/src/lib/libc/sys/w_open.c:24
24      {
(gdb) bt
#0  *_libc_open_cancel (
    path=0x7f7ffffee590 "/usr/share/locale/UTF-8/LC_CTYPE", flags=65536)
    at /usr/src/lib/libc/sys/w_open.c:24
#1  0x000013a282e79b62 in *_libc_fopen (
    file=0x7f7ffffee590 "/usr/share/locale/UTF-8/LC_CTYPE",
    mode=<optimized out>) at /usr/src/lib/libc/stdio/fopen.c:54
#2  0x000013a282e78800 in _newrunelocale (
    path=0x7f7ffffee590 "/usr/share/locale/UTF-8/LC_CTYPE")
    at /usr/src/lib/libc/locale/setrunelocale.c:140
#3  0x000013a282e789be in _xpg4_setrunelocale (locname=<optimized out>)
    at /usr/src/lib/libc/locale/setrunelocale.c:203
#4  0x000013a282e6eebc in load_locale_sub (locname=<optimized out>,
    category=<optimized out>) at /usr/src/lib/libc/locale/setlocale.c:237
#5  loadlocale (category=<optimized out>, locname=0x7f7ffffeea40 "ja_JP.UTF-8")
    at /usr/src/lib/libc/locale/setlocale.c:261
#6  0x000013a282e6f20c in *_libc_setlocale (category=2,
    locale=0x139f9d9042b0 "") at /usr/src/lib/libc/locale/setlocale.c:152
#7  0x0000139f9d553d7c in _Py_InitializeEx_Private (install_sigs=1,
    install_importlib=1) at ../Python/pylifecycle.c:322
#8  0x0000139f9d554426 in Py_InitializeEx (install_sigs=1)
    at ../Python/pylifecycle.c:474
#9  0x0000139f9d55443a in Py_Initialize () at ../Python/pylifecycle.c:480
#10 0x0000139f9d55367d in main () at main.c:5

イニシャライザーの中で呼んでますねえ。これは、もう少し丁寧に追った方が良さそうですよ。

そして、こんなのも有った。 pythonのモジュールをC言語から使うを試してみる。

#include <stdio.h>
#include "Python.h"

int main() {
        PyObject *pModule, *pTmp;
        char *sTmp;

        Py_Initialize();
        pModule = PyImport_ImportModule("hoge");
        pTmp = PyObject_CallMethod(pModule, "foo", NULL);
        PyArg_Parse(pTmp, "s", &sTmp);
        printf("%s\n", sTmp);
        Py_Finalize();
        return 0;
}
[ob: tmp]$ cat hoge.py
def foo():
        print('this printed by python')
        return 'byt, this printed by C'
[ob: tmp]$ ./a.out
Segmentation fault (コアダンプ)

ありゃりゃ。こういう時は、セカンドオピニオンしてみましょ。一穴主義じゃなくて博愛精神ですよ。 (田中)角栄研究によると、妾だか2号さんだか、側室さんだかがいたそうな。おとーちゃん、おとーちゃんと慕われていたとか。

CentOSに行ってみる。

[cent tmp]$ ./a.out
Segmentation fault (core dumped)
[cent tmp]$ python -q
>>> import hoge
>>> hoge.foo()
this printed by python
'byt, this printed by C'

用意したモジュールは正常。ならば、gdbさんに賭けるしか。

[cent tmp]$ gdb -q a.out
Reading symbols from a.out...done.
(gdb) b main
Breakpoint 1 at 0x41ce1d: file main.c, line 4.
(gdb) r
Starting program: /tmp/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 1, main () at main.c:4
4       int main() {
(gdb) n
8               Py_Initialize();
(gdb) n
9               pModule = PyImport_ImportModule("hoge");
(gdb) n
10              pTmp = PyObject_CallMethod(pModule, "foo", NULL);
(gdb) p pModule
$1 = (PyObject *) 0x0
(gdb) n
11              PyArg_Parse(pTmp, "s", &sTmp);
(gdb) n
12              printf("%s\n", sTmp);
(gdb) p sTmp
$1 = 0x0
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff717db71 in __strlen_sse2 () from /lib64/libc.so.6

作者さんも言ってたけど、チェックを省いた弊害が如実に出てますなあ。モジュールの読み込みに失敗したって事。長い長い旅が始まりそうですよ。

1.3. 純粋な埋め込み

その前に、上記をやってみた。

[cent tmp]$ cat multiply
def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c

[cent tmp]$ ./a.out multiply multiply 3 2
ModuleNotFoundError: No module named 'multiply'
Failed to load "multiply"

やはり、エラーだよ。gdbで追ってみても、PyImport_Importが、NULLを返してくる。 普通のPythonからは、ちゃんと実行出来るんだけど。

[cent tmp]$ python -i multiply
>>> multiply(3,5)
Will compute 3 times 5
15

解決策見つけた。こういう穴が有るとは知らなかった。

[cent tmp]$ PYTHONPATH='.' ./a.out multiply multiply 3 2
Will compute 3 times 2
Result of call: 6

まあ、分かってしまえば極当たり前の事。C語のアプリと言えどもpython呼んでるんだから、 パスに倣うと言う事か。

C語の中で、イニシャライズが終わった後に

  PyObject* sysPath = PySys_GetObject("path");
  PyObject* dir = PyUnicode_DecodeFSDefault(".");
  PyList_Append(sysPath, dir);

を入れると良いらしい。

etc

デスクリプタ HowTo ガイド

これで、やたらアンダーバーが多いの克服出来るかな?

正規表現 HOWTO

冒頭でさぼったアレのpython流解決方法。

Python初心者がScikit-imageの例題を自分用に使うためのヒント9 C言語からの利用