4. `./configure --build=mipsel-linux --host=i386-linux
--target=mipsel-linux' will cross-build mipsel-linux cross-binutils for
i386-linux on mipsel-linux.
說明我們利用mipsel-linux的編譯器對binutils進行編譯,編譯出來的binutils運行在i386-linux,這個binutils用來編譯能夠在mipsel-linux運行的代碼。“這個選項可以用來在i386主機上建立一個mipsel-linux的交叉編譯環境,但是交叉編譯環境在mipsel-linux 編譯出來,安裝到i386-linux主機上,估計沒有多少人會這么用吧”
總的來說,只有host !=build的時候編譯才是交叉編譯。否則就是正常編譯。
1. NAT分類
根據Stun協議(RFC3489),NAT大致分為下面四類
http://blog.csdn.net/ronmy/category/819006.aspx
1) Full Cone
這種NAT內部的機器A連接過外網機器C后,NAT會打開一個端口.然后外網的任何發到這個打開的端口的UDP數據報都可以到達A.不管是不是C發過來的.
例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88
A(192.168.8.100:5000) -> NAT(202.100.100.100 : 8000) -> C(292.88.88.88:2000)
任何發送到 NAT(202.100.100.100:8000)的數據都可以到達A(192.168.8.100:5000)
2) Restricted Cone
這種NAT內部的機器A連接過外網的機器C后,NAT打開一個端口.然后C可以用任何端口和A通信.其他的外網機器不行.
例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88
A(192.168.8.100:5000) -> NAT(202.100.100.100 : 8000) -> C(292.88.88.88:2000)
任何從C發送到 NAT(202.100.100.100:8000)的數據都可以到達A(192.168.8.100:5000)
3) Port Restricted Cone
這種NAT內部的機器A連接過外網的機器C后,NAT打開一個端口.然后C可以用原來的端口和A通信.其他的外網機器不行.
例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88
A(192.168.8.100:5000) -> NAT(202.100.100.100 : 8000) -> C(292.88.88.88:2000)
C(202.88.88.88:2000)發送到 NAT(202.100.100.100:8000)的數據都可以到達A(192.168.8.100:5000)
以上三種NAT通稱Cone NAT.我們只能用這種NAT進行UDP打洞.
4) Symmetic
對于這種NAT.連接不同的外部目標.原來NAT打開的端口會變化.而Cone NAT不會.雖然可以用端口猜測.但是成功的概率很小.因此放棄這種NAT的UDP打洞.
2. UDP hole punching
對于Cone NAT.要采用UDP打洞.需要一個公網機器C來充當”介紹人”.內網的A,B先分別和C通信.打開各自的NAT端口.C這個時候知道A,B的公網IP: Port. 現在A和B想直接連接.比如A給B發.除非B是Full Cone.否則不能通信.反之亦然.但是我們可以這樣.
A要連接B.A給B發一個UDP包.同時.A讓那個介紹人給B發一個命令,讓B同時給A發一個UDP包.這樣雙方的NAT都會記錄對方的IP,然后就會允許互相通信.
3. 同一個NAT后面的情況
如果A,B在同一個NAT后面.如果用上面的技術來進行互連.那么如果NAT支持loopback(就是本地到本地的轉換),A,B可以連接,但是比較浪費帶寬和NAT.有一種辦法是,A,B和介紹人通信的時候,同時把自己的local IP也告訴服務器.A,B通信的時候,同時發local ip和公網IP.誰先到就用哪個IP.但是local ip就有可能不知道發到什么地方去了.比如A,B在不同的NAT后面但是他們各自的local ip段一樣.A給B的local IP發的UDP就可能發給自己內部網里面的某某某了.
還有一個辦法是服務器來判斷A,B是否在一個NAT后面.(網絡拓樸不同會不會有問題?)
本文出自 “淡泊明志,寧靜致遠” 博客,請務必保留此出處http://keren.blog.51cto.com/720558/170822
程序描述:
打開一個文件描述符,分別適用dup和賦值語句進行復制,復制之后,打印原始和被復制的文件描述符id,看看是否具有相同的值,然后關閉文件,測試關閉是否成功。
程序示例:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int sys_err(char *str)
{
puts(str);
exit(0);
}
int main(void)
{
int p,q;
if((p=open("c_fid.c", O_RDONLY)) == -1)
sys_err("open error");
q = dup(p);
puts("dup:");
printf("file p,q fd is:%d %d\n", q, p);
printf("close file p ok?: %d\n", close(p));
printf("close file q ok?: %d\n", close(q));
if((p=open("c_fid.c", O_RDONLY)) == -1)
sys_err("open error");
q = p;
puts("=:");
printf("file p,q fd is:%d %d\n", q, p);
printf("close file p ok?: %d\n", close(p));
printf("close file q ok?: %d\n", close(q));
return 0;
}
程序運行結果:
dup:
file p,q fd is:4 3 //文件p,q使用不同的文件描述符
close file p ok?: 0
close file q ok?: 0 //文件關閉成功
=:
file p,q fd is:3 3 //簡單復制
close file p ok?: 0
close file q ok?: -1//關閉失敗,原因是此描述符已經被關閉了
由此證明,dup是產生一個新的文件描述符id和指針在進程表項中,但是他們共用文件表,這時,關閉一個文件描述符,另外一個仍舊可用,文件表并不會被釋放。而賦值語句不同,它只是簡單的在另外一個變量中記錄原始文件指針等,2個變量的文件描述符相同,進程表項中并不產生新的項目。
關于socket的文件描述符
socket接口增加了網絡通信操作的抽象定義,與文件操作一樣,每個打開的socket都對應一個整數,我們稱它為socket描述符,該整數也是socket描述符在文件描述符表中的索引值。但socket描述符在描述符表中的表項并不指向文件表,而是指向一個與該socket有關的數據結構。BSD UNIX中新增加了一個socket調用,應用程序可以調用它來新建一個socket描述符,注意進程用open只能產生文件描述符,而不能產生socket描述符。socket調用只能完成建立通信的部分工作,一旦建立了一個socket,應用程序可以使用其他特定的調用來為它添加其他詳細信息,以完成建立通信的過程。
給定了命令參數的數量 (argc
)、指向這些參數的數組 (argv
) 和選項字符串 (optstring
) 后,getopt()
將返回第一個選項,并設置一些全局變量。使用相同的參數再次調用該函數時,它將返回下一個選項,并設置相應的全局變量。如果不再有識別到的選項,將返回 -1
,此任務就完成了。
getopt()
所設置的全局變量包括:
optarg
——指向當前選項參數(如果有)的指針。optind
——再次調用 getopt()
時的下一個 argv 指針的索引。optopt
——最后一個已知選項。 ./getopt -a -d -b foo
optind: 2
HAVE option: -a
./getopt: invalid option -- d
optind: 3
Unknown option: d
optind: 5
HAVE option: -b
The argument of -b is foo
if (execute_command) { run_init_process(execute_command); printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command); } run_init_process("/sbin/init"); run_init_process("/etc/init"); run_init_process("/bin/init"); run_init_process("/bin/sh"); panic("No init found. Try passing init= option to kernel.");
mkdir /newroot/nfsroot/xxx <- 建立用戶的home 路徑
adduser xxx -d /newroot/nfsroot/xxx/ -g pnd <- 添加用戶到組
passwd wyn <- 設置用戶密碼
chown xxx:pnd /newroot/nfsroot/xxx/ <- 更改home路徑擁有者和組
echo xxx ALL=(ALL) NOPASSWD:NOPASSWD:ALL >> /etc/sudoers <- 添加sudo權限
smbpasswd -a xxx <- 添加samba 用戶
ps: /etc/samba/smb.conf 的內容:
[global]
workgroup = TUX-NET
printing = cups
printcap name = cups
printcap cache time = 750
cups options = raw
map to guest = Bad User
include = /etc/samba/dhcp.conf
logon path = \\%L\profiles\.msprofile
logon home = \\%L\%U\.9xprofile
logon drive = P:
usershare allow guests = Yes
add machine script = /usr/sbin/useradd -c Machine -d /var/lib/nobody -s /bin/false %m$
domain logons = Yes
domain master = Yes
local master = Yes
os level = 65
preferred master = Yes
security = user
[homes]
comment = Home Directories
valid users = %S, %D%w%S
browseable = No
read only = No
inherit acls = Yes
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/stevenliyong/archive/2009/03/12/3984926.aspx
asctime(將時間和日期以字符串格式表示) |
|
相關函數 |
time,ctime,gmtime,localtime |
表頭文件
|
#include<time.h> |
定義函數
|
char * asctime(const struct tm * timeptr); |
函數說明
|
asctime()將參數timeptr所指的tm結構中的信息轉換成真實世界所使用的時間日期表示方法,然后將結果以字符串形態返回。此函數已經由時區轉換成當地時間,字符串格式為:“Wed Jun 30 21:49:08 1993\n” |
返回值
|
若再調用相關的時間日期函數,此字符串可能會被破壞。此函數與ctime不同處在于傳入的參數是不同的結構。 |
附加說明
|
返回一字符串表示目前當地的時間日期。 |
范例
|
#include <time.h> main() { time_t timep; time (&timep); printf(“%s”,asctime(gmtime(&timep))); } |
執行
|
Sat Oct 28 02:10:06 2000 |
|
ctime(將時間和日期以字符串格式表示) |
相關函數
|
time,asctime,gmtime,localtime |
表頭文件
|
#include<time.h> |
定義函數
|
char *ctime(const time_t *timep); |
函數說明
|
ctime()將參數timep所指的time_t結構中的信息轉換成真實世界所使用的時間日期表示方法,然后將結果以字符串形態返回。此函數已經由時區轉換成當地時間,字符串格式為“Wed Jun 30 21 :49 :08 1993\n”。若再調用相關的時間日期函數,此字符串可能會被破壞。 |
返回值
|
返回一字符串表示目前當地的時間日期。 |
范例
|
#include<time.h> main() { time_t timep; time (&timep); printf(“%s”,ctime(&timep)); } |
執行
|
Sat Oct 28 10 : 12 : 05 2000 |
|
gettimeofday(取得目前的時間) |
相關函數
|
time,ctime,ftime,settimeofday |
表頭文件
|
#include <sys/time.h> #include <unistd.h> |
定義函數
|
int gettimeofday ( struct timeval * tv , struct timezone * tz ) |
函數說明
|
gettimeofday()會把目前的時間有tv所指的結構返回,當地時區的信息則放到tz所指的結構中。 timeval結構定義為: struct timeval{ long tv_sec; /*秒*/ long tv_usec; /*微秒*/ }; timezone 結構定義為: struct timezone{ int tz_minuteswest; /*和Greenwich 時間差了多少分鐘*/ int tz_dsttime; /*日光節約時間的狀態*/ }; 上述兩個結構都定義在/usr/include/sys/time.h。tz_dsttime 所代表的狀態如下 DST_NONE /*不使用*/ DST_USA /*美國*/ DST_AUST /*澳洲*/ DST_WET /*西歐*/ DST_MET /*中歐*/ DST_EET /*東歐*/ DST_CAN /*加拿大*/ DST_GB /*大不列顛*/ DST_RUM /*羅馬尼亞*/ DST_TUR /*土耳其*/ DST_AUSTALT /*澳洲(1986年以后)*/ |
返回值
|
成功則返回0,失敗返回-1,錯誤代碼存于errno。附加說明EFAULT指針tv和tz所指的內存空間超出存取權限。 |
范例
|
#include<sys/time.h> #include<unistd.h> main(){ struct timeval tv; struct timezone tz; gettimeofday (&tv , &tz); printf(“tv_sec; %d\n”, tv,.tv_sec) ; printf(“tv_usec; %d\n”,tv.tv_usec); printf(“tz_minuteswest; %d\n”, tz.tz_minuteswest); printf(“tz_dsttime, %d\n”,tz.tz_dsttime); } |
執行
|
tv_sec: 974857339 tv_usec:136996 tz_minuteswest:-540 tz_dsttime:0 |
|
gmtime(取得目前時間和日期) |
相關函數
|
time,asctime,ctime,localtime |
表頭文件
|
#include<time.h> |
定義函數
|
struct tm*gmtime(const time_t*timep); |
函數說明
|
gmtime()將參數timep 所指的time_t 結構中的信息轉換成真實世界所使用的時間日期表示方法,然后將結果由結構tm返回。 結構tm的定義為 struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }; int tm_sec 代表目前秒數,正常范圍為0-59,但允許至61秒 int tm_min 代表目前分數,范圍0-59 int tm_hour 從午夜算起的時數,范圍為0-23 int tm_mday 目前月份的日數,范圍01-31 int tm_mon 代表目前月份,從一月算起,范圍從0-11 int tm_year 從1900 年算起至今的年數 int tm_wday 一星期的日數,從星期一算起,范圍為0-6 int tm_yday 從今年1月1日算起至今的天數,范圍為0-365 int tm_isdst 日光節約時間的旗標 此函數返回的時間日期未經時區轉換,而是UTC時間。 |
返回值
|
返回結構tm代表目前UTC 時間 |
范例
|
#include <time.h> main(){ char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; time_t timep; struct tm *p; time(&timep); p=gmtime(&timep); printf(“%d%d%d”,(1900+p->tm_year), (1+p->tm_mon),p->tm_mday); printf(“%s%d;%d;%d\n”, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec); } |
執行
|
2000/10/28 Sat 8:15:38 |
|
localtime(取得當地目前時間和日期) |
相關函數
|
time, asctime, ctime, gmtime |
表頭文件
|
#include<time.h> |
定義函數
|
struct tm *localtime(const time_t * timep); |
函數說明
|
localtime()將參數timep所指的time_t結構中的信息轉換成真實世界所使用的時間日期表示方法,然后將結果由結構tm返回。結構tm的定義請參考gmtime()。此函數返回的時間日期已經轉換成當地時區。 |
返回值
|
返回結構tm代表目前的當地時間。 |
范例
|
#include<time.h> main(){ char *wday[]={“Sun”,”Mon”,”Tue”,”Wed”,”Thu”,”Fri”,”Sat”}; time_t timep; struct tm *p; time(&timep); p=localtime(&timep); /*取得當地時間*/ printf (“%d%d%d ”, (1900+p->tm_year),( l+p->tm_mon), p->tm_mday); printf(“%s%d:%d:%d\n”, wday[p->tm_wday],p->tm_hour, p->tm_min, p->tm_sec); } |
執行
|
2000/10/28 Sat 11:12:22 |
|
mktime(將時間結構數據轉換成經過的秒數) |
相關函數
|
time,asctime,gmtime,localtime |
表頭文件
|
#include<time.h> |
定義函數
|
time_t mktime(strcut tm * timeptr); |
函數說明
|
mktime()用來將參數timeptr所指的tm結構數據轉換成從公元1970年1月1日0時0分0 秒算起至今的UTC時間所經過的秒數。 |
返回值
|
返回經過的秒數。 |
范例
|
/* 用time()取得時間(秒數),利用localtime() 轉換成struct tm 再利用mktine()將struct tm轉換成原來的秒數*/ #include<time.h> main() { time_t timep; strcut tm *p; time(&timep); printf(“time() : %d \n”,timep); p=localtime(&timep); timep = mktime(p); printf(“time()->localtime()->mktime():%d\n”,timep); } |
執行
|
time():974943297 time()->localtime()->mktime():974943297 |
|
settimeofday(設置目前時間) |
相關函數
|
time,ctime,ftime,gettimeofday |
表頭文件
|
#include<sys/time.h> #include<unistd.h> |
定義函數
|
int settimeofday ( const struct timeval *tv,const struct timezone *tz); |
函數說明
|
settimeofday()會把目前時間設成由tv所指的結構信息,當地時區信息則設成tz所指的結構。詳細的說明請參考gettimeofday()。注意,只有root權限才能使用此函數修改時間。 |
返回值
|
成功則返回0,失敗返回-1,錯誤代碼存于errno。 |
錯誤代碼
|
EPERM 并非由root權限調用settimeofday(),權限不夠。 EINVAL 時區或某個數據是不正確的,無法正確設置時間。 |
|
time(取得目前的時間) |
相關函數
|
ctime,ftime,gettimeofday |
表頭文件
|
#include<time.h> |
定義函數
|
time_t time(time_t *t); |
函數說明
|
此函數會返回從公元1970年1月1日的UTC時間從0時0分0秒算起到現在所經過的秒數。如果t 并非空指針的話,此函數也會將返回值存到t指針所指的內存。 |
返回值
|
成功則返回秒數,失敗則返回((time_t)-1)值,錯誤原因存于errno中。 |
范例
|
#include<time.h> mian() { int seconds= time((time_t*)NULL); printf(“%d\n”,seconds); } |
執行
|
9.73E+08 |
1. 函數庫libdbus,用于兩個應用程序呼叫聯系和交互消息。
2. Message bus daemon,總線守護進程可同時與多個應用程序相連,并能把來自一個應用程序的消息路由到0或者多個其他程序。
3. 一系列基于特定應用程序框架的Wrapper庫。 比如libdbus-glib, libdbus-python.
參看圖1-1, Bus Daemon Process就是運行在linux的daemon(dbus-daemon, 用戶可以在/etc/init.d/dbus 操作,stop, start等等), dbus-daemon運行時會調用libdus的庫。 在Application Process1里面就是應用層的東西了,應用程序調用特定的應用程序框架的Wrapper庫與dbus-daemon進行通信。
我前段時間就是用Python寫程序與dbus-daemon通信,所以就需要libdbus-python,后來又用c寫程序,又裝了libdus-glib。實質上在dbus主頁上(http://www.freedesktop.org/wiki/Software/dbus)提供了很多Wrapper庫, for QT4, JAVA, Perl, C++, Pascal, QT3, .NET, Ruby等等。這個Wrapper庫呢其實就是對dbus下層調用做了封裝,給上層暴露一個友好的接口。dbus的底層其實也是通過socket通信的
圖 1-1
我再給一張bluez的例子讓大家更理解dbus; 有四個應用想與bluz的damon通信,bluez注冊到dbus中,其它的應用只需要向dbus要bluez的數據,
dbus負責再和bluez溝通了,但是bluez一定要把接口告訴其它應用。
select系統調用是用來讓我們的程序監視多個文件句柄(file descriptor)的狀態變化的。程序會停在select這里等待,直到被監視的文件句柄有某一個或多個發生了狀態改變。 文件在句柄在Linux里很多,如果你man某個函數,在函數返回值部分說到成功后有一個文件句柄被創建的都是的,如man socket可以看到“On success, a file descriptor for the new socket is returned.”而man 2 open可以看到“open() and creat() return the new file descriptor”,其實文件句柄就是一個整數,看socket函數的聲明就明白了:
int socket(int domain, int type, int protocol);
當然,我們最熟悉的句柄是0、1、2三個,0是標準輸入,1是標準輸出,2是標準錯誤輸出。0、1、2是整數表示的,對應的FILE *結構的表示就是stdin、stdout、stderr,0就是stdin,1就是stdout,2就是stderr。比如下面這兩段代碼都是從標準輸入讀入9個字節字符:
#include <stdio.h> #include <unistd.h> #include <string.h> int main(int argc, char ** argv) { char buf[10] = ""; read(0, buf, 9); /* 從標準輸入 0 讀入字符 */ fprintf(stdout, "%s\n", buf); /* 向標準輸出 stdout 寫字符 */
return 0; } /* **上面和下面的代碼都可以用來從標準輸入讀用戶輸入的9個字符** */ #include <stdio.h> #include <unistd.h> #include <string.h> int main(int argc, char ** argv) { char buf[10] = ""; fread(buf, 9, 1, stdin); /* 從標準輸入 stdin 讀入字符 */ write(1, buf, strlen(buf));
return 0; } |
繼續上面說的select,就是用來監視某個或某些句柄的狀態變化的。
select函數原型如下:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
函 數的最后一個參數timeout顯然是一個超時時間值,其類型是struct timeval *,即一個struct timeval結構的變量的指針,所以我們在程序里要申明一個struct timeval tv;然后把變量tv的地址&tv傳遞給select函數。struct timeval結構如下:
struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ }; |
第2、 3、4三個參數是一樣的類型: fd_set *,即我們在程序里要申明幾個fd_set類型的變量,比如rdfds, wtfds, exfds,然后把這個變量的地址&rdfds, &wtfds, &exfds 傳遞給select函數。
這三個參數都是一個句柄的集合,第一個rdfds是用來保存這樣的句柄的:當句柄的狀態變成可讀的時系統就會告訴select函數返回,同理第二個wtfds是指有句柄狀態變成可寫的時系統就會告訴select函數返回,同理第三個參數exfds是特殊情況,即句柄上有特殊情況發生時系統會告訴select函數返回。特殊情況比如對方通過一個socket句柄發來了緊急數據。如果我們程序里只想檢測某個socket是否有數據可讀,我們可以這樣:
fd_set rdfds; /* 先申明一個 fd_set 集合來保存我們要檢測的 socket句柄 */ struct timeval tv; /* 申明一個時間變量來保存時間 */ int ret; /* 保存返回值 */ FD_ZERO(&rdfds); /* 用select函數之前先把集合清零 */ FD_SET(socket, &rdfds); /* 把要檢測的句柄socket加入到集合里 */
tv.tv_sec = 1; tv.tv_usec = 500; /* 設置select等待的最大時間為1秒加500微秒 */
ret = select(socket + 1, &rdfds, NULL, NULL, &tv); /* 檢測我們上面設置到集合rdfds里的句柄是否有可讀信息 */ if(ret < 0) perror("select");/* 這說明select函數出錯 */ else if(ret == 0) printf("超時\n"); /* 說明在我們設定的時間值1秒加500毫秒的時間內,socket的狀態沒有發生變化 */ else { /* 說明等待時間還未到1秒加500毫秒,socket的狀態發生了變化 */ printf("ret=%d\n", ret); /* ret這個返回值記錄了發生狀態變化的句柄的數目,由于我們只監視了socket這一個句柄,所以這里一定ret=1,如果同時有多個句柄發生變化返回的就是句柄的總和了 */ /* 這里我們就應該從socket這個句柄里讀取數據了,因為select函數已經告訴我們這個句柄里有數據可讀 */ if(FD_ISSET(socket, &rdfds)) { /* 先判斷一下socket這外被監視的句柄是否真的變成可讀的了 */ /* 讀取socket句柄里的數據 */ recv(...); } } |
注意select函數的第一個參數,是所有加入集合的句柄值的最大那個值還要加1。比如我們創建了3個句柄:
int sa, sb, sc; sa = socket(...); /* 分別創建3個句柄并連接到服務器上 */ connect(sa,...); sb = socket(...); connect(sb,...); sc = socket(...); connect(sc,...); FD_SET(sa, &rdfds);/* 分別把3個句柄加入讀監視集合里去 */ FD_SET(sb, &rdfds); FD_SET(sc, &rdfds); |
在使用select函數之前,一定要找到3個句柄中的最大值是哪個,我們一般定義一個變量來保存最大值,取得最大socket值如下:
int maxfd = 0; if(sa > maxfd) maxfd = sa; if(sb > maxfd) maxfd = sb; if(sc > maxfd) maxfd = sc; |
然后調用select函數:
ret = select(maxfd + 1, &rdfds, NULL, NULL, &tv); /* 注意是最大值還要加1 */ |
同樣的道理,如果我們要檢測用戶是否按了鍵盤進行輸入,我們就應該把標準輸入0這個句柄放到select里來檢測,如下:
FD_ZERO(&rdfds);
FD_SET(0, &rdfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = select(1, &rdfds, NULL, NULL, &tv); /* 注意是最大值還要加1 */
if(ret < 0)
perror("select");/* 出錯 */
else if(ret == 0)
printf("超時\n"); /* 在我們設定的時間tv內,用戶沒有按鍵盤 */
else { /* 用戶有按鍵盤,要讀取用戶的輸入 */
scanf("%s", buf); }
Linux環境下的軟件安裝,并不是一件容易的事情;如果通過源代碼編譯后在安裝,當然事情就更為復雜一些;現在安裝各種軟件的教程都非常普遍;但萬變不離其中,對基礎知識的扎實掌握,安裝各種軟件的問題就迎刃而解了。Configure腳本配置工具就是基礎之一,它是autoconf的工具的基本應用。
與一些技巧相比,Configure顯得基礎一些,當然使用和學習起來就顯得枯燥乏味一些,當然要成為高手,對基礎的熟悉不能超越哦。
為此我轉載了一篇關于Configure選項配置的詳細介紹。供大家參考
'configure'腳本有大量的命令行選項。對不同的軟件包來說,這些選項可能會有變化,但是許多基本的選項是不會改變的。帶上'--help'選項執行'configure'腳本可以看到可用的所有選項。盡管許多選項是很少用到的,但是當你為了特殊的需求而configure一個包時,知道他們的存在是很有益處的。下面對每一個選項進行簡略的介紹:
--cache-file=FILE
'configure'會在你的系統上測試存在的特性(或者bug!)。為了加速隨后進行的配置,測試的結果會存儲在一個cache file里。當configure一個每個子樹里都有'configure'腳本的復雜的源碼樹時,一個很好的cache file的存在會有很大幫助。
--help
輸出幫助信息。即使是有經驗的用戶也偶爾需要使用使用'--help'選項,因為一個復雜的項目會包含附加的選項。例如,GCC包里的'configure'腳本就包含了允許你控制是否生成和在GCC中使用GNU匯編器的選項。
--no-create
'configure'中的一個主要函數會制作輸出文件。此選項阻止'configure'生成這個文件。你可以認為這是一種演習(dry run),盡管緩存(cache)仍然被改寫了。
--quiet
--silent
當'configure'進行他的測試時,會輸出簡要的信息來告訴用戶正在作什么。這樣作是因為'configure'可能會比較慢,沒有這種輸出的話用戶將會被扔在一旁疑惑正在發生什么,使用這兩個選項中的任何一個都會把你扔到一旁。(譯注:這兩句話比較有意思,原文是這樣的:If there was no such output, the user would be left wondering what is happening. By using this option, you too can be left wondering!)
--version
打印用來產生'configure'腳本的Autoconf的版本號。
--prefix=PEWFIX
'--prefix'是最常用的選項。制作出的'Makefile'會查看隨此選項傳遞的參數,當一個包在安裝時可以徹底的重新安置他的結構獨立部分。舉一個例子,當安裝一個包,例如說Emacs,下面的命令將會使Emacs Lisp file被安裝到"/opt/gnu/share":
$ ./configure --prefix=/opt/gnu
--exec-prefix=EPREFIX
與'--prefix'選項類似,但是他是用來設置結構倚賴的文件的安裝位置,編譯好的'emacs'二進制文件就是這樣一個問件。如果沒有設置這個選項的話,默認使用的選項值將被設為和'--prefix'選項值一樣。
--bindir=DIR
指定二進制文件的安裝位置,這里的二進制文件定義為可以被用戶直接執行的程序。
--sbindir=DIR
指定超級二進制文件的安裝位置。這是一些通常只能由超級用戶執行的程序。
--libexecdir=DIR
指定可執行支持文件的安裝位置。與二進制文件相反,這些文件從來不直接由用戶執行,但是可以被上面提到的二進制文件所執行。
--datadir=DIR
指定通用數據文件的安裝位置。
--sysconfdir=DIR
指定在單個機器上使用的只讀數據的安裝位置。
--sharedstatedir=DIR
指定可以在多個機器上共享的可寫數據的安裝位置。
--localstatedir=DIR
指定只能單機使用的可寫數據的安裝位置。
--libdir=DIR
指定庫文件的安裝位置。
--includedir=DIR
指定C頭文件的安裝位置。其他語言如C++的頭文件也可以使用此選項。
--oldincludedir=DIR
指定為除GCC外編譯器安裝的C頭文件的安裝位置。
--infodir=DIR
指定Info格式文檔的安裝位置.Info是被GNU工程所使用的文檔格式。
--mandir=DIR
指定手冊頁的安裝位置。
--srcdir=DIR
這個選項對安裝沒有作用,他會告訴'configure'源碼的位置。一般來說不用指定此選項,因為'configure'腳本一般和源碼文件在同一個目錄下。
--program-prefix=PREFIX
指定將被加到所安裝程序的名字上的前綴。例如,使用'--program-prefix=g'來configure一個名為'tar'的程序將會使安裝的程序被命名為'gtar'。當和其他的安裝選項一起使用時,這個選項只有當他被`Makefile.in'文件使用時才會工作。
--program-suffix=SUFFIX
指定將被加到所安裝程序的名字上的后綴。
--program-transform-name=PROGRAM
這里的PROGRAM是一個sed腳本。當一個程序被安裝時,他的名字將經過`sed -e PROGRAM'來產生安裝的名字。
--build=BUILD
指定軟件包安裝的系統平臺。如果沒有指定,默認值將是'--host'選項的值。
--host=HOST
指定軟件運行的系統平臺。如果沒有指定。將會運行`config.guess'來檢測。
--target=GARGET
指定軟件面向(target to)的系統平臺。這主要在程序語言工具如編譯器和匯編器上下文中起作用。如果沒有指定,默認將使用'--host'選項的值。
--disable-FEATURE
一些軟件包可以選擇這個選項來提供為大型選項的編譯時配置,例如使用Kerberos認證系統或者一個實驗性的編譯器最優配置。如果默認是提供這些特性,可以使用'--disable-FEATURE'來禁用它,這里'FEATURE'是特性的名字,例如:
$ ./configure --disable-gui
-enable-FEATURE[=ARG]
相反的,一些軟件包可能提供了一些默認被禁止的特性,可以使用'--enable-FEATURE'來起用它。這里'FEATURE'是特性的名字。一個特性可能會接受一個可選的參數。例如:
$ ./configure --enable-buffers=128
`--enable-FEATURE=no'與上面提到的'--disable-FEATURE'是同義的。
--with-PACKAGE[=ARG]
在自由軟件社區里,有使用已有軟件包和庫的優秀傳統。當用'configure'來配置一個源碼樹時,可以提供其他已經安裝的軟件包的信息。例如,倚賴于Tcl和Tk的BLT器件工具包。要配置BLT,可能需要給'configure'提供一些關于我們把Tcl和Tk裝的何處的信息:
$ ./configure --with-tcl=/usr/local --with-tk=/usr/local
'--with-PACKAGE=no'與下面將提到的'--without-PACKAGE'是同義的。
--without-PACKAGE
有時候你可能不想讓你的軟件包與系統已有的軟件包交互。例如,你可能不想讓你的新編譯器使用GNU ld。通過使用這個選項可以做到這一點:
$ ./configure --without-gnu-ld
--x-includes=DIR
這個選項是'--with-PACKAGE'選項的一個特例。在Autoconf最初被開發出來時,流行使用'configure'來作為Imake的一個變通方法來制作運行于X的軟件。'--x-includes'選項提供了向'configure'腳本指明包含X11頭文件的目錄的方法。
--x-libraries=DIR
類似的,'--x-libraries'選項提供了向'configure'腳本指明包含X11庫的目錄的方法。
在源碼樹中運行'configure'是不必要的同時也是不好的。一個由'configure'產生的良好的'Makefile'可以構筑源碼屬于另一棵樹的軟件包。在一個獨立于源碼的樹中構筑派生的文件的好處是很明顯的:派生的文件,如目標文件,會凌亂的散布于源碼樹。這也使在另一個不同的系統或用不同的配置選項構筑同樣的目標文件非常困難。建議使用三棵樹:一棵源碼樹(source tree),一棵構筑樹(build tree),一棵安裝樹(install tree)。這里有一個很接近的例子,是使用這種方法來構筑GNU malloc包:
$ gtar zxf mmalloc-1.0.tar.gz
$ mkdir build && cd build
$ ../mmalloc-1.0/configure
creating cache ./config.cache
checking for gcc... gcc
checking whether the C compiler (gcc ) works... yes
checking whether the C compiler (gcc ) is a cross-compiler... no
checking whether we are using GNU C... yes
checking whether gcc accepts -g... yes
checking for a BSD compatible install... /usr/bin/install -c
checking host system type... i586-pc-linux-gnu
checking build system type... i586-pc-linux-gnu
checking for ar... ar
checking for ranlib... ranlib
checking how to run the C preprocessor... gcc -E
checking for unistd.h... yes
checking for getpagesize... yes
checking for working mmap... yes
checking for limits.h... yes
checking for stddef.h... yes
updating cache ../config.cache
creating ./config.status
這樣這棵構筑樹就被配置了,下面可以繼續構筑和安裝這個包到默認的位置'/usr/local':
$ make all && make install
圖1-1
接著介紹下藍牙里面profile的定義,profile既是配置文件,配置文件定義了可能的應用,藍牙配置文件表達了一般行為,藍牙設備可以通過這些行為與其它設備進行通信。藍牙技術定義了廣泛的配置文件,描述了許多不同類型的使用案例。按照藍牙規格中提供的指導,開發商可以創建應用程序以與其它符合藍牙規格的設備協同工作。 到目前為止,藍牙一共有22個profile,在這里我就不詳細介紹圖1-1的協議和每個Profile了,在www.bluetooth.com上有詳細的文檔說明。
在這里我想詳細介紹下已經實現了r的協議棧。
我們是基于BlueMagic3的,最近呢也在研究bluez 4的移植和profile工作,后面我會再針對bluez做詳細介紹。
時間有限,簡單的寫了下,如果各位網友知道一些協議棧的動態,或對我寫的有補充,請給我留言,我會及時改正,
chdir("..");
_findclose(filehandle);
通過查證MSDN得知類似于_findfirst,findnext都是針對ASCII碼的,要讀unicode(windows默認字符集),就得用_wfindfirst,_wfindnext等讀寬字符的操作函數,最終解決問題,但我沒有松氣,因為程序主要是運行在linux中的,Linux真不知道怎么整了。
Linux上讀多國語言的文件和目錄就需要對Linux系統深入了解,因為我要讀的文件是usb上的文件,所以得先掛載到一個目錄,
mount -t vfat /dev/sda1 /mnt/usb,然后readdir讀入文件,與Windows上同樣的錯,讀入的是"?",我想和windows一樣去找一個類似wreaddir,但是沒有。于是應該從掛載著手,目前在NTFS和FAT32/VFAT下的文件系統上都使用了Unicode,這就需要系統在讀取這些文件名時動態將其轉換為相應的語言編碼,也就是說掛載的時候要把usb上的編碼轉化成16位的Unicode編碼,改命令如下后成功。
mount -o iocharset = utf8 /dev/sda1 /mnt/usb.
Linux對iocharset的解釋如下:
Character set to use for converting between 8 bit characters and 16 bit unicode charaters.The default is iso8859-1. Long filenames are stored on disk in Unicode format.
至此終于解決了多國語言的問題,接著我無法想象還有什么問題會出來,但我準備好了。
ubuntu已經被我從硬盤上擦除了,呵呵,因為一些問題,找了張suse,安裝時選了KDE,現在突然感覺不錯,從可用性上,界面上都不再是那個死板的Linux,而且我沒裝什么驅動用跑起來也沒問題(對于菜鳥來說這個比較重要),然后U盤也不用掛載就可用,不會出中文問題,就感覺還可以了,先給張圖片大家看看。