• Android emulator 遇到 libGL error: unable to load driver: i965_dri.so 錯誤的處理方法

    在 Arch Linux 底下遇到太多次,神煩,今天索性找出雖不是終極、但至少是中級不低級的解。

    主因其實是 Android emulator 與系統裡的 libstdc++ 版本打架,解法參考 [Start the Emulator from the Command Line | Android Studio] 有二:

    • 用 command line 啟動 emulator,後面補上 ‘-use-system-libs’ 參數
    • 設定環境變數 ‘ANDROID_EMULATOR_USE_SYSTEM_LIBS=1’

    第二種方法比較不反人類,不過還是要記得放對地方,如果從 desktop environment 啟動 Android Studio,這個時候吃的環境變數設定是從 ~/.xprofile 這邊載入(假設圖形環境使用的是 X Window System),如果是從 terminal 下的 command line 啟動,就是 ~/.zshrc 之類。

    搞定之後就不用跟 command line 搏鬥了…。

  • Lamp LP-740 懷爐惡搞心得

    這篇是爬了 Mobile01 某棟懷爐耐久賽大樓後,自己也買了兩組回來使用&惡搞的心得:

    1. 千萬不要用酒精(乙醇),不然氣味不只是酒味而已,可能還會有醋酸菌發酵產生的酸臭味!國中理化其實就有講過,酒在空氣中放久了就會變成醋。
    2. 酒精含的水分會留在內膽棉花裡,很麻煩,我最後只好把棉花挖出來用微波爐烘乾。
    3. 使用酒精造成白金觸媒損害也是真的,不過主因是懷爐因為酒精揮發性低,遠比環保去漬油難點著,所以打火機在火口上烘烤的時間也變長,造成燃燒不全的黑色積碳,變相讓觸媒折壽。
    4. 那些耐久測試數據,我覺得是這樣啦,實驗組、對照組、控制變因沒幾個交代清楚,今天突破幾小時,明天又突然降到剩幾小時的,還是看看就好。
    5. 把油氣揮發口徑改小,「不見得」就會延長懷爐工作時間,但是「某種程度上」會改善油氣揮發的嗆鼻味。懷爐工作時間取決於「火口效能」、「供氧量」與「供油氣量」,其中給的氧氣多,導致燃燒的作用快,就會縮短工作時間,今天你改了油氣揮發口徑得到很漂亮的工作時間數據,明天卻不盡然如此,就是因為你的實驗沒有控制「供氧量」這個因素,而實務上你會把懷爐拿去各種不同場合使用,「供氧量」會不斷變化,所以…。
    6. 把可能有漏氣的地方補起來,「某種程度上」會改善油氣揮發的嗆鼻味,這點也是對的,但是能否延長懷爐工作時間?根據前項,我還是覺得這無從斬釘截鐵地認定,但是理論上來說,減少油氣從不該揮發的地方揮發掉,就能相對增加能源利用效率,這點我是可以肯定的。
    7. 承上,我主要是補上爐體側邊兩處那有點大的縫,曾經用過鋁箔膠帶,但是太厚,會導致上蓋蓋不上。接著用美工材料「超輕土」也不是很順利。最後想到了「石膏」這種耐熱材料,在文具店買一包只要 13 元,調一點石膏漿,用水彩筆輕輕抹上去,等它乾燥後,就補得很密合了。順道一提,石膏在油漆行也有賣,雖然油漆工程用的與美術用的石膏成份不太一樣,不過在這個只是填補縫隙的場合,應該都適用。
    8. 我沒有用過那棟大樓提的一些舶來品與外國品牌懷爐,所以無從比較,不過 Lamp 真的如某些人揶揄的那麼不堪嗎?我也不覺得,主要是它的加油口設計就是可以讓你很順手的延長懷爐工作時間,而且我這幾次試用,它再怎麼不濟,都能有四小時,如果在你活動範圍內,油料添加對你不是問題,那買 Lamp 來用就是經濟實惠的選擇。
  • 修好了觸控面板故障的 NDSL

    原本買這台 NDSL 是想要嘗試在上面寫個遊戲,沒想到買回來後,用清潔海綿把污垢清潔過一遍,先還原它該有的整潔模樣,再開機測試,便發現觸控面板失靈。除了極左側的觸控還算準確,此外其他地方都向左偏移了約一公分。

    經驗告訴我,這種電阻式觸控面板出現這樣的問題,就是長期下來的內傷,只能換一片新的觸控面板了事。事前的功課還是要做的,其中我覺得這個 YouTube 上的影片教學 [Nintendo DS lite Repair – Touchscreen Replacement | Memories in 8Bit] 很不錯。

    雖然電阻式觸控面板在這個時代已經顯得有點落伍,但是好處也就是它夠落伍,與液晶顯示面板「各自為政」,不像現在主流的電容式觸控面板用貼合技術緊密整合成一塊面板,而是用雙面膠與液晶顯示面板黏在一起而已,所以維修的技術力還在我能負擔的程度。

    不過,在網拍上買了維修料件後,在東西收到前,還是一直很煩惱,因為那雙面膠如果要用人工撕下、移植到新的觸控面板,其實還是很難做得完美無暇。好在最後確認新的觸控面板原本就附上了雙面膠,這個阿雜的問題就不是問題了。

    過程中,最麻煩的就是那個觸控面板的軟板連接器,肉眼看過去真的很小,要把它摳起,單用指甲摳不起來,用刀片如果使力過猛,又容易整塊弄毀,如果沒有事前做過功課,把這個地方弄壞,那就慘了。處理這邊一定要非常注意自己的力道與勁道,甚至可以說,只要把這邊處理好,其他地方全然都不是難事。

    換上新的觸控面板後,這台又可以正常服役了。只是我拿了幾個網上的 homebrew 遊戲作品,才知道 R4 這種燒錄卡要處理載入程式的相容性,可說是見招拆招,如果它的「內核」沒有特別處理到某個程式的特殊行為,就無法正常執行。

    若不是為了「在實機上運作」這種無謂的虛榮,還不如用模擬器,理應可以少掉很多這種相容性的毛邊要處理。(爆)

  • 修好了電壓不足的 Raspberry Pi

    之前想要拿 Raspberry Pi 接上一個 Wi-Fi adaptor dongle 做點事情,因為插座與網路孔的配置不甚方便,所以才想要走無線網路,但是出現了「只要我一接上這個 dongle, Pi 就整個失靈當機」的情況。

    與另外一片 Pi 交叉比對之下,只有這片出問題,參考 [R-Pi Troubleshooting – eLinux.org] 的指引,用三用電錶測試後,確定是電壓不足的問題,而問題的成因,就是板子上面的 F3 保險絲故障,各從 F3 兩側接點與 TP2 間量測電壓,都呈現非常低的數值,形成了「若是單純啟動 Pi 勉強可動,但是再接上一個有點吃電的 USB 裝置,就罷工給你看」的窘態。

    拿尺量了一下這顆 SMT 保險絲,確定元件尺寸規格是 1812 ,便上網訂購了修復材料。

    SMD 的手動焊接有點難度,但是我還是靠著紙膠帶的輔助,把新的保險絲固定住後,順利焊接上去。再測試一次,電壓回到了正常應有的數值 (4.75~5.25V),接上 dongle 後也沒再發生當機的情況了。

    這種平時不接特別吃電的外接裝置時好端端的、但是接上去後就失常的硬體「內傷」,如果沒有文件指引,我也無法快速抓出問題成因,也是學了一課。

  • Rust 程式做 static linking

    這篇主要是參考 [Advanced Linking: Static linking] 這節。

    因為平時在工作時如果有處理到 Go 程式,沒有意外的話,編譯過程會產出一個 static linked binary,這對 deploy 流程很方便,所以我想在 Rust 底下也比照辦理。

    截自目前,在 Linux 底下,Rust 如果要這樣做,libc 標準函式庫要用 musl,而不是最常見的 glibc,所以要先安裝 musl,在 Arch Linux 底下就是執行:

    sudo pacman -S musl

    多裝 musl 不會有與 glibc 打架的情況,所以可以大膽放心裝下去。(又或者是我還沒踩到兩者打架的雷?)

    然後利用 rustup 工具,新增一組支援 x86_64-unknown-linux-musl 這個 build target 的 Rust toolchain:

    rustup target add x86_64-unknown-linux-musl

    這樣基本環境其實就搞定了,當然,在建置時,除非是將 x86_64-unknown-linux-musl 設為預設 toolchain,不然都需要特別指定使用這個 target:

    cargo build --target=x86_64-unknown-linux-musl

    可以用 ldd 與 file 指令觀察、對照一下這組 target 的 binary 與預設的 target 有什麼不同。

    實務上,我發現如果把這個 build 出來的 binary 丟進 Docker 裡,用 alpine:3.6 這個 base image 來做個無腦執行容器映像,則會發生 ld.so, ld-linux.so 路徑、檔名不符的問題,換用 debian:stable-slim 就沒這阿雜事了。

    考慮到目前頻寬足夠充裕的現實,一個約 4MB 的 alpine:3.6 與一個約 55MB 的 debian:stable-slim,疊上一個約 20MB 的 static linked binary,在 push 效率上,其實對人來說,是感覺不到會覺得「煩」、「痛」這樣的差異的,我自己真的不太喜歡使用 Alpine 這種為了精簡而常常埋雷的 base image 來給自己找麻煩,不過這與本篇沒有直接相關,只是我的一點小抱怨罷了。

  • 在 Ansible 新開機器時,運用 add_host 於執行時期立即加進 in-memory inventory 的方法

    最近在評估 GCP,不能免俗地要嘗試使用 Ansible 自動開 GCE 機器、設定組態,遇到一個之前在 AWS EC2 上印象中沒有遇過的問題。

    一般來說,我們會先在 localhost 上用 gce module 透過 GCP API 發出建立機器的操作命令,大概會像這樣(註:這邊大量借用了 Ansible 這頁的範例):

    - name: Create instance(s)
      hosts: localhost
      gather_facts: no
      connection: local
    
      vars:
        machine_type: n1-standard-1
        image: 'ubuntu-1604-xenial-v20170811'
        service_account_email: unique-id@developer.gserviceaccount.com
        credentials_file: /path/to/project.json
        project_id: project-id
    
      tasks:
        - name: Launch instances
          gce:
              instance_names: running_man
              machine_type: "{{ machine_type }}"
              image: "{{ image }}"
              service_account_email: "{{ service_account_email }}"
              credentials_file: "{{ credentials_file }}"
              project_id: "{{ project_id }}"
              tags: consumer_server

    然後在機器建起來之後,我直覺會利用 Dynamic Inventory 透過 tag 之類的資源定位方式,把開好的機器找出來:

    - name: Provision instance(s)
      hosts: tag_consumer_server
      # 以下省略

    但是可能是 GCE dynamic inventory script (gce.py) 預設的 cache 時效問題,我在這步常常需要「踩發」好幾次才能成功得出機器列表。

    我找了一下網上的討論,才發現我沒有看到 Ansible 的 GCE 範例文件裡有個眉眉角角的地方,叫做 add_host:

    ---
    - name: Create instance(s)
    # 中略
    # ...
      tasks:
        - name: Launch instances
          gce:
              instance_names: dev
              machine_type: "{{ machine_type }}"
              image: "{{ image }}"
              service_account_email: "{{ service_account_email }}"
              credentials_file: "{{ credentials_file }}"
              project_id: "{{ project_id }}"
              tags: webserver
          register: gce
    
        - name: Wait for SSH to come up
          wait_for: host={{ item.public_ip }} port=22 delay=10 timeout=60
          with_items: "{{ gce.instance_data }}"
    
        - name: Add host to groupname
          add_host: hostname={{ item.public_ip }} groupname=new_instances
          with_items: "{{ gce.instance_data }}"

    當我們處理好機器開設時,可以設一個 register,讓接下來的 tasks 去捕捉這個 task 的處理結果。

    在 ‘Wait for SSH to come up’ 我們就先使用 wait_for module 先偵測 SSH port (22) 是否起來了,來判斷這台機器是否「大致上可用」(因為 Ansible 主要原理還是靠 SSH 去遠端下一些控制命令)。如果是,我們接下來在 ‘Add host to groupname’ 就用 add_host 把這台跑起來的機器加進 in-memory inventory 當中一個叫做 new_instances 的 group,於是接下來我們就可以直接利用這份 inventory 列表來對這台(些)機器進行各種組態設定:

    - name: Manage new instances
      hosts: new_instances
      connection: ssh
      become: True
      tasks:
        - name: Install essential packages
          apt:
            name: "{{ item }}"
            state: present
          with_items:
            - 'redis-tools'
            - 'ruby2.3'

    這個 add_host 看起來不管用在哪家雲端服務業者都可以,因此還可以省去多 call 一次 API 重抓 inventory 的工。又學到了一課。