Saturday, October 10, 2009

POSIX termios interface for canonical/non-canonical mode switching


前言
POSIX termios interface,提供一個介面讓我們可以做Termios Programming然而,Termios Programming是一個很大的主題,並且有許多的應用我們可以透過它來控制terminal在處理字元上的一些設定此外Serial Programming也是需要透過它來做一些設定,例如:設定Baud Rate或Parity Checking。甚至,它可以用來存取RS-232的serial port,並且做client-server終端控制的一些應用。而在這篇我想介紹的是利用termios來切換終端機接收字元的標準/非標準模式(canonical/non-canonical mode

Termios簡介
Termios是一個符合POSIX的介面有定義一些函式或巨集除了控制I/O; 它還可以控制硬體,例如決定使用多少位元來傳送跟接收字元; 並且,它也可以控制終端機的特性,例如決定終端機接收字元的模式(接下來本篇文章將以此來舉例); 最後,它也針對一些字元提供特殊的控制

標準/非標準模式(canonical/non-canonical mode)
不管在MS-DOS或是LINUX的終端機相信大家較常使用的是標準模式,而簡單的說,它就是允許使用者在按下Enter鍵前仍然可以修改輸入的字元(例如使用Backspace鍵來修改),所以按下Enter鍵,程式才會讀取字元。相對來說,非標準模式會讀取使用者輸入的任何字元,當然,我們可以利用termios來控制這些輸入,例如我們可以決定在非標準模式下,當使用者輸入多少個字元時即把這些字元傳送給終端機

如何利用termios來切換標準與非標準模式
底下就開始介紹如何使用termios來切換標準與非標準模式
1) 首先,要使用termios我們當然需要先把它include進來

#include <termios.h>

2) 接下來,宣告兩個termios結構(需要宣告兩個是因為,程式在做完任何只有程式本身所需的設定後,在程式結束前必須負責切換回終端機原本的設定,以免影響其它使用)

struct termios initial_settings, new_settings;

3) 取得目前終端機初始設定,並將設定存到initial_settings

tcgetattr(fileno(stdin),&initial_settings);

4) initial_settings複製給new_settings

new_settings = initial_settings;

5) 利用new_settings來做我們想要的設定,以我們的例子來講,我們需要切換成非標準模式

new_settings.c_lflag &= ~ICANON
6) 復原終端機原本的設定

tcsetattr(fileno(stdin),TCSANOW,&initial_settings);

如此,便可以切換成非標準模式,此外,在非標準模式下termios還有很多功能例如使用VTIMEVMIN來控制輸入舉個例子,每當使用者輸入兩個字元,終端機就自動接收這兩個字元,可以這麼寫

new_settings.c_cc[VMIN] = 2;
new_settings.c_cc[VTIME] = 0;

VMIN代表的是非canonical模式讀的最小字元數目。而VTIME代表讀取字元跟字元中間的延遲時間,設定成0代表不可慮VTIME。然而VMIN跟VTIME有許多不同組合,各代表著不同的意義,這就不是本篇文章討論範圍了

結論
termios允許我們去跟一些硬體做溝通,例如透過serial port跟其他設備溝通,目前又以嵌入式系統比較常需要使用,然而在PC上,由於各種傳輸規格日益增進,因此serial port的方法也慢慢被取代了

[Reference]
Beginning Linux Programming 4/e, Richard Stones and Neil Matthew


Wednesday, October 7, 2009

[AVR] Storing/Retrieving Data in the Program Space (Flash Memory)

AVR Atmel ATmega328P
微處理器 - AVR Atmel ATmega328P提供了32KB的Flash Memory(Program Memory),以及2KB的RAM(Data Memory)。而由於AVR是採用Harvard architecture,因此會利用Flash Memory來儲存program;並利用RAM儲存data,且有各自的address space。 


Harvard architecture V.S. Von Neumann architecture
因為Data Memory容量比較有限,因此我們希望能將一些constant data存放在空間較大的Flash Memory。加上,C語言是for Von Neumann architecture,也就是code跟data皆存在同一個address space,所以,針對AVR(Harvard architecture)所設計的compiler必須符合code跟data存放在不同address space這個設計標準。


AVR GCC __attribute__
要達到Harvard architecture的特性有許多方法
而AVR則利用類似GCC的__attribute__這個tag來實作,簡單講,__attribute__可以附加在函式變數的宣告,就是在編譯時會告訴compiler要特別對該函式變數做一些處理。AVR提供一些特殊用途的attribute,例如它提供__attribute__((__progmem__))這個attribute讓programmer可以將constant data儲存在Flash Mem.(Program Mem.)
In AVR GCC, there is a special attribute called progmem. This attribute is use on data declarations, and tells the compiler to place the data in the Program Memory (Flash). ~ avr-libc user manual 1.6.6
PROGMEM是AVR-Libc自行定義的一個macro,它被定義成類似GCC的attribute syntax,以下是<avr/pgmspace.h>這個標頭檔對於特殊attribute定義的節錄

#ifndef __ATTR_PROGMEM__
#define __ATTR_PROGMEM__ __attribute__((__progmem__))
#endif
/**
   \ingroup avr_pgmspace
   \def PROGMEM

   Attribute to use in order to declare an object being located in
   flash ROM.
 */
#define PROGMEM __ATTR_PROGMEM__


Storing/Retrieving Data in the Program Space 
接下來,我們來看如何利用AVR-Libc所提供的macro來存取program space的data:
首先,假設我們有以下的data
unsigned char mydata[2][10] =
{
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09},
{0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13}
};

我們可能會利用以下的方式來存取data
byte = mydata[i][j];

但是我們想要把它存放在program space,因此需要用到PROGMEM這個macro來幫助我們達成目的,因為PROGMEM是在<avr/pgmspace.h>定義,所以我們需將它include進來
#include <avr/pgmspace.h>


然後在變數宣告後面加上PROGMEM
unsigned char mydata[2][10] PROGMEM =
{
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09},
{0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13}
};

經過以上幾個步驟,就可以將data存在program space,接下來介紹如何從program space取出data。需要注意的是,我們已經將data搬到了program space了,因此我們沒辦法使用一般的方法來取出data,因為data space的data已被搬到program space。為此,AVR-Libc提供一個pgm_read_* macro讓我們可以取出program space的data,我們只需將data的位址當成pgm_read_* macro的參數即可,用法如下
byte = pgm_read_byte(&(mydata[i][j]));


結論
The macros and functions used to retrieve data from the Program Space have to generate some extra code in order to actually load the data from the Program Space. This incurs some extra overhead in terms of code space (extra opcodes) and execution time. ~ avr-libc user manual 1.6.6
另外,雖然user manual中也提到,從program space中取出data所花費的時間小於把data存入program space的時間,但是,如果程式在呼叫pgm_read_* macro上可以最佳化,當然是至上之選了 : ) 

[Reference]
AVR-Libc user manual (v1.6.6)



Saturday, October 3, 2009

如何將Pololu AVR Library加入自己的Project

前言
Pololu是一家由三個MIT的學生在2000年所創立(http://www.pololu.com/),Pololu主要是生產自家Robot,並且提供一些Robot的週邊零件及相關Library,至於Pololu如何發音?是這樣發的:polo-lu,polo跟俗稱的polo衫發音是一樣的。底下是該公司在Las Vegas的辦公室一景










Pololu AVR Library
這是Pololu公司針對AVR系列的微處理器所提供的Library

如何使用Pololu AVR Library
  1. 首先,根據自己所使用的產品來include所需的標頭檔,例如你購買了Pololu的3pi且想要使用C來coding,則需加入

    #include <pololu/3pi.h>
    

    另外
    ,假如是想使用C++,則加入

    #include <pololu/Pololu3pi.h>
    

  2. 加入所屬微處理器型號的靜態函式庫的連結,例如libpololu_atmega328p.a
  3. 基本上以上兩點已經可以成功編譯,但是為了減少code的大小有個指令可以讓程式在編譯時忽略不必要的function,即-Wl,-gc-sections (for linker option)
下面圖中顯示的是加入Step3前的memory使用狀況


      















而這是加入後的使用狀況
 
可見得把不必要的function拿掉後,程式明顯變小許多

[Reference]
Pololu AVR C/C++ Library User's Guide

Thursday, October 1, 2009

Windows Programming - A Short Introduction

使用環境:Visual C++ 2008


至今在Visual C++中,想要建立一個可以跟使用者互動的應用程式大概有三種方式,
分別是使用Windows API,MFC以及Windows Forms。以下將分別簡介這三種方法:


(1) Windows API:透過Windows API的函式,我們所寫的應用程式就可以跟作業系統做溝通。而利用Windows API來撰寫一個Windows程式至少需要透過兩個函式:WinMain(),它負責程式視窗的初始化;以及WindowProc(),負責處理應用程式的訊息,當有訊息產生,Windows會自動呼叫此函式。當然,這兩個函式都是透過Windows提供的API來跟Windows做溝通。我們來看一下利用這兩個函式所建立的視窗樣貌:


















(2) MFC:MFC是一個封裝Windows API之類別的集合,它簡化了利用Windows API來開發程式,也就是說,我們可以經由一些簡單的類別繼承,加上一些簡單的程式碼,就可以產生我們想要的結果。例如,下圖是繼承CWinAppCFrameWnd,且透過這兩個類別的成員來幫我們產生的視窗圖示:















(3) Windows Forms: Windows Forms應用程式需在CLR環境下執行,它比前面兩種分法更方便建立視窗,programmer完全不需要寫任何code就可以產生如下圖的視窗,並且自動產生code:

















結論:
就以寫GUI為目的來講的話,透過Windows API當然是最吃力的方法,至於剩下來的兩種方法的話,只能說看應用來決定要使用哪種方法,兩種方法各有所長。

[Reference]
Ivor Horton's Beginning Visual C++ 2005, Ivor Horton

Tuesday, September 29, 2009

Syntaxhighlighter for Blogger

在Blog中,
為了讓程式碼看起來更整齊且好閱讀,
有許多大大們引用一些tool,
這些tool可以讓我們更方便來介紹自己post的code,
而我決定使用的是Syntaxhighlighter,
它是利用java script完成的,
以下是google code底下對於Syntaxhighlighter這個project的介紹,


The idea behind SyntaxHighlighter is to allow insertion of colored code snippets on a web page without relying on any server side scripts.


而下面的貼圖是我試著把C++程式貼上來的結果,


// read a file into memory
#include <iostream>
using namespace std;

int main () {
char first, second;

cout << "Please, enter a word: ";
first=cin.get();
cin.sync();

cout << "Please, enter another word: ";
second=cin.get();

cout << "The first word began by " << first << endl;
cout << "The second word began by " << second << endl;

return 0;
}

更清楚的教學及如何使用Syntaxhighlighter可以參考以下的Blog,我就不再贅述了:
http://sharedderrick.blogspot.com/2007/12/blogger-syntaxhighlighter.html

Saturday, September 26, 2009

[轉貼] 独家:/dev/tty文件在Unix操作系统中的妙用

作者: Tina,  出处:IT专家网, 责任编辑: 罗丽艳, 2009-04-22 08:00
Unix系统中,文件是其中最重要的资源。如标准输出文件、标准输入文件、标准错误文件等等。不过这些文件普通用户与系统工程师都需要用到。而在实际工作中,对于系统工程师来说,还需要掌握/dev/tty这个文件。
【IT专家网独家】在Unix系统中,文件是其中最重要的资源。如标准输出文件、标准输入文件、标准错误文件等等。不过这些文件普通用户与系统工程师都需要用到。而在实际工作中,对于系统工程师来说,还需要掌握/dev/tty这个文件。
这个文件顾名思义,主要用来表示用户的终端,但是它跟普通的终端又有差异。普通的终端是指一些硬件设备,如显示器等等。通常情况下,标准输出或者标准错误流的文件都会输出到终端中。但是,这些标准的输入输出往往不能够输入到/dev/tty文件中。而是需要通过重定向功能,把一些命令的输出重定向到这个文件中。另外需要说明的是,普通终端的话往往是每个用户之间相互独立的。也就是说,每个用户的输出彼此之间是互不干涉的。在用户A的终端中不能够看到用户B的终端信息。但是/det/tty这个文件由其特殊性。这个终端文件可以由各个用户共享。正是因为这个文件有这方面的特殊性,为此在实际工作中系统工程师经常需要用到这个文件。


       一、系统工程师常见需求描述及实现方案。
       
       利用这个特殊文件,可以帮助系统工程师解决很多实际问题。


       1、利用这个文件来屏蔽不需要的结果信息。通常情况下,为了提高与用户沟通界面的友好性,往往会在脚本程序中,利用echo命令向用户显示一些提示信息。如一个简单的计算器脚本程序,会提示用户输入相关的参数,如“Put one number”等等。有时候,还会在程序的开头显示一大堆的程序说明。这毋庸置疑,可以提高脚本程序的可读性。即方便了用户的使用,而且别的系统工程师借助这些说明也可以顺利对其进行功能上的调整与扩展。不过这也会赞成一些工作上的困扰。如当系统工程师调试脚本程序的时候,这些显示的提示信息反而会增加系统工程师的困扰,会增加他们的阅读量。因为此时用户终端上显示的将士全部的信息,即包括对于应用程序没有实际价值的提示信息,也包括一些应用程序执行过程中的错误信息。这显然会给系统工程师阅读错误信息带来一定的麻烦。另外如笔者谈过,系统工程师可以通过重定向符号把这个终端输出的信息重定向到一个文件中。可是此时这个文件中也会显示全部的信息。而这些信息大部分是系统工程师不需要看到的。系统工程师可能只需要一些相关的参数以及具体的执行结果。如 10*10=100。就这么简单,而不需要看到一大堆的提示说明。而且如果这个文件中带有这么多的无用信息,对于其他脚本程序来调用这个文件也不是很方便。遇到这种情况时该如何处理呢?其实系统工程师可以轻松的通过/dev/tty文件来过滤这些无用的提示信息。如只需要把脚本程序的运行结果通过重定向服务重定向到/dev/tty文件中。在这个重定向的过程中,Unix系统的shell会采取一定的内部处理机制,会忽略掉echo等命令。也就是说,只要把命令的标准输出重定向到这个文件中,则利用echo命令设置的一些提示信息都会被忽略掉。此时在这个文件中,存储的只有一些必要的运行信息,如错误或者警告信息等等。


       2、当作其他命令的参数。/dev/tty文件不仅可以用作终端设备来管理,而且这个文件还可以被用来当作其他命令的参数。因为一个终端就相当于一个文件,为此在一些命令中如tee命令就可以拿这个文件当作参数。Tee命令是一个分流命令,其主要用途就是把一个输入流的一个副本保存到另外一个文件中。有时候这个特性非常有用。如现在系统工程师需要利用who命令来显示Unix系统的当前登录用户。同时希望把这个显示结果保存到一个特定的文件中。 如果没有tee这个命令的话,则需要通过两个步骤才能够完成。首先需要利用who命令在当前终端中显示相关的结果。然后再利用who >重定向符号把这个命令的显示结果保存到一个特定的文件中。如果一开始就采用who >进行重定向的话,则在用户终端将不会显示任何信息。因为其直接把结果保存到了一个文件中。而现在系统工程师即希望把命令的结果输出到终端中,同时保存到一个文件中,就需要利用tee命令,如who | tee userinfo.txt。(注意,如果利用了tee命令的话,在可以不再使用重定向符号)。到这里为止没有涉及到/dev/tty这个文件。who | tee userinfo.txt这个命令的显示结果,只会显示当前登录的用户明细,而不会显示当前有多少个用户登录到系统中。可能或许有人回说只要数一下就可以了呀。确实数数的话可以实现,但是计算机不会自己数呀。如果其他脚本程序需要用到当前登录用户的总数而不需要明细,那么该如何处理呢?此时就需要利用 /dev/tty文件作为参数了。如可以使用who | tee /dev/tty |wc –l 命令。这个命令可以把当前用户的明细以及总共的用户数量显示出来。以上这个命令其实我们可以分为四个步骤。第一步系统先执行who命令;第二步tee命令把who命令执行对结果保存到/dev/tty文件中;第三步wc命令会统计/dev/tty文件中的行数。由于一个终端对相当于一个文件,故利用wc命令可以统计出当前系统登录用户的数量。第四步再把这个统计的结果显示在终端上。所以说,把/dev/tty文件当作其他命令的一个参数,一个一起组合以实现一些比较复杂的功能


       二、/dev/tty文件使用的注意点。

在使用这个文件中,特别需要关注的是其权限文件。默认情况下,普通用户也可以实现这个文件,从而可能造成一定的安全隐患。如现在系统中有两个普通用户sa01与sa02。而他们两个都是通过远程终端连入到Unix操作系统中。 此时假设用户sa01知道用户sa02的用户名以及登录密码。那么就可以假冒用户sa02的身份,把一些命令的执行结果重定向到/dev/tty文件中。 同时利用tee命令进行分流。此时对于用户sa02时,因为其执行相关的命令在终端上仍然可以正常显示,不会产生什么怀疑。但是这个用户其可能不知道,自己执行命令的结果已经保存到/dev/tty文件中。而其他用户就可以通过这个文件来显示在其用户终端上所显示的信息。这显然会导致用户SA02信息的泄 漏,给其带来一定的损失。


        /dev/tty这个文件可以有多个用户同时使用,而且相互之间不会发生冲突。这个特性可以帮助系统工程师实现很多有用的功能。但是毋庸置疑的是,也造成了一定的安全隐患。为此对于大部分情况下,Unix系统工程师要对这个文件进行一定的权限限制,如只有系统工程师(不一定是特权用户)才可以使用这个文件。从而防止非法攻击者利用这个文件来获取其攻击所必要的信息。

  另外需要注意的是命令 >/dev/tty与命令> file连个命令其最终的结果有可能相同,也有可能不同。前者在把命令的显示结果保存到/dev/tty文件中的时候,会过滤掉echo等命令设置的信息。而后者这个命令这会把显示的结果一五一十的照搬到file文件中去。也就是说,如果在命令或者脚本程序中没有echo等类似的命令设置信息的话在,则这两个命令重定向文件后所保存文件的内容是一致的。但是如果在命令或者脚本程序中有类似的提示命令的话,则两个文件的显示结果则会不同。为此系统工程师就需要根据自己的实际需要,来选择合适的重定向文件,看看有否必要采用/dev/tty文件。笔者的态度是,只有在确实有必要的情况下,才能够使用/dev/tty文件。因为这个文件是比较稀缺的,只由在缺其不可的情况下,才启用这个文件

Tuesday, September 15, 2009

Hello AVR - Atmel ATmega328P

AVR是由Atmel公司從1996年開始發行的一系列單晶片
它採用Modified Harvard architecture(8-bit)的RISC架構
它採用Flash memory[註一]來儲存program採用RAM來儲存data


我試著將一個簡單的code寫入AVR
首先我利用AVR Studio 4將程式編譯 (編譯成.hex檔)
然後透過ISP功能(In-System Programming)將它寫(燒)入其中一款microcontroller - ATmega328P
這個程式的目的是將一些文字show在LCD上


需要注意的一點是
當你要利用AVR Studio 4來compile時
要注意code的路徑是否有包含中文名稱
因為有中文名稱的話
compiler會出現以下錯誤訊息:












於是乎,我們即可開始把玩AVR。

[註一]
我們來看一下Flash Memory的歷史 應用及其優點,
以下資料取自http://shop.transcend.com.tw/index.asp

快閃記憶體(Flash Memory)  
對一般消費者是陌生的科技名詞,但目前當紅的數位記憶卡、讀卡機、隨身碟等,卻都是由快閃記憶體製造而成的數位產品。快閃記憶體到底具備何種魔力讓資料儲存變得快速且易於攜帶?

快閃記憶體v.s.一般電腦記憶體
快閃記憶體和一般電腦記憶體最大不同為:一般電腦記憶體(DRAM),當使用硬體電源關閉後,儲存於記憶體中的資料會消失,因此,又稱為動態隨機存取記憶體。而快閃記憶體卻不需要電力來維持已儲存的資料。在電源關閉後,原本寫入的資料仍可保存於記憶體中,再加上小體積大容量的特性,使快閃記憶體廣泛應用於許多可攜式的3C產品,如PDA、手機、數位相機搭配使用數位記憶卡(如CF、MMC、SM Card)、讀卡機、行動碟、轉接卡等。

快閃記憶體簡史與應用
1984年,日本東芝職員藤尾增岡(Fujio Masuoka)率先提出快閃記憶體概念。快閃屬於非揮發記憶體,即使電腦關機資料依然還留存在晶片上,與一般電腦記憶體不同,由於這種記憶體可以非常快速的存取資料,因此稱為快閃記憶體。

快閃記憶體 的產品優點與主要應用產品 
產品優點
主要應用產品
體積小容量大
讀取速度快
低耗電量
高耐久性:可重複讀寫資料十萬次


記憶卡:使用於數位相機、PDA等3C產品
行動碟
讀卡機
轉接卡
微型硬碟記憶卡(DOM)
 

Saturday, September 12, 2009

Physical Computing

這是最近常看到的一個名詞,
在看了一些資料後,
我認為應該可以這樣子來解釋它,


Physical Computing:
當我們藉由程式(軟體)來控制某個裝置上的Microcontroller(硬體),
使得該裝置可以跟人們產生某些互動,
即是Physical Computing,
因此, 它的概念就像"如何設計出一款有創意或是實用的Embedded System"!


例如:
當有了完善的Physical Computing,
我們就可以讓Robot變聰明,
讓Robot有辨識人類或是幫人類打掃...等等功能




大家也可以參考wiki上的解釋:
http://en.wikipedia.org/wiki/Physical_computing


以及相關課程
http://itp.nyu.edu/physcomp/

Friday, September 11, 2009

mmap()

mmap is sometimes used for Interprocess Communication (IPC). On modern operating systems mmap is typically preferred to the System V IPC Shared Memory facility.
~ http://en.wikipedia.org/wiki/Mmap


mmap(), 即memory map,用來將某個檔案的內容map到memory,使得各個process之間可以利用shared memory的方式來做資料的存取。


例如,在一個存取資料的程式中,我們可能透過fread來將資料讀出,經過修改後,再經由fwrite將資料寫入,但fread與fwrite皆需先透過fseek找出讀寫的記憶體位置。


然而,mmap()一開始會分配固定的記憶體區塊給某個檔案,因此多個程式便可以直接存取該共同記憶體區塊裡的任何資料。當然,shared memory可能引起race condition等問題,關於這部份可以參考其它資料說明。


[Ref.]
Beginning Linux Programming 4/e, Richard Stones and Neil Matthew

Wednesday, September 9, 2009

[轉載] ubuntu8.04 解决pdf中文乱码问题

1、sudo apt-get install xpdf-chinese-simplified xpdf-chinese-traditional


2、搜索并安装poppler-data软件包


3、sudo rm /etc/fonts/conf.d/49-sansserif.conf


[Ref.]
http://evan2008.blog.51cto.com/509463/112539

Tuesday, September 8, 2009

System Call

簡單講, System Call就是一些低階函式, 它可以讓我們存取和控制檔案和設備。利用System Call, 且透過Linux Kernel的一些device driver, 可以讓我們跟硬體設備溝通。


然而, 執行system call會降低系統效率, 因為程式需經由切換到Kernel來呼叫system call, 且執行完還需返回。


舉個例子:
"read" system call, read會從檔案中讀取我們所設定的資料大小, 並將它存放在buffer中, 接著, 我們可以用"write"這個system call來將buffer裡的資料寫出來。


因此我們可以做個實驗, 也就是觀察在不同的buffer大小底下, 程式執行時間的差別。我們可以發現在buffer設定越大的時候, 其程式執行時間越短。原因就是, 在所要讀取的檔案大小固定之下, 當buffer越大, 則所需的system call次數就越少, 其執行時間當然就會越短




[Ref.]
Beginning Linux Programming 4/e, Richard Stones and Neil Matthew

Sunday, September 6, 2009

如何在Linux線上收聽ICRT或Apple Line等電台

[Step1]


安裝mplayer


[Step2]


在終端機輸入指令 

ICRT:
mplayer mms://bcr.media.hinet.net/RA000038

Apple Line
mplayer mms://bcr.media.hinet.net/RA000001


Kiss Radio
mplayer mms://bcr.media.hinet.net/RA000042

台北愛樂
mplayer mms://bcr.media.hinet.net/RA000018


POP Radio
mplayer mms://bcr.media.hinet.net/RA000080

Tuesday, September 1, 2009

Windows 常用快速鍵及操作

(1) 全螢幕與小視窗的互相切換 : Alt + Enter


(2) 叫出windows的"執行" : Windows鍵 + R


(3) 如何刪除常駐程式 ? "開始" → "執行" → 輸入"msconfig" → 在"啟動"中即可設定


(4) 如何將副檔名顯示或隱藏 ? "我的電腦" → "工具" → "資料夾選項" → "顯示" → "進階設定" 

Saturday, August 22, 2009

[轉貼] 利用gcc 自製 Library

轉自 PTT LinuxDev


作者: cole945 (躂躂..) 看板: LinuxDev
標題: [心得] 用gcc 自製Library
時間: Sun Nov 5 04:15:45 2006
Library可分成三種,static、shared與dynamically loaded。
1. Static libraries
Static 程式庫用於靜態連結,簡單講是把一堆object檔用ar(archiver)
包裝集合起來,檔名以`.a’ 結尾。優點是執行效能通常會比後兩者快,
而且因為是靜態連結,所以不易發生執行時找不到library或版本錯置而
無法執行的問題。缺點則是檔案較大,維護度較低;例如library如果發
現bug需要更新,那麼就必須重新連結執行檔。
1.1 編譯
編譯方式很簡單,先例用`-c’ 編出object 檔,再用ar 包起來即可。
____ hello.c ____
#include
void hello(){ printf(”Hello “); }
____ world.c ____
#include
void world(){ printf(”world.”); }
____ mylib.h ____
void hello();
void world();
$ gcc -c hello.c world.c /* 編出hello.o 與world.o */
$ ar rcs libmylib.a hello.o world.o /* 包成limylib.a */
這樣就可以建出一個檔名為libmylib.a 的檔。輸出的檔名其實沒有硬性規定,
但如果想要配合gcc 的’-l’ 參數來連結,一定要以`lib’ 開頭,中間是你要
的library名稱,然後緊接著`.a’ 結尾。
1.2 使用
____ main.c ____
#include “mylib.h”
int main() {
hello();
world();
}
使用上就像與一般的object 檔連結沒有差別。
$ gcc main.c libmylib.a
也可以配合gcc 的`-l’ 參數使用
$ gcc main.c -L. -lmylib
`[1;33m-L[1;32mdir[m' 參數用來指定要搜尋程式庫的目錄,`.' 表示搜尋現在所在的目錄。
通常預設會搜/usr/lib 或/lib 等目錄。
`[1;33m-l[1;32mlibrary[m' 參數用來指定要連結的程式庫,'mylib' 表示要與mylib進行連結
,他會搜尋library名稱前加`lib'後接`.a'的檔案來連結。
$ ./a.out
Hello world.
2. Shared libraries
Shared library 會在程式執行起始時才被自動載入。因為程式庫與執行檔
是分離的,所以維護彈性較好。有兩點要注意,shared library是在程式起始
時就要被載入,而不是執行中用到才載入,而且在連結階段需要有該程式庫
才能進行連結。
首先有一些名詞要弄懂,soname、real name與linker name。
soname 用來表示是一個特定library 的名稱,像是libmylib.so.1 。
前面以`lib' 開頭,接著是該library 的名稱,然後是`.so' ,接著
是版號,用來表名他的介面;如果介面改變時,就會增加版號來維護相容度。
real name 是實際放有library程式的檔案名稱,後面會再加上minor 版號與
release 版號,像是libmylib.so.1.0.0 。
一般來說,版號的改變規則是(印象中在APress-Difinitive Guide to GCC中有
提到,但目前手邊沒這本書),最尾碼的release版號用於程式內容的修正,
介面完全沒有改變。中間的minor用於有新增加介面,但相舊介面沒改變,所以
與舊版本相容。最前面的version版號用於原介面有移除或改變,與舊版不相容
時。
linker name是用於連結時的名稱,是不含版號的soname ,如: libmylib.so。
通常linker name與real name是用ln 指到對應的real name ,用來提供
彈性與維護性。
2.1 編譯
shared library的製作過程較複雜。
$ gcc -c -fPIC hello.c world.c
編譯時要加上-fPIC 用來產生position-independent code。也可以用-fpic
參數。(不太清楚差異,只知道-fPIC 較通用於不同平台,但產生的code較大
,而且編譯速度較慢)。
$ gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 \
hello.o world.o
-shared 表示要編譯成shared library
-Wl 用於參遞參數給linker,因此-soname與libmylib.so.1會被傳給linker處理。
-soname用來指名soname 為limylib.so.1
library會被輸出成libmylib.so.1.0.0 (也就是real name)
若不指定soname 的話,在編譯結連後的執行檔會以連時的library檔名為
soname,並載入他。否則是載入soname指定的library檔案。
可以利用objdump 來看library 的soname。
$ objdump -p libmylib.so | grep SONAME
SONAME libmylib.so.1
若不指名-soname參數的話,則library不會有這個欄位資料。
在編譯後再用ln 來建立soname 與linker name 兩個檔案。
$ ln -s libmylib.so.1.0.0 libmylib.so
$ ln -s libmylib.so.1.0.0 libmylib.so.1
2.2 使用
與使用static library 同。
$ gcc main.c libmylib.so
以上直接指定與libmylib.so 連結。
或用
$ gcc main.c -L. -lmylib
linker會搜尋libmylib.so 來進行連結。
如果目錄下同時有static與shared library的話,會以shared為主。
使用-static 參數可以避免使用shared連結。
$ gcc main.c -static -L. -lmylib
此時可以用ldd 看編譯出的執行檔與shared程式庫的相依性
$ldd a.out
linux-gate.so.1 => (0xffffe000)
[1;33mlibmylib.so.1 => not found[m
libc.so.6 => /lib/libc.so.6 (0xb7dd6000)
/lib/ld-linux.so.2 (0xb7f07000)
輸出結果顯示出該執行檔需要libmylib.so.1 這個shared library。
會顯示not found 因為沒指定該library所在的目錄,所找不到該library。
因為編譯時有指定-soname參數為libmylib.so.1 的關係,所以該執行檔會
載入libmylib.so.1。否則以libmylib.so連結,執行檔則會變成要求載入
libmylib.so
$ ./a.out
./a.out: error while loading shared libraries: [1;33mlibmylib.so.1[m:
cannot open shared object file: No such file or directory
因為找不到libmylib.so.1 所以無法執行程式。
有幾個方式可以處理。
a. 把libmylib.so.1 安裝到系統的library目錄,如/usr/lib下
b. 設定/etc/ld.so.conf ,加入一個新的library搜尋目錄,並執行ldconfig
更新快取
c. 設定LD_LIBRARY_PATH 環境變數來搜尋library
這個例子是加入目前的目錄來搜尋要載作的library
$ LD_LIBRARY_PATH=. ./a.out
Hello world.
3. Dynamically loaded libraries
Dynamicaaly loaded libraries 才是像windows 所用的DLL ,在使用到
時才載入,編譯連結時不需要相關的library。動態載入庫常被用於像plug-ins
的應用。
3.1 使用方式
動態載入是透過一套dl function來處理。
#include
void *dlopen(const char *filename, int flag);
開啟載入filename 指定的library。
void *dlsym(void *handle, const char *symbol);
取得symbol 指定的symbol name在library被載入的記憶體位址。
int dlclose(void *handle);
關閉dlopen開啟的handle。
char *dlerror(void);
傳回最近所發生的錯誤訊息。
____ dltest.c ____
#include
#include
#include
int main() {
void *handle;
void (*f)();
char *error;
/* 開啟之前所撰寫的libmylib.so 程式庫*/
handle = dlopen("./libmylib.so", RTLD_LAZY);
if( !handle ) {
fputs( dlerror(), stderr);
exit(1);
}
/* 取得hello function 的address */
f = dlsym(handle, "hello");
if(( error=dlerror())!=NULL) {
fputs(error, stderr);
exit(1);
}
/* 呼叫該function */
f();
dlclose(handle);
}
編譯時要加上-ldl 參數來與dl library 連結
$ gcc dltest.c -ldl
結果會印出Hello 字串
$ ./a.out
Hello
關於dl的詳細內容請參閱man dlopen
--
參考資料:
Creating a shared and static library with the gnu compiler [gcc]
http://www.adp-gmbh.ch/cpp/gcc/create_lib.html
Program Library HOWTO
http://tldp.org/HOWTO/Program-Library-HOWTO/index.html
APress – Definitive Guide to GCC

※發信站: 批踢踢實業坊(ptt.cc)
◆From: 220.139.148.148

Ref:
http://kaineshu.wordpress.com/2007/05/02/%E8%BD%89%E8%B2%BC%E7%94%A8gcc-%E8%87%AA%E8%A3%BD-library/