日記

内容の正しさは保証しません

emscriptenをインストールしてwebassemblyを実行するまで

環境

pythonのインストール

pacman -S mingw-w64-x86_64-python

でインストールできる。次に

python

を叩くとWindows Storeが開くと思うので、環境変数の順番を入れ替えて直す。

emscriptenのインストール

コマンドは公式サイト1に書いてある。まずmsys2で

cd <任意のディレクトリ>
git clone https://github.com/emscripten-core/emsdk.git

によりemscriptenをダウンロードする。次にcmd.exeで

cd <任意のディレクトリ>/emsdk
emsdk install latest
emsdk activate latest
emsdk_env.bat

を実行する。しかし4行目のemsdk_env.batを実行しても環境変数が追加されなかった。なので追加したとされる(されてない)パス

<任意のディレクトリ>\emsdk
<任意のディレクトリ>\upstream\emscripten
<任意のディレクトリ>\emsdk\node\14.18.2_64bit\bin

を追加する。14.18.2は適当に書き換える。

webassemblyにコンパイルして実行

適当にソース書いて

em++ -s WASM=1 -o <任意の名前>.html <ソース>.cpp

コンパイルした。実行ファイル(みたいなやつ)は.htmlになるが、開いてもCORSのエラーで動かない。 そこでAtomをインストールしてatom-live-serverを入れて.htmlがあるディレクトリでサーバを起動し実行した。

コンパイルのオプション2

  • -s WASM=1は必須
  • -o *.htmlはwebassemblyを呼び出すコードの記述を省略するなら必須
  • その他、clangで動くオプションはそのまま使える?例:-std=c++20, -Wall
    • -std=c++20については、つけないとコンパイルエラーになるコードで確認した

em++ -vの結果

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.10 (c3fe57af0504fe24fc4ba697feb8c204f3c80022)
clang version 15.0.0 (https://github.com/llvm/llvm-project 8bc29d14273b05b05d5a56e34c07948dc2c770d3)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: <任意のディレクトリ>\emsdk\upstream\bin

msysでQt6を使う

5年くらい前はQtのインストールが出来なかった気がするけどできた。

手順

1. Qt6-baseをインストール

pacman -Ss qt6-base

で検索して好きなやつインストール。いつもmingw64.exe起動してるから適当にmingw64入れてる。

2. サンプルのコードを拾ってくる

第1章 Hello Qt! | densan-labs.net

3. サンプルを入れたディレクトリに移動

4. .proファイルを作成

qmake-qt6 -project

5. .proファイルを編集1 2

例えばQLabelを使う場合は

QT += widgets

を追記する。

6. makefileを作成

qmake-qt6

7. makeコマンドを実行

注意点

4.で.proファイルを作るときにフォルダが存在していると

called on an invalid qregularexpression object

云々のエラーが超高速で出力されてメモリ全部食われる(何で?)。


  1. Qt Documentationのリファレンスのqmakeの項目に書いてある

  2. Qt 6.1

markdownをhtmlに変換して脚注を表示する

Githubwikiでドキュメントを公開しようとしたら、脚注が使用できなかったので、htmlに変換することにした。変換にはPandocを用いた。

pandoc -f markdown -t html --template=template --mathjax ファイル名.md > ファイル名.html

ついでに、

を行った。

外観

Githubと外観を合わせるために、Githubからcssをコピーしてtemplateから参照するようにする。

Pandocを使ってMarkdownを整形されたHTMLに変換する - Qiita

githubのmarkdown-cssをぶっこ抜く方法 - Qiita

ツールチップ

jqueryを使ってhtmlを書き換える。

$(() => {
    $(".footnote-ref").each((i, x) => {
        $(x).wrap("<span class='tooltip'></span>");
        
        let foot_note = $("#fn" + (i + 1) + "> p")
            .text()
            .replace("↩︎", "");
        $(x).after("<span class='tooltip-frame'><span class='tooltip-text'>" + foot_note + "</span></span>");
    });
});

jQuery 日本語リファレンス

ツールチップの実装は省略。

数式

pandocに--mathjaxを与えるだけで、$$数式$$で囲まれた数式が表示される。

$$ i = \sqrt{-1} $$


i = \sqrt{-1}
と表示される。

インデックス付きtransform

jsのように添え字が欲しいことがあったので書いた。

#include <type_traits>
#include <algorithm>

struct result_of
{
    template <class T, class R>
    struct y {
        using type = R;
        static inline constexpr bool value = T::value;
    };
    
    template <class C, class F, class... Args>
    static auto f() -> y<std::false_type, std::invoke_result_t<F&, Args...>>;
    
    template <class C, class F, class... Args>
    static auto f() -> y<std::true_type, std::invoke_result_t<F&, Args..., C>>;
};

template <class C, class F, class... Args>
using result_of_t = decltype(result_of::f<C, F, Args...>());

//添え字を与えてくれるstd::transform
template <
    template <class...> class C, 
    class... Args,
    class F,
    class R = result_of_t<std::size_t, F, typename C<Args...>::value_type>
>
static inline auto transform(C<Args...> const& t, F&& f)
{
    //Cはテンプレート引数を省略できるとする
    auto u = C<typename R::type>(t.size());
    
    if constexpr (R::value)
    {
        std::transform(t.begin(), t.end(), u.begin(), [&f](auto const& x) {
            static size_t i = 0;
            return f(x, i++);
        });
    }
    else {
        std::transform(t.begin(), t.end(), u.begin(), f);
    }
    return u;
}

result_of_t<C, F, Args...>::valueはファンクタをArgs..., Cで呼び出せるならtrue, そうでないときはfalseとなる。またresult_of_t<C, F, Args...>::typeはファンクタの返り値の型である。

#include <iostream>
#include <vector>
int main() {
    auto v = transform(std::vector{2, 4, 6, 8}, [](auto x, auto i) {
        std::cout << i << ":" << x * i << std::endl;
        return x * i; 
    });
}

結果

0:0
1:4
2:12
3:24

ノート 12月

std::moveとstd::forward

  • 関数テンプレートでは, 引数がT&&のときにX&&およびX&を与えることができる
    • このとき, TはX&と推論され, &&は無視して結局X&となる
  • そのせいでT&&(rvalue reference)特有の処理がそのままではできなくなる
  • std::moveはT&をT&&にstatic_castする
  • std::forwardはそのどちらか分からないT&&をキャストして元に戻す
    • この関数を使うことでT&&を受け取る関数を呼び出せる

参照

本の虫: rvalue reference 完全解説

//使ったことないので自信なし

ノート 8/10

最近Javascriptに興味があってPixi,jsを使ってみた。初めて使う言語なので書き方がおかしいかも

基本的なコード

PixiJS API Documentation

JSONで読み込む

  • スプライトシートを扱いたいときに必要
const app = new PIXI.Application();
document.body.appendChild(app.view);

app.loader
.add('imgs', './img.json')
.load((loader, resources) => {
    const imgs = resources['img'].textures;
    img = new PIXI.Sprite(imgs['001']);
    app.renderer.resize(img.width, img.height);
    app.stage.addChild(img);
});

参照

選択した画像を読み込んで表示する

<input id="file" type="file"></input>
const app = new PIXI.Application();
document.body.appendChild(app.view);

var $ = function (x) { return document.getElementById(x); };
$('file')
.addEventListener('change', (e) => {
    var file = e.target.files[0];
    if (!file.type.includes('image')) {
        return;
    }
    var reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function () { //ファイル名と拡張子と最終更新日時が同じファイルは同一と見なされて読み込まれない
        var name = file.name + file.type + file.size + file.lastModifiedDate;
        app.loader
        .add(name, reader.result)
        .load((loader, resources) => {
            img = new PIXI.Sprite(resources[name].texture);
            app.renderer.resize(img.width, img.height);
            app.stage.removeChild();
            app.stage.addChild(img);
        });
    };
},
false);

ノート 7/24

std::transformは処理を適用・結果を格納するコンテナの範囲をイテレータとして受け取る関数だが、一々

std::vector<int> w(v.size());
std::transform(v.begin(), v.end(), w.begin(), w.end(), f);

と書くのが面倒な上、二行も使う。 そこで、コンテナvの参照と関数fから上記の処理をしてwを返すようなラッパが欲しい。

テンプレートテンプレート

クラステンプレート(名前だけでは不完全な型)をテンプレートで表すにはテンプレートテンプレートを使う。

template <class T>
sturct A {
    T t;
};

//Tとしてstruct Aを指定できる
template <template <class> class T>
struct B {
    T<double> t;
};

実引数からクラステンプレートを推論させる

template <template <class> class T, class U>
void f(T<U>);
  • 上記の関数fにA<int>{}を与えた場合、T=A, U=intと判断される。

実装する

template <
    template <class...> class C
    class... Args,
    class F,
    class R = typename std::invoke_result_t<F&, typename C<Args...>::value_type const&>
>
auto transform(C<Args...> const& t, F&& f)
{
    //Args...の中でR以外のパラメータは省略可能と仮定する
    auto u = C<R>(t.size()); 
    std::transform(t.begin(), t.end(), u.begin(), f);
    return u;
}
  • template <class...> class Cは任意のコンテナを表すことができる
  • Args...はCのテンプレート引数
  • Fはファンクタ
  • RはFをCの要素に適用して返ってくる値の型
  • transform関数の第一引数では上で述べた推論を利用している。例えばstd::vector<int, std::allocator<int>>{}を与えればC=std::vector, Args...=int, std::allocator<int>になる。

欠点

  • std::mapは引数にstd::pair<S, T>を取らないためC<R>の実体化に失敗してコンパイルエラー.何か工夫が必要

参考

transformをラップして変換後のオブジェクトを返すようにしてみる - Qiita