Tcl/Tk 釋出了 8.6 系列的新版本,8.6.18。
這個版本的主要更新內容可以參考 tcltk-release-notes-8.6.18.txt。
注意:This is the last release of the 8.6 series unless very severe issues are found. Only Tcl/Tk 9 will be actively developed from now on.
關於各種 Tcl/Tk 的資訊,以及 Tcl/Tk 各種使用上的記錄分享
Tcl/Tk 釋出了 8.6 系列的新版本,8.6.18。
這個版本的主要更新內容可以參考 tcltk-release-notes-8.6.18.txt。
注意:This is the last release of the 8.6 series unless very severe issues are found. Only Tcl/Tk 9 will be actively developed from now on.
TclTLS 釋出了一個十分重要的重大更新版本,v2.0。下面是這次更新的內容:
下面則是我的簡單測試程式。
#!/usr/bin/env tclsh
package require http
package require tls
set protocol "http/1.1"
http::register https 443 [list ::tls::socket -autoservername 1 -require 1 -alpn [list [string tolower $protocol]]]
set tok {}
set url {https://duckduckgo.com/}
try {
set tok [http::geturl $url -method GET -timeout 3000]
puts "Status: [::http::ncode $tok]"
puts "Status Text: [http::status $tok]"
puts "Headers: [http::meta $tok]"
} on error {em} {
puts "Error: $em"
} finally {
# cleanup here
if {[info exists tok]==1} {
http::cleanup $tok
}
}
NaviServer 目前提供了二種資料庫介面, nsdb 與 後來擴充一些功能的 nsdbi。 nsdb 為 NaviServer 的內建模組(只是需要自行設定載入模組),而 nsdbi 需要使用者自己編譯並且加入到 NaviServer。
注意:如果想要使用 OpenACS 並且資料庫使用 PostgreSQL,那麼必須安裝 nsdbpg 模組。 下面使用 PostgreSQL 測試 nsdb 以及 nsdbpg 模組。使用者需要編譯 nsdbpg 模組並且加入到 NaviServer。 如果要自己編譯 nsdbpg 模組,注意其 Makefile 中 NAVISERVER 所設定的位置, 以及 dbpg.h 中 pg_config.h 和 libpq-fe.h 標頭檔的位置(openSUSE 安裝的位置放在 /usr/include/pgsql)。 下面是標示差異點的 patch 檔案。
--- dbpg.h.org 2025-12-03 16:37:40.171256167 +0800
+++ dbpg.h 2025-12-03 16:37:58.707205142 +0800
@@ -25,7 +25,7 @@
* pg_config.h. However, the PACKAGE_* macros conflict with
* NaviServer's packaging information, so we drop these.
*/
-#include <pg_config.h>
+#include <pgsql/pg_config.h>
#undef PACKAGE_VERSION
#undef PACKAGE_TARNAME
#undef PACKAGE_STRING
@@ -34,7 +34,7 @@
#undef PACKAGE_URL
#include <nsdb.h>
-#include <libpq-fe.h>
+#include <pgsql/libpq-fe.h>
/*
* Forward compatibility, in case a new version of the module is compiled
--- Makefile.org 2025-12-03 16:39:07.524319290 +0800
+++ Makefile 2025-12-03 16:39:23.699037548 +0800
@@ -27,7 +27,7 @@
# version of this file under either the License or the GPL.
ifndef NAVISERVER
- NAVISERVER = /usr/local/ns
+ NAVISERVER = /var/lib/naviserver
endif
#
不過除了直接修改,也可以使用設定參數的方式,下面就是編譯與安裝的指令:
make NAVISERVER=/var/lib/naviserver PGLIB=/usr/lib64 PGINCLUDE=/usr/include/pgsql
sudo make NAVISERVER=/var/lib/naviserver install
在安裝完 nsdbpb 以後,接下來修改 nsd-config.tcl,首先加入相關的變數:
# For database
dict set defaultConfig db_name danilo
dict set defaultConfig db_user danilo
dict set defaultConfig db_password danilo
dict set defaultConfig db_host localhost
dict set defaultConfig db_port 5432
加入 nsdb 模組,讓 NaviServer 在啟動時會載入模組。
ns_section ns/server/default/modules {
if {$nscpport ne ""} {ns_param nscp nscp}
ns_param nslog nslog
ns_param nscgi nscgi
ns_param nsperm nsperm
ns_param nsdb nsdb
ns_param revproxy tcl
}
然後加入 nsdbpg driver 的設定。
ns_section ns/db/drivers {
ns_param postgres nsdbpg
}
接下來加入 connection pool 的設定。使用者可以設定不止一個 pool,我在這裡只是驗證如何設定,所以只加入一個。
ns_section ns/server/default/db {
#ns_param Pools pool1,pool2
ns_param Pools pool1
ns_param defaultpool pool1
}
ns_section ns/db/pools {
ns_param pool1 "This is pool1 for PostgreSQL"
}
ns_section ns/db/pool/pool1 {
ns_param Connections 10
ns_param LogMinDuration 10ms
ns_param LogSQLerrors false
ns_param driver postgres
ns_param DataSource ${db_host}:${db_port}:${db_name}
ns_param user $db_user
ns_param password $db_password
}
最後寫一個簡單的測試程式測試。
<%
ns_adp_puts "NaviServer nsdbpg module - get PostgreSQL version<br>"
set db [ns_db gethandle]
set result [ns_db 1row $db "select version() as version"]
ns_adp_puts [ns_set get $result version]
%>
下面嘗試安裝 nsdbi 以及 nsdbipg。
首先是 nsdbi,下面就是編譯與安裝的指令:
make NAVISERVER=/var/lib/naviserver
sudo make NAVISERVER=/var/lib/naviserver install
再來是 nsdbipg,下面就是編譯與安裝的指令:
make NAVISERVER=/var/lib/naviserver PGLIB=/usr/lib64 PGINCLUDE=/usr/include/pgsql
sudo make NAVISERVER=/var/lib/naviserver install
接下來修改 nsd-config.tcl,首先是加入模組(有二種方式,一種是全域的加入方法,一種是 per server 的加入方式, 這裡使用後一種):
ns_section ns/server/default/modules {
if {$nscpport ne ""} {ns_param nscp nscp}
ns_param nslog nslog
ns_param nscgi nscgi
ns_param nsperm nsperm
ns_param revproxy tcl
ns_param nsdbipg1 nsdbipg
}
以及 nsdbipg1 的設定:
ns_section ns/server/default/module/nsdbipg1 {
ns_param default true ;# This is the default pool
ns_param handles 10 ;# Max open handles to db.
ns_param maxwait 10 ;# Seconds to wait if handle unavailable.
ns_param maxidle 0 ;# Handle closed after maxidle seconds if unused.
ns_param maxopen 0 ;# Handle closed after maxopen seconds, regardless of use.
ns_param maxqueries 0 ;# Handle closed after maxqueries SQL queries.
ns_param checkinterval 600 ;# Check for idle handles every 10 minutes.
ns_param datasource "host='localhost' port=5432 user='danilo' password='danilo' dbname='danilo'"
}
最後寫一個簡單的測試程式測試。
<%
ns_adp_puts "NaviServer nsdbipg module - get PostgreSQL version<br>"
dbi_1row -array result {select version() as version}
ns_adp_puts $result(version)
%>
如果將取得結果回傳為一個串列:
set result [dbi_rows {select a, b from t}]
foreach {a b} $result {
lappend lresult [list $a $b]
}
nsdbi 使用 dbi_dml 執行 insert/update/delete 指令。nsdbi 支援 bind variable,使用 :variable 的形式來代表變數。
dbi_dml {insert into test values (3, 'z')}
dbi_dml {insert into test (a, b, c) values (:a, :b, :c)}
set numRows [dbi_dml {update test set b = 'z' where a = 1}]
dbi_dml {delete from test where a = 3}
要注意的是,database handle 由 NaviServer 所管理,所以你在測試程式並沒有看到開啟 handle 的動作。
另外,如果使用 NaviServer 提供的資料庫介面,建議修改 systemd service 檔案 nsd.service, 以 PostgreSQL 來說,最好加入 postgresql.service 的部份,所以可以改為如下:
[Unit]
Description=NaviServer
#After=network.target
After=network.target postgresql.service
Wants=postgresql.service
NaviServer 本身支援 ASP/PHP 類似的寫法,可以內嵌 Tcl 程式碼到網頁中,
稱為 NaviServer Dynamic Pages (ADPs),其副檔名為 adp,可以參考下列的網頁:
NaviServer ADP Development
主要的語法有以下三種,第一種為使用 script 標籤:
<script language="tcl" runat="server" stream="on">
...
</script>
第二種則是短標籤:
<% ... %>
第三種則是印出變數的短標籤:
<%= ... %>
NaviServer 已經內建 nscgi 模組。檢查 nsd-config.tcl(或者是你使用的設定檔),確定有載入模組:
ns_section ns/server/default/modules {
if {$nscpport ne ""} {ns_param nscp nscp}
ns_param nslog nslog
ns_param nscgi nscgi
ns_param nsperm nsperm
ns_param revproxy tcl
}
如果想要使用以前使用 Tcl 寫的 CGI 程式、或者是要使用 NaviServer 練習撰寫 CGI 程式, 只要注意 NaviServer cgi-bin 設定的位置正確的放置檔案,以及正確的加入 Tcl interpreter 的設定即可。 接下來修改 nsd-config.tcl:
ns_section ns/server/default/module/nscgi {
ns_param map "GET /cgi-bin $home/cgi-bin"
ns_param map "POST /cgi-bin $home/cgi-bin"
ns_param interps CGIinterps
#ns_param allowstaticresources true ;# default false; serve static resources from cgi directories
}
ns_section ns/interps/CGIinterps {
ns_param .pl "/usr/bin/perl"
ns_param .tcl "/usr/bin/tclsh"
ns_param .sh "/bin/bash"
}
PHP 目前在網頁伺服器主要有三種執行的方式,使用 CGI,使用 FastCGI 以及內嵌到網頁伺服器裡。 如果使用 PHP 8.x,php cgi 程式 (php-cgi) 在 openSUSE Tumbleweed 的套件為 php8-fastcgi。 如果想透過 NaviServer 使用 CGI 的方式執行 PHP 是可行的,只要修改 nsd-config.tcl 加入 PHP interpreter 的設定:
ns_section ns/interps/CGIinterps {
ns_param .pl "/usr/bin/perl"
ns_param .php "/usr/bin/php-cgi"
ns_param .tcl "/usr/bin/tclsh"
ns_param .sh "/bin/bash"
}
然後寫一個測試程式:
<?php
phpinfo();
?>
Tcl/Tk 釋出了一個 9.0 的維護版本,9.0.3,說明檔案看起來是從 9.0.2 改的(似乎沒有改完全),不過公告看起來是沒問題的。
Tcl/Tk 9.0.3 的主要改變可以參考 tcl-release-notes-9.0.3.md, tk-release-notes-9.0.3.md。
這版整合了 paho.mqtt.c-1.3.15 的相關檔案。至於 C23 中 bool 關鍵字的解法,paho.mqtt.c 使用了更簡單的解法,直接將變數名稱改掉,這樣就可以避免掉問題。
Tcl/Tk 釋出了一個 9.0 的維護版本,9.0.2。
Tcl/Tk 9.0.2 的主要改變可以參考 tcl-release-notes-9.0.2.md, tk-release-notes-9.0.2.md。
GCC15 C 編譯器如果沒有使用 -std 選項指定,編譯時使用的標準為 C23,bool 在 C23 成為關鍵字,所以自定義 bool 的做法在 GCC15 會編譯失敗。目前上遊還沒有確定解法,我只是選一個比較簡單的改法先讓程式能夠編譯成功,然後再看上遊會怎麼修改再進行修正。
#if defined __STDC__ && defined __STDC_VERSION__ && __STDC_VERSION__ <= 201710L
typedef unsigned int bool;
#endif
也就是使用 __STDC_VERSION__ 進行判斷。