Yocto を使ったプロジェクトをビルドする際に、Git プロトコルを使わないとアクセスできないリポジトリがあります。
Git プロトコル(git:// から始まる URL のリポジトリ)は無害なんですけど、大抵の社内プロキシを越えられなくて苦労するので、越え方をメモしておきます。
まず Git のプロキシ設定を行います。この例では git-proxy というコマンドを使ってくれと指示しています。
git config --global --add core.gitProxy git-proxy
そんなコマンドはないので、自分で作ります。パスの通った場所、例えば ~/bin/git-proxy のようなファイルを作成して、下記のシェルスクリプトを書いておきます。
#!/bin/sh
exec socat STDIO PROXY:192.168.x.x:$1:$2,proxyport=8080
もちろん別途 socat コマンドのインストールが必要です。Debian なら apt-get install socat でインストールできます。
最初は netcat でやってみたんですがダメでした。何でだろ?
年末に喰らった A 型インフルエンザのダメージも回復したので、RK3328 の I2S1 の MCLK(マスタークロック)の設定がおかしくなる問題の追跡を再開しました。
思っていた以上に難しくて理解できず、かれこれ 1週間以上費やしてしまいましたが、やっと見えてきました。
ざっくり言えば Rockchip の SoC が持つクロック分周器の構成がかなり変わっていることが関係している、と言えるんじゃないでしょうか。良し悪しはさておいて、問題の原因になっています。
再現方法はとても簡単です。48kHz → 44kHz の順で再生すると正常に再生できますが、32kHz → 44kHz の順で再生するとエラーになって再生できません。これだけです。
早速、問題の原因を説明したいところですが、Rockchip のクロックがどのように繋がっているか説明しないと、全く何も意味が分からないと思いますので、軽く説明します。
RK3328 や Rockchip の 他の SoC は、1〜128分周まで可能な Integer Divider と、有理数で分周(例えば 7/500 など、分子、分母は 16ビット精度の整数で指定可能)が可能な Fractional Divider の 2つを持っています。
RK3328 の TRM(Technical Reference Manual)では、前者に i2s1_pll_div、後者に i2s1_frac_div という名前を付けており、Linux のクロックドライバでは前者に clk_i2s1_div、後者に clk_i2s1_frac という名前を付けています。
媒体 | Integer Divider | Fractional Divider |
---|---|---|
TRM(Technical Reference Manual) | i2s1_pll_div | i2s1_frac_div |
Linux Clock ドライバ | clk_i2s1_div | clk_i2s1_frac |
今後は Linux の名前で表記しますが、接頭辞の clk_ は省きます。
I2S 系のクロックは Integer Divider と Fractional Divider の両方を利用可能です。他のハードウェアブロックは Integer Divider しか使えませんが、UART と I2S と S/PDIF は両方使えるようです。
PLL と分周器と I2S1 の接続は下記のようになっています。
CPLL --> | selector |-----> i2s1_div --+--> | selector |--> I2S1 MCLK GPLL --> | | ,---------------' | | `--> i2s1_frac ----> | |
図からもわかる通り、必要に応じて i2s1_frac は使ったり、使わなかったりします。
例えば 48kHz, 32kHz で再生する場合は、GPLL -> i2s1_div -> I2S1 の経路が使われます。i2s1_frac は使いません。44kHz で再生する場合は、GPLL -> i2s1_div -> i2s1_frac -> I2S1 の経路が使われます。
サンプリング周波数 Fs と、正しく再生できているときの各分周器の出力周波数、分周比は下記のとおりです。
Fs | i2s1_div 出力 | i2s1_div 分周比 | i2s1_frac 出力 | i2s1_frac 分周比 |
---|---|---|---|---|
32kHz | 8.192MHz | 1/60 | 未使用 | 未使用 |
44.1kHz | 491.52MHz | 1/1 | 11.2896MHz | 147/6400 |
48kHz | 12.288MHz | 1/40 | 未使用 | 未使用 |
ちなみに i2s1_div の入力は GPLL が選択されることが多く、周波数は 491.52MHz で固定のようです。CPLL/GPLL の周波数は可変のはずですが、切り替わったところを見たことがありません。まあ、GPLL は今回の話に関係ないから、どうでも良いですけど……。
Linux のクロックドライバは、セレクタで選択可能なクロック系統(この場合だと i2s1_div と i2s1_frac)全てに対して、同じ目標周波数で設定して、目標に一番近い周波数を出力できるクロック系統を選択する仕組みになっています。
例えば先ほど 44.1kHz の再生のときは i2s1_frac が選ばれると言いましたが、実はこのときクロックドライバの裏側では、
この 2つの選択肢(※)が提示されており、i2s1_frac の方が目標値に近い(誤差 0)ため、i2s1_frac が選択されています。
(※)正確に言うと 12MHz clkin もあるので 3つの選択肢から選びますが、ここでは説明を省いています。12MHz clkin が選ばれることはほぼありません。
先ほど示した表のとおり、32kHz の再生後は i2s1_div の出力が 8.192MHz になります。この状態で 44.1kHz を再生しようとすると、クロックドライバは i2s1_frac の出力を 11.2896MHz にしようと試みます、しかし…。
今のクロックドライバは i2s1_frac の親にあたるクロック、つまり i2s1_div の周波数が目標の出力周波数 11.2896MHz より低いと、設定を諦めてしまう実装になっています。
コードで言うとこの部分です。
//drivers/clk/clk-fractional-divider.c
static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned long m, n;
u64 ret;
if (!rate || rate >= *parent_rate) //★★この部分★★
return *parent_rate;
if (fd->approximation)
fd->approximation(hw, rate, parent_rate, &m, &n);
else
clk_fd_general_approximation(hw, rate, parent_rate, &m, &n);
//...
32kHz → 44.1kHz の再生時は rate = 11.2896MHz, *parent_rate = 8.192MHz となり、★の部分の if 文が発動します。これは「i2s1_frac は 8.192MHz しか設定できません」という結果を返すことと等しいです。
この結果を受けたクロックドライバの選択肢は下記のようになります。
いずれも目標の 11.2896MHz と合いませんが、目標に近いのは i2s1_div と言えます。このためクロックドライバは i2s1_div が最適と判断し、I2S1 のマスタークロックが 11.214954MHz というおかしな値に設定されてしまいます。
このマスタークロック周波数は、サンプリング周波数 44.1kHz の整数倍ではないため、サウンドドライバがエラーと判断して PCM 再生を止めてしまいます。
48kHz → 44.1kHz の再生時は rate = 11.2896MHz, *parent_rate = 12.288MHz となるため、★の if 文を突破して fd->approximation の呼び出しに到達します。Rockchip の Fractional divider の場合、この関数ポインタは rockchip_fractional_approximation() 関数を指しています。
この関数は変わった処理で、ある条件を満たすと、親のクロックを使うのを諦めて、親の親のクロックを使う処理になっています。
static void rockchip_fractional_approximation(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate,
unsigned long *m, unsigned long *n)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned long p_rate, p_parent_rate;
struct clk_hw *p_parent;
unsigned long scale;
p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
if ((rate * 20 > p_rate) && (p_rate % rate != 0)) { //★★目標値が親クロックの 20倍より大きく、割り切れないとき★★
p_parent = clk_hw_get_parent(clk_hw_get_parent(hw)); //★★親の親(CPLL か GPLL)を使う★★
p_parent_rate = clk_hw_get_rate(p_parent);
*parent_rate = p_parent_rate;
}
通常ならば、存在するかどうかわからない「親の親のクロック」の存在を仮定しており、Rockchip のクロックトポロジー(PLL -> i2s1_div -> i2s1_frac)と、ハードウェア制約に強く依存した特殊な処理になっていることが伺えます。
しかし、この特殊処理のおかげで i2s1_div の周波数が i2s1_frac にとって扱いづらい変な値に設定されていたとしても、親の親(CPLL か GPLL)の周波数に戻すことができます。
48kHz → 44.1kHz の再生時に i2s1_frac だけでなく、i2s1_div の周波数まで変わってしまっているのは、なんだか不思議だなあと思った方も居るかもしれません。その理由は、この関数が親クロックの周波数目標値を書き換えてしまうから、だったんです。
ここまで読んでいただいている方はほぼゼロだと思いますが……、分周器 i2s1_div と i2s1_frac の設定が可能かどうか?どちらを選ぶべきか?を判定する部分は、こんな感じの呼び出し経路になっています。
rockchip_i2s_set_sysclk
clk_set_rate
clk_core_set_rate_nolock
clk_core_req_round_rate_nolock
clk_core_get_boundaries
clk_core_round_rate_nolock // I2S1 クロックの設定
clk_core_determine_round_nolock
clk_mux_determine_rate
clk_mux_determine_rate_flags // I2S1 手前のセレクタの設定
__clk_determine_rate
clk_core_round_rate_nolock // i2s1_div の設定
clk_core_determine_round_nolock
clk_composite_determine_rate // i2s1_div のセレクタの設定
clk_divider_round_rate // Integer divider の設定
__clk_determine_rate
clk_core_round_rate_nolock // i2s1_frac の設定
clk_core_determine_round_nolock
clk_composite_round_rate // i2s1_frac のセレクタの設定
clk_fd_round_rate // Fractional divider の設定
rockchip_fractional_approximation // Rockchip の Fractional divider 固有の設定
何度も同じ関数名が出てきて奇妙に見えると思いますが、目標となるクロック周波数の設定を 1ブロックだけで解決できないとき、親クロックに対して再帰呼び出しを行い、親の設定を変更しようとする仕組みになっています。
良くできている素晴らしい仕組みだとは思うのですが…、関数ポインタを使って高度に抽象化されているため、コードを見てもどの関数が呼ばれるのか、もう全く全然わかりません。動作もかなり追いづらいし、デバッグが辛いです……。
Tinker Board 上で linux-next を実行すると reboot 時にハングしてしまい、その後ウンともスンとも言わなくなるので、外部からボードの電源 ON/OFF する方法を探していました。考え付いた方法は 3つです。
1番目は下手なハンダ付けをして、失敗するとボードが壊れることと、制御用にもう 1つボードが要るのは何だかダサいのでやりたくありません。
2番目の線で探していたのですが、USB の給電を ON/OFF できる製品って、意外とないですね……。
仕方なく 3番目の線で、TP-Link のスマートプラグ HS105 を購入しました(メーカーの製品サイト)。Amazon で 2,600円です。Wi-Fi が内蔵されている割に、ずいぶん値段が安いですね。
メモ: 技術系の話は Facebook から転記しておくことにした。少し加筆した。
TP-Link のスマートプラグを利用するには KASA Smart というアプリをスマホに入れないと微塵も動きません。このアプリの利用規約には同意不可能な条項があって、
法的資格
(中略)お客様は利用にあたりお客様に適用するすべての法律を遵守しなければなりません。準拠法が利用を禁ずる場合はお客様は本サービスを利用することはできません。
ユーザーのコンテンツ
(中略)
2. 世界のあらゆる場所で享受できるユーザーコンテンツに対する全ての人格権を放棄し、そのような権利の主張ができないことを確認する。
と書いてあります。TP-Link は、ユーザーがフォーラムに投稿した質問、レビュー、回答などを勝手に使うけど、文句言わないでね?と言いたいみたいです。
その主張については同意しますけど、、、
日本では著作者人格権は譲渡できません(著作権法 59条)、放棄規定はありませんが、包括的に放棄はできないと考えられており、日本において TP-Link の利用規約に Yes と答えることはできません。
規約内で矛盾がある場合に、利用者が同意してしまうと、この契約はどうなるんでしょう、無効になるの…?
TP-Link は中国の会社ですから、この利用規約は中国でもほぼ同じなのではないかと思うんですが、中国って著作者人格権の放棄はできるんですかね?
規約のことは忘れて、スマートプラグを使ってみました。
スマホから電源 ON/OFF の指示を送ると、スマートプラグから「カッ!!」というかなり大きめのリレー音がしてうるさいです。今日も元気なことがわかって安心……?
使って初めて知ったのですが、スマホからスマートプラグへの電源 ON/OFF の指示は必ず TP-Link のサーバーに飛んで行くんですね。インターネット接続のできない場所ではスマホのアプリが起動しないため、電源 ON/OFF 指示ができません。
インターネット接続がなくても、スマートプラグ本体の電源ボタンを押せば電源 ON/OFF できますが、そこまで行けるなら Tinker Board を直接リセットした方が遥かに早いです。
昔から、ネットワーク対応の AC タップは売られていましたが(Ping を打つと電源が落ちる、Web インタフェースで ON/OFF できるなど)、いずれも 1万円〜数万円の製品です。
従来製品と比較して、サーバーの維持費も追加で必要なはずなのに、大抵のスマートプラグは 2,000円〜5,000円で販売されています。機能の割に破格の値段だと思います。
単純に考えると、外出中(=インターネット側から)に、宅内の電源を ON/OFF するため、何らかのサーバーを経由しているのでしょう。
嫌らしく考えると、スマートプラグはサーバーを経由させることで、ユーザーの生活情報を強制的に奪えますから、将来に情報が何かに使えることを見込んで、破格の値付けでばら撒いているのでしょう。
海外で最近話題らしい Zephyr OS を動かしてみました。
Linux に似ている、という説明をどこかで見ましたが、ビルドシステムに関して言えば全く似ていません……。コードは似ているのかもしれませんが、見ていません。
動かし方は Zephyr OS の Getting Started にあります。
Zephyr OS をビルドするためには、いくつか Python のパッケージをインストールする必要があります。pip を実行しても良いという方は pip3 install --user -r zephyr/scripts/requirements.txt で、依存するモジュールをインストールしてくれるそうです。
私は以前 pip で Python 環境が壊れて嫌な思いをしたので、apt-get で頑張りました。参考までに下記のパッケージをインストールしています。環境は Debian Testing amd64 版です。
python3-colorama python3-yaml python3-pyelftools python3-sphinx-rtd-theme sphinx-rtd-theme-common python3-breathe ninja-build sphinx-common
パッケージが足りない場合の探し方ですけども、パッケージが足りないときは Python のエラーメッセージに ModuleNotFoundError: No module named 'aaaa' こんなメッセージが出ることが多いです。apt-file search aaaa を実行すると、パッケージ名がずらーっと出てきますので、その中から python3- で始まるパッケージを探してください(Python3 モジュールのパッケージは python3-xxxx という名前が多い)。
Getting Started の通り
git clone https://github.com/zephyrproject-rtos/zephyr
です。
Getting Started には Zephyr SDK とやらをインストールせよと書いてありますが、色々大切な部分が全部ぶっ飛んでいてわからなくなっている感じがします。幸い crosstool-NG にも対応していると書いてあったので、crosstool-NG を使ってみました。
基本的には以前紹介した(2018年 7月 15日の日記参照)、AArch64 Linux 用の環境と同じ手順ですが、./ct-ng menuconfig で設定する項目が多少違います。
$ ./ct-ng menuconfig Target options ---> Target Architecture ---> arm にする Bitness: ---> 32-bit にする Toolchain options ---> Tuple's vendor string zephyr にする Operating System ---> Target OS ---> bare-metal にする $ ./ct-ng build [00:34] /
しばらく待つと arm-zephyr-eabi というプレフィクスを持つクロスコンパイラが生成されるはずです。
Zephyr OS のビルドに使用するクロスコンパイラを、~/.zephyrrc に環境変数を定義して指定します。変な作りだなあ……。
export ZEPHYR_TOOLCHAIN_VARIANT=xtools
export XTOOLS_TOOLCHAIN_PATH=/home/katsuhiro/x-tools
注意点としては XTOOLS_TOOLCHAIN_PATH の x-tools の後のパスは勝手に arm-zephyr-eabi が使われ、自由に指定できないことです。この点については Linux の CROSS_COMPILE 環境変数とは異なるうえ、Zephyr の方が後発にも関わらず退化しています。どうしてこうなった……。
ビルドする前に 2手ほど準備が必要です。1手目は環境変数のセットアップです。
cd zephyr source zephyr-env.sh
2手目は cmake の実行です。
$ cd sample/hello_world $ mkdir build $ cd build $ cmake -GNinja -DBOARD=qemu_cortex_m3 ../ Zephyr version: 1.13.99 -- Found PythonInterp: /usr/bin/python3 (found suitable version "3.7.2", minimum required is "3.4") -- Selected BOARD qemu_cortex_m3 Parsing Kconfig tree in /home/katsuhiro/share/projects/oss/zephyr/Kconfig Loading /home/katsuhiro/share/projects/oss/zephyr/boards/arm/qemu_cortex_m3/qemu_cortex_m3_defconfig as base Merging /home/katsuhiro/share/projects/oss/zephyr/samples/hello_world/prj.conf Configuration written to '/home/katsuhiro/share/projects/oss/zephyr/samples/hello_world/build/zephyr/.config' -- Loading /home/katsuhiro/share/projects/oss/zephyr/boards/arm/qemu_cortex_m3/qemu_cortex_m3.dts as base -- Overlaying /home/katsuhiro/share/projects/oss/zephyr/dts/common/common.dts -- Cache files will be written to: /home/katsuhiro/.cache/zephyr -- The C compiler identification is GNU 8.2.0 -- The CXX compiler identification is GNU 8.2.0 -- The ASM compiler identification is GNU -- Found assembler: /home/katsuhiro/x-tools/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc -- Performing Test toolchain_is_ok -- Performing Test toolchain_is_ok - Success -- Configuring done -- Generating done -- Build files have been written to: /home/katsuhiro/share/projects/oss/zephyr/samples/hello_world/build
CMake を採用しているプロジェクトは大抵、ソースコードのトップディレクトリにある CMakeLists.txt を指定しますが、Zephyr OS の場合、sample/* の下にある CMakeLists.txtを使わなければなりません。わからんわ、そんなの。変な作りだな……。
間違って Zephyr OS のトップディレクトリにある CMakeLists.txt を指定すると、こんなエラーメッセージで怒られます。
$ cmake -GNinja -DBOARD=qemu_cortex_m3 ../ CMake Error at CMakeLists.txt:13 (message): A user error has occured. cmake was invoked with '/home/katsuhiro/share/projects/oss/zephyr' specified as the source directory, but it must be invoked with an application source directory, such as '/home/katsuhiro/share/projects/oss/zephyr/samples/hello_world'. Debug variables: CMAKE_CACHEFILE_DIR: CMake Warning (dev) in CMakeLists.txt: No cmake_minimum_required command is present. A line of code such as cmake_minimum_required(VERSION 3.13) should be added at the top of the file. The version specified may be lower if you wish to support older CMake versions for this project. For more information run "cmake --help-policy CMP0000". This warning is for project developers. Use -Wno-dev to suppress it. -- Configuring incomplete, errors occurred!
エラーメッセージからは、何が悪いのか全く分かりません……。
ビルドと実行は難しくありません。どちらかというとここまでたどり着くのがかなり面倒くさいです。
$ cd sample/hello_world/build $ ninja [1/103] Preparing syscall dependency handling [98/103] Linking C executable zephyr/zephyr_prebuilt.elf Memory region Used Size Region Size %age Used FLASH: 8604 B 256 KB 3.28% SRAM: 4160 B 64 KB 6.35% IDT_LIST: 120 B 2 KB 5.86% [103/103] Linking C executable zephyr/zephyr.elf $ ninja run [0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-m3 qemu-system-arm: warning: nic stellaris_enet.0 has no peer ***** Booting Zephyr OS zephyr-v1.13.0-3162-g73956a398e ***** Hello World! qemu_cortex_m3
何をしているのか全然わかりません。仕方ないので build.ninja ファイルから qemu を実行しているところを発掘してみたら、下記のコマンドを実行しているようです。
$ /usr/bin/qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -vga none -net none -pidfile qemu.pid -serial mon:stdio -kernel /home/katsuhiro/share/projects/oss/zephyr/samples/hello_world/build/zephyr/zephyr.elf qemu-system-arm: warning: nic stellaris_enet.0 has no peer ***** Booting Zephyr OS zephyr-v1.13.0-3162-g73956a398e ***** Hello World! qemu_cortex_m3
期待される結果が良くわからないんですが、これで動いたと言って良いんだろうか…??
完全に自分のためのメモですが、ROCK64 と Tinker Board で使用している U-Boot の distro boot の設定ファイル(extlinux.conf)を貼っておきます。
オリジナルのファイルに linux-next の起動用設定(label kernel-next の部分)を追加しました。
menu title select kernel
label kernel-4.4.132-1075-rockchip-ayufan-ga83beded8524
kernel /boot/vmlinuz-4.4.132-1075-rockchip-ayufan-ga83beded8524
initrd /boot/initrd.img-4.4.132-1075-rockchip-ayufan-ga83beded8524
devicetreedir /boot/dtbs/4.4.132-1075-rockchip-ayufan-ga83beded8524
append rw panic=10 init=/sbin/init coherent_pool=1M ethaddr=${ethaddr} eth1addr=${eth1addr} serial=${serial#} cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1 root=LABEL=linux-root rootwait rootfstype=ext4
label kernel-next
kernel /boot/Image
initrd /boot/initrd.img-4.4.132-1075-rockchip-ayufan-ga83beded8524
fdt /boot/rk3328-rock64.dtb
append rw panic=10 init=/sbin/init coherent_pool=1M ethaddr=${ethaddr} eth1addr=${eth1addr} serial=${serial#} cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1 root=LABEL=linux-root rootwait rootfstype=ext4
label kernel-4.4.132-1075-rockchip-ayufan-ga83beded8524-memtest
kernel /boot/vmlinuz-4.4.132-1075-rockchip-ayufan-ga83beded8524
initrd /boot/initrd.img-4.4.132-1075-rockchip-ayufan-ga83beded8524
devicetreedir /boot/dtbs/4.4.132-1075-rockchip-ayufan-ga83beded8524
append rw panic=10 init=/sbin/init coherent_pool=1M ethaddr=${ethaddr} eth1addr=${eth1addr} serial=${serial#} cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1 root=LABEL=linux-root rootwait rootfstype=ext4 memtest
クロスコンパイル用マシンにて実行 $ cd linux-next $ scp arch/arm64/boot/Image arch/arm64/boot/dts/rockchip/rk3328-rock64.dtb 192.168.1.xxx:~/ ROCK64 にて実行 $ sudo cp Image /boot/ ; sudo cp rk3328-rock64.dtb /boot/ ; sync ; sudo reboot
CPU が AArch64 なので生成されるイメージファイルは Image です。デバイスツリーは rk3328-rock64.dtb です。ネットワーク経由で ROCK64 のユーザ(なんでもよいですが)のホームディレクトリにコピーし、ボード側で /boot にコピーして使っています。また initrd はオリジナルのものを拝借しています。
1行目の menu title select kernel が結構大事で、この行を書いておくと U-Boot がカーネルを起動する際に下記のような選択肢が表示されます。
Found /boot/extlinux/extlinux.conf Retrieving file: /boot/extlinux/extlinux.conf 1433 bytes read in 28 ms (49.8 KiB/s) select kernel 1: kernel-4.4.132-1075-rockchip-ayufan-ga83beded8524 2: kernel-next 3: kernel-4.4.132-1075-rockchip-ayufan-ga83beded8524-memtest Enter choice:
この設定はとにかくボードから SD カードの抜き差しをやりたくない一心でできています。
普段は boot メニューで 2番を選び linux-next カーネルを起動します。もし起動しないカーネルを書き込んでしまったり、ネットワークが死んでいるカーネルを書き込んでしまい、カーネルの更新ができなくなったときは、リブートし 1番を選び元々書かれていたカーネルを起動して復旧させます。
何も選択せず放置すると 1番が勝手に選ばれますので、おかしくなったら電源を ON/OFF して放置すれば、必ずオリジナルのカーネルが起動します。ボードが少し遠くに置いてあって、AC 電源 ON/OFF から U-Boot の選択肢タイムアウトまでの間にキー入力ができないので、このような設定にしています……。
Tinker Board の設定も同じ思想で作っています。
# cat /boot/extlinux/extlinux.conf
menu title select kernel
label kernel-4.4
kernel /zImage
fdt /rk3288-miniarm.dtb
append earlyprintk console=ttyS1,115200n8 root=/dev/mmcblk0p2 rw init=/sbin/init
label kernel-next
kernel /linux-next
fdt /rk3288-tinker.dtb
append earlyprintk console=ttyS1,115200n8 root=/dev/mmcblk0p2 rw init=/sbin/init
クロスコンパイル用マシンにて実行 $ linux-next $ scp arch/arm/boot/zImage arch/arm/boot/dts/rk3288-tinker.dtb 192.168.1.xxx:~/ Tinker Board にて実行 # cp /home/katsuhiro/zImage /boot/linux-next; cp /home/katsuhiro/rk3288-tinker.dtb /boot/; sync; reboot
ROCK64 との違いは CPU が AArch32 なので生成されるイメージファイルは zImage であることと、デバイスツリーは rk3288-tinker.dtb であることでしょうか。
カーネルをネットワーク経由で更新する点は同じですが、zImage というファイル名だと元々存在するカーネルと被っているので、リネームしています。
昔(2017年 5月 2日の日記参照)作った我が家の PC の Passmark スコア表に、Ryzen 7 デスクトップ(2018年 12月 1日の日記参照)も加えました。
用途 | CPU | シングル | マルチ | コア、スレッド数 | TDP |
---|---|---|---|---|---|
デスクトップ | AMD Ryzen7 2700 | 2005 | 14985 | 8C16T | 65W |
旧デスクトップ | AMD A10-7800 | 1537 | 5069 | 4C4T | 65W |
ノート | Intel Core i5 2450M | 1404 | 3404 | 2C4T | 35W |
サーバ | Intel Pentium J4205 | 899 | 2394 | 4C4T | 10W |
旧サーバ | Intel Atom D2700 | 349 | 840 | 2C4T | 10W |
サブマシン | Intel Atom D525 | 284 | 701 | 2C4T | 13W |
2年前は Ryzen 7 の 8コアを欲しいなと思いつつも、何に使うか疑問に思っていましたが、Linux のビルドに最適だということがわかって、とても役に立っております。買って良かった。
以前 Cocos2d-x をビルドして(2017年 6月 30日の日記参照)、Linux で動くサンプルプログラムをビルドしました。あの時は結局、ゲームは作らずじまいでした。懲りずに、今回は Android 向けにビルドします。
その前にまず Linux 向けにビルドします。簡単かと思ったら、めちゃくちゃハマりました……。
公式ドキュメント(リンク)に載っている通りの手順を試すと、下記のようなエラーが出ます。
$ git clone https://github.com/cocos2d/cocos2d-x $ cd cocos2d-x/ $ git submodule update --init Submodule path 'tests/cpp-tests/Resources/ccs-res': checked out '5d65db4c5f18c0df1305ff32b076425ab228cc4a' Submodule path 'tools/bindings-generator': checked out '2aa9b21f11bf514ca80f243b21750e8c7c28f05e' Submodule path 'tools/cocos2d-console': checked out '643f423415c62a1b610549323c4bf5499683baab' Submodule path 'web': checked out 'e79acd062363818af809c51804083a5989a9aedc' $ ./download-deps.py ======================================================= ==> Prepare to download external libraries! ==> version file doesn't exist ==> Ready to download 'v3-deps-156.zip' from 'https://github.com/cocos2d/cocos2d-x-3rd-party-libs-bin/archive/v3-deps-156.zip' (...snip...) ==> Would you like to save 'v3-deps-156.zip'? So you don't have to download it later. [Yes/no]: Yes $ cd build/ $ mkdir linux-build $ cd linux-build/ $ cmake ../../ -- The C compiler identification is GNU 8.2.0 -- The CXX compiler identification is GNU 8.2.0 -- Check for working C compiler: /usr/lib/ccache/cc -- Check for working C compiler: /usr/lib/ccache/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features (...snip...) -- Found Threads: TRUE -- Configuring done -- Generating done -- Build files have been written to: /home/katsuhiro/share/projects/oss/cocos2d-x/build/linux-build $ make [ 0%] Building CXX object engine/external/unzip/CMakeFiles/ext_unzip.dir/ioapi.cpp.o [ 0%] Building CXX object engine/external/unzip/CMakeFiles/ext_unzip.dir/unzip.cpp.o [ 0%] Building CXX object engine/external/unzip/CMakeFiles/ext_unzip.dir/ioapi_mem.cpp.o [ 1%] Linking CXX static library ../../../lib/libext_unzip.a (...snip...) [ 84%] Built target jscocos2d [ 84%] Building CXX object engine/tests/cpp-empty-test/CMakeFiles/cpp-empty-test.dir/Classes/AppDelegate.cpp.o [ 84%] Building CXX object engine/tests/cpp-empty-test/CMakeFiles/cpp-empty-test.dir/Classes/HelloWorldScene.cpp.o [ 84%] Building CXX object engine/tests/cpp-empty-test/CMakeFiles/cpp-empty-test.dir/proj.linux/main.cpp.o [ 84%] Linking CXX executable ../../../bin/Debug/cpp-empty-test/cpp-empty-test /usr/bin/ld: ../../../../../external/freetype2/prebuilt/linux/64-bit/libfreetype.a(ftbase.linux64.o): relocation R_X86_64_32 against `.rodata' can not be used when making a PIE object; recompile with -fPIC (...snip...) /usr/bin/ld: ../../../../../external/freetype2/prebuilt/linux/64-bit/libfreetype.a(ftbitmap.linux64.o): relocation R_X86_64_32S against `.rodata' can not be used when making a PIE object; recompile with -fPIC /usr/bin/ld: final link failed: nonrepresentable section on output collect2: error: ld returned 1 exit status make[2]: *** [engine/tests/cpp-empty-test/CMakeFiles/cpp-empty-test.dir/build.make:153: bin/Debug/cpp-empty-test/cpp-empty-test] Error 1 make[1]: *** [CMakeFiles/Makefile2:1362: engine/tests/cpp-empty-test/CMakeFiles/cpp-empty-test.dir/all] Error 2 make: *** [Makefile:84: all] Error 2
エラーで指摘されている freetype2/prebuilt/linux/64-bit/libfreetype.a は、download-deps.py がダウンロードしてきた v3-deps-156.zip に含まれているスタティックライブラリです。recompile with -fPIC と言われても、自分でビルドしたものではないので、何もできません。そんなこと言われても困る。
困った挙句に Cocos2d-x の issue list(リンク)に辿りつきました。議論を見ると cocos2d-x-3rd-party-libs-src リポジトリの build.sh でライブラリが作れるみたいです。うえ〜、そんなの知らんがな。
$ git clone https://github.com/cocos2d/cocos2d-x-3rd-party-libs-src $ cd cocos2d-x-3rd-party-libs-src/build/ $ ./build.sh -p=linux --libs=freetype --arch=x86_64 --mode=release $ cp linux/freetype/prebuilt/x86_64/libfreetype.a ../../cocos2d-x/external/freetype2/prebuilt/linux/64-bit/libfreetype.a
依存ライブラリを自前でビルドして置き換えることで、無事に Cocos2d-x のコンパイルが通りました。
心配だったゲームプロジェクトの作り方は以前と同じ(2017年 7月 2日の日記参照)でした。こちらはハマらなくて本当に良かったです。
生成されたゲームプロジェクトの中に proj.android という名前のディレクトリが作成されます。Android Studio で proj.android を開けば後は勝手に Gradle がビルドしてくれるはずです。
$ ls CMakeLists.txt Resources proj.android proj.linux Classes cocos2d proj.ios_mac proj.win32
Linux 向けにビルドしたいときは、以前と同じ手順で OK です。同じコードで Android も Linux も対応できて便利ですよね。
弱者を抹殺する。 不謹慎な質問ですが、疑問に… - Yahoo! 知恵袋を読んで。
Twitter で知りました。7年以上前の話題ですが、ベストアンサーに選ばれた回答が素晴らしかったです。
ベストアンサーの中に出てくる「人間の生存戦略は、、、、「社会性」」の一文が非常に興味深かったので、社会性についてちょっと調べてみました。まず、大前提として、生物は生きようとしますし、子孫を増やそうとします。死にたがりや増えない生物は存続不能なので自明だと思います。
生物の行動は利己的、利他的があります(他に相利的行動、いじわる行動もありますが省略)。
利他的行動は一見すると合理的には見えません。しかし、世の中には社会性を持ち、利他的行動を取る生物がいます。人間もそうです。
これらの生物が、あえて利他的行動を取るのはなぜか?言われてみると確かに不思議です。
利他的行動についてはいくつか説があり、
個人的には、人間の社会性に関して言えば、群選択より、互恵的利他の説明が一番しっくりきます。互恵的利他の考えに基づくと、Yahoo! 知恵袋の問いに対しては「将来的に自身の利益になると期待しているから」が答えですかね?
まあ、社会性の仕組みは追々明らかになっていくことでしょう。楽しみですね。
どうでも良いですが、この手の仮説は、立証が大変そうだと思いました。私には利他的行動で得る利益が何かすら定義できないし、どの個体がいくら利益を得ているか示す手段も思いつきません……。
メモ: 技術系の話は Facebook から転記しておくことにした。加筆修正した。
目次: マンガ紹介 - まとめリンク
Facebook で教えてもらったマンガ「ハコヅメ」を買ってみました。面白いです。次が楽しみです。
警察を描くマンガは多いですが、大抵シリアスです。ハコヅメはゆるいギャグ調ですが、警察の大変さも伝わってきます。初めて出会ったタイプかも。
メモ: 趣味の話は Facebook から転記しておくことにした。
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2021.
Powered by PHP 5.2.17.
using GD bundled (2.0.34 compatible)(png support.)