ブログ

プログラミング

RustとC言語の連携

RustからC言語で作成したライブラリを呼び出すのは比較的簡単に実現できます。以下の1本のシェルでは,Cのライブラリを書き出して,Rustから呼び出すプログラムを作成します。

Rustのコード内にextern “C”でC言語の関数のプロトタイプ宣言に相当するインタフェース定義を記述した上で,呼び出す時にunsafeで囲んでやれば呼び出せます。rustcでコンパイルする際に,-lオプションでライブラリ名を指定して,-Lオプションでライブラリの場所を指定する必要があります。

#!/bin/bash

gcc --shared -o libadd.so -xc - << EOF
int add(int x, int y) { return x + y; }
EOF

cat << EOS > main.rs
extern "C" {
    fn add(x: i32, y: i32) -> i32;
}
fn main() {
    unsafe {
      println!("add(100,200) = {}", add(100, 200));
    };
}
EOS

rustc main.rs -l add -L .
if [ $? -eq 0 ]; then
  ./main
fi

プログラミング, JDK

JavaとC言語の連携

JavaとC言語との連携については過去にも述べていますが,改めて紹介します。現在,公式リリースされている機能ではJNI(Java Native Interface)を使います。最新のJDKにプレビューとして含まれているForeieng Function and Memory APIが正式リリースされると,より簡便に連携できるようになると期待されます。

以下のシェル(jni.sh)でソースプログラムを生成してコンパイルし実行します。public static native int add(int a, int b);という部分で,ネイティブ関数を呼び出すことを宣言しておき,javacコマンドに-hオプションをつけてC言語のヘッダファイルを生成します。このヘッダファイルにはネイティブ関数のプロトタイプ宣言JNIEXPORT jint JNICALL Java_JniAdd_add(JNIEnv*, jclass, jint jint)が含まれているので,これに倣ってCプログラムを作成します。単に2つの引数を足し算して返すだけのものです。Cプログラムをコンパイルしてライブラリを作成します。ライブラリのファイル名はLinuxの場合はlibXXX.soという命名にする必要があるようです。Java側でSystem.loadLibrary(“XXX”)を実行するとJava VMに読み込まれて実行できるようになります。

#!/bin/bash
LIB=lib
mkdir -p $LIB
cat << EOS > JniAdd.java
public class JniAdd
{
    public static void main(String[] args)
    {
        System.out.println("START");
        System.loadLibrary("JniAdd");
        int result = add(1, 2);
        System.out.println(String.format("add(1,2)=%d", result));
        System.out.println("END");
    }
    public static native int add(int a, int b);
}
EOS
javac -h . JniAdd.java
cat << EOF > JniAdd.c
#include "JniAdd.h"
JNIEXPORT jint JNICALL Java_JniAdd_add(JNIEnv* env, jclass clazz, jint x, jint y)
{
     return x + y;   
}
EOF
gcc -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux/ -o $LIB/libJniAdd.so JniAdd.c

java -classpath . -Djava.library.path=$LIB JniAdd

プログラミング

RubyとC言語の連携

RubyからC言語で作成したライブラリを呼び出すプログラムを作成してみました。FFIというC言語連携用のライブラリを使うとPythonと比べて簡便に記述できました。

#!/bin/bash
gcc -shared -o add.so -xc - << EOS
    int add(int x, int y) { return x + y; }
EOS
if [ ! $? -eq 0 ]; then echo "ERROR"; fi

cat << EOF > add.rb
  require 'ffi'

  module Mod
    extend FFI::Library
    ffi_lib "add.so"

    attach_function :add, [:int, :int], :int
  end
  puts "Mod.add(1,2) = #{Mod.add(1, 2)}"
EOF

ruby add.rb
rm -f add.rb

# ./add.sh
Mod.add(1,2) = 3

新型コロナウイルス関連

感染症対応力向上プロジェクトコースI達成

東京商工会議所より,「感染症対応力向上プロジェクト」の達成確認書が届きました。東京都と東京都医師会の事業だったかと思います。従業員1人なので私が受講すれば達成になるというものなのですが,社員が大勢いる会社では大変そうです。

https://www.fukushihoken.metro.tokyo.lg.jp/iryo/kansen/project/project-start.html

プログラミング

PythonとCの連携

PythonからC言語のライブラリを呼び出してみました。PythonからC言語で作成したライブラリsystem2のsystem2を呼び出し,その中でLinuxのコマンドを実行するsystem()関数を呼び出すというものです。すべて1つのシェルの中にインラインで記述しています。

#!/bin/bash

libname=system2.so

gcc -I /usr/local/include/python3.11 -fPIC -Wall -xc -shared -o ${libname} - << EOF
#include <Python.h>
#include <stdlib.h>

PyObject* system2(PyObject* self, PyObject* args)
{
    const char* command;
    if(!PyArg_ParseTuple(args, "s", &command)) return NULL;

    long len = strlen(command);
    int result = system(command);
    if(result == EOF) len = result;

    return PyLong_FromLong(len);
}
static PyMethodDef system2_methods[] = 
{
    {"system2", system2, METH_VARARGS, "execute system command"},
    {NULL},
};
#define system2_doc "module.\n"
static struct PyModuleDef module = 
{
    PyModuleDef_HEAD_INIT,
    "system2",
    system2_doc,
    -1,
    system2_methods
};
PyMODINIT_FUNC PyInit_system2(void)
{
    return PyModule_Create(&module);
}
EOF

if [ $? -eq 0 ]; then
  python3 -c "import system2; system2.system2(\"ls -la\")"
else
  echo "Compiling failed"
fi

 [kubo@centos7 link2c]$ ./system.sh
合計 32
drwxrwxr-x. 2 kubo kubo 70 4月 5 08:39 .
drwxrwxr-x. 6 kubo kubo 58 4月 4 19:06 ..
-rwxrwxr-x. 1 kubo kubo 875 4月 5 08:21 hello.sh
-rwxrwxr-x. 1 kubo kubo 8600 4月 5 08:24 my.so
-rwxrwxr-x. 1 kubo kubo 915 4月 5 08:39 system.sh
-rwxrwxr-x. 1 kubo kubo 8608 4月 5 08:39 system2.so
雑記

特別管理産業廃棄物

UPS(無停電電源装置)のバッテリーを交換して処分しようと色々調べてみたところ,かなり面倒なことが判明しました。自動車用バッテリーと同じ仕組みのバッテリー(鉛蓄電池)なので,内部に希硫酸や鉛といった有害物質が含まれていて,「特別管理産業廃棄物」という産業廃棄物の中でも特に厳しく管理を求められるものに該当してしまうことがわかりました。

まず,特別管理産業廃棄物管理責任者の資格を得るための講習を受けました。講習自体はWeb上のe-learningで受講できるのですが,修了試験はリアルな会場でマークシート式の試験です。それに合格した上で,自らを特別管理産業廃棄物管理責任者に選任した届を都庁に提出しました。

しかし,なかなか処分業者がみつかりません。1Kgあたり10円程度の安価での買い取りを提案してくださる業者様はいくつかみつかったのですが,この価格では運搬費用を考えると赤字になってしまいます。消費者として処分するならまったく問題ないのですが,事業者が産業廃棄物として処分する場合はこの方法では有価物の譲渡とは認められず,「不適切な産業廃棄物処理」となってしまうのです(注1)。1ヵ月あまり探し回って,ようやくきちんとマニフェスト対応までやってくださる業者をみつけることができました。

注1)東京都環境局による不適正事例の説明

「不要になった物を、自ら自動車で運搬し(燃料費100円)、業者に、1円で買い取ってもらった。」という行為が「形式的な有価物」として不適正とされています。

https://www.kankyo.metro.tokyo.lg.jp/resource/industrial_waste/improper_handling/case.html

JDK

Java 20

Java 20がリリースされました。今回は小規模な変更に留まっているようです。まったく新しく導入された機能はScoped Valuesのみで,他は2回目以降のインキュベーターまたはプレビューとしての更新です。

  • Scoped Values (JEP-429)
  • レコードパターン (JEP-432)
  • switch文のパターンマッチ (JEP-433)
  • 外部メモリ/ファンクションAPI (JEP-434)
  • 仮想スレッド (JEP-436) 
  • 構造化同時実行 (JEP-437)

Scoped Values

大規模プログラムにおいて,コンポーネント間で安全かつ効率的にデータを共有するための新たなメカニズムのようです。ScopedValue<T>というクラスが導入されています。Javaでは変数のスコープはクラスやメソッド,ブロックなどで定義される静的なスコープでしたが,今回導入されたスコープは動的なものです。

以下の例ではScopedValue<>型のstatic変数PRINCIPALを用いて,ServerクラスからDBAccessクラスへデータを共有させています。Serverクラスの(1)の部分で作成されたオブジェクトをDBAccesクラスの(3)の部分で読み取ることができるようになるというもののようです。Webサーバへアクセスしてきたユーザにデータベース接続権限がなかった場合は例外をスローするということが,メソッド呼出の際に権限情報を渡さずとも実現できるということでしょうか・・・。

class Server {
    final static ScopedValue<Principal> PRINCIPAL = new ScopedValue<>();   // (1)

    void serve(Request request, Response response) {
        var level     = (request.isAdmin() ? ADMIN : GUEST);
        var principal = new Principal(level);
        ScopedValue.where(PRINCIPAL, principal)                            // (2)
                   .run(() -> Application.handle(request, response));
    }
}

class DBAccess {
    DBConnection open() {
        var principal = Server.PRINCIPAL.get();                            // (3)
        if (!principal.canOpen()) throw new  InvalidPrincipalException();
        return newConnection(...);
    }
}

https://openjdk.org/jeps/429 より引用

雑記

Rocky Linux 9

CentOSがサポート終了になってしまったので,乗換先候補の筆頭ともいえるRocky LinuxをHyper-V上にインストールしてみました。いきなりRocky Linuxリポジトリのサーバ証明書が検証できないというエラーでひっかかりましたが,どうにかパッチもインストールして使える状態になりました。

https://rockylinux.org/

雑記

SQL Server アップグレード

SQL Serverを2019から2022へアップグレードしました。アップグレードにあたってデータをエクスポートしてインポートするといった面倒な作業は一切不要というのがありがたいです。OSS製品の場合は互換性で苦労することもよくありますが,さすが商用製品です。

https://www.microsoft.com/ja-jp/sql-server/sql-server-2022