轉載
甚麼是ssl?
security socket layer指的是透過加密機制來保護client端與server端之間傳輸的資料
apache web server對於ssl加密保護的選擇
目前在ports tree裡面有兩種選擇:
01./usr/ports/www/apache13-modssl/
02./usr/ports/www/apache13-ssl/
這兩者之間最主要的差別在於apache13-ssl是直接將ssl包成apache的一部份,而apache13-modssl則是採用模組的方式
來載入ssl,兩者都可以讓web server使用ssl加密傳輸資料,各有好有壞,在這邊,我選擇apache13-modssl
目前for apache2的modssl只有rh有作成for rh8的rpm檔,在FreeBSD上目前還沒有出現,暫時不考慮使用apache2
為甚麼需要apache + modssl?
除了架設電子商務網站的需求之外,最常見的原因就是為了發展能夠在web上使用的應用程式如:web mail , web apps等
有需要對傳輸的資料作保護的應用,特別是企業如果提供使用者web mail功能,為了防範使用者密碼被竊取,加上ssl保護
是必須的,對於電子商務網站而言更是取得消費者信任的必要的東西,這邊不討論對於電子商務的應用的部份
甚麼是php?
php是目前在web上應用的相當廣泛的一種script語言,也有許多的web ap使用php來開發,如phpbb這個相當有名的討論版程式
這裡只介紹怎麼將php4安裝成apache + modssl的模組
這邊只介紹以ports安裝,在安裝前務必要先更新過ports tree
安裝apache + modssl
cd /usr/ports/www/apache13-modssl/
make install clean
安裝mod_php4
cd /usr/ports/www/mod_php4
make install clean
這時會出現一個選單,其中有些選項是互相衝突的,例如gd1 , gd2這兩個功能是互相衝突的,如果發現這樣的問題時
make clean之後在重新make install clean重新選取一次
ports安裝最大的好處在於,ports maintainer已經事先做好的script,能夠自動為使用者修改httpd.conf,使用者只要完成
這些手續之後,如果編譯系統無誤的話,就已經建制完成了有ssl加密保護的apache server
apache + modssl的設定檔說明
上面這些動作編譯完成之後,/usr/local/etc/apache/會出現apache13-modssl的設定檔
.htaccess的應用
使用者個人網頁
mod_php4的設定檔說明
安裝完成mod_php4之後,預設不會有php.ini,必須自己手動將php.ini.dist複製成php.ini
cp /usr/local/etc/php.ini.dist /usr/local/etc/php.ini
啟動apache server
預設安裝完成之後並不會自動在/usr/local/etc/rc.d/裡面產生apache.sh,需要自己手動將apache.sh.dist複製成apache.sh
並加上可執行的屬性
cp /usr/local/etc/rc.d/apache.sh.dist /usr/local/etc/rc.d/apache.sh
chmod +x /usr/local/etc/rc.d/apache.sh
/usr/local/etc/rc.d/apache.sh start
這樣就啟動了web server
測試服務是否正常
sockstat | grep http有看到出現就表示apache已經成功的執行了
www httpd 52640 16 tcp4 *:443 *:*
www httpd 52640 17 tcp4 *:80 *:*
這時候在用瀏覽器輸入http://your.server.ip.address/就可以看到預設的網頁了
建立apache專用的newsyslog.conf選項
在/etc/newsyslog.conf中加入這兩行指令
/var/log/httpd-access.log 644 7 100 24 B /var/run/httpd.pid 30
/var/log/httpd-error.log 644 7 100 24 B /var/run/httpd.pid 30
搜尋並安裝適合的webmail
通常為了方便使用者在公司外使用信箱,一般都會提供webmail的功能,當然,前提是mail server的功能必須先能夠正常工作
ports tree中也提供了許多種的webmail可以選擇,有支援imap4的,有支援其他功能的,可以簡單的使用指令來搜尋
cd /usr/ports/
make search key=webmail | more
這邊選擇中文支援程度比較好,且主要由成大電機開發與維護的openwebmail來安裝
cd /usr/ports/mail/openwebmail/
make install clean
修改成中文版
修改/usr/local/www/cgi-bin-dist/openwebmail/etc/openwebmail.conf中的
default_language改成zh_TW.Big5
建立openwebmail的log檔
cd /var/log/
touch openwebmail.log
使用瀏覽器開啟http://your.server.ip.address/cgi-bin/openwebmail/openwebmail.pl就可以看到登入畫面了
Posted by antony at 02:52 PM | Comments (0) | TrackBack
ports 的原理
轉載
再談ports的原理之前必須先理解:誰有權力去更動ports裡面的東西
port maintainer:負責維護自己有興趣的port的更新、問題修正等相關問題(任何人都可以擔任)
port committer:負責對port maintainer做出來的port做再次確認的工作,有問題的話也會加以修正
(需要一定的考核之後才能成為committer)
接下來必須瞭解:什麼是dependency(相依性) , dependency hell
以openwebmail為例,這是一個web mail(web interface mua),可想而知,必須要有web server才能跑
openwebmail,而少了web server,openwebmail就無法正常工作,於是openwebmail有了web server這個
dependency(相依性)
而web server在這裡以apache為例,要安裝apache就必須先安裝好expat2這個軟體,這樣一路連貫下去直
到滿足所有openwebmail所需要的相依性
而在安裝軟體時最怕遇到的就是dependency hell,也就是安裝一個東西,這東西有很多相依性,而有相依
性的東西又有很多相依性,使的安裝軟體非常的痛苦
在程式開發的觀點來看的話,寫一個軟體,但其中有呼叫其他lib提供的function,這時候寫出來的軟體對
提供function的lib就有了相依性,如果這個lib又有其他的相依性,就很容易形成安裝軟體時的
dependency hell
理解了相依性的問題之後,再來談ports的架構
分類:依照不同的用途來分類
搜尋:針對INDEX做搜尋
make search key=
make search name=
安裝最簡單的方法為
cd /usr/ports/xxxx/yyyy/
make install clean
解析一個port
damon[/usr/ports/chinese/xcin25]-damon->ls
Makefile README.html distinfo files/ pkg-descr pkg-plist
這是一個很典型的port,裡面有
Makefile:定義了編譯時所使用的參數
README.html:說明檔
distinfo:記錄了所抓下來的檔案的md5 checksum
files/:放的是port maintainer所寫的patch
pkg-descr:port maintainer所寫的簡單的說明
pkg-plist:記錄了安裝了哪些檔案到什麼地方
先看pkg-descr
damon[/usr/ports/chinese/xcin25]-damon->cat pkg-descr
xcin is a Chinese INput application in X, well support in both Traditional
Chinese(Big5) and Simplified Chinese(GB) charsets. New version of xcin support
standard XIM too. You can activate one xcin-XIM server, meanwhile, use
different locale configuration to input Big5/GB words at the different
sessions. This port is current version of xcin, code rewritten by
Tung-Han Hsieh .
WWW: http://xcin.linux.org.tw/
Porting to FreeBSD by Yung-Jen Hung
& Keith Jang .
再來看pkg-plist
damon[/usr/ports/chinese/xcin25]-damon->cat pkg-plist
bin/xcin2.5
etc/xcinrc
lib/X11/xcin25/bimsphone.a
lib/X11/xcin25/bimsphone.la
lib/X11/xcin25/bimsphone.so
lib/X11/xcin25/bin/cin2tab
lib/X11/xcin25/chewing.a
lib/X11/xcin25/chewing.la
lib/X11/xcin25/chewing.so
%%PORTDOCS%%lib/X11/xcin25/doc/Bugs
%%PORTDOCS%%lib/X11/xcin25/doc/COPYING
%%PORTDOCS%%lib/X11/xcin25/doc/CREDITS
以下省略
再來看Makefile
# New ports collection makefile for: xcin25
# Date created: 18 Oct 1999
# Whom: Keith Jang
#
# $FreeBSD: ports/chinese/xcin25/Makefile,v 1.46 2003/02/21 11:06:31 knu Exp $
#
PORTNAME= xcin
PORTVERSION= 2.5.3.p2
PORTREVISION= 2
CATEGORIES= chinese x11
MASTER_SITES= ftp://xcin.linux.org.tw/pub/xcin/xcin/ \
ftp://xcin.linux.org.tw/pub/xcin/xcin/devel/ \
http://chewing.good-man.org/snapshot/
DISTNAME= ${PORTNAME}-${PORTVERSION:S/p/pre/}
DISTFILES= ${DISTNAME}${EXTRACT_SUFX} chewing-2002Jan07-snapshot.tar.gz
MAINTAINER= kcwu@ck.tp.edu.tw
COMMENT= Chinese input method server under X
LIB_DEPENDS= tabe.2:${PORTSDIR}/chinese/libtabe \
intl.4:${PORTSDIR}/devel/gettext \
iconv.3:${PORTSDIR}/converters/libiconv
.if !defined(USE_DB2)
LIB_DEPENDS+= db3.3:${PORTSDIR}/databases/db3
.else
LIB_DEPENDS+= db2.0:${PORTSDIR}/databases/db2
.endif
RUN_DEPENDS= ${X11BASE}/lib/X11/fonts/local/kc15f.pcf.gz:${PORTSDIR}/chinese/
kcfonts \
${LOCALBASE}/share/tabe/libtabe-0.2.5:${PORTSDIR}/chinese/libtabe
WRKSRC= ${WRKDIR}/xcin
USE_X_PREFIX= yes
GNU_CONFIGURE= yes
INSTALLS_SHLIB= yes
CONFIGURE_ARGS= --prefix=${PREFIX} \
--x-libraries=${X11BASE}/lib \
--with-xcin-dir=${PREFIX}/lib/X11/xcin25 \
--with-db-lib=${LOCALBASE}/lib \
--with-tabe-inc=${LOCALBASE}/include/tabe \
--with-tabe-lib=${LOCALBASE}/lib \
--with-intl-inc=${LOCALBASE}/include \
--with-intl-lib=${LOCALBASE}/lib \
--with-iconv-inc=${LOCALBASE}/include \
--with-iconv-lib=${LOCALBASE}/lib
.if !defined(USE_DB2)
CONFIGURE_ARGS+= --with-db-inc=${LOCALBASE}/include/db3
.else
CONFIGURE_ARGS+= --with-db-inc=${LOCALBASE}/include/db2
.endif
MAN1= xcin.1
pre-fetch:
.if !defined(USE_DB2)
@${ECHO} --
@${ECHO} "Type \"make -DUSE_DB2\" if you want use DB2."
@${ECHO} "Otherwise, xcin2.5 will use DB3."
@${ECHO} --
.endif
post-extract:
${MV} ${WRKDIR}/chewing ${WRKSRC}/src/Cinput
post-patch:
@cd ${WRKSRC}/src/Cinput/chewing; ${SH} ./patch_chewing
post-install:
.if !defined(NOPORTDOCS)
${MKDIR} ${PREFIX}/lib/X11/xcin25/doc
.for DOC in Bugs COPYING CREDITS Changes Cin CopyRight FAQ README \
SETUP Todo Usage UserGuide
${INSTALL_DATA} ${WRKSRC}/doc/${DOC} ${PREFIX}/lib/X11/xcin25/doc
.endfor
${MKDIR} ${PREFIX}/lib/X11/xcin25/doc/En
${MKDIR} ${PREFIX}/lib/X11/xcin25/doc/En/internal
.for En in README.En SETUP.En Usage.En UserGuide.En
${INSTALL_DATA} ${WRKSRC}/doc/En/${En} ${PREFIX}/lib/X11/xcin25/doc/En
.endfor
.for Eninternal in module.En structer.En
${INSTALL_DATA} ${WRKSRC}/doc/En/internal/${Eninternal} ${PREFIX}/lib/X1
1/xcin25/doc/En/internal
.endfor
${MKDIR} ${PREFIX}/lib/X11/xcin25/doc/history
${INSTALL_DATA} ${WRKSRC}/doc/history/Changes-19991011 \
${PREFIX}/lib/X11/xcin25/doc/history
${MKDIR} ${PREFIX}/lib/X11/xcin25/doc/internal
.for INTERNAL in IMdkit gen_inp gui_request module structer
${INSTALL_DATA} ${WRKSRC}/doc/internal/${INTERNAL} \
${PREFIX}/lib/X11/xcin25/doc/internal
.endfor
${MKDIR} ${PREFIX}/lib/X11/xcin25/doc/modules
.for MODULES in bimsphone gen_inp im_comm zh_hex
${INSTALL_DATA} ${WRKSRC}/doc/modules/${MODULES} \
${PREFIX}/lib/X11/xcin25/doc/modules
.endfor
.endif
.include
再談什麼是Makefile , /usr/ports/Mk/之前必須先理解:什麼module的概念,什麼是include的概念
在程式開發時,可以採用module的作法,把常用的function寫成module,以後需要用到時再把module
include進來
理解了什麼是module , include之後,再來看/usr/ports/Mk/
damon[/usr/ports/Mk]-damon->ls
bsd.emacs.mk bsd.kde.mk bsd.port.pre.mk bsd.ruby.mk
bsd.gnome.mk bsd.port.mk bsd.port.subdir.mk bsd.sites.mk
bsd.java.mk bsd.port.post.mk bsd.python.mk
這裡可以看到core team已經為幾個主要的ports分別建立了在編譯時所需要用的參數,可以用module
的觀念來理解這些mk檔的用途
這裡只對bsd.port.mk做部分解讀,其餘觀念相同
#-*- mode: makefile; tab-width: 4; -*-
# ex:ts=4
#
# $FreeBSD: ports/Mk/bsd.port.mk,v 1.447 2003/04/19 22:35:28 kris Exp $
# $NetBSD: $
#
# bsd.port.mk - 940820 Jordan K. Hubbard.
# This file is in the public domain.
#
# Please view me with 4 column tabs!
# This is the master file for the most common elements to all port
# Makefile in the ports system. For a more general overview of its
# use and importance, see the Porter's Handbook.
# There are two different types of "maintainers" in the ports framework.
# The maintainer alias of the bsd.port.mk file is listed below in the
# FreeBSD_MAINTAINER entry. You should consult them if you have any
# questions/suggestions regarding this file.
#
# DO NOT COMMIT CHANGES TO THIS FILE BY YOURSELF, EVEN IF YOU DID NOT GET
# A RESPONSE FROM THE MAINTAINER(S) WITHIN A REASONABLE TIMEFRAME! ALL
# UNAUTHORISED CHANGES WILL BE UNCONDITIONALLY REVERTED!
FreeBSD_MAINTAINER= portmgr@FreeBSD.org
# For each port, the MAINTAINER variable is what you should consult for
# contact information on the person(s) to contact if you have questions/
# suggestions about that specific port. By default (if no MAINTAINER
# is listed), a port is maintained by the subscribers of the ports@FreeBSD.org
# mailing list, and any correspondence should be directed there.
#
# MAINTAINER - The e-mail address of the contact person for this port
# (default: ports@FreeBSD.org).
#
# These are meta-variables that are automatically set to the system
# you are running on. These are provided in case you need to take
# different actions for different values.
#
# ARCH - The architecture, as returned by "uname -p".
# OPSYS - Portability clause. This is the operating system the
# makefile is being used on. Automatically set to
# "FreeBSD," "NetBSD," or "OpenBSD" as appropriate.
# OSREL - The release version (numeric) of the operating system.
# OSVERSION - The value of __FreeBSD_version.
# PORTOBJFORMAT - The object format ("aout" or "elf").
#
# This is the beginning of the list of all variables that need to be
# defined in a port, listed in order that they should be included
# to fit in with existing conventions. (Exception: MAINTAINER actually
# should appear after EXTRACT_ONLY and before MASTER_SITE_BACKUP).
#
# These variables are used to identify your port.
#
# PORTNAME - Name of software. Mandatory.
# PORTVERSION - Version of software. Mandatory.
# PORTREVISION - Version of port. Optional. Commonly used to indicate
# that an update has happened that affects the port
# framework itself, but not the distributed software
# (e.g., local patches or Makefile changes).
# PORTEPOCH - Optional. In certain odd cases, the PORTREVISION logic
# can be fooled by ports that appear to go backwards
# numerically (e.g. if port-0.3 is newer than port-1998).
# In this case, incrementing PORTEPOCH forces the revision.
# Default: 0 (no effect).
# PKGNAMEPREFIX - Prefix to specify that port is language-specific, etc.
# Optional.
# PKGNAMESUFFIX - Suffix to specify compilation options. Optional.
# PKGNAME - Always defined as
# ${PKGNAMEPREFIX}${PORTNAME}${PKGNAMESUFFIX}-${PORTVERSION}.
# Do not define this in your Makefile.
# DISTNAME - Name of port or distribution used in generating
# WRKSRC and DISTFILES below (default:
# ${PORTNAME}-${PORTVERSION}).
# CATEGORIES - A list of descriptive categories into which this port falls.
# Mandatory.
#
# These variable describe how to fetch files required for building the port.
#
# DISTFILES - Name(s) of archive file(s) containing distribution
# (default: ${DISTNAME}${EXTRACT_SUFX}). Set this to
# an empty string if the port doesn't require it.
# EXTRACT_SUFX - Suffix for archive names (default: .tar.bz2 if USE_BZIP2
# is set, .zip if USE_ZIP is set, .tar.gz otherwise).
# You never have to set both DISTFILES and EXTRACT_SUFX.
# MASTER_SITES - Primary location(s) for distribution files if not found
# locally. See bsd.sites.mk for common choices for
# MASTER_SITES.
# MASTER_SITE_SUBDIR - Subdirectory of MASTER_SITES (default: empty).
# Will sometimes need to be set to ${PORTNAME} for (e.g.)
# MASTER_SITE_SOURCEFORGE. Only guaranteed to work for
# choices of ${MASTER_SITES} defined in bsd.sites.mk.
# PATCHFILES - Name(s) of additional files that contain distribution
# patches (default: none). make will look for them at
# PATCH_SITES (see below). They will automatically be
# uncompressed before patching if the names end with
這邊可以發現,core team為每個可以用在Makefile中的指令都做了簡單的說明,詳細看完這些說明的話
更能夠理解為什麼FreeBSD能做到每次安裝完的軟體,設定檔、執行檔該放哪裡就是放哪裡,man page該放
在哪一個部分就是在哪個部分,怎麼讓ports安裝的軟體也做到,這些都定義在/usr/ports/Mk/中的這些
設定檔,尤其是LOCALBASE , X11BASE這類的參數,每個port maintainer在做port時都必須按照這些規範
來放安裝之後的檔案
前面都是為這些指令做說明,再來看相對應的動作的部分
# Start of pre-makefile section.
.if !defined(AFTERPORTMK)
.if defined(_PREMKINCLUDED)
.BEGIN:
@${ECHO_CMD} "${PKGNAME}: You cannot include bsd.port[.pre].mk twice"
@${FALSE}
.endif
_PREMKINCLUDED= yes
AWK?= /usr/bin/awk
BASENAME?= /usr/bin/basename
.if exists(/usr/bin/bzip2)
BZCAT?= /usr/bin/bzcat
BZIP2_CMD?= /usr/bin/bzip2
.else
BZCAT?= ${LOCALBASE}/bin/bzcat
BZIP2_CMD?= ${LOCALBASE}/bin/bzip2
BZIP2DEPENDS= yes
.endif
CAT?= /bin/cat
CHGRP?= /usr/bin/chgrp
CHMOD?= /bin/chmod
CHOWN?= /usr/sbin/chown
CP?= /bin/cp
CUT?= /usr/bin/cut
DC?= /usr/bin/dc
EGREP?= /usr/bin/egrep
EXPR?= /bin/expr
FALSE?= false # Shell builtin
FILE?= /usr/bin/file
FIND?= /usr/bin/find
GREP?= /usr/bin/grep
GUNZIP_CMD?= /usr/bin/gunzip -f
GZCAT?= /usr/bin/gzcat
GZIP?= -9
GZIP_CMD?= /usr/bin/gzip -nf ${GZIP}
HEAD?= /usr/bin/head
ID?= /usr/bin/id
IDENT?= /usr/bin/ident
LDCONFIG?= /sbin/ldconfig
LN?= /bin/ln
這邊定義了每個所需要的指令放的絕對位置
# ECHO is defined in /usr/share/mk/sys.mk, which can either be "echo",
# or "true" if the make flag -s is given. Use ECHO_CMD where you mean
# the echo command.
ECHO_CMD?= echo # Shell builtin
# Used to print all the '===>' style prompts - override this to turn them off.
ECHO_MSG?= ${ECHO_CMD}
# Get the architecture
.if !defined(ARCH)
ARCH!= ${UNAME} -p
.endif
# Kludge for pre-3.0 systems
MACHINE_ARCH?= i386
# Get the operating system type
.if !defined(OPSYS)
OPSYS!= ${UNAME} -s
.endif
這裡定義了前面說明的地方提到的每一個能夠利用在Makefile中的指令所相對應的動作,對於shell
script有研究的話更容易理解這些變數(都是大寫的那些字串)的傳遞,就不多做說明,但需要絕對
注意的是:除非知道自己在幹嘛,否則絕對不要任意修改/usr/ports/Mk/裡面的設定檔
這時再回過頭來看Makefile,可以發現,其實就是實際再利用bsd.port.mk裡面所先定義好的參數與
function來告訴compiler做什麼動作,這也是就為什麼每個port maintainer寫的Makefile都會有一行
.include
當然有需要的話會include其他的mk檔
這時就可以很簡單的理解ports怎麼解決相依性的問題以及自動安裝所需要的有相依性的軟體了,答案
很簡單,就靠BUILD_DEPENDS , RUN_DEPENDS , LIB_DEPENDS這幾個與相依性有關係的指令,至於這些
指令之間的差異,就不再多做說明,bsd.port.mk裡面說的很詳細了
而由誰來確定這些相依性呢?port maintainer會先確定相依性之後加入這些參數,而committet ,
port maintainer都會實際測試過沒問題之後才會submit到ports tree裡面讓大家透過cvsup來更新
port的參數
前面可以看到,在/usr/ports/xxxx/yyyy/Makefile裡面定義了所有的安裝參數,通常port maintainer
都會做好了選項,如
.if !defined(USE_DB2)
LIB_DEPENDS+= db3.3:${PORTSDIR}/databases/db3
.else
LIB_DEPENDS+= db2.0:${PORTSDIR}/databases/db2
.endif
.if !defined(USE_DB2)
@${ECHO} --
@${ECHO} "Type \"make -DUSE_DB2\" if you want use DB2."
@${ECHO} "Otherwise, xcin2.5 will use DB3."
@${ECHO} --
.endif
這類的訊息來告訴使用者,這個port有什麼選項可以使用,這時候
cd /usr/ports/chinese/xcin25/
make install clean
就會看到
Type \"make -DUSE_DB2\" if you want use DB2.
Otherwise, xcin2.5 will use DB3.
這樣的訊息,如果有多個時候會出現多個,或是如mod_php4實在太多的話,port maintainer甚至會
做一個簡單的選單來讓使用者選擇需要加入哪些參數,再透過if來判斷加入哪些需要的相依性
如果有缺少自己想要的參數,要自己加入也可以加在
CONFIGURE_ARGS= --prefix=${PREFIX} \
--x-libraries=${X11BASE}/lib \
--with-xcin-dir=${PREFIX}/lib/X11/xcin25 \
--with-db-lib=${LOCALBASE}/lib \
--with-tabe-inc=${LOCALBASE}/include/tabe \
--with-tabe-lib=${LOCALBASE}/lib \
--with-intl-inc=${LOCALBASE}/include \
--with-intl-lib=${LOCALBASE}/lib \
--with-iconv-inc=${LOCALBASE}/include \
--with-iconv-lib=${LOCALBASE}/lib
這邊自己手動加入,不過很少有需要自己手動調整參數的狀況
有需要加入自己特殊的patch的話,可以放在files/裡面,在修改Makefile來加入這些patch
這些都是簡單的方法來保持ports安裝的軟體的彈性,但同時,如果不想要了,也可以簡單的移除不需要的
軟體
一些其他的利用
在bsd.port.mk中可以發現,ports對於make install這個動作,預設就是只有安裝上去,而對於有相依性的
軟體也只是安裝上去而已,這時候如果說我管理了十台機器,十台機器都想安裝同樣的軟體時,分別到十台
機器上下cd /usr/ports/xxxx/yyyy/ ; make install clean很浪費時間
這時候可以在其他一台cpu速度比較快的機器上建立好package,其他機器只要用pkg_add指令就可以完成安裝
了,在bsd.port.mk中定義了,如果要做成package時,如果沒有找到/usr/ports/packages/的話就放在
/usr/ports/xxxx/yyyy/中,而發現DEPENDS_TARGET預設都是install,又發現package這個參數可以包成package
於是,最簡單的解決方法就是
cd /usr/ports/
mkdir packages
cd /usr/ports/xxxx/yyyy
make DEPENDS_TARGET=package package clean
等這台編譯完成之後,到/usr/ports/packages/All/驗收剛剛編譯好的package
也許這也是每次有新的release推出時,製作package的方法,不過我不確定
沒有留言:
張貼留言