TAG

首都機能移轉 (2) 歌詞 (2) 靠北文 (40) 戲言 (30) 糟糕 (7) ACG (23) Assembly (2) Boost (2) C (31) C++ (69) CMake (4) CSIE (67) Debian (34) Design_Pattern (2) Django (1) Eclipse (1) en_US (13) FFmpeg (3) FoolproofProject (26) FreeBSD (2) Git (4) GNU_Linux (65) IDE (5) Java (11) JavaScript (19) KDE (15) Khopper (16) KomiX (3) Kubuntu (18) Life (1) Lighttpd (2) Mac_OS_X (2) Opera (1) PHP (2) PicKing (2) Programing (21) Prolog (1) Python (7) QSnapshot (2) Qt (30) Qt_Jambi (1) Regular_Expression (1) Shell_Script (7) Talk (98) VirtualBox (7) Visual_Studio (13) Windows (18) zh_TW (36)
顯示具有 CSIE 標籤的文章。 顯示所有文章
顯示具有 CSIE 標籤的文章。 顯示所有文章

2011年4月1日 星期五

Another Observer Pattern implementation in Java

由於實在不喜歡 Swing 的 listener 方式,因此我嘗試使用 Java 內建的 ObserverObservable 來套用 Observer Pattern,但它比我想像中地還不靈活,原因有三:
  1. 必須要呼叫 Observable.setChanged 才會讓 Observable.notifyObservers 生效,而 Observable.setChanged 是 protected,這意味著你至少必須繼承 Observable 類別,這對於不允許多重繼承的 Java 來說很要命,因為 host class 很有可能來自另一繼承體系。
  2. 你沒辦法透過 composition 繞過這個限制,因為 Observer.update 帶有一個型態為 Observable 的參數,語義上這個參數必須要是發出事件的物件,但若是使用 composition 持有 Observable 物件,Observer 收到的參數就會跟真正發出事件的物件無關,這會破壞這組範式的假設。
  3. 你有可能需要在同一個類別裡發送不同的事件,但使用繼承的做法你只能使用一種通知。如果要達到分派不同事件的目的,就必須要在那唯一的一個 Object 參數上作手腳。

2011年2月2日 星期三

Lambda binding issue in VC10

VC10 的 lambda expression 的 bug 還真多 ... 這應該是我第三次踩到相關的 bug 了吧。
auto f( std::bind( []( int a, int b )->int {
    return a + b;
}, std::placeholders::_1, 2 ) );

f( 1 ); // returns 3

2011年1月23日 星期日

Use pyside-uic to compile ui files automatically

PySide 可以用 pyside-uic 來轉換 *.ui 到 python code,但每次都要手動弄這個真的很煩。所以我把所有的 ui 檔案集中放到一個資料夾內作為 package,並在 __init__.py 上動點手腳:

2011年1月9日 星期日

Embed external viewers into Firefox

# aptitude install mozplugger
Then Firefox will open your default external viewers with tabs, instead of external windows.

2010年12月29日 星期三

Mozilla Add-On 要求使用者更改密碼以策安全

昨天 MAO 寄了封信, 大意是他們在 12/17 發生了被第三方使用者洩漏密碼的事件, 因此 MAO 為了安全性把所有使用者的密碼都砍掉了, 必須要用忘記密碼的方式重設才能啟用帳號.

2010年4月2日 星期五

Converting literal

為了避免荒廢,來貼個廢文充數好了。
上一篇有提到 string literal 的問題,這是把文字轉成 hex 的 C 程式,不過要用 C99 去編譯才行。
#include <stdio.h>

int main() {
  for( char tmp[1024]; fgets( tmp, sizeof( tmp ), stdin ) != NULL; ) {
    for( unsigned char * c = tmp; *c; ++c ) {
      if( *c == '\n' ) {
        printf( "\n" );
      } else {
        printf( "\\x%02X", *c );
      }
    }
  }
  return 0;
}

2010年3月14日 星期日

Using UTF-8 literals in source code

直接在 code 裡打 UTF-8 字元在有的 IDE 會無法辨識,像是 Visual C++ 2005 和 2008 堅持使用 locale 的編碼來解讀 source,導致換 locale 就會編譯失敗。
這種時候沒什麼有效的解決方法,就是用 hex escape 字元啦 ...
/* 正體中文 in UTF-8 */
const char * utf8 = "\xE6\xAD\xA3\xE9\xAB\x94\xE4\xB8\xAD\xE6\x96\x87";
很煩,很難讀,不過至少所有的字元都保證在 C / C++ 的標準字元集裡;只是最好在旁加上註解說明那應該是什麼字,否則很難維護。

2010年3月12日 星期五

Forward declaration with template parameters

在避免編譯時間拉長的時候,forward declaration 是個很好的選擇。但是有一些時候你無法使用 forward declaration,一個是該型別其實是個 typedef 的時候,另一個是當這個型別用在 template parameter 的時候。
由於 template class 經常是 inline 的,所以它可能在 header 就必須要知道 template parameter 的大小或成員這些細節。這導致你必須要 include definition 或是改用 pointer。
你說 smart pointer? 不會吧?(笑)

2010年3月10日 星期三

Export the symbols of QtSingleApplication

現在 Qt Solution 只能在 git 上取得了。
若想要編成 library,在 configure 參數加上 -library 即可:
configure -library
qmake
make # or nmake for MSVC
真正需要的 header 只有 QtSingleApplication, qtsingleapplication.h, qtcoresingleapplication.h。
The following content is obsolete. Latest update: 2011/04/23
Qt Solutions 的慣例似乎是把它內附的 pri include 到 qmake 的專案檔內,直接把原始檔包進去編譯,而不會做出封裝檔[?]。但是這種做法只適用於用 qmake 管理的專案檔內,且編譯時間可能會拉長。如果想弄出封裝檔,就要自己對它作一點手腳。
QtSingleApplication 為例,可以對 buildlib/buildlib.pro 動手腳。這個設定主要是給 dynamic loading 使用的,只要在 CONFIG 加上 shared 就可以了。
-CONFIG += qt dll qtsingleapplication-buildlib
+CONFIG += qt dll qtsingleapplication-buildlib shared

2010年2月15日 星期一

Create source groups in Visual C++ solutions with CMake

使用 qmake 時,Visual C++ 的方案會自動把產生的檔案(e.g.: ui_*.h, moc_*.cpp ... etc.)歸類到 Generated Files,讓原始碼樹看起來比較清爽。但是 CMake 不會幫你做這件事,專案一大就會讓這些不必修改的檔案佔滿整個專案。
但是 CMake 其實是可以做到的,使用 SOURCE_GROUP 巨集就可以建造一個群組,把原始碼組織起來。過濾的方式有二:使用 regular expression,或是直接指明檔案路徑。以下是範例。
# 明指 moc, rcc, uic, qm 檔案為 Generated Files
source_group("Generated Files" FILES ${MOC_SOURCES} ${RCC_RESOURCES} ${UIC_HEADERS} ${QM_FILES})
# 使用 RE 把資源檔找出來
source_group("Resource Files" REGULAR_EXPRESSION .*\\.rc)
# 使用 RE 把 Designer forms 歸類在 Form Files
source_group("Form Files" REGULAR_EXPRESSION .*\\.ui)
注意 regular expression 要跳出 \。

2009年12月18日 星期五

Ubuntu 又被婊了

這陣子為了 CMake 嘗試轉用 KDevelop 做為開發平台,不過在其首頁上看到一個聳動的標題:Don’t install Ubuntu 9.10 if you want a stable KDevelop - apaku。究竟 Ubuntu 哪裡惹到 KDevelop 了呢?
原來是 Ubuntu 把 KDevelop 4 beta 5 放進 Karmic 的官方套件庫裡,導致 KDevelop 的 upstream 被一堆重複回報的 bug 淹沒,而且其中還有己在 beta 6 修正的 bug。
其實作者要抱怨的不是這堆實際上沒什麼用的 bug report,而是 Ubuntu 把尚未正式釋出的軟體放到正式釋出的套件庫裡。然後自動回報又設定成回報給 KDevelop upstream,而不是 Ubuntu 的 package maintainer,因此 upstream 才會一直收到重複的 bug report。
有人反駁目前穩定的 KDevelop 3 使用的是 KDE3,而現在己不再被 upstream 支援,因此對 Ubuntu 來說別無選擇。但是有趣的是 KOffice 在 Karmic 裡就有分成 koffice (for KDE3, stable) 和 koffice-kde4 (for KDE4, unstable)。
由於作者釋出 beta 的目的是為了測試,但是 Ubuntu 的釋出並不是為了讓使用者測試並回報 bug,並且由於 Ubuntu 本身定位成給新手使用的發行版,他們遇到 bug 大多不會自己解決,也不會看 bug 有沒有被回報過,或是自行從 upstream 下載己修正的最新版原碼回來使用。
作者本人的建議是,尚未正式釋出的軟體不是不能放,而是應該放到另外的套件庫,不要預設就能裝這些不穩定的軟體。他用過的其他發行版都不會有這些問題(Arch, Gentoo, Debian)。
以我正在重度使用的 Debian 來說,它雖龜毛,但是也有龜毛的好處。它的 stable 依然停留在 KDE3,避開了 KDE4 目前尚未被證明的穩定度;而 testing 和 unstable 則是用無接縫升級,因為它們一開始就明講這些軟體尚未經過足夠測試,其使用者多少會有點心理準備;它甚至還提供 experimental 來放那些連 unstable 的條件都無法滿足的軟體。Ubuntu 經常為了新軟體而犧牲其穩定度。

2009年12月11日 星期五

CMake to QMake note

前幾天腦袋壞掉把手上的 Qt project 全換成 CMake,原因是 QMake 的功能實在是不太夠用。最糟糕的一點是建置的彈性太差,你很難在 qmake 的執行選項裡更改專案的設定,通常你要直接修改 *.pro files。然後是它的 install 和設定相依性的能力也很差,跟前述的問題一樣,都是寫死的。
CMake 做為一個建置系統(應該說前端)就還算是優秀,對於相依性的處理可以自己寫一套 script 來自動設定,找不到也可以讓使用者手動設定,雖然有些聲音認為 pkg-config 的方式較為方便,但是畢竟在 Windows(Mac 我不確定) 上這東西是不流行的,而且也不是每個專案都有附上 *.pc 設定。
以下是我從 QMake 到 CMake 轉換的對應處理:
前置動作
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
這會檢查 Qt4 的設定,然後把該有的 macro 和變數引入。
子專案設定
TEMPLATE = subdirs
SUBDIRS = dir1 dir2
轉換為
add_subdirectory(dir1)
add_subdirectory(dir2)
如果有
CONFIG += ordered
的子專案間相依設定的話,要在各子資料夾內加上設定
add_dependencies(A B)
執行檔的設定
SOURCES = a.cpp b.cpp # ... program sources
TARGET = exec
TEMPLATE = app
改為
set(SOURCES a.cpp b.cpp ... )
add_executable(exec ${SOURCES})
動態連結函式庫
TARGET = shared
TEMPLATE = lib
由於 add_library 預設是生成靜態連結函式庫,要明確指定 SHARED
add_library(shared SHARED ${SOURCES})
Qt plugin
TARGET = $$qtLibraryTarget(plugin)
TEMPLATE = lib
CONFIG += plugin
這裡要自己加上 Qt 的 flags
add_definitions(${QT_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED)
add_library(plugin SHARED ${SOURCES})
Qt 模組,預設是會打開 QtCore 和 QtGui 兩個。
QT += phonon
set(QT_USE_PHONON TRUE)
除了 QtCore 和 QtGui 分別是 QT_DONT_USE_QTCORE 和 QT_DONT_USE_QTGUI 外,其他的都是 QT_USE_XXX。如果發生找不到 header 或是連結錯誤的話,變數分別是 QT_XXX_INCLUDE_DIR 和 QT_XXX_LIBRARY。
QMake 會自動找需要 moc 的 header, 但是 CMake 在這個功能上還沒有完整支援,qt4_automoc macro 需要在原始碼最後加上 #include "header.moc"。如果你不是採用此做法,就只好手動加入需要 moc 的 header;怎麼找呢?找連結錯誤的 compile unit 就好了。
qt4_wrap_cpp(MOC_SOURCES a.h b.h)
add_executable(exe ${SOURCES} ${MOC_SOURCES})
Resource system
RESOURCES = a.qrc b.qrc
一樣要透過 wrapper
qt4_add_resources(RCC_SOURCES a.qrc b.qrc)
add_executable(exe ${SOURCES} ${RCC_SOURCES})
header 位置
INCLUDEPATH += src
include_directories(src)
連結
LIBS += -la -lb
記得也要連結 Qt 自己的 library
target_link_libraries(exe ${QT_LIBRARIES} a b)
如果什麼都沒做的話,在 MSVC 底下會出現多餘的 console prompt,需要做一點手腳
add_executable(exe WIN32 ${SOURCES})
target_link_libraries(exe ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY})
版本設定
VERSION = 1.2.3
set_target_properties(exe PROPERTIES VERSION 1.2.3)
set_target_properties(lib PROPERTIES VERSION 1.2.3 SOVERSION 1.2.3)
輸出路徑
DESTDIR = build
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/build")
set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/build")
基本上是建議除非你真的很閒才轉啦 ...

2009年11月29日 星期日

Array IS NOT pointer

呣,其實我大一的時候也有這種觀念,畢竟那時 pointer 還是個陌生的怪物,那還是個「如果你不會傳 array 就宣告成 global」的時代。
基本上 C 的 array 實在不怎麼討喜,包括它的「陣列大小一定要跟在陣列名稱後面」這種鳥語法,如果再加上 function pointer 那可真是醜斃了。之所以 array 經常和 pointer 混為一談,最大的原因應是 array 會被隱式轉型[?]為 pointer,且 array 變數本身的值就是 array 第一個元素的位址。這讓你可以把陣列丟入如下的函式裡:
void f1( const int * array );
呃,那二維陣列呢?
void f2( const int * * const array );
因為並不存在多維陣列對 pointer 的隱式轉換,因此你無法直接丟進去。
接下來要談談 array 和 pointer 有什麼不同。
最顯著的性質是,array 變數本身是唯讀的,它無法再被賦值,其代表的空間也無法被手動釋放,而 pointer 值則可以變動,指向的內容可能可以被手動釋放;這也是 pointer 令新手感到易混淆的地方,因為它同時有資源的持有者以及迭代性質。
此外,pointer 可以被取址,但是 array 的址和它自己一樣,也就是陣列開始的第一個位址:
int cla[1];
printf( "%p %p\n", cla, &cla );    // the same
另一個較為有用的不同點是,array 可利用 sizeof 求大小,而 pointer 就只是個 pointer。
int8_t a[10];
sizeof( a ); // 10
int8_t * b = a;
sizeof( b ); // 4 or 8, depends on your compiler
那如果你很希望陣列在傳入函式後還是個陣列,C++ 的 template 可以幫得上忙:
template< typename T, std::size_t N >
std::size_t getByteLength( const T ( & array )[N] ) {
    return sizeof( array );
}

// how to use:
int32_t tmp[4];
getByteLength( tmp );  // will return 16
坦白說,我不是很清楚為什麼一定要用 reference to array,不過你的確可以用這個 template function 傳 array。再多維也可以:
template< typename T, std::size_t N, std::size_t M >
std::size_t getByteLength2( const T ( & array )[N][M] ) {
    return sizeof( array );
}
以此類推。

2009年11月11日 星期三

Casting function pointers from void * in C++

在拿 DLL 裡的 symbol 時,它會回傳一個 void *,你必須要自己轉型成對應的 function pointer。不過問題是 C++98/03 都把 void * 視為指向某個物件的指標,而不會是一個 function pointer,所以使用 C++ style 轉型會失敗;既然標準沒有定義,就代表這種行為基本上是依賴實作的,為此我們需要一些怪怪的 reinterpret_cast
作法一,先轉成指標長度的整數,再轉成函式指標。
void * gptr = dlsym( ... );
typedef void ( * fptr )();
fptr my_fptr = reinterpret_cast< fptr >( reinterpret_cast< intptr_t >( gptr ) );
intptr_t 是 C99/C++0x 的新型別,一定是一個指標的大小,如果沒有辦法的話,也可以用 long 代替,大部分的平台上 long 都和指標同長。
作法二,把函式指標的位址轉型成 void * * 再指定。
fptr my_ptr = 0;
*reinterpret_cast< void * * >( &my_ptr ) = gptr;
...

2009年11月9日 星期一

不 try 一下怎麼會知道呢

最近用自己定出的編碼器介面寫外掛時, 才發現原本定的介面怪怪的。
首先是 hook 的呼叫順序。由於 libav* 是先開完檔再呼叫寫入 header 的函式,因此我也讓 openResource 在 writeHeader 之前先呼叫。但是其他的編碼器並不一定是這個順序,其實有的根本就沒有分 setupEncoder 和 setupMuxer 的步驟。反正我也沒有檢查每個 hook 要做什麼事,也不可能檢查 ... 所以這倒是沒什麼關係。
第二個問題是我在抽象類別上有定義 buffer 機制,原本是希望可以減輕具象類別的負擔,沒想到現在用起來覺得有點累贅,多了不必要的介面操作。這部分需要在 0.3 修正。
最嚴重的問題是,編碼器似乎不太需要動態載入外掛,應該說不需要和操作它的圖形介面分開發佈。原本的用意是希望降低耦合度,並且讓其他的外掛也有機會使用它,但是操作用的外掛不可能不知道它要呼叫哪個編碼器,而且分開發佈導致無法使用編碼器特殊的設定,像是壓縮率等。目前看來唯一的好處是其他人也可以産生這個實體 ... so what? 難道 mp3 設定會呼叫 ogg vorbis 的編碼器嗎?總之這個外掛的介面真的有點多餘。

2009年10月30日 星期五

Framework 終究只是 Framework

最近這個禮拜的 debug 過程又讓我深刻地體會到這點。
從以前到現在我遇到的問題:
  • Qt Phonon 的 SeekSlider 沒有訂製點,所以我幹了一個自己的
  • Qt Webkit 沒有 DOM 的存取方法(不過已在 4.6 加入)
  • Java 的 ZipEntry 不支援 unicode
  • FFmpeg 可以編 MP3 VBR,但是沒有寫 VBR 用的 header (I dont think we write the optional vbr tag, so its not a bug. by michaelni)
  • FFmpeg 不能 seek FLAC,解碼出來的時間點也都是垃圾
其他還有很多臨時沒想到的。Framework 只會讓你有機會省一點時間,但是不代表你可以完全依賴它。就跟學了 jQuery 就以為自己懂 AJAX,或是學 Java 就以為不用搞懂指標,不過就是自我感覺良好而已。

2009年9月13日 星期日

Install Windows XP on VirtualBox with SATA support

Briefly in Windows XP:
  1. Download the drivers from Intel
  2. Extract the archive:
    • Windows: Just extract it. You will get an floppy image named F32.IMA
    • Linux: Because of it is a self-extract archive, you can use unzip or p7zip to extract f6flpy32.exe and can still get F32.IMA
  3. Mount the floppy image. No bother to use a real floppy.
  4. In the initialization stage, press F6 to get the external SATA drivers.
  5. Press S to select driver. Please select Intel(R) 82801HEM/HBM SATA AHCI Controller (Mobile ICH8M-E/M)
  6. Then go ahead

2009年9月11日 星期五

Packages in Opera's FTP repository

There is a deb repository that provides apt service. But packages in that one are still depends on Qt3. Packages which are built with Qt4 are only avaliable in FTP repository. Weird Opera.