研究一个open source project从编译它开始。像这个Facebook Open Platform这样编译起来过程这么烦琐,还真是头一次碰到。
要编译Facebook Open Platform,至少需要先安装Apache, MySQL, PHP。而且PHP至少包含下列PHP extensions:
ctype, curl, date, iconv, json, mysql, pcre, SimpleXML, standard, xmlwriter
在Facebook Open Platform的安装包里,其实还包含了Firefox的代码,最后这些代码会被编译成一个PHP extension,供apache和PHP使用。
环境:
OS: Fedora7 (kernel 2.6.21)
Shell: bash v3.2.9
GCC: v4.1.2
make: v3.81
---------------------------------------------------------------
第一部分,安装apache。
Apache 2.2.9 (httpd-2.2.9.tar.bz2)
假设安装路径为/home/tielei/opensrc/httpd-2.2.9-installed。
1, 将httpd-2.2.9.tar.bz2拷贝到/home/tielei/opensrc/目录下
2, tar xjf httpd-2.2.9.tar.bz2
3, mkdir httpd-2.2.9-installed
4, cd httpd-2.2.9
5, 执行configure脚本。顺便把常用的module都enable了,命令比较长。
./configure --prefix=/home/tielei/opensrc/httpd-2.2.9-installed --enable-so --enable-authz_groupfile=shared --enable-expires=shared --enable-alias=shared --enable-actions=shared --enable-auth_basic=shared --enable-auth_digest=shared --enable-authn_dbd=shared --enable-authn_dbm=shared --enable-authn_default=shared --enable-authn_file=shared --enable-authz_owner=shared --enable-authz_user=shared --enable-cgi=shared --enable-cgid=shared --enable-charset_lite=shared --enable-dbd=shared --enable-deflate=shared --enable-env=shared --enable-headers=shared --enable-imagemap=shared --enable-include=shared --enable-info=shared --enable-log_config=shared --enable-log_forensic=shared --enable-logio=shared --enable-mime=shared --enable-mime_magic=shared --enable-negotiation=shared --enable-speling=shared --enable-ssl=shared --enable-status=shared
6, make
7, make install
测试一下刚刚装好的apache server
8, cd /home/tielei/opensrc/httpd-2.2.9-installed
9, 检查和修改配置文件conf/httpd.conf,根据需要,可能需要修改DocumentRoot
10, su (切换到root)
11, 以root身份启动apache server
./bin/apachectl -f conf/httpd.conf
12, 保证DocumentRoot路径上的目录对other用户具有rx权限,DocumentRoot路径下的文件对other用户具有r权限
13, 可能需要关闭防火墙。在redhat/fedora系统中,执行
/etc/rc.d/init.d/iptables stop
14, 在另一台机器中访问http://192.168.1.102 (apache server所在机器的IP地址),如果httpd.conf没有被修改过,则访问的文件则是/home/tielei/opensrc/httpd- 2.2.9-installed/htdocs/index.html。它显示“It Works”!
15,关闭apache server
./bin/apachectl -k stop
16, 退出root身份:Ctrl+D
---------------------------------------------------------------
第二部分,安装Mysql (mysql-5.0.51a-linux-i686-icc-glibc23.tar.gz)
为简单起见,下载了一个已经编译好的package,下载链接是
http://dev.mysql.com/get/Downloads/MySQL-5.0/mysql-5.0.51a-linux-i686-icc-glibc23.tar.gz/from/http://mysql.cs.pu.edu.tw/
1, 将mysql-5.0.51a-linux-i686-icc-glibc23.tar.gz拷贝到/home/tielei/opensrc/目录下
2, tar xzf mysql-5.0.51a-linux-i686-icc-glibc23.tar.gz
拷贝完就算是已经安装好了。完成安装后的配置:
3, cd mysql-5.0.51a-linux-i686-icc-glibc23
4, 查看文档
info docs/mysql.info
进入文档目录installing/installing-cs/post-installation/unix-post-installation
文档中说明了初次安装后应该初始化grant tables,执行:
5, script s/mysql_install_db --user=mysql
6, 启动mysql server
bin/mysqld_safe --user=mysql &
测试一下刚配置好的mysql server
7, 连接mysql server
bin/mysql -u mysql
Welcome to MYSQL Monitor. Commands end with ; or /g.
...
mysql>quit
8, 关闭mysql server
bin/mysqladmin -u root shutdown
---------------------------------------------------------------
第三部分,安装PHP
PHP5 (php-5.2.6.tar.bz2)
假设安装路径为/home/tielei/opensrc/php-5.2.6-installed。
1, 将php-5.2.6.tar.bz2拷贝到/home/tielei/opensrc/目录下
2, tar xjf php-5.2.6.tar.bz2
3, mkdir php-5.2.6-installed
4, cd php-5.2.6
5, ./configure --prefix=/home/tielei/opensrc/php-5.2.6-installed --with-apxs2=/home/tielei/opensrc/httpd-2.2.9-installed/bin/apxs --with-mysql=/home/tielei/opensrc/mysql-5.0.51a-linux-i686-icc-glibc23 --with-curl
6, make
7, make install
8, 如果make install执行时出现如下错误
/home/tielei/opensrc/php-5.2.6/sapi/cli/php: error while loading shared libraries: /home/tielei/opensrc/mysql-5.0.51a-linux-i686-icc-glibc23/lib/libmysqlclient.so.15: cannot restore segment prot after reloc: Permission denied则先执行
chcon -t texrel_shlib_t /home/tielei/opensrc/mysql-5.0.51a-linux-i686-icc-glibc23/lib/lib*
然后重新执行make install
9, 检查。
至此,在apache的ServerRoot/modules/目录下,即/home/tielei/opensrc/httpd-2.2.9-installed/modules/目录下,会出现libphp5.so
10, 设置配置文件
cp php.ini-dist ../php-5.2.6-installed/lib/php.ini
11, cd ../httpd-2.2.9-installed
12, 检查。
apache的配置文件中,即conf/httpd.conf中,有下面的一行:
LoadModule php5_module modules/libphp5.so
13,在配置文件conf/httpd.conf中,加入下面一行:
AddType application/x-httpd-php .php
测试一下刚配置好的PHP。
14, 以root身份启动apache server
./bin/apachectl -f conf/httpd.conf
15, 如果上面的命令出现如下错误提示:
httpd: Syntax error on line 85 of /home/tielei/opensrc/httpd-2.2.9-installed/conf/httpd.conf: Cannot load /home/tielei/opensrc/httpd-2.2.9-installed/modules/libphp5.so into server: /home/tielei/opensrc/httpd-2.2.9-installed/modules/libphp5.so: cannot restore segment prot after reloc: Permission denied则需先执行chcon -t texrel_shlib_t modules/libphp5.so
16, 在htdocs目录下建一个.php文件,用浏览器访问,看是否能正常解析php脚本。
17, 测试完毕,关闭apache server
./bin/apachectl -k stop
18, cd ../php-5.2.6-installed
19, 检查。
运行 bin/php -m
检查打印出的module列表是否包含所有下列PHP extensions:
ctype, curl, date, iconv, json, mysql, pcre, SimpleXML, standard, xmlwriter
---------------------------------------------------------------
第四部分,安装和配置Facebook Open Platform (fb-open-platform.tar.gz)。
Facebook Open Platform软件包里面包含FBML的代码(libfbml.tar.gz,解压后libfbml-1.2.0),FBML的实现用到了 firefox,而firefox又依赖于一系列open source package(见下面第5步)。
1,将fb-open-platform.tar.gz拷贝到/home/tielei/opensrc/httpd-2.2.9-installed/htdocs/目录下
2,tar xzf fb-open-platform.tar.gz
3, tar xzf libfbml.tar.gz
4, cd libfbml-1.2.0
5, 下载firefox所依赖的代码。
在dependencies目录下,存放的是firefox的代码。由于firefox依赖下面列表所给出的project,所以需要先从括号中所示的URL下载所有这些软件包,并将它们都放入dependencies目录。
glib-2.14.6.tar.gz (http://ftp.acc.umu.se/pub/GNOME/sources/glib/2.14/glib-2.14.6.tar.gz)
pkg-config-0.20.tar.gz (ftp://ftp.gtk.org/pub/gtk/v2.10/dependencies/pkg-config-0.20.tar.gz)
atk-1.9.1.tar.bz2 (ftp://ftp.gtk.org/pub/gtk/v2.10/dependencies/atk-1.9.1.tar.bz2)
freetype-2.3.4.tar.gz (http://download.savannah.gnu.org/releases/freetype/freetype-2.3.4.tar.gz)
fontconfig-2.3.97.tar.gz (http://fontconfig.org/release/fontconfig-2.3.97.tar.gz)
libpng-1.2.25.tar.gz (http://internap.dl.sourceforge.net/sourceforge/libpng/libpng-1.2.25.tar.gz)
cairo-1.2.6.tar.gz (ftp://ftp.gtk.org/pub/gtk/v2.10/dependencies/cairo-1.2.6.tar.gz)
tiff-3.7.4.tar.gz (ftp://ftp.gtk.org/pub/gtk/v2.10/dependencies/tiff-3.7.4.tar.gz)
pango-1.18.4.tar.bz2 (http://ftp.gnome.org/pub/gnome/sources/pango/1.18/pango-1.18.4.tar.bz2)
gtk+-2.10.13.tar.bz2 (ftp://ftp.gtk.org/pub/gtk/v2.10/gtk+-2.10.13.tar.bz2)
libIDL-0.8.8.tar.gz (http://ftp.gnome.org/pub/gnome/sources/libIDL/0.8/libIDL-0.8.8.tar.gz)
libXft-2.1.12.tar.gz (http://xorg.freedesktop.org/releases/individual/lib/libXft-2.1.12.tar.gz)
xproto-7.0.7.tar.gz (http://xorg.freedesktop.org/releases/individual/proto/xproto-7.0.7.tar.gz)
xrender-0.8.3.tar.bz2 (http://freeware.sgi.com/source/xrender/xrender-0.8.3.tar.bz2)
6, 修改/etc/sudoers文件。
将自己的用户名(tielei)加入到/etc/sudoers文件,使之允许以root身份执行make install和cp命令(在下面执行build-all.py脚本时会用到这两个命令)。具体做法是执行
/usr/sbin/visudo
在文件尾部加入两行:
tielei localhost=NOPASSWD: /usr/bin/make install
tielei localhost=NOPASSWD: /bin/cp pangocairo.pc /usr/local/lib/pkgconfig
7, export LD_LIBRARY_PATH=/usr/local/lib
保证连接的是刚装到/usr/local/lib/的库,而不是原来环境里就有的库(比如在/usr/lib/)。
8, 修改build-all.py脚本。
共三处修改:
(1)将第104行编译xrender-0.8.3.tar.bz2的命令改为:
'xrender-0.8.3.tar.bz2': ("./configure --x-includes=/usr/include/X11/extersions", "make", "sudo make install")
(2)将第82行到第85行packages变量中的'xrender-0.8.3.tar.bz2'换到'libIDL-0.8.8.tar.gz'和'libXft-2.1.12.tar.gz'之间的位置
(3)将第91行到第104行commands变量中的'xrender-0.8.3.tar.bz2'那一行换到'libIDL-0.8.8.tar.gz'一行和'libXft-2.1.12.tar.gz'一行中间的位置
否则编译xrender-0.8.3时提示找不到X11/extensions/Xrender.h和X11/extensions/render.h
修改脚本后会先编译xrender-0.8.3再编译libXft-2.1.12,会生成libXft-2.1.12需要的头文件Xrender.h
9, 修改源文件fbml.cpp的bug (libfbml-1.2.0/src/fbml.cpp)
将第1233行到第1330行的代码用{}括起来,代码片段:
if (!chars) goto exit;
{ //line 1233
// 3. Initialize tokenizer
JSTokenStream *ts =
js_NewTokenStream(cx, chars, length, NULL, line_number, NULL);
if (!ts) goto exit;
...
...
if (error) {
*error = m(strdup(sError.c_str()));
}
} //line 1330
exit:
if (chars) JS_free(cx, chars);
如果不在这里加上{},则编译时会提示如下错误:
fbml.cpp: In function ‘int fbml_sanitize_js(char*, int, int, int,
fbml_js_sanitizer*, char**, char**)’:
fbml.cpp:1331: error: jump to label ‘exit’
fbml.cpp:1237: error: from here
fbml.cpp:1317: error: crosses initialization of ‘char* deflated’
fbml.cpp:1254: error: crosses initialization of ‘jschar* userbuf_pos’
fbml.cpp:1250: error: crosses initialization of ‘jschar* this_rep’
fbml.cpp:1249: error: crosses initialization of ‘size_t this_len’
fbml.cpp:1245: error: crosses initialization of ‘char* this_replacement’
fbml.cpp:1241: error: crosses initialization of ‘jschar* prefix’
fbml.cpp:1240: error: crosses initialization of ‘size_t prefix_len’
fbml.cpp:1331: error: jump to label ‘exit’
fbml.cpp:1232: error: from here
fbml.cpp:1317: error: crosses initialization of ‘char* deflated’
fbml.cpp:1254: error: crosses initialization of ‘jschar* userbuf_pos’
fbml.cpp:1250: error: crosses initialization of ‘jschar* this_rep’
fbml.cpp:1249: error: crosses initialization of ‘size_t this_len’
fbml.cpp:1245: error: crosses initialization of ‘char* this_replacement’
fbml.cpp:1241: error: crosses initialization of ‘jschar* prefix’
fbml.cpp:1240: error: crosses initialization of ‘size_t prefix_len’
fbml.cpp:1235: error: crosses initialization of ‘JSTokenStream* ts’
make[1]: *** [fbml.o] Error 1
make: *** [src] Error 2
Failed to make libfbml.... Aborting
错误的原因在于有些变量(如ts, prefix_len等)的生存期包含到1331行的"exit" label,如果在第1232或1237行直接跳到第1331行的"exit" label时,这些变量就没有机会被初始化。
10, 修改源文件jsbit.h的bug (libfbml-1.2.0/src/js/jsbit.h)
在第173行代码
JS_STATIC_ASSERT(sizeof(unsigned long long) == sizeof(JSUword));
中删掉一个"long"
否则编译时会提示以下错误:
In file included from js/jsarena.c:50:
js/jsbit.h:173: error: size of array ‘js_static_assert_line_173’ is negative
make[1]: *** [js/jsarena.o] Error 1
make: *** [src] Error 2
11, export LDFLAGS="-L/usr/local/lib -lX11 -lXrender"
否则编译firefox时很多符号(libX11.so/libXrender.so里的符号)找不到
12,export PATH=/home/tielei/opensrc/php-5.2.6-installed/bin:$PATH
是为了在编译fbml PHP extension时正确调用到刚刚安装好的PHP程序phpize (/home/tielei/opensrc/php-5.2.6-installed/bin/phpize)
13,编译libfbml-1.2.0。
./build-all.py
一个命令全部搞定!
这个脚本大概做了三件事:
(a) 将第5步中列出的firefox所依赖的库进行编译,并安装到/usr/local/lib/。
(b) 编译firefox-2.0.0.4 (但没有安装,因为编译libfbml的时候用不到)。
(c) 编译libfbml-1.2.0。将libfbml编译成一个新的PHP extension。
注 意要确保自己的主目录下(~/)没有一个叫做.mozconfig的文件,否则编译firefox-2.0.0.4时会去这个文件取回一些配置,造成混 乱。通常如果同时在编译或者编译过某一个firefox的版本,可能会在主目录下留下一个.mozconfig文件,这会对这里的编译造成影响。
脚本执行完毕后,会打印出:
Build complete. You'll need to restart Apache before the new PHP extension can be used
14, 检查。
编 译完libfbml-1.2.0后,应该在php的安装目录下会产生一个.so库文件,即 /home/tielei/opensrc/php-5.2.6-installed/lib/php/extensions/no-debug-non-zts-20060613/fbml.so
15, 修改php.ini文件。
打开/home/tielei/opensrc/php-5.2.6-installed/lib/php.ini文件,做两个改动:
(a) 找到这一行
extension_dir = "./"
改为
extension_dir = "/home/tielei/opensrc/php-5.2.6-installed/lib/php/extensions/no-debug-non-zts-20060613/"
(b) 增加一行
extension=fbml.so
如果不修改php.ini,则apache/PHP找不到新安装好的PHP extension libfbml,调用facebook platform api时会出现如下类似的错误:
Fatal error : Call to undefined function fbml_complex_expand_tag_list_11() in /home/tielei/opensrc/httpd-2.2.9-installed/htdocs/lib/fbml/wrapper.php on line 62
16, 检查和修改源文件中所有出现"FBOPEN:SETUP"的地方。
先找到所有的文件:
cd /home/tielei/opensrc/httpd-2.2.9-installed/
grep -r "FBOPEN:SETUP" .
所有包含"FBOPEN:SETUP"的文件有:
(a) html/fbopentest/js_typeahead.php
app的名字"fbopentest",可以不做修改
(b) html/fbopentest/demo_libs/server_url.php
修改为:
$YOUR_PLATFORM_SERVER_URL = 'http://192.168.1.102/html';
$YOUR_APP_SERVER_URL = 'http://192.168.1.102/html';
(假定apache server所在机器的IP是192.168.1.102)
($YOUR_PLATFORM_SERVER_URL表示平台服务器的url;$YOUR_APP_SERVER_URL表示app server的url)
(c) html/fbopentest/demo_libs/config.php
这里指明了app fbopentest的api key 和 secret key,可以不做修改。
(d) html/fbopentest/ajax_typeahead.php
不用修改
(e) html/fbml/fbjs_ajax_proxy.php
user ID,可以不做修改
(f) fbopen_data_dump
将该文件里面出现的所有"YOUR_APP_SERVER_URL"都替换成"192.168.1.102/html"
(g) lib/core/init.php
这个文件中"FBOPEN:SETUP"共出现4次。第一次和第四次出现的地方必须要修改,其他两处可以不做修改。
第一次出现处,修改成
$DB_USERNAME = 'root'; // FBOPEN:NOTE - replace here with your own.
$DB_IP = 'localhost'; // FBOPEN:NOTE - replace here with your own.
$DB_PWD = ''; // FBOPEN:NOTE - replace here with your own.
(或者修改成其它任意配置好的用户名、密码)
第四次出现处,修改成
$YOUR_PLATFORM_SERVER_URL = 'http://192.168.1.102/html/';
(注意最后一定要有一个反斜杠)
17, 修改canvas.php/fbjs_ajax_proxy.php定义PHP_ROOT。
在html/canvas.php文件开头加入一行:
$_SERVER['PHP_ROOT'] = "/home/tielei/opensrc/httpd-2.2.9-installed/htdocs";
如果想运行ajax功能,则还需在html/fbml/fbjs_ajax_proxy.php文件开头也要加上这一行。
18, 创建数据表
如果mysql server没有启动,则先启动它
cd /home/tielei/opensrc/mysql-5.0.51a-linux-i686-icc-glibc23
bin/mysqld_safe --user=mysql &
执行fbopen_data_dump,创建数据表
cd /home/tielei/opensrc/httpd-2.2.9-installed
/home/tielei/opensrc/mysql-5.0.51a-linux-i686-icc-glibc23/bin/mysql -u root -h localhost < fbopen_data_dump
19,修改html/js/base.js
将该文件中的倒数第5行
document.domain = 'facebook.com';
改为
document.domain = '192.168.1.102';
否则会违反js的Same-Origin原则。
20,修改html/js/fbjs.js
找到这一行
fbjs_ajax.proxy_url = '/fbml/fbjs_ajax_proxy.php';
根据源码解压缩后存放的位置不同,这一行有可能不对。找到fbjs_ajax_proxy.php文件所在的正确位置,加以改正。
在我的环境中,该文件的路径为/home/tielei/opensrc/httpd-2.2.9-installed/htdocs/html/fbml/fbjs_ajax_proxy.php,因此将该行改为:
fbjs_ajax.proxy_url = '/html/fbml/fbjs_ajax_proxy.php';
21, 再次启动apache server
cd /home/tielei/opensrc/httpd-2.2.9-installed
bin/apachectl -f conf/httpd.conf
22, 测试Facebook Platform API
在浏览器中键入:
http://192.168.1.102/html/canvas.php?fb_app_name=fbopentest&fb_user_id=1240077&fb_url_suffix=apitest.php%3Fparam1%3Dfoo%26param2%26param3%3Dbar
还会有simplexml_load_string函数打印出的一些warning message,暂时忽略。
23, 测试FBML
在浏览器中键入:
http://192.168.1.102/html/canvas.php?fb_app_name=fbopentest&fb_user_id=1240077&fb_url_suffix=fbml.php
24, 同时测试API, FBML和FBJS
在浏览器中键入:
http://192.168.1.102/html/fbopentest/testall.php