変奏現実

パソコンやMMORPGのことなどを思いつくまま・・・記載されている会社名・製品名・システム名などは、各社の商標、または登録商標です。

この画面は、簡易表示です

インターネット

[AlmaLinux10] J1900: 非推奨,非推奨,非推奨

ログに

Warning: Deprecated Hardware is detected: x86_64-v2:GenuineIntel:Intel(R) Celeron(R) CPU  J1900  @ 1.99GHz will not be maintained in a future major release and may be disabled

という悲しいお知らせが載っていた。

x86_64だけど

# uname -a
Linux ******.******.****** 5.14.0-570.21.1.el9_6.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Jun 11 07:22:35 EDT 2025 x86_64 x86_64 x86_64 GNU/Linux

x86_64-v2のハズなんだが?

ググってみるとRedHat10では、AVX2命令が無いatom系やceleron系は未対応の様だ。

lscpuで調べると確かにavx2の文字が無かった。

過去には子猫(開発)版は対応してたらしいが今の開発版のleapp preupgradeでも同じだった。

ま、それはそれとして・・・

ELevateでAlmaLionux9から10へのアップデートを試みると

==================================================================
レポートの概要
=======================================================================

以下の問題によりアップグレードが中止されました。
1. 現在の x86-64 マイクロアーキテクチャは RHEL10 ではサポートされていません。

重大度が HIGH および MEDIUM のレポート:
1. システム上に Red Hat によって署名されていないパッケージが見つかりました。
2. GRUB2 コアはアップグレード中に自動的に更新されます。
3. カスタム leapp アクターまたはファイルが検出された。
4. Leapp は、RHEL 10 でメンテナンスが終了したカーネルドライバーがロードされていることを検出しました。
5. Leapp は、RHEL 10 でメンテナンスが終了したプロセッサーを検出しました。
6. システムに Berkeley DB (libdb) が検出されました。
7. システムに MariaDB (mariadb-server) が検出されました。

と、トドメを刺された。(CPUががが

レポートファイルを読むと

リスク要因: 高(阻害要因)
タイトル: 現在の x86-64 マイクロアーキテクチャは RHEL10 ではサポートされていません
概要: RHEL10 は以前のバージョンよりも CPU 要件が高く、x86-64-v3 命令セット以上と互換性のある CPU が必要です。

不足しているフラグ: avx2、bmi1、bmi2、f16c、fma、abm、xsave

関連リンク:
- x86-64-v3 マイクロアーキテクチャレベル向けの Red Hat Enterprise Linux 10 のビルド: https://red.ht/rhel-10-intel-microarchitectures
対策: [ヒント] 仮想化を使用する場合、仮想化プラットフォームでは、異なる CPU モデル間の移行時に互換性を確保するために、最小要件の CPU モデルを設定できることがよくあります。最小要件が RHEL10 の要件を下回らないことを確認してください。

x86-64-v3じゃないとダメらしい。

avx2、bmi1、bmi2、f16c、fma、abm、xsave

不足する機能も多い。(諦め

でもアップグレードが無理でも

クリーンインストールなら可能性があるかも(無いかも

嘆いても仕方が無いので仮想マシンかPodmanでAlmaLinux10が動くか確認してみる。

VMを作成できるが、OSのダウンロードで失敗。

でもサーバーが調整中かもしれない(よくある現象

isoイメージをダウンロードして/tmpに配置してみるもisoイメージが読めないエラー

Podmanでイメージをダウンロードし、コンテナを作成すると、【起動】しても一瞬も「実行」にならない。

ブートすらできない。

多分、ブートもx86_64-v3のみ対応するバージョンらしい。

先のISOを使ってi9-9900のWin11のHyper-VでVMを作成してみるとブートするのでDVDイメージ自体がCPUの依存が高い様だ。

そのままインストを続ける

(中略)

で、起動してみると、

残念、J1900はもう先が無い事が確定した。

firewall-cmd –list-allでポートを確認するとSSH(Secure ShellをON)とcockpitはポート開放しているので

接続できたけど、リモートデスクトップ(Desktop Sharing)がWindows11から繋がらない。やはりxrdp入れないとダメかと思ったらポート(3389)を解放したら繋がったがパスワードを覚えてくれないのがめんどくさい。

INTELのcore i3-n300あたりがTDPが7Wと少なくブログサーバに良さそうだ。RasberryPi4は発熱が酷いから常時稼働には不向き、他はパワーがJ1900未満で圧倒的に足りない。

古いCPUでもavx2をサポートしてるので、I5-5200U+DDR3も手かもしれない。

AMDはAMD Ryzen™ Embedded V2000のMini-ITXマザーボードも国外で売ってるっぽいが高い



[certbot-auto] fail 403

certbot-autoで403エラーが起きていた。

エラーの原因がよく解らないので放置してたけど

期限が近づいたので

そろそろ片付けないといけない

certbot-autoが使用するパスに「.」が含まれていたので、

 <Directory ~ "\/\..+\/">
   Require all denied
   Require ip {LANのセグメント}
 </Directory>
 <Files ~ "\/\..+\/">
   Require all denied
   Require ip {LANのセグメント}
 </Files>

の設定で403になっていたことに気が付いたので、以下を後付けした。

 <Location   {certbot-autoで使用する作業用urlパス}>
   Require all granted
 </Location>

普段certbot-autoで使用する作業用urlパスは存在しないので{ヨシ}としよう。

なお、IPアドレスでのアクセスを阻止する方法がうまく動作しないようだ



[javascript]クラスやメソッドの名前を表示する

処理中にクラス名を表示するのはコンストラクタのnameを表示するのが簡単です。

console.log(this.constructor.name);

クラスでは無いトコで使うと

Uncaught TypeError TypeError: Cannot read properties of undefined (reading 'constructor')

になります。

メソッド名が表示したい時はメソッドのnameプロパティが使えます。

class foo {
  xxxx() {
  const methodName = this.xxxx.name;
    console.log(methodName);  /* xxxx になる */
  }
}

ベタでmethodName = ‘xxxx’で良さそうですが、リファクタリングするとボロボロです。

厄介なのは派生クラスから基底クラスのメソッドを利用している時です。

class hoge extends foo {
  className = this.constructor.className;
  xxxx() {
    console.log(this.className); /* hoge になる */
    this.yyyy();
  }
}

class foo {
  className = this.constructor.className;
  yyyy() {
    console.log(this.className); /* hoge になる */
  }
}

大抵はこれで満足ですが、クラスfooのyyyならfooになって欲しい場合に

class hoge extends foo {
  /* className = new hoge().constructor.name; ではループするので、一旦staticなメンバーに入れます */
  static className = new hoge().constructor.name;
  className = hoge.className;
  xxxx() {
    console.log(this.className); /* hoge になる */
    this.yyyy();
  }
}

class foo {
  static className = new foo().constructor.name;
  className = foo.className;
  yyyy() {
    console.log(this.className); /* hoge になる */
  }
}

と書き込んでも、thisのコンストラクタのnameでは派生クラスの名前が出てきます。

そんな時はクラスのメンバーにclassName=クラス名を書けば解決しそうですが、

class hoge extends foo {
  static className = new hoge().constructor.name;
  className = hoge.className;
  xxxx() {
    console.log(this.className); /* hoge になる */
    this.yyyy();
  }
}

class foo {
  static className = new foo().constructor.name;
  className = foo.className;
  xxxx() {
    console.log(this.className); /* hoge になる */
  }
}

やはり、thisが強いので、派生クラスの名前が出てしまいますので、自分以外には見えない#classNameを使うと

class hoge extends foo {
  static className = new hoge().constructor.name;
  className = hoge.className;
  #className = hoge.className;
  xxxx() {
    console.log(this.className);  /* hoge になる */
    console.log(this.#className); /* hoge になる */
    this.yyyy();
  }
}

class foo {
  static className = new foo().constructor.name;
  className = foo.className;
  #className = foo.className;
  xxxx() {
    console.log(this.className);  /* hoge になる */
    console.log(this.#className); /* foo になる */
  }
}

やっと希望どおりになりますが、メンドクサイですし、new すると困る場合には向きません。

クラス名でコンストラクタの名前を取得すると・・・

class hoge {
   #className = hoge.constructor.name;
   xxxx() {
      console.log(this.#className); /* Function になる残念 */
   }
}

new した時にコンストラクタが名付けられるっぽい。



[spreadSheet7]デバッグ

ES-moduleにしたせいで、サーバに上げないと使えなくなってる。

index.htmlを開いて「Open with live server」でchromeでspreadSheet7を開き

chromeのDevToolでチマチマするのも面倒なので

VScodeの「chrome アタッチ」はchromeにデバッグオプションを付けないのでアタッチに失敗するので改造。urlはliveServerに合わせる。

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "Launch Chrome",
            "url": "http://127.0.0.1:5500",
            "webRoot": "${workspaceFolder}",
            "runtimeArgs": [
                "--remote-debugging-port=9222"
            ]
        }
    ]
}

これで無事live serverで表示しながらVScodeのデバッガが使えるようになる。

問題点は、やはりspreadSheet7がローカルで動かないことかな



[EBNF+]リテラルの記述

SpreadSheetでちょっと拡張したEBNFをベースに計算式等を評価させていたけど、

やはり顔文字にしか見えない正規表現とかメンドクサイ(ちょっと変えると拗ねるので)

特にリテラルの記述が面倒で、BNFっぽく

wq string   =   (*$ NO SPACE SKIP $*) '"', /(?!\\\\)[^"]*/, '"' ;

と苦し紛れだったので

wq string   =   '"' ・・・ '"' ;

BNFにこんな感じで書けると、とても楽そう

内部では

const encloseParser = parser.enclose(parser.token('"'), parser.search('"', true));

な感じで[ ” ]と[ ” ]で囲まれた文字リテラルを判定できる(ハズ

encloseはこんな感じで、囲まれたテキストを返す

/**
 * 記号で囲むリテラル用のパーサを作成する
 * @param {Function} leftParser   左囲みtoken
 * @param {Function} rightParser  右囲みsearch
 * @return {Function} 			  生成した連結パーサ
 */
enclose(leftParser, rightParser) {
  const methodName = 'enclose';
  const encloseParser = () => {
    const bkPosition = this.position;
    const leftParsed = leftParser();
    if (!leftParsed.status) {
      return new ParserResult(false, null, bkPosition);
    }
    const rightParsed = rightParser();
    if (!rightParsed.status) {
      return new ParserResult(false, null, bkPosition);
    }
    const encloseText = this.target.substring(leftParsed.position, rightParsed.position - rightParsed.result.length);
    return new ParserResult(true, encloseText, this.position);
  };
  encloseParser.type = methodName;
  return this.parserWraper(encloseParser;
};

見慣れないsearchパーサは、

/**
 * 一致するパターンを検索するパーサを生成する
 * yオプションを付けないregExpバージョン
 * @param {string} text       検索パターン
 * @param {boolean} fEscape   エスケープ処理
 * @return {Function}         生成したパーサ
 */
search(text, fEscape = undefined) {
  const methodName = 'token';
  const len = text.length;
  // エスケープ処理の指定が無い場合
  if (fEscape === undefined) { fEscape = this.fEscape; }
  const rePat = `(${(fEscape) ? '?<!\\\\)(' : ''}${regExpEscape(text)})`;
  const re = new RegExp(rePat, '');
  const searchParser = this.regexp(re, 'gm'); // yオプションを付けないregExpバージョン
  searchParser.type = methodName;
  return searchParser;  // regexpParserでparserWraper済
};

ほぼyオプションの無いパターンを探しにいってしまうregexp処理になっているので

regexpもちょっと変更

/**
  *  正規表現パーサを作成する
  * @param {RegExp} re  正規表現
  * @param {*} options  オプション  ※未設定の場合は、正規表現のオプション+gmyオプション
  * @return {Function}  生成したパーサ
  */
regexp(re, options) { // g:lastIndexから開始、m:複数行、y:lastIndexでのみ判定
  const methodName = 'regexp';
  const source = re.source;
  if (options === undefined) {
    options = (re.hasIndices ? 'd' : '')
      + (re.global ? 'g' : 'g')     /* lastIndex利用が必須なため、常時gオプションを付加 */
      + (re.ignoreCase ? 'i' : '')
      + (re.multiline ? 'm' : 'm')  /* 改行を跨いで処理すたい場合もあるので、常時mオプションを付加 */
      + (re.dotAll ? 's' : '')
      + (re.unicode ? 'u' : '')
      + (re.unicodeSets ? 'v' : '')
      + (re.sticky ? 'y' : 'y')     /* regexpは index=0 のみ判定する方が都合が良いので、常時yオプションを付加 */
      ;
  }
  try {
    re = new RegExp(source, options);
  } catch (ex) {
    const msg = `${rgis.className}.${methodName}: new RegExp fail, ex:'${ex}'`;
    console.error(msg);
    throw new Error(msg);
  }
  /**
   *  生成した正規表現パーサ
   * @return {ParserResult}       パースした結果
   */
  const regexpParser = () => {/* regexp */
    re.lastIndex = this.position;                                       // 再利用時のため
    const result = re.exec(this.target);                        // とりあえず正規表現で実行
    if (result) {
      // 読取りに成功した場合
      const foundText = result[0];
      // ログに追記
      this.mapLog.addSuccessToken(foundText);
      // 読取り位置を更新
      this.position = result.index + foundText.length;
      return new ParserResult(true, foundText, this.position);
    } else {
      // 読取りに失敗した場合
      // ログに追記
      this.mapLog.addFailToken(source);
      return new ParserResult(false, null, this.position);
    }
  };
  regexpParser.type = methodName;
  return this.parserWraper(regexpParser, true, false);
};

普通は、こんなBNF表記を挟まずに直接パーサコンビネーションを作りはじめるハズだが・・・

最終的には「湯出たてのスパゲッティー」にソースや香辛料をかけて、食べやすく「フォークで絡めて」食べる訳で、文法をちょっとイジるにも脳内のイメージを頼りにパーサコンビネーションをイジるから

バグると「脳内のイメージが間違ってる場合」と「勘違いしてコードしている場合」を切り分けるのが非常に難しい。

あと、パーサはまとめてクラス化してるので各パーサにテキストや読込位置をパラメータで渡すのを止めてみたから、SpreadSheetに組み込むのは完成した後になる。

今は、

    {
        title: "sequenceメソッド:正常パターン4",
        testCase: () => {
            const parser = new CoreParser('abc=defghijklmnopqrstuvwxyz')
            const sequenceParser1 = parser.sequence([parser.token('abc'), parser.token('='), parser.token('def')]);
            const rc = [];
            rc.push(sequenceParser1());
            return rc;
        },
        expectedResult: [
            { status: true, result: ['abc', '=', 'def'], position: 7, },
        ],
    },
test[4:sequenceメソッド:正常パターン4] success. => [ 0:{ "status": true, result:[ "0": "abc", "1": "=", "2": "def", ], "position": 7, }, ], 

単体テストを消化中。

これがいっぱい修正漏れが出るんだなぁ(笑

後になって、実行するパーサや結果がどのパーサが作ったのか判るようにtypeを追加してみたり

※用途未定

テスト結果の判定経過を出力させたり

[ 0:{ "status": true, result:[ "0": "abc", "1": "=", "2": "def", ], "position": 7, }, ], 

とか、出来てしまえば不要に思えるけど、バグったら必須な機能をパーサ本体の外においても

パーサ本体が600行にもなってしまう。

ps.2025/5/12

「?」最小マッチングで

/'.*?'/
👉 / ' .* ? ' /          ※見やすいように空白を挟んでみた

と’…..’をお手軽にマッチングできるけど、エスケープ(\’)が混ざるとどうして良いのか判らなかったけど、

'(.*?\\')*.*?'
👉 ' (.* ? \\' )* .* ? '   ※見やすいように空白を挟んでみた

の様に「エスケープ(\’)を0回以上繰り返す」を挟めばOKだった。

気づけば簡単すぎ。(大笑

だがどうやってうまく処理できてるのか?

.* ? \’ から .* ? ‘ に遷移するには

先回りして「\\’」や「’」の位置を把握し存在を確認し、「\\’」や「’」の直後に切り詰めてマッチングし、存在しなければ左部のマッチングをしないのかな?

※\\’が存在しない長いテキストを渡すと重そうだけど

正規表現も

/ .* /
こんなザックリとした表現は意味は読み取れるけど使い物にならないが
👉 / .* ? /
でちょっとは使えるので、
正規表現内で/が出現する状況を挟み込んで
👉 / ((.* ? \/)|(.* ? [/)|(.* ?(/)|(.* ?{/))* .* ? /  ※ / に 4連の (.* ? を仕掛けるぞ(的な
で良いのかもしれない。
※とても十分な検証をする気にはならないががが

で済むのかな?

顔文字表現より見やすい気がするけど、ジェットストリームっぽくドムだから処理が重いかも。



[spreadsheet6]組込関数の登録

functionsディレクトリィの組込関数の登録にはHTMLにscriptタグをいっぱい書かないと処理しないのでfunctionsディレクトリィのjsファイルの一覧をfunctions.jsonに手書きで作成し起動時に読込でimport() ×jsファイル数で関数を登録させてた

手書きしなくても

  • ファイル一覧を取得
  • jsonテキストに変換
  • ファイルに出力

をググってサンプルを探し

// 組込関数まとめ.js
//
// path変数が示すディレクトリィに存在する拡張子がjsのファイルの一覧を
// fname変数で指定したファイルにJSON形式で出力する
//
import { default as fs } from "fs";

const path = './js/spreadSheet/functions/';
// ディレクトリィのファイルリストを取得
const files = fs.readdirSync(path)
    .filter((fname) => {
        // 拡張子がjsのファイルのみ残す
        const [name, ext] = fname.split('.');
        return (ext === 'js');
    })
    ;

// ファイル一覧(型:配列)をJSON形式のテキストに変換する
const text = JSON.stringify(files, "", 2);

// 非同期にファイルに書き込む
const fname = "functions.json";
fs.writeFile(`${path}${fname}`, text, (err) => {
    if (err) {
        console.log(`'${path}${fname}' file write err\n${err.message}\n${err.stack.split('\\n')}`);
    } else {
        console.log(`'${path}${fname}' file write\n'${text}'\n`);
    }
});
// end of 関数集計.js/

繋げたら出来ました。

たまにはこんなこともあるんだなぁ~

ただし、実行してみると

[MODULE_TYPELESS_PACKAGE_JSON] Warning: Module type ・・・

と長い注意書きがコンソールに出てきた。

package.jsonにtype=’model’を書いて無いから、common jsだと思って実行したけど、import文があるからES-moduleのハズだからやっといたよ?的な内容だった。

やっぱり、何事も無く無事に完了するワケがなかった。(合掌



[AlmaLinux]wasmerって何?

wasmerは色々な言語のソースコードをWebAssemblyに変換して実行環境を作成し実行してみせるパッケージ。WebAssemblyしか動かない軽量なコンテナっぽいモノは外部とは実行時にパラメータとして与えるCallBackしかなさげなので安全性は高め。

また、jsモジュール化したパッケージがあり、ブラウザで動作するためコンテナっぽいモノはドコでも動く感じ。しかし普通に考えればHTMLにコンテナのソース数分つまり大量の<script>タグを書かないと動かない気もするが、wasmerを利用する自前のJSファイルをESモジュール化し、

<script type="module" src="xxxxx.js">

そのjs1行目にwasmer/sdkをimportすれば、

import { init, Wasmer } from "@wasmer/sdk";

後はwasmer/sdkが必要な分のimportをしてくれるので、ブラウザで容易に動作できそうな感じ。

勿論、直接指示しなくて良くても、大量のアクセスが起きうるので、以降のコードも同期が取れるまで待機する様にawait指示が必須になる。

import { init, Wasmer } from "@wasmer/sdk";
await init();
const pkg = await Wasmer.fromRegistry("python/python");

一応外部とはオフラインでもfromFileで利用可能だが、他プロジェクトへ提供しているパッケージではテストスイートが数GBにもなっているモノもあるのが難

※ パッケージを/path/にダウンロード済みなら
Wasmer.fromFile(/path/);
※も可。

無理と思いつつ、wordpressをwasmerでコンパイルする方法をググってみたが、

WordPressをWasmerでコンパイルするというのは、WordPressの主要な言語であるPHPをWebAssembly(WASM)に変換し、
WasmerというWASMランタイム環境で実行するという意味です。しかし、WordPressの構造がPHPに依存しているため、
WordPress全体をWasmerで動かすことは現実的ではありません。Wasmerは主にC/C++、Rustなどの言語で記述された
コードをWASMに変換し、ブラウザの外でも実行できる環境を提供するもので、WordPressのような動的なウェブアプリ
ケーションを直接コンパイルするような仕組みではありません。

やはり無理っぽいが作ってる人もいるが全部ブラウザ上で動くみたいでプラグイン作成者向けらしい。

ふと、spreadsheet5のscriptタグが多すぎなのに気が付いたのでESモジュール化してHTMLを短くし、CSSや処理中表示もカスタムエレメントに組込んだ。jsスクリプトファイルはネームスペースを圧縮した後だったのでごっそりと圧縮前に戻した。HTMLは短くなるけど、1ファイル毎にしっかりimport/exportしないとエラるので大変で、実行時にエラる時もあるのがとてもメンドイ。数値、文字を入力し計算式も結果が出るからOKかな?

本題に戻りwasmerインストの通りにインストしてみる。

$ curl https://get.wasmer.io -sSfL | sh
/usr/bin/which: no wasmer in (/home/***/.local/bin:/home/***/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)
Welcome to the Wasmer bash installer!

               ww
               wwwww
        ww     wwwwww  w
        wwwww      wwwwwwwww
ww      wwwwww  w     wwwwwww
wwwww      wwwwwwwwww   wwwww
wwwwww  w      wwwwwww  wwwww
wwwwwwwwwwwwww   wwwww  wwwww
wwwwwwwwwwwwwww  wwwww  wwwww
wwwwwwwwwwwwwww  wwwww  wwwww
wwwwwwwwwwwwwww  wwwww  wwwww
wwwwwwwwwwwwwww  wwwww   wwww
wwwwwwwwwwwwwww  wwwww
   wwwwwwwwwwww   wwww
       wwwwwwww
           wwww

downloading: wasmer-linux-amd64
Latest release: v6.0.0
/usr/bin/which: no wasmer in (/home/***/.wasmer/bin)
Downloading archive from https://github.com/wasmerio/wasmer/releases/download/v6.0.0/wasmer-linux-amd64.tar.gz
######################################################################## 100.0%
installing: /home/***/.wasmer
Updating bash profile /home/***/.bashrc
we've added the following to your /home/***/.bashrc
If you have a different profile please add the following:

# Wasmer
export WASMER_DIR="/home/***/.wasmer"
[ -s "$WASMER_DIR/wasmer.sh" ] && source "$WASMER_DIR/wasmer.sh"
check: wasmer 6.0.0 installed successfully ✓
wasmer will be available the next time you open the terminal.
If you want to have the commands available now please execute:

source /home/***/.wasmer/wasmer.sh
$

「すぐ使うなら・・・」と書いてある様に上のsourceコマンドを手打ちすると即使える。

wasmerのtemplatesでserverを検索すると静的WebServerがあったのでインストしてみた。

$ curl --proto '=https' --tlsv1.2 -sSfL https://get.static-web-server.net | sh
info: platform 'x86_64-unknown-linux-gnu' supported
info: downloading the 'static-web-server v2.36.1' pre-compiled binary...
info: installing pre-compiled binary in /usr/local/bin...
Copying SWS pre-compiled binary to /usr/local/bin...
[sudo] password for ***: 
info: pre-compiled binary installed on /usr/local/bin/static-web-server
Version:      2.36.1
Built:        2025-04-01 22:00:32 +00:00
Git commit:   ab44158182e4e29dcece4c3b10068dc596bf9e03
Build target: x86_64-unknown-linux-gnu
Rust version: rustc 1.85.1 (4eb161250 2025-03-15)
License:      MIT OR Apache-2.0
Homepage:     https://static-web-server.net
Author:       Jose Quintana <https://joseluisq.net>
SWS was installed successfully!
To uninstall SWS just remove it from its location.
$
$ static-web-server
Caused by:
    path ./public was not found or inaccessible
$ mkdir public
$ static-web-server
・・・
INFO static_web_server::info: cache control headers: enabled=true
INFO static_web_server::info: security headers: enabled=false
INFO static_web_server::info: http1 server is listening on http://[::]:80
INFO static_web_server::info: press ctrl+c to shut down the server
^C WARN static_web_server::warn: termination signal caught, shutting down the server execution
$ 

デフォルトでは”./public”らしいので、swsの設定ファイルは~/.wasmer/sws/config.tomlに変更し、

# Wasmer config
export WASMER_DIR="/home/***/.wasmer"
export WASMER_CACHE_DIR="$WASMER_DIR/cache"
export PATH="$WASMER_DIR/bin:$PATH"
# for sws
export SERVER_CONFIG_FILE="$WASMER_DIR/sws/config.toml"
# end of wasmer.sh.

その中で、rootフォルダは~/.wasmer/sws/publicに、ポートも8080に変更してみた。

設定のデフォルト値はこちら

[general]

#### Address & Root dir
host = "::"
port = 8080
root = "${WASMER_DIR}/sws/public"

#### Logging
log-level = "error"
・・・


[javascript]binaryen.js

binaryen.jsはbinaryenのjs版。延々とビルドせずに使えるのが嬉しい。

binaryenの説明文に「 used from JavaScript. 」って書いてあるけど、その先はパスにwikiがあるので説明だけ。ググり続け、npmのリポジトリィを見つけた。

npm install binaryen

元ネタのリポジトリィは、github.com/AssemblyScript/binaryen.jsのindex.jsだそうだ。

ちなみにそこをクローンすると6GB以上あるのでnpmで済ませる。

パッケージ本体はTypeScriptで書かれていて配布用のindex.jsは圧縮されほぼ解読不能。

npmのページのサンプルコードを入力して実行すると

Uncaught Error Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. To see where the top-level await comes from, use --experimental-print-required-tla.

どうやらnpmのページのサンプルは5年前の書き方らしい。
var binaryen = require(“binaryen”);
を元ネタのページのサンプルの様に
import binaryen from “binaryen”;
に直すと動き出したが、直ぐエラってしまうので、※5年の間に色々変わり過ぎ
全部元ネタのページのサンプルに差し替えると最後まで動いた。
ちなみにこの記事を書いている時点でのモジュールのupdateは4時間前。※出来たてホヤホヤ

それにしても
jsのアロー関数とか、
wasmのテキストがS式とか、
大昔に卒論で(デバッグのために)いっぱい書いたから違和感はないけど
なんで大昔(半世紀くらい前)に流行ったフォーマットを使うんだろう?

謎(闇?)は深い。

binaryen.jsはTypeScriptベースのjavascriptソースで提供されている。

Node.jsでサンプルを実行する分にはnpmで作った設定ファイル等を参照してくれるのでパッケージ名だけ指定すればOK。

import binaryen from "binaryen";

ブラウザ(Chrome)で使用する場合はスクリプト・タグのタイプを”module”指定しimport文を使用可能にしてもnpmプロジェクトとか気に留めてないので直接node_modules/binaryenプロジェクトのpackage.jsonに”main”:”index.js”と書かれたファイルを相対パスで指定しないといけない。

chromeで表示するHTMLで<script type="module" src="./worker.js">とtypeでmodule指定しないとimportが使えない

import binaryen from "./node_modules/binaryen/index.js"; ※npm install binaryen したなら皆同じになるハズ

※ローカルな環境(file:///)ではimportがアクセスエラーで使えないっぽく、何かのWebサービス(apache等)上にHTML等を配置する必要がある。

index.html:1 Access to script at 'file:///・・・/test/worker.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: chrome, chrome-extension, chrome-untrusted, data, http, https, isolated-app.
worker.js:1 
Failed to load resource: net::ERR_FAILED

さらに厄介なのが、HTMLやtype=”text/script”(デフォルト設定)のjavascriptからtype=”module”を指定するモジュールが見えない(DevToolでモジュール欄すら出ない)のでpostMessageを経由してイベントを通知しないとダメらしい。※moduleと指定してるのでworker.jsをワーカーとして実行しなくてよい。

window.addEventListener("load", () => {
    document.querySelector("#btn").addEventListener("click", test);
});
const test = () => {
    postMessage("test", "http://localhost:xxxxx"とか);
}

それより全スクリプトをtype=”module”にすればいい、モジュールにはwindow.addEventListener(“load”, の通知が来ないが、 モジュールにはdefer属性が自動付与されるから、即DOMにアクセスできる。

import binaryen from "./node_modules/binaryen/index.js";

//# とりあえず、urlからドメインとポートを取り出してポストメッセージのチェックに使用する
//# function getDomainPort() {
//#     const url = import.meta.url;
//#     const result = /^(http[s]?:\/\/([.0-9a-z]+)(:\d+)?)/.exec(url);
//#     return result[0];
//# }
document.querySelector("#btn").addEventListener("click", workerTest);※これで解決

// アロー関数にするとworkerTest実行時にChromeのDevToolの範囲のモジュールに
// 自分の関数名が出ないので再帰する時は困るかもしれない。
function workerTest(event) {
    try {
        //# if (event.origin !== getDomainPort()) {
        //#     return;
        //# }
        // Create a module with a single function
        myModule.addFunction("add",                                 // 以下、ボクの理解範囲
            binaryen.createType([binaryen.i32, binaryen.i32]),      // parames: [引数[0]の型, 引数[1]の型]
            binaryen.i32,                                           // result: 戻り値の型
            [binaryen.i32],                                         // vars: スタックを型付き配列風に宣言
            myModule.block(null, [
                myModule.local.set(2,                               // 結果を スタック[2] に格納
                    myModule.i32.add(                               //   加算(スタックの2つの変数を加算)
                        myModule.local.get(0, binaryen.i32),        //      引数[0]をスタックに積む
                        myModule.local.get(1, binaryen.i32)         //      引数[1]をスタックに積む
                    )
                ),
                myModule.return(                                    // 戻り値は下記の様にスタックされる
                    myModule.local.get(2, binaryen.i32)             //   スタック[2]をスタックに積む
                )
            ])
        );
        myModule.addFunctionExport("add", "add");                   // 上の"add"関数を"add"の名前で外部参照を宣言

        // Optimize the module using default passes and levels
        myModule.optimize();                                        // 最適化

        // Validate the module
        if (!myModule.validate())                                   // 計算でエラったら
            throw new Error("validation error");                    // "validation error"とスローする

        // Generate text format and binary
        var textData = myModule.emitText();                         // 上記の設定からテキスト(S式)で得る
        var wasmData = myModule.emitBinary();                       // 上記の設定からWebAssemblyコードで得る

        // Example usage with the WebAssembly API
        var compiled = new WebAssembly.Module(wasmData);            // WebAssemblyコードを含むモジュールを生成
                                      //  importのリンク情報等を設定?
        var instance = new WebAssembly.Instance(compiled, {});      // 実行可能なモジュールのインスタンスを生成
        const result = (instance.exports.add(41, 1));               // インスタンスを実行させてみる

        document.querySelector("#result").innerHTML = `textData:${textData}<br/>result:${result}<br/>`;
};
window.addEventListener("message", workerTest);

うっかりすると、localってローカルな変数かと思うけどスタックマシンなのでlocal=stack。

myModule.local.set(2, よりも myModule.local.set(0, の方が良いと思うけど、最適化(Module.optimize())でS式はいづれも同じになる。

(module
   (type $0 (func (param i32 i32) (result i32)))
     (export "add" (func $add))
       (func $add (param $0 i32) (param $1 i32) (result i32)
         (i32.add (local.get $0) (local.get $1) ) ) )    ※明示的にパラメータをスタックに積む様になってる

ここまで面倒になってるものの、以前はmodule側からは一切DOMにアクセスできなかったと思うが

document.querySelector(“#result”)が可能になってるのは助かる。

とりあえず、podmanの未公開なapacheにソースを配置してVScodeでリモートデバッグを心掛ければ支障は無さそう。

VScodeの拡張機能でLive ServerLive Previewを使うのも手軽かも。いづれもVScode上でのデバッグはできないが、

Live Serverは、HTMLエディタ上で右クリックして「Open with Live Server」でブラウザで開けるしDevToolでデバッグが可能。

Live Previewも同様に「Show Preview」でスグ見れる、見れるダケだけど。

LiveServerがどのポートを使うのか判らないのでgetDomainPort()みたいにLiveServerが割り当てたurlからドメインとポートが得られるようにした方が気楽。



[AlmaLinux]Ninja

wabtのtestスイートのmakeにはPython3が必須。

条件を満たしているのでビルドしてみると

$ make test
which: no emcc in (/home/****/.local/bin:/home/****/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)
cd out/clang/Debug/ && cmake -G Ninja /home/****/wabt/ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug 
CMake Error: CMake was unable to find a build program corresponding to "Ninja".  CMAKE_MAKE_PROGRAM is not set.  You probably need to select a different build tool.
-- Configuring incomplete, errors occurred!
make: *** [Makefile:156: out/clang/Debug/build.ninja] エラー 1

Ninjaが必要らしいが、dnfのepelリポジトリにも無い

ソースからビルドしてみる。詳細はgithub

# git clone https://github.com/ninja-build/ninja.git
Cloning into 'ninja'...
remote: Enumerating objects: 13476, done.
remote: Counting objects: 100% (369/369), done.
remote: Compressing objects: 100% (222/222), done.
remote: Total 13476 (delta 266), reused 147 (delta 147), pack-reused 13107 (from 6)
Receiving objects: 100% (13476/13476), 5.12 MiB | 1.82 MiB/s, done.
Resolving deltas: 100% (9425/9425), done.
# cmake -Bbuild-cmake ※ビルド事前設定のオプションらしい -DBUILD_TESTING=OFF付加でユニットテスト無効も可
-- The CXX compiler identification is GNU 11.5.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- IPO / LTO enabled
-- Performing Test flag_no_deprecated
-- Performing Test flag_no_deprecated - Success
-- Looking for ppoll
-- Looking for ppoll - found
CMake Warning at CMakeLists.txt:82 (message):
  re2c 2 or later was not found; changes to src/*.in.cc will not affect your
  build.


-- Looking for fork
-- Looking for fork - found
-- Looking for pipe
-- Looking for pipe - found
-- Could NOT find GTest (missing: GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY) 
-- The C compiler identification is GNU 11.5.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found Python: /usr/bin/python3.9 (found version "3.9.21") found components: Interpreter 
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE  
-- Configuring done (10.9s)
-- Generating done (0.2s)
-- Build files have been written to: /root/ninja/build-cmake
# cmake --build build-cmake
[  1%] Building CXX object CMakeFiles/libninja-re2c.dir/src/depfile_parser.cc.o
[  2%] Building CXX object CMakeFiles/libninja-re2c.dir/src/lexer.cc.o
[  2%] Built target libninja-re2c
[  3%] Building CXX object CMakeFiles/libninja.dir/src/build_log.cc.o
[  5%] Building CXX object CMakeFiles/libninja.dir/src/build.cc.o
[  6%] Building CXX object CMakeFiles/libninja.dir/src/clean.cc.o
[  7%] Building CXX object CMakeFiles/libninja.dir/src/clparser.cc.o
[  8%] Building CXX object CMakeFiles/libninja.dir/src/dyndep.cc.o
[ 10%] Building CXX object CMakeFiles/libninja.dir/src/dyndep_parser.cc.o
[ 11%] Building CXX object CMakeFiles/libninja.dir/src/debug_flags.cc.o
[ 12%] Building CXX object CMakeFiles/libninja.dir/src/deps_log.cc.o
[ 14%] Building CXX object CMakeFiles/libninja.dir/src/disk_interface.cc.o
[ 15%] Building CXX object CMakeFiles/libninja.dir/src/edit_distance.cc.o
[ 16%] Building CXX object CMakeFiles/libninja.dir/src/elide_middle.cc.o
[ 17%] Building CXX object CMakeFiles/libninja.dir/src/eval_env.cc.o
[ 19%] Building CXX object CMakeFiles/libninja.dir/src/graph.cc.o
[ 20%] Building CXX object CMakeFiles/libninja.dir/src/graphviz.cc.o
[ 21%] Building CXX object CMakeFiles/libninja.dir/src/json.cc.o
[ 23%] Building CXX object CMakeFiles/libninja.dir/src/line_printer.cc.o
[ 24%] Building CXX object CMakeFiles/libninja.dir/src/manifest_parser.cc.o
[ 25%] Building CXX object CMakeFiles/libninja.dir/src/metrics.cc.o
[ 26%] Building CXX object CMakeFiles/libninja.dir/src/missing_deps.cc.o
[ 28%] Building CXX object CMakeFiles/libninja.dir/src/parser.cc.o
[ 29%] Building CXX object CMakeFiles/libninja.dir/src/real_command_runner.cc.o
[ 30%] Building CXX object CMakeFiles/libninja.dir/src/state.cc.o
[ 32%] Building CXX object CMakeFiles/libninja.dir/src/status_printer.cc.o
[ 33%] Building CXX object CMakeFiles/libninja.dir/src/string_piece_util.cc.o
[ 34%] Building CXX object CMakeFiles/libninja.dir/src/util.cc.o
[ 35%] Building CXX object CMakeFiles/libninja.dir/src/version.cc.o
[ 37%] Building CXX object CMakeFiles/libninja.dir/src/subprocess-posix.cc.o
[ 37%] Built target libninja
[ 38%] Generating build/browse_py.h
[ 39%] Building CXX object CMakeFiles/ninja.dir/src/ninja.cc.o
[ 41%] Building CXX object CMakeFiles/ninja.dir/src/browse.cc.o
[ 42%] Linking CXX executable ninja
[ 42%] Built target ninja
[ 43%] Building CXX object _deps/googletest-build/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o
[ 44%] Linking CXX static library ../../../lib/libgtest.a
[ 44%] Built target gtest
[ 46%] Building CXX object CMakeFiles/ninja_test.dir/src/build_log_test.cc.o
[ 47%] Building CXX object CMakeFiles/ninja_test.dir/src/build_test.cc.o
[ 48%] Building CXX object CMakeFiles/ninja_test.dir/src/clean_test.cc.o
[ 50%] Building CXX object CMakeFiles/ninja_test.dir/src/clparser_test.cc.o
[ 51%] Building CXX object CMakeFiles/ninja_test.dir/src/depfile_parser_test.cc.o
[ 52%] Building CXX object CMakeFiles/ninja_test.dir/src/deps_log_test.cc.o
[ 53%] Building CXX object CMakeFiles/ninja_test.dir/src/disk_interface_test.cc.o
[ 55%] Building CXX object CMakeFiles/ninja_test.dir/src/dyndep_parser_test.cc.o
[ 56%] Building CXX object CMakeFiles/ninja_test.dir/src/edit_distance_test.cc.o
[ 57%] Building CXX object CMakeFiles/ninja_test.dir/src/elide_middle_test.cc.o
[ 58%] Building CXX object CMakeFiles/ninja_test.dir/src/explanations_test.cc.o
[ 60%] Building CXX object CMakeFiles/ninja_test.dir/src/graph_test.cc.o
[ 61%] Building CXX object CMakeFiles/ninja_test.dir/src/json_test.cc.o
[ 62%] Building CXX object CMakeFiles/ninja_test.dir/src/lexer_test.cc.o
[ 64%] Building CXX object CMakeFiles/ninja_test.dir/src/manifest_parser_test.cc.o
[ 65%] Building CXX object CMakeFiles/ninja_test.dir/src/missing_deps_test.cc.o
[ 66%] Building CXX object CMakeFiles/ninja_test.dir/src/ninja_test.cc.o
[ 67%] Building CXX object CMakeFiles/ninja_test.dir/src/state_test.cc.o
[ 69%] Building CXX object CMakeFiles/ninja_test.dir/src/string_piece_util_test.cc.o
[ 70%] Building CXX object CMakeFiles/ninja_test.dir/src/subprocess_test.cc.o
[ 71%] Building CXX object CMakeFiles/ninja_test.dir/src/test.cc.o
[ 73%] Building CXX object CMakeFiles/ninja_test.dir/src/util_test.cc.o
[ 74%] Linking CXX executable ninja_test
[ 74%] Built target ninja_test
[ 75%] Building CXX object CMakeFiles/build_log_perftest.dir/src/build_log_perftest.cc.o
[ 76%] Linking CXX executable build_log_perftest
[ 76%] Built target build_log_perftest
[ 78%] Building CXX object CMakeFiles/canon_perftest.dir/src/canon_perftest.cc.o
[ 79%] Linking CXX executable canon_perftest
[ 79%] Built target canon_perftest
[ 80%] Building CXX object CMakeFiles/clparser_perftest.dir/src/clparser_perftest.cc.o
[ 82%] Linking CXX executable clparser_perftest
[ 82%] Built target clparser_perftest
[ 83%] Building CXX object CMakeFiles/depfile_parser_perftest.dir/src/depfile_parser_perftest.cc.o
[ 84%] Linking CXX executable depfile_parser_perftest
[ 84%] Built target depfile_parser_perftest
[ 85%] Building CXX object CMakeFiles/elide_middle_perftest.dir/src/elide_middle_perftest.cc.o
[ 87%] Linking CXX executable elide_middle_perftest
[ 87%] Built target elide_middle_perftest
[ 88%] Building CXX object CMakeFiles/hash_collision_bench.dir/src/hash_collision_bench.cc.o
[ 89%] Linking CXX executable hash_collision_bench
[ 89%] Built target hash_collision_bench
[ 91%] Building CXX object CMakeFiles/manifest_parser_perftest.dir/src/manifest_parser_perftest.cc.o
[ 92%] Linking CXX executable manifest_parser_perftest
[ 92%] Built target manifest_parser_perftest
[ 93%] Building CXX object _deps/googletest-build/googlemock/CMakeFiles/gmock.dir/src/gmock-all.cc.o
[ 94%] Linking CXX static library ../../../lib/libgmock.a
[ 94%] Built target gmock
[ 96%] Building CXX object _deps/googletest-build/googlemock/CMakeFiles/gmock_main.dir/src/gmock_main.cc.o
[ 97%] Linking CXX static library ../../../lib/libgmock_main.a
[ 97%] Built target gmock_main
[ 98%] Building CXX object _deps/googletest-build/googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o
[100%] Linking CXX static library ../../../lib/libgtest_main.a
[100%] Built target gtest_main
#

うまくいったみたいなのでインスト

# cmake --install ./build-cmake/
-- Install configuration: ""
-- Up-to-date: /usr/local/include
-- Installing: /usr/local/include/gmock
-- Installing: /usr/local/include/gmock/gmock-actions.h
-- Installing: /usr/local/include/gmock/gmock-cardinalities.h
-- Installing: /usr/local/include/gmock/gmock-function-mocker.h
-- Installing: /usr/local/include/gmock/gmock-matchers.h
-- Installing: /usr/local/include/gmock/gmock-more-actions.h
-- Installing: /usr/local/include/gmock/gmock-more-matchers.h
-- Installing: /usr/local/include/gmock/gmock-nice-strict.h
-- Installing: /usr/local/include/gmock/gmock-spec-builders.h
-- Installing: /usr/local/include/gmock/gmock.h
-- Installing: /usr/local/include/gmock/internal
-- Installing: /usr/local/include/gmock/internal/custom
-- Installing: /usr/local/include/gmock/internal/custom/README.md
-- Installing: /usr/local/include/gmock/internal/custom/gmock-generated-actions.h
-- Installing: /usr/local/include/gmock/internal/custom/gmock-matchers.h
-- Installing: /usr/local/include/gmock/internal/custom/gmock-port.h
-- Installing: /usr/local/include/gmock/internal/gmock-internal-utils.h
-- Installing: /usr/local/include/gmock/internal/gmock-port.h
-- Installing: /usr/local/include/gmock/internal/gmock-pp.h
-- Installing: /usr/local/lib64/libgmock.a
-- Installing: /usr/local/lib64/libgmock_main.a
-- Installing: /usr/local/lib64/pkgconfig/gmock.pc
-- Installing: /usr/local/lib64/pkgconfig/gmock_main.pc
-- Installing: /usr/local/lib64/cmake/GTest/GTestTargets.cmake
-- Installing: /usr/local/lib64/cmake/GTest/GTestTargets-noconfig.cmake
-- Installing: /usr/local/lib64/cmake/GTest/GTestConfigVersion.cmake
-- Installing: /usr/local/lib64/cmake/GTest/GTestConfig.cmake
-- Up-to-date: /usr/local/include
-- Installing: /usr/local/include/gtest
-- Installing: /usr/local/include/gtest/gtest-assertion-result.h
-- Installing: /usr/local/include/gtest/gtest-death-test.h
-- Installing: /usr/local/include/gtest/gtest-matchers.h
-- Installing: /usr/local/include/gtest/gtest-message.h
-- Installing: /usr/local/include/gtest/gtest-param-test.h
-- Installing: /usr/local/include/gtest/gtest-printers.h
-- Installing: /usr/local/include/gtest/gtest-spi.h
-- Installing: /usr/local/include/gtest/gtest-test-part.h
-- Installing: /usr/local/include/gtest/gtest-typed-test.h
-- Installing: /usr/local/include/gtest/gtest.h
-- Installing: /usr/local/include/gtest/gtest_pred_impl.h
-- Installing: /usr/local/include/gtest/gtest_prod.h
-- Installing: /usr/local/include/gtest/internal
-- Installing: /usr/local/include/gtest/internal/custom
-- Installing: /usr/local/include/gtest/internal/custom/README.md
-- Installing: /usr/local/include/gtest/internal/custom/gtest-port.h
-- Installing: /usr/local/include/gtest/internal/custom/gtest-printers.h
-- Installing: /usr/local/include/gtest/internal/custom/gtest.h
-- Installing: /usr/local/include/gtest/internal/gtest-death-test-internal.h
-- Installing: /usr/local/include/gtest/internal/gtest-filepath.h
-- Installing: /usr/local/include/gtest/internal/gtest-internal.h
-- Installing: /usr/local/include/gtest/internal/gtest-param-util.h
-- Installing: /usr/local/include/gtest/internal/gtest-port-arch.h
-- Installing: /usr/local/include/gtest/internal/gtest-port.h
-- Installing: /usr/local/include/gtest/internal/gtest-string.h
-- Installing: /usr/local/include/gtest/internal/gtest-type-util.h
-- Installing: /usr/local/lib64/libgtest.a
-- Installing: /usr/local/lib64/libgtest_main.a
-- Installing: /usr/local/lib64/pkgconfig/gtest.pc
-- Installing: /usr/local/lib64/pkgconfig/gtest_main.pc
-- Installing: /usr/local/bin/ninja

とんでもない数

ninja --version
1.13.0.git

一応インストできたっぽい

ところが先のtestスイートの実行がfailする。あきらめてtest/run-tests.py




top