emcc
cq by scheme
前回やったQを求めるやつ。rubyで書いたけどやっぱりschemeでも書いておくかと思った。 rubyに有ったComplexは、gaucheに有るのかと調べたらmake-rectangularって名前で提供してた。
rubyの時のwhileのtest句は、schemeでそのまま変換するとごちゃごちゃするのが眼に見えているので、valって関数に括り出した。この関数はcqの中に閉じているので、外からは見えない。
後はruby語を素直にschemeに翻訳しただけ。何の気負いもない。
;; calc Q (define (cq l c r) (define (val xl xc r f) (abs (/ (make-rectangular r (- (* xl f) (/ 1 (* xc f))))))) (let* ([step 0.01e6] [fc (/ (* 6.28 (sqrt (* l c))))] [th (/ 0.7 r)] [xl (* 6.28 l)] [xc (* 6.28 c)] [fh (+ fc step)] [fl (- fc step)] ) (while (> (val xl xc r fh) th) (set! fh (+ fh step))) (while (> (val xl xc r fl) th) (set! fl (- fl step))) (/ fc (- fh fl)) ) )
sakae@pen:/tmp$ gosh -l cq.scm gosh> (cq 2e-6 100e-12 1.0) 112.59662120804897 gosh> (cq 1e-6 200e-12 1.0) 62.553678448916095
勿論結果はrubyのそれと一緒だ。喜んで今度はguileで試してみる。
sakae@pen:/tmp$ guile -l cq.scm GNU Guile 2.2.4 : scheme@(guile-user)> (cq 1e-6 200e-12 1.0) ERROR: In procedure abs: In procedure abs: Wrong type argument in position 1: 0.9844832009064911-0.12359622987535078i
あらエラーになった。
scheme@(guile-user)> (abs 3+4i) ERROR: In procedure abs: In procedure abs: Wrong type argument in position 1: 3.0+4.0i Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. scheme@(guile-user) [1]> (magnitude 3+4i) $1 = 5.0
magunitudeが複素数対応なのか。
sakae@pen:/tmp$ scheme Chez Scheme Version 9.5.3 Copyright 1984-2019 Cisco Systems, Inc. > (abs 3+4i) Exception in abs: 3+4i is not a real number Type (debug) to enter the debugger. > (magnitude 3+4i) 5
Chezもguileと同様。って事はgaucheは過保護なのかな?
-- Function: abs z [R7RS+] 実数のZに対しては、その絶対値を返します。 複素数のZに対して は、そのmagnitudeを返します。 複素数を扱うのはGaucheの拡張です。 (abs -1) ⇒ 1 (abs -1.0) ⇒ 1.0 (abs 1+i) ⇒ 1.4142135623731
やっぱり、気配りと言うか、おもてなしの心だな。
sakae@pen:/tmp$ scheme Chez Scheme Version 9.5.3 Copyright 1984-2019 Cisco Systems, Inc. > (load "./cq.scm") > (cq 1e-6 200e-12 1.0) Exception: variable while is not bound Type (debug) to enter the debugger.
ChezはWhileも無い、硬派なschemeなんだな。これはこれで捨てがたい処理系だ。
(define-syntax while (syntax-rules () ((_ pred b1 ...) (let loop () (when pred b1 ... (loop))))))
こんなのを追加して、命令風言語に仕立て上げる。
> (load "./cq.ss") > (cq 1e-6 200e-12 1.0) 62.553678448916095
emcc
以前から目を付けていた、 Emscripten をやってみるか。こういう新種は32Bitのリナで試すんだけど、やってみたら32Bitお断りって言われた。リナ自身も32Bitをサポートしてるやつは少なくなってしまったから、自然にそうなるのか。寂しいのう。
install
sakae@pen:~/src$ git clone https://github.com/emscripten-core/emsdk.git sakae@pen:~/src$ cd emsdk/ sakae@pen:~/src/emsdk$ git pull sakae@pen:~/src/emsdk$ ./emsdk install latest : sakae@pen:~/src/emsdk$ ./emsdk activate latest Setting the following tools as active: node-12.18.1-64bit releases-upstream-e7e39da9c81faecd9ecf44065cee864d76e4e34d-64bit Next steps: - To conveniently access emsdk tools from the command line, consider adding the following directories to your PATH: /home/sakae/src/emsdk /home/sakae/src/emsdk/node/12.18.1_64bit/bin /home/sakae/src/emsdk/upstream/emscripten - This can be done for the current shell by running: source "/home/sakae/src/emsdk/emsdk_env.sh" - Configure emsdk in your bash profile by running: echo 'source "/home/sakae/src/emsdk/emsdk_env.sh"' >> $HOME/.bash_profile sakae@pen:~/src/emsdk$ source ./emsdk_env.sh Adding directories to PATH: PATH += /home/sakae/src/emsdk PATH += /home/sakae/src/emsdk/upstream/emscripten PATH += /home/sakae/src/emsdk/node/12.18.1_64bit/bin Setting environment variables: EMSDK = /home/sakae/src/emsdk EM_CONFIG = /home/sakae/src/emsdk/.emscripten EM_CACHE = /home/sakae/src/emsdk/upstream/emscripten/cache EMSDK_NODE = /home/sakae/src/emsdk/node/12.18.1_64bit/bin/node
説明にも有るけど、環境設定の為に .bash_profile
を作成したよ。そしたら.bashrcより優先度が高いものだから、.bashrcが無視されちゃったぞ。使う時だけ、環境を作るか。
about
どんな物なのか少し探検する。
sakae@pen:~/src$ du -sh emsdk/ 682M emsdk/
大掛かりなシステムだ箏。して中身は? node clang が根底にあるな。clang一式を入れているのは、flake8とか言うまとめ役になるのか。後はこれらをアップデートするメンテナンス系。 面倒嫌いって人用にdocker環境も内蔵。
核になるemccは、これらを酷使するんで、糊としてpythonが使われている。
sakae@pen:/tmp$ echo $PATH | tr ':' '\n' /home/sakae/src/emsdk /home/sakae/src/emsdk/upstream/emscripten /home/sakae/src/emsdk/node/12.18.1_64bit/bin :
公開されてる場所はこんな感じ。
sakae@pen:/tmp$ node Welcome to Node.js v12.18.1. Type ".help" for more information. >
もったいない病が発症したんで、隠れているclangの場所を追加
sakae@pen:/tmp$ PATH=/home/sakae/src/emsdk/upstream/bin:$PATH sakae@pen:/tmp$ clang -v clang version 12.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 55fa315b0352b63454206600d6803fafacb42d5e) Target: x86_64-unknown-linux-gnu Thread model: posix InstalledDir: /home/sakae/src/emsdk/upstream/bin Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8 Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8 Candidate multilib: .;@m64 Selected multilib: .;@m64
こんな具合だから、図体が大きいんだな。正体みたり、、だ。
マニュアルは、emcc –help で見るのがお約束だ。古い人には馴染まんなあ。
sakae@pen:/tmp$ emcc -v emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.39.20 clang version 12.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 55fa315b0352b63454206600d6803fafacb42d5e) Target: x86_64-unknown-linux-gnu Thread model: posix InstalledDir: /home/sakae/src/emsdk/upstream/bin Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8 Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8 Candidate multilib: .;@m64 Selected multilib: .;@m64 shared:INFO: (Emscripten: Running sanity checks)
clangにpythonで一皮かぶせてemccって名前のコマンドを作っているとな。
how to use
emccのマニュアルを見ていると、WebAssembly なんて言うオイラーに取っては微妙な名前が出て来る。で、ぐぐる辞書を引いてみる。
WebAssembly から C/C++からWebAssemblyにコンパイルする を試してみるか。
try
sakae@pen:/tmp/z$ cat >hoge.c #include <stdio.h> int main(int argc, char ** argv) { printf("Hello World\n"); } sakae@pen:/tmp/z$ emcc hoge.c -s WASM=1 -o hello.html sakae@pen:/tmp/z$ ls -ltr total 244 -rw-r--r-- 1 sakae sakae 84 Jul 29 07:54 hoge.c -rw-r--r-- 1 sakae sakae 21738 Jul 29 07:54 hello.wasm -rw-r--r-- 1 sakae sakae 112060 Jul 29 07:54 hello.js -rw-r--r-- 1 sakae sakae 102675 Jul 29 07:54 hello.html
server
資料によるとwasmを含むやつは、Webサーバーから取得しないと機能しないらしい。 apacheサーバーを立てる? そんな面倒はしたくない。こういう時はpythonをこき使うのが正しい利用法
alias server='python3 -m http.server 8080'
こんなのを起動
akae@pen:/tmp/z$ server Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ... 127.0.0.1 - - [29/Jul/2020 07:56:17] "GET /hello.html HTTP/1.1" 200 - 127.0.0.1 - - [29/Jul/2020 07:56:19] "GET /hello.js HTTP/1.1" 200 - 127.0.0.1 - - [29/Jul/2020 07:56:19] code 404, message File not found 127.0.0.1 - - [29/Jul/2020 07:56:19] "GET /favicon.ico HTTP/1.1" 404 - 127.0.0.1 - - [29/Jul/2020 07:56:19] "GET /hello.wasm HTTP/1.1" 200 -
そしてfirefoxからアクセス。黒いエリアが2つ出て来た。そして下側のエリアに結果が出て来た。生成したファイル類を余す所なく読み込んでいる。
ダメ元でw3mから読み込んでみる。
sakae@pen:/tmp$ w3m http://localhost:8080/hello.html image/svg+xml Downloading... [ ]Resize canvas [*]Lock/hide mouse pointer [Fullscreen] [ ] [ ] : [ ] [ ]
読み込むのは当然htmlファイルだけだった。でも、上記のような結果になった。firefoxでは、 テキストエリアに結果が表示されるのね。jsだかwasmの恩恵を受けてね。
実践
そもそもemccなんてのに興味を持ったのは、KiwiSDRがらみでcsdrのMakefileを見ている時だった。emccって、C語(あるいはCフラフラ語)で書かれたコードをjavascript(or wasm)に変換して、Webに公開しましょってやつだ。
javascriptに落ちこぼれた旧世界のC語の住人を救済するためのものだな。js世界に背を向けて生きる人に最適(って、理解で宜しいか?)。3分でわかる WebAssembly を見ると、オイラーの見解と一致した。
早速csdr/Makefileの該当部分を駆動してみるか。
make emcc
sakae@pen:/tmp/csdr$ make emcc emcc -O3 -Isdr.js/fftw-3.3.3/api -Lsdr.js/fftw-3.3.3/emscripten-lib -o sdr.js/sdrjs-compiled.js fft_fftw.c libcsdr_wrapper.c -s TOTAL_MEMORY=67108864 -DLIBCSDR_GPL -DUSE_IMA_ADPCM -DUSE_FFTW -lfftw3f -s EXPORTED_FUNCTIONS="`python sdr.js/exported_functions.py`" In file included from fft_fftw.c:3: ./fft_fftw.h:7:10: error: 'fftw3.h' file not found with <angled> include; use "quotes" instead #include <fftw3.h> ^~~~~~~~~ "fftw3.h" 1 error generated.
おかしい、ヘッダーファイルが無いなんて。気を取り直して上記のヘッダーをちゃんと読むようにしてあげる。そしたら今度は、lfftw3が無いってエラーになった。
エラーばかりに注目してて、-I… とか -L… に注目出来なかったのがそもそもの敗因。それよりREADME.mdを熟読しなかったのが最大の失敗だな、と後で反省しました。
これはもう、根本的なミスがあるな。Makefileを見直し。そしたら、
emcc-get-deps: echo "getting and compiling fftw3 with emscripten..." cd sdr.js; \ wget http://fftw.org/$(FFTW_PACKAGE).tar.gz; \ tar -xvf $(FFTW_PACKAGE).tar.gz; \ rm $(FFTW_PACKAGE).tar.gz; \ cd $(FFTW_PACKAGE); \ emconfigure ./configure --enable-float --disable-fortran --prefix=`pwd`/emscripten-install --libdir=`pwd`/emscripten-lib; \ emmake make; \ emmake make install
こんなのを発見! 下準備をしておけって事だな。 emcc系のツールチェーンを使ってfftw3をコンパイルしてる。そうか、emccで扱えるようにライブラリーを作るのね。今コンパイルしてるんだけど、結構fftw3って大物なのね。ああ、出来上がった。
sakae@pen:/tmp/csdr/sdr.js/fftw-3.3.3$ file a.out a.out: a /home/sakae/src/emsdk/node/12.18.1_64bit/bin/node script, ASCII text executable, with very long lines sakae@pen:/tmp/csdr/sdr.js/fftw-3.3.3$ ls -l emscripten-lib/ total 916 -rw-r--r-- 1 sakae sakae 933808 Jul 31 07:42 libfftw3f.a -rwxr-xr-x 1 sakae sakae 920 Jul 31 07:42 libfftw3f.la drwxr-xr-x 2 sakae sakae 60 Jul 31 07:42 pkgconfig
お約束でa.outが出来上がって、ライブラリーも作成されてた。これでいいはずなんで、再度コンパイルに挑戦。
sakae@pen:/tmp/csdr$ make emcc emcc -O3 -Isdr.js/fftw-3.3.3/api -Lsdr.js/fftw-3.3.3/emscripten-lib -o sdr.js/sd rjs-compiled.js fft_fftw.c libcsdr_wrapper.c -s TOTAL_MEMORY=67108864 -DLIBCSDR_ GPL -DUSE_IMA_ADPCM -DUSE_FFTW -lfftw3f -s EXPORTED_FUNCTIONS="`python sdr.js/exported_functions.py`" : 6 warnings generated. cat sdr.js/sdrjs-header.js sdr.js/sdrjs-compiled.js sdr.js/sdrjs-footer.js > sdr.js/sdr.js
多少の警告は出たけど、コンパイル成功。sdrjs-compiled.jsが成果物なんだな。それにヘッダーファイルとフッターファイルを加えて、最終成果物のsdr.jsにするとな。
sakae@pen:/tmp/csdr/sdr.js$ ls -ltr total 124 -rw-r--r-- 1 sakae sakae 1859 Jul 21 14:48 sdrjs-test.html -rw-r--r-- 1 sakae sakae 1031 Jul 21 14:48 sdrjs-header.js -rw-r--r-- 1 sakae sakae 2611 Jul 21 14:48 exported_functions.py -rw-r--r-- 1 sakae sakae 10735 Jul 21 14:48 sdrjs-footer.js drwxr-xr-x 20 sakae sakae 1120 Jul 31 07:42 fftw-3.3.3 -rw-r--r-- 1 sakae sakae 38721 Jul 31 07:47 sdrjs-compiled.wasm -rw-r--r-- 1 sakae sakae 21703 Jul 31 07:47 sdrjs-compiled.js -rw-r--r-- 1 sakae sakae 33469 Jul 31 07:47 sdr.js
最終成果物を見ると、いやがらせの密になったjsが挟まっていた。綺麗にして見たいな。
Makefileに綺麗にするターゲットが有ったぞ。
js-beautify
高須クリニックじゃなくて、js-beautifyは何処に有るの?
debian:tmp$ apt-file search bin/js-beautify jsbeautifier: /usr/bin/js-beautify node-js-beautify: /usr/lib/nodejs/js-beautify/js/bin/js-beautify.js
取り合えず入れてあげた。で、整形手術を実行。
sakae@pen:/tmp/csdr$ make emcc-beautify bash -c 'type js-beautify >/dev/null 2>&1; if [ $? -eq 0 ]; then js-beautify sdr.js/sdr.js >sdr.js/sdr.js.beautiful; mv sdr.js/sdr.js.beautiful sdr.js/sdr.js; fi'
成果物だけ整形するなら
sakae@pen:/tmp/csdr/sdr.js$ js-beautify sdrjs-compiled.js > zzz.js
disる
wasmを解釈する機械と言うか仮想マシンは、最近のブラウザーでは標準装備されてる。また、javascriptを解釈するインタプリタもブラウザー内に昔から(ネスケの頃から)ある。
大変な世の中だ。猫も杓子も仮想マシンなんて言ってるから最近のインテルは元気が無い。アプルは電気を喰わないCPUに移行するというしね。
このブラウザーに内蔵する仮想マシンの規格はM$とアプルとググルが決めているそうな。そこにはインテルは入っていない。ハードなCPUよりブラウザーの方がリッチだからね。入力、出力、そして仮想マシンで演算力があれば、これはもう、コンピュータですから。
一世を風靡したJavaもボラクル主導になって、みんな躊躇してる。落ち目になる事目に見えているな。これからは土台をブラウザーにしたアプリが主導権を握るのね。
で、仮想マシンならそれ用のコードが有るはず。逆アセンブラが用意されてるので上でコンパイルして出来たバイナリーを人目に晒してみる。
sakae@pen:/tmp$ which wasm-dis /home/sakae/src/emsdk/upstream/bin/wasm-dis sakae@pen:/tmp$ wasm-dis hello.wasm (module (type $i32_=>_i32 (func (param i32) (result i32))) (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32))) (type $i32_=>_none (func (param i32))) :
こんなlisp風の言語になった。昔からlisp系をかじっていて良かったなと思う瞬間です。