2017-10-30

List tm file

#!/usr/bin/tclsh
package require fileutil

set tmpaths [::tcl::tm::path list]
foreach tmpath $tmpaths {
    if {[file exists $tmpath] && [file isdirectory $tmpath]} {
        foreach file [fileutil::find $tmpath {string match -nocase *.tm}] {
            puts $file
        }
    }
}

這只是練習用的程式。使用 tcllib fileutil,利用 fileutil::find 尋找副檔名為 tm 的檔案。雖然我有寫第一行,不過目前只有在 Windows 7 測試過。

Eclipse Dynamic Languages Toolkit

還不確定我會不會使用 Eclipse 一段時間,但是記錄一下 Eclipse 對於 Tcl 的支援。支援的能力來自於 Eclipse Dynamic Languages Toolkit (DLTK),需要自己安裝 plug-in。

DLTK 有支援 Tcl Syntax highlighting。
  • 根據 Which tools support Java 9’s new modularity features 的資訊,目前並沒有所有的工具都準備好迎接 Java 9 的模組系統。隨著 Java 9 的正式發佈,比較大量的測試才正開始而已。
  • 但是 Eclipse 和 Apache Maven,也就是接下來我準備要測試的工具已經準備好迎接 Java 9 的模組化了。
  • 在升級到 JDK 9 以後,我安裝用來測試的 Eclipse 和 Apache Maven 可以正確運作。接下來測試 DLTK (Tcl),看起來是正常的,不過實際上要等更多的使用情況才知道。
另外,就 openSUSE: tclBlend and OpenJDK 9 注意到的,JDK 9 的目錄架構有所改變,看起來是因為 openSUSE drop 掉三十二位元的支援,所以可以進行目錄簡化的工作。但是還不確定這是否會成為通例。(PS. JRE_HOME 需要注意是否有正確設定,至少我的沒有)

更新:
JDK and JRE File Structure (JDK 8)
Installed Directory Structure of JDK and JRE (JDK 9)

2017-10-26

openSUSE: tclBlend and OpenJDK 9

使用 zypper addrepo 的方式增加 Java 的 Repository,然後升級到 OpenJDK 9(警語:這樣有可能會讓系統不穩定,所以除非需要才這樣做),但是沒有 Java plugin。

OpenJDK 9 的目錄架構略有改變,所以編譯 tclBlend 會失敗。經過查看 openSUSE 的目錄架構,按照錯誤提示,修改 tcljava.m4,下面是 github 上的修改記錄:

+        # OpenJDK 9 Linux (server JVM)
+
+        F=lib/libjava.so
+        if test "x$ac_java_jvm_jni_lib_flags" = "x" ; then
+            AC_MSG_LOG([Looking for $ac_java_jvm_dir/$F], 1)
+            if test -f $ac_java_jvm_dir/$F ; then
+                AC_MSG_LOG([Found $ac_java_jvm_dir/$F], 1)
+
+                D=`dirname $ac_java_jvm_dir/$F`
+                ac_java_jvm_jni_lib_runtime_path=$D
+                ac_java_jvm_jni_lib_flags="-L$D -ljava -lverify"
+
+                D=$ac_java_jvm_dir/lib/server
+                ac_java_jvm_jni_lib_runtime_path="${ac_java_jvm_jni_lib_runtime_path}:$D"
+                ac_java_jvm_jni_lib_flags="$ac_java_jvm_jni_lib_flags -L$D -ljvm"
+            fi
+        fi
+

然後使用 autoconf 更新設定,下面是 github 上 configure 的修改記錄:
+        # OpenJDK 9 Linux (server JVM)
+
+        F=lib/libjava.so
+        if test "x$ac_java_jvm_jni_lib_flags" = "x" ; then
+
+    echo Looking for $ac_java_jvm_dir/$F >&5
+
+
+            if test -f $ac_java_jvm_dir/$F ; then
+
+    echo Found $ac_java_jvm_dir/$F >&5
+
+
+
+                D=`dirname $ac_java_jvm_dir/$F`
+                ac_java_jvm_jni_lib_runtime_path=$D
+                ac_java_jvm_jni_lib_flags="-L$D -ljava -lverify"
+
+                D=$ac_java_jvm_dir/lib/server
+                ac_java_jvm_jni_lib_runtime_path="${ac_java_jvm_jni_lib_runtime_path}:$D"
+                ac_java_jvm_jni_lib_flags="$ac_java_jvm_jni_lib_flags -L$D -ljvm"
+            fi
+        fi
+

這樣就可以正確編譯。

不過還沒辦法拿去 openSUSE build service 進行驗證。

BuildRequires:    java-1_8_0-openjdk-devel

目前主流的 JDK 版本仍然是 8,openSUSE build service 我暫時沒有更動。如果使用者升級到 OpenJDK 9,那麼要改 BuildRequires,
BuildRequires:    java-9-openjdk-devel

更新(目前的 Oracle 規畫):



所以如果是甲骨文,JDK 9 將會是一個過渡的版本,接下來將會推出 18.3,然後再來是 18.9,而 18.9 才是一個長期支援的版本。而 OpenJDK 對應的是 JDK Project,目前還沒有開 18.3 repositories 出來。

這表示大規模遷移到 Java 9 的機率不大,目前大多數仍然會留在 Java 8,直到下一個長期支援版本到來(目前 Oracle 設定為 18.9)。

這也代表我不用急著更新 RPM spec 以後丟上去 openSUSE build service 測試,至少在 18.9 出現以前,JDK 8 都會是目前的主要版本。

所以策略還是一樣,要等 openSUE LEAP 15 才知道是否需要修改 tclBlend RPM spec。如果預設的 JDK 還是 8,那就不用更動,如果升到 18.9,我就需要研究一下按照版本不同而進行設定的 BuildRequires。

2017-10-24

openSUSE tcl-dbif: let it run

目前 openSUSE OBS 上找到的是 1.0 版,相依性的設定有設 tcl-dbus,所以要先安裝 tcl-dbus,然後才安裝 tcl-dbif。

不過如果你真的使用下列的指令安裝:
sudo zypper install tcl-dbif


你很快就會發現無法正確使用。使用 package require dbif 並不會正確的找到套件。原因也很簡單,

在 tclsh 下使用下列的指令查詢:
::tcl::tm::path list


dbif 會安裝在 /usr/share/tcl/dbif1.0 目錄,但是這個目錄卻沒有在 openSUSE LEAP 42.3 tclsh 搜尋目錄的列表內。修正的方法很簡單,使用 ::tcl::tm::path 指令修正,在家目錄下的 ~/.tclshrc 一開始的時候加上我們想搜尋的目錄,
::tcl::tm::path add /usr/share/tcl/dbif1.0


這樣就可以讓 tcl-dbif 目錄正常的使用。但是會需要這樣是因為 .tclshrc 需要放在家目錄,這樣就…… 不知道怎麼從 rpm spec 修改。

* 原本我以為會去搜尋 /usr/share/tcl 目錄,結果沒有,但是還是可以透過修改 .tclshrc 方式來使用。

* 其實還有個違反 tm 檔案設計想法的改法,就是加上 pkgIndex.tcl,就可以讓 Tclsh 搜尋到。這個方法還沒測試。

更新:雖然和 tm 檔案設計的想法衝突,但是 RPM spec 加上 pkgIndex.tcl 就可以正常運作
使用 build script 建立 RPM 來測試 (注意:tcl-dbif 1.2 需要使用 tcl-dbus 2.1 版本才行)

The ActiveState of Tcl: TEApot and TEAcup Are Now Open Source

The ActiveState of Tcl: TEApot and TEAcup Are Now Open Source


所以 ActiveState 開源了  TEApot 和 TEAcup。Source code 放在 Gihub:
https://github.com/ActiveState/teapot


使用 Magicsplat Tcl/Tk for Windows 執行時出現問題。

比對:
tcllib 1.18 下載以後解壓縮,modules\fumagic,pkgIndex.tcl
if {![package vsatisfies [package provide Tcl] 8.4]} {return}

# Recognizers
package ifneeded fileutil::magic::filetype 1.0.2 [list source [file join $dir filetypes.tcl]]
package ifneeded fileutil::magic::mimetype 1.0.2 [list source [file join $dir mimetypes.tcl]]

# Runtime
package ifneeded fileutil::magic::rt 1.0 [list source [file join $dir rtcore.tcl]]

# Compiler packages
package ifneeded fileutil::magic::cgen   1.0 [list source [file join $dir cgen.tcl]]
package ifneeded fileutil::magic::cfront 1.0 [list source [file join $dir cfront.tcl]]

與 Magicsplat Tcl/Tk for Windows 的版本:
if {![package vsatisfies [package provide Tcl] 8.6]} {return}
# Recognizers
package ifneeded fileutil::magic::filetype 1.2.0 [list source [file join $dir filetypes.tcl]]

# Runtime
package ifneeded fileutil::magic::rt 1.2.0 [list source [file join $dir rtcore.tcl]]

# Compiler packages
package ifneeded fileutil::magic::cgen   1.2.0 [list source [file join $dir cgen.tcl]]
package ifneeded fileutil::magic::cfront 1.2.0 [list source [file join $dir cfront.tcl]]

在比對完 github 的 check-in 記錄以後,應該是有人直接修改了 tcllib 的部份,所以如果是從 github 或者是 1.18 release 之後(精確的說是 2016 年 6 月 13 日)從 trunk 拿的版本,就可能會出現這個問題。

* 即使 fileutil::magic::mimetype 問題解決,還是需要 Trf 套件
* 有 Trf 套件還是無法執行,需要修改 Trf 套件的 pkgIndex.tcl 版本號(ActiveTcl 8.6.6 issue)
* 改了版號還是無法執行,pref-devkit.tm 需要 projectInfo 套件
* 移除掉 package require projectInfo 也無法正確執行,沒有 jobs-async.tm 檔案


更新:
看起來我的做法錯誤, 下載 ActiveTcl 8.6.6 以後重做一次。

can't find package fileutil::magic::mimetype
    while executing
"package require fileutil::magic::mimetype   "
    (file "C:/Temp/teapot/lib/metadata/teapot-metadata-read.tm" line 38)


ActiveTcl 使用 Tcllib 1.18,所以不會有這個問題,如果有遇到;
更新 mimetype 變成 filetype (不知道這個做法會不會影響程式執行)
然後

attempt to provide package Trf 2.1 failed: package Trf 2.1.4 provided instead
    ("package ifneeded Trf 2.1" script)


ActiveTcl 會遇到這個問題,把版本修正為精確版本。
更新 C:/ActiveTcl/lib/trf21/pkgIndex.tcl, 修改 2.1 為 2.1.4.
然後

couldn't read file "C:/Temp/teapot/lib/misc/jobs-async.tm": no such file or dire
ctory
    while executing
"source C:/Temp/teapot/lib/misc/jobs-async.tm"
    ("package ifneeded jobs::async 0.1" script)
    invoked from within
"package require jobs::async"
    (file "C:/Temp/teapot/lib/tap/tap-db-files.tm" line 31)


更新 C:/Temp/teapot/lib/tap/tap-db-files.tm,
修改 jobs::async 變成 jobs

can't find package projectInfo
    while executing
"package require projectInfo     "
    (file "C:/Temp/teapot/lib/prefdk/pref-devkit.tm" line 44)


重做以後遇到這個問題,目前的暫時解法是移除掉package require projectInfo 這一行。

然後終於有一個可以正確執行的東西。


不過可惜的是到這裡還沒有結束,使用 tclsh main.tcl list [package name] 以後,會出現

Bad configuration
No archives known

的訊息,有可能是需要一些其它設定,那麼即使修改到可以執行,還是沒用(PS. 已經使用有包含 mimetype 的 1.18 版測試過,看起來不是這個套件的問題)。所以有可能需要包裝為 teapot 的工具並且經過適當設定才能夠使用。

外部的開發者無法在自己環境使用的工具等於沒有開源一樣,而等於沒有開源的意思就是還是只有 ActiveState 自己的人在開發。經過測試,雖然 ActiveState 開源了 teapot,但是就目前的有限資訊下,對於非 ActiveState 的人(甚至是 ActiveTcl 8.6.6 的使用者)來說是個沒有用的工具。

更新:
我發了一個訊息到 comp.lang.tcl,這樣如果有使用 fileutil::magic::mimetype 的人在 Tcllib 被修改以後的版本遇到問題,他們才知道發生了什麼情況。

2017-10-05

Sugar: Lisp-like macro system for Tcl

Sugar


會注意到是因為 Debian/Ubuntu 有這個套件 (套件名叫 tcl-sugar),然後就去 Tcler's wiki 看是不是有資料。沒想到可以用 pure Tcl 實作了一個類似 Lisp 的 macro system。

2017-10-02

Magicsplat Tcl/Tk for Windows, Visual Studio 2017 and Jsonnet

Google Jsonnet 在 v0.9.5 加入一個 Visual Studio 2017 的專案檔,這表示已經成功的移植到 Windows(使用 Visual Studio 2017 編譯)。

我按照以前寫的 extension,改寫之前 win 目錄下的 makefile.vc 等檔案,試看看能不能使用 Visual Studio 2017 來編譯 tcljsonnet。結果出現一個很奇怪的狀況,在最後連結的時候,Visual Studio 2017 會一直抱怨 BAWT-Tcl (使用 MinGW-W64 編譯) 所使用的是舊的格式,我需要重新編譯才能夠正確連結。

經過思考,換成 Magicsplat Tcl/Tk for Windows 來測試(注:我安裝 在 c:\Tcl,而 Magicsplat  使用 Visual Studio 編譯),然後就很順利的編譯了,而且 tcljsonnet 也可以很正確的使用,不會有 C++ exception 模式不相容的問題。

但是這樣也代表,微軟 Windows 平台出現了格式的相容性問題,但是除非是一個環境中會使用 MinGW-W64 與 Visual Studio 2017 的人才會很快就遇到這個問題。

但是如果將 MinGW-W64 與 Visual Studio 2017 因為 binary 格式不相容而視為二個平台,就會出現很大的維護問題,至少對我而言會很吃力。而目前看起來,並沒有一個好的解法,還蠻麻煩的。 更新:我把使用 MinGW-64 編譯的 extension(例如我自己寫的 tcl-lmdb)放到 Magicsplat Tcl/Tk for Windows 的 lib 目錄下,發現可以使用,所以看起來問題沒那麼大。目前我還是以使用 Mingw-W64 為主,只有需要 Visual Studio 的時候才使用 Visual Studio。

2017-09-19

BAWT-Tcl Windows installer

BAWT 提供了 8.6.x 系列的 Windows 安裝程式,並且安裝了一些常用的擴充套件以及 BAWT 作者自己的作品。


如果你使用 MSYS2/MinGW-w64 的組合,然後 Tcl 使用 BAWT-Tcl 安裝 (假設是安裝在 c:/Tcl),在編譯自己的套件時有可能會出現一些小亂流。

這是因為 tclConfig.sh 和 tkConfig.sh 在編譯的機器所指向的目錄和目標機器並不相同。也就是 TCL_PREFIX, TCL_EXEC_PREFIX, TCL_BUILD_LIB_SPEC, TCL_LIB_SPEC 等目錄所記錄的資料不是正確的。但是要修改很簡單,只要指向正確的目銾就可以解決問題,下面是一個例子:

# Top-level directory in which Tcl's platform-independent files are
# installed.
TCL_PREFIX='/c/Tcl'


假設要改善的話,應該只能夠從安裝程式著手,也就是使用者設定好安裝目錄以後,按照安裝目錄的位置進行改寫。取巧的做法是編譯機器和目標機器的環境很像,然後目標機器的預設目錄符合預設的設定(還是有可能出問題,因為使用者有可能不是安裝在預設位置,但是機率大幅度降低)。

2017-09-17

regex_rez: Tcl bindings for RE2

regex_rez


可是,我目前只需要基本功能,所以只實作最簡單的 fullmatch, partialmatch, replace 和 globalrelpace。


維基百科:
RE2 (software)


第一個測試程式使用內建的正規表示式:
puts -nonewline "Please input a number: "
flush stdout
gets stdin number
if {$number <= 0 || $number >= 10} {
   puts "The range is 1 - 9."
   exit
}

set max [expr pow(10, $number)]
set result [list]

puts "\nNow get the result:"
puts "==========="
puts "Start"
puts "==========="
puts [time {
set re {1.*1|2.*2|3.*3|4.*4|5.*5|6.*6|7.*7|8.*8|9.*9|0.*0}
for {set i 1} {$i < $max} {incr i} {
    if {[regexp $re $i] != 1} {
        lappend result $i
    }
}
} 1]
puts "\n"
puts [join $result ", "]
puts "\n==========="
puts "End"
puts "==========="

第二個測試程式使用 RE2:

package require regex_rez

puts -nonewline "Please input a number: "
flush stdout
gets stdin number
if {$number <= 0 || $number >= 10} {
   puts "The range is 1 - 9."
   exit
}

set max [expr pow(10, $number)]
set result [list]

puts "\nNow get the result:"
puts "==========="
puts "Start"
puts "==========="
puts [time {
set re [regex::re2 create {1.*1|2.*2|3.*3|4.*4|5.*5|6.*6|7.*7|8.*8|9.*9|0.*0}]
for {set i 1} {$i < $max} {incr i} {
    if {[$re partialmatch $i] != 1} {
        lappend result $i
    }
}
} 1]
puts "\n"
puts [join $result ", "]
$re close
puts "\n==========="
puts "End"
puts "==========="

(* 更新測試程式二,加上 $re close,這樣才會正確 close)

內建從輸入數字一到數字九:
475 microseconds per iteration
1029 microseconds per iteration
6884 microseconds per iteration
36152 microseconds per iteration
315566 microseconds per iteration
3134428 microseconds per iteration
32075931 microseconds per iteration
325211857 microseconds per iteration
2147483648 microseconds per iteration

RE2 從輸入數字一到數字九:
325 microseconds per iteration
649 microseconds per iteration
7262 microseconds per iteration
48204 microseconds per iteration
347111 microseconds per iteration
2727082 microseconds per iteration
21171756 microseconds per iteration
173788033 microseconds per iteration
1628503061 microseconds per iteration


雖然沒有很仔細的比較,在這個測試中如果是百萬級數目或者是以前比對,內建的正規表示式表現都很不錯,但是如果數目到達百萬級或者是以後比對,Tcl 內建的正規表示式速度看起來明顯的比較慢。

很有趣的問題。

2017-09-12

tclmixer - use SDL2/SDL2_mixer

tclmixer


TclMixer 使用 SDL 1.2 和 SDL_Mixer 1.2,我這幾天突然有個神奇的想法,那就是如果切換到 SDL2/SDL2_mixer 不知道會不會很難。

所以我下載了 TEA sample extension 然後將 TclMixer 的 source code 移過來,做了一點點小修改(主要是改版本,改成 2.0.0),然後發現…… SDL 和 SDL2 的 API 差距沒想像中大,因為沒改什麼東西,可是看起來 TclMixer 可以用。

實測 openSUSE 42.3 的結果,雖然可以使用,但是 SDL_mixer 還沒有 mp3 的部份,不過 OGG/Vorbis 是可用的。

MP3 的最後一個軟體專利在今年到期,所以一些原本無法直接使用的 MP3 自由軟體應該會開始逐漸重新進入 Linux 世界。至少在我測試 mpg123 的時候,我發現 openSUSE 在 42.3 將這個軟體放進來了(只是 devel package name 有改變,與 packman 的不同,但是主套件和 shared library package name 看起來是一致的)。