<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                nginx的編譯旅程將從configure開始,configure腳本將根據我們輸入的選項、系統環境參與來生成所需的文件(包含源文件與Makefile文件)。configure會調用一系列auto腳本來實現編譯環境的初始化。 ### auto腳本[](http://tengine.taobao.org/book/chapter_09.html#auto "永久鏈接至標題") auto腳本由一系列腳本組成,他們有一些是實現一些通用功能由其它腳本來調用(如have),有一些則是完成一些特定的功能(如option)。 接下來,我們結合代碼來分析下configure的原理: 1. 初始化 . auto/options . auto/init . auto/sources 這是configure源碼開始執行的前三行,依次交由auto目錄下面的option、init、sources來處理。 1. auto/options主是處理用戶輸入的configure選項,以及輸出幫助信息等。讀者可以結合nginx的源碼來閱讀本章內容。由于篇幅關系,這里大致列出此文件的結構: ##1. 設置選項對應的shell變量以及他們的初始值 help=no NGX_PREFIX= NGX_SBIN_PATH= NGX_CONF_PREFIX= NGX_CONF_PATH= NGX_ERROR_LOG_PATH= NGX_PID_PATH= NGX_LOCK_PATH= NGX_USER= NGX_GROUP= ... ## 2, 處理每一個選項值,并設置到對應的全局變量中 for option do opt="$opt `echo $option | sed -e \"s/\(--[^=]*=\)\(.* .*\)/\1'\2'/\"`" # 得到此選項的value部分 case "$option" in -*=*) value=`echo "$option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; *) value="" ;; esac # 根據option內容進行匹配,并設置相應的選項 case "$option" in --help) help=yes ;; --prefix=) NGX_PREFIX="!" ;; --prefix=*) NGX_PREFIX="$value" ;; --sbin-path=*) NGX_SBIN_PATH="$value" ;; --conf-path=*) NGX_CONF_PATH="$value" ;; --error-log-path=*) NGX_ERROR_LOG_PATH="$value";; --pid-path=*) NGX_PID_PATH="$value" ;; --lock-path=*) NGX_LOCK_PATH="$value" ;; --user=*) NGX_USER="$value" ;; --group=*) NGX_GROUP="$value" ;; ... *) # 沒有找到的對應選項 echo "$0: error: invalid option \"$option\"" exit 1 ;; esac done ## 3. 對選項進行處理 # 如果有--help,則輸出幫助信息 if [ $help = yes ]; then cat << END --help print this message --prefix=PATH set installation prefix --sbin-path=PATH set nginx binary pathname --conf-path=PATH set nginx.conf pathname --error-log-path=PATH set error log pathname --pid-path=PATH set nginx.pid pathname --lock-path=PATH set nginx.lock pathname --user=USER set non-privileged user for worker processes --group=GROUP set non-privileged group for worker processes END exit 1 fi # 默認文件路徑 NGX_CONF_PATH=${NGX_CONF_PATH:-conf/nginx.conf} NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH` NGX_PID_PATH=${NGX_PID_PATH:-logs/nginx.pid} NGX_LOCK_PATH=${NGX_LOCK_PATH:-logs/nginx.lock} ... 上面的代碼中,我們選用了文件中的部分代碼進行了說明。大家可結合源碼再進行分析。auto/options的目的主要是處理用戶選項,并由選項生成一些全局變量的值,這些值在其它文件中會用到。該文件也會輸出configure的幫助信息。 1. auto/init 該文件的目錄在于初始化一些臨時文件的路徑,檢查echo的兼容性,并創建Makefile。 # 生成最終執行編譯的makefile文件路徑 NGX_MAKEFILE=$NGX_OBJS/Makefile # 動態生成nginx模塊列表的路徑,由于nginx的的一些模塊是可以選擇編譯的,而且可以添加自己的模塊,所以模塊列表是動態生成的 NGX_MODULES_C=$NGX_OBJS/ngx_modules.c NGX_AUTO_HEADERS_H=$NGX_OBJS/ngx_auto_headers.h NGX_AUTO_CONFIG_H=$NGX_OBJS/ngx_auto_config.h # 自動測試目錄與日志輸出文件 NGX_AUTOTEST=$NGX_OBJS/autotest # 如果configure出錯,可用來查找出錯的原因 NGX_AUTOCONF_ERR=$NGX_OBJS/autoconf.err NGX_ERR=$NGX_OBJS/autoconf.err MAKEFILE=$NGX_OBJS/Makefile NGX_PCH= NGX_USE_PCH= # 檢查echo是否支持-n或\c # check the echo's "-n" option and "\c" capability if echo "test\c" | grep c >/dev/null; then # 不支持-c的方式,檢查是否支持-n的方式 if echo -n test | grep n >/dev/null; then ngx_n= ngx_c= else ngx_n=-n ngx_c= fi else ngx_n= ngx_c='\c' fi # 創建最初始的makefile文件 # default表示目前編譯對象 # clean表示執行clean工作時,需要刪除makefile文件以及objs目錄 # 整個過程中只會生成makefile文件以及objs目錄,其它所有臨時文件都在objs目錄之下,所以執行clean后,整個目錄還原到初始狀態 # 要再次執行編譯,需要重新執行configure命令 # create Makefile cat << END > Makefile default: build clean: rm -rf Makefile $NGX_OBJS END 1. auto/sources 該文件從文件名中就可以看出,它的主要功能是跟源文件相關的。它的主要作用是定義不同功能或系統所需要的文件的變量。根據功能,分為CORE/REGEX/EVENT/UNIX/FREEBSD/HTTP等。每一個功能將會由四個變量組成,”_MODULES”表示此功能相關的模塊,最終會輸出到ngx_modules.c文件中,即動態生成需要編譯到nginx中的模塊;”INCS”表示此功能依賴的源碼目錄,查找頭文件的時候會用到,在編譯選項中,會出現在”-I”中;”DEPS”顯示指明在Makefile中需要依賴的文件名,即編譯時,需要檢查這些文件的更新時間;”SRCS”表示需要此功能編譯需要的源文件。 拿core來說: CORE_MODULES="ngx_core_module ngx_errlog_module ngx_conf_module ngx_emp_server_module ngx_emp_server_core_module" CORE_INCS="src/core" CORE_DEPS="src/core/nginx.h \ ? ? ? ? src/core/ngx_config.h \ ? ? ? ? src/core/ngx_core.h \ ? ? ? ? src/core/ngx_log.h \ ? ? ? ? src/core/ngx_palloc.h \ ? ? ? ? src/core/ngx_array.h \ ? ? ? ? src/core/ngx_list.h \ ? ? ? ? src/core/ngx_hash.h \ ? ? ? ? src/core/ngx_buf.h \ ? ? ? ? src/core/ngx_queue.h \ ? ? ? ? src/core/ngx_string.h \ ? ? ? ? src/core/ngx_parse.h \ ? ? ? ? src/core/ngx_inet.h \ ? ? ? ? src/core/ngx_file.h \ ? ? ? ? src/core/ngx_crc.h \ ? ? ? ? src/core/ngx_crc32.h \ ? ? ? ? src/core/ngx_murmurhash.h \ ? ? ? ? src/core/ngx_md5.h \ ? ? ? ? src/core/ngx_sha1.h \ ? ? ? ? src/core/ngx_rbtree.h \ ? ? ? ? src/core/ngx_radix_tree.h \ ? ? ? ? src/core/ngx_slab.h \ ? ? ? ? src/core/ngx_times.h \ ? ? ? ? src/core/ngx_shmtx.h \ ? ? ? ? src/core/ngx_connection.h \ ? ? ? ? src/core/ngx_cycle.h \ ? ? ? ? src/core/ngx_conf_file.h \ ? ? ? ? src/core/ngx_resolver.h \ ? ? ? ? src/core/ngx_open_file_cache.h \ ? ? ? ? src/core/nginx_emp_server.h \ ? ? ? ? src/core/emp_server.h \ ? ? ? ? src/core/task_thread.h \ ? ? ? ? src/core/standard.h \ ? ? ? ? src/core/dprint.h \ ? ? ? ? src/core/ngx_crypt.h" CORE_SRCS="src/core/nginx.c \ ? ? ? ? src/core/ngx_log.c \ ? ? ? ? src/core/ngx_palloc.c \ ? ? ? ? src/core/ngx_array.c \ ? ? ? ? src/core/ngx_list.c \ ? ? ? ? src/core/ngx_hash.c \? ? ? ? ? src/core/ngx_buf.c \ ? ? ? ? src/core/ngx_queue.c \ ? ? ? ? src/core/ngx_output_chain.c \ ? ? ? ? src/core/ngx_string.c \ ? ? ? ? src/core/ngx_parse.c \ ? ? ? ? src/core/ngx_inet.c \ ? ? ? ? src/core/ngx_file.c \ ? ? ? ? src/core/ngx_crc32.c \ ? ? ? ? src/core/ngx_murmurhash.c \ ? ? ? ? src/core/ngx_md5.c \ ? ? ? ? src/core/ngx_rbtree.c \ ? ? ? ? src/core/ngx_radix_tree.c \ ? ? ? ? src/core/ngx_slab.c \ ? ? ? ? src/core/ngx_times.c \ ? ? ? ? src/core/ngx_shmtx.c \ ? ? ? ? src/core/ngx_connection.c \ ? ? ? ? src/core/ngx_cycle.c \ ? ? ? ? src/core/ngx_spinlock.c \ ? ? ? ? src/core/ngx_cpuinfo.c \ ? ? ? ? src/core/ngx_conf_file.c \ ? ? ? ? src/core/ngx_resolver.c \ ? ? ? ? src/core/ngx_open_file_cache.c \ ? ? ? ? src/core/nginx_emp_server.c \ ? ? ? ? src/core/emp_server.c \ ? ? ? ? src/core/standard.c \ ? ? ? ? src/core/task_thread.c \ ? ? ? ? src/core/dprint.c \? ? ? ? ? src/core/ngx_crypt.c" 如果我們自己寫一個第三方模塊,我們可能會引用到這些變量的值,或對這些變量進行修改,比如添加我們自己的模塊,或添加自己的一個頭文件查找目錄(在第三方模塊的config中),在后面,我們會看到它是如何加框第三方模塊的。 在繼續分析執行流程之前,我們先介紹一些工具腳本。 1. auto/have cat << END >> $NGX_AUTO_CONFIG_H #ifndef $have #define $have 1 #endif END 從代碼中,我們可以看到,這個工具的作用是,將$have變量的值,宏定義為1,并輸出到auto_config文件中。通常我們通過這個工具來控制是否打開某個特性。這個工具在使用前,需要先定義宏的名稱 ,即$have變量。 1. 再回到configure文件中來: # NGX_DEBUG是在auto/options文件中處理的,如果有--with-debug選項,則其值是YES if [ $NGX_DEBUG = YES ]; then # 當有debug選項時,會定義NGX_DEBUG宏 have=NGX_DEBUG . auto/have fi 這段代碼中,可以看出,configure是如何定義一個特性的:通過宏定義,輸出到config頭文件中,然后在程序中可以判斷這個宏是否有定義,來實現不同的特性。 configure文件中繼續向下: # 編譯器選項 . auto/cc/conf # 頭文件支持宏定義 if [ "$NGX_PLATFORM" != win32 ]; then . auto/headers fi # 操作系統相關的配置的檢測 . auto/os/conf # unix體系下的通用配置檢測 if [ "$NGX_PLATFORM" != win32 ]; then . auto/unix fi configure會依次調用其它幾個文件,來進行環境的檢測,包括編譯器、操作系統相關。 1. auto/feature nginx的configure會自動檢測不同平臺的特性,神奇之處就是auto/feature的實現,在繼續向下分析之前,我們先來看看這個工具的實現原理。此工具的核心思想是,輸出一小段代表性c程序,然后設置好編譯選項,再進行編譯連接運行,再對結果進行分析。例如,如果想檢測某個庫是否存在,就在小段c程序里面調用庫里面的某個函數,再進行編譯鏈接,如果出錯,則表示庫的環境不正常,如果編譯成功,且運行正常,則庫的環境檢測正常。我們在寫nginx第三方模塊時,也常使用此工具來進行環境的檢測,所以,此工具的作用貫穿整個configure過程。 先看一小段使用例子: ngx_feature="poll()" ngx_feature_name= ngx_feature_run=no ngx_feature_incs="#include <poll.h>" ngx_feature_path= ngx_feature_libs= ngx_feature_test="int n; struct pollfd pl; pl.fd = 0; pl.events = 0; pl.revents = 0; n = poll(&pl, 1, 0); if (n == -1) return 1" . auto/feature if [ $ngx_found = no ]; then # 如果沒有找到poll,就設置變量的值 EVENT_POLL=NONE fi 這段代碼在auto/unix里面實現,用來檢測當前操作系統是否支持poll函數調用。在調用auto/feature之前,需要先設置幾個輸入參數變量的值,然后結果會存在$ngx_found變量里面, 并輸出宏定義以表示支持此特性: $ngx_feature 特性名稱 $ngx_feature_name 特性的宏定義名稱,如果特性測試成功,則會定義該宏定義 $ngx_feature_path 編譯時要查找頭文件目錄 $ngx_feature_test 要執行的測試代碼 $ngx_feature_incs 在代碼中要include的頭文件 $ngx_feature_libs 編譯時需要link的庫文件選項 $ngx_feature_run 編譯成功后,對二進制文件需要做的動作,可以是yes value bug 其它 #ngx_found 如果找到,并測試成功,其值為yes,否則其值為no 看看ngx_feature的關鍵代碼: # 初始化輸出結果為no ngx_found=no #將特性名稱小寫轉換成大寫 if test -n "$ngx_feature_name"; then # 小寫轉大寫 ngx_have_feature=`echo $ngx_feature_name \ | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ` fi # 將所有include目錄轉換成編譯選項 if test -n "$ngx_feature_path"; then for ngx_temp in $ngx_feature_path; do ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp" done fi # 生成臨時的小段c程序代碼。 # $ngx_feature_incs變量是程序需要include的頭文件 # $ngx_feature_test是測試代碼 cat << END > $NGX_AUTOTEST.c #include <sys/types.h> $NGX_INCLUDE_UNISTD_H $ngx_feature_incs int main() { $ngx_feature_test; return 0; } END # 編譯命令 # 編譯之后的目標文件是 $NGX_AUTOTEST,后面會判斷這個文件是否存在來判斷是否編譯成功 ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \ -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs" # 執行編譯過程 # 編譯成功后,會生成$NGX_AUTOTEST命名的文件 eval "/bin/sh -c \"$ngx_test\" >> $NGX_AUTOCONF_ERR 2>&1" # 如果文件存在,則編譯成功 if [ -x $NGX_AUTOTEST ]; then case "$ngx_feature_run" in # 需要運行來判斷是否支持特性 # 測試程序能否正常執行(即程序退出后的狀態碼是否是0),如果正常退出,則特性測試成功,設置ngx_found為yes,并添加名為ngx_feature_name的宏定義,宏的值為1 yes) # 如果程序正常退出,退出碼為0,則程序執行成功,我們可以在測試代碼里面手動返回非0來表示程序出錯 # /bin/sh is used to intercept "Killed" or "Abort trap" messages if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then echo " found" ngx_found=yes # 添加宏定義,宏的值為1 if test -n "$ngx_feature_name"; then have=$ngx_have_feature . auto/have fi else echo " found but is not working" fi ;; # 需要運行程序來判斷是否支持特性,如果支持,將程序標準輸出的結果作為宏的值 value) # /bin/sh is used to intercept "Killed" or "Abort trap" messages if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then echo " found" ngx_found=yes # 與yes不一樣的是,value會將程序從標準輸出里面打印出來的值,設置為ngx_feature_name宏變量的值 # 在此種情況下,程序需要設置ngx_feature_name變量名 cat << END >> $NGX_AUTO_CONFIG_H #ifndef $ngx_feature_name #define $ngx_feature_name `$NGX_AUTOTEST` #endif END else echo " found but is not working" fi ;; # 與yes正好相反 bug) # /bin/sh is used to intercept "Killed" or "Abort trap" messages if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then echo " not found" else echo " found" ngx_found=yes if test -n "$ngx_feature_name"; then have=$ngx_have_feature . auto/have fi fi ;; # 不需要運行程序,最后定義宏變量 *) echo " found" ngx_found=yes if test -n "$ngx_feature_name"; then have=$ngx_have_feature . auto/have fi ;; esac else # 編譯失敗 echo " not found" # 編譯失敗,會保存信息到日志文件中 echo "----------" >> $NGX_AUTOCONF_ERR # 保留編譯文件的內容 cat $NGX_AUTOTEST.c >> $NGX_AUTOCONF_ERR echo "----------" >> $NGX_AUTOCONF_ERR # 保留編譯文件的選項 echo $ngx_test >> $NGX_AUTOCONF_ERR echo "----------" >> $NGX_AUTOCONF_ERR fi # 最后刪除生成的臨時文件 rm $NGX_AUTOTEST* 1. auto/cc/conf 在了解了工具auto/feature后,繼續我們的主流程,auto/cc/conf的代碼就很好理解了,這一步主要是檢測編譯器,并設置編譯器相關的選項。它先調用auto/cc/name來得到編譯器的名稱,然后根據編譯器選擇執行不同的編譯器相關的文件如gcc執行auto/cc/gcc來設置編譯器相關的一些選項。 1. auto/include 這個工具用來檢測是頭文件是否支持。需要檢測的頭文件放在$ngx_include里面,如果支持,則$ngx_found變量的值為yes,并且會產生NGX_HAVE_{ngx_include}的宏定義。 1. auto/headers 生成頭文件的宏定義。生成的定義放在objs/ngx_auto_headers.h里面: #ifndef NGX_HAVE_UNISTD_H #define NGX_HAVE_UNISTD_H ?1 #endif#ifndef NGX_HAVE_INTTYPES_H #define NGX_HAVE_INTTYPES_H ?1 #endif#ifndef NGX_HAVE_LIMITS_H #define NGX_HAVE_LIMITS_H ?1 #endif#ifndef NGX_HAVE_SYS_FILIO_H #define NGX_HAVE_SYS_FILIO_H ?1 #endif#ifndef NGX_HAVE_SYS_PARAM_H #define NGX_HAVE_SYS_PARAM_H ?1 #endif 1. auto/os/conf 針對不同的操作系統平臺特性的檢測,并針對不同的操作系統,設置不同的CORE_INCS、CORE_DEPS、CORE_SRCS變量。nginx跨平臺的支持就是在這個地方體現出來的。 1. auto/unix 針對unix體系的通用配置或系統調用的檢測,如poll等事件處理系統調用的檢測等。 1. 回到configure里面 # 生成模塊列表 . auto/modules # 配置庫的依賴 . auto/lib/conf 1. auto/modules 該腳本根據不同的條件,輸出不同的模塊列表,最后輸出的模塊列表的文件在objs/ngx_modules.c: #include <ngx_config.h> #include <ngx_core.h> extern ngx_module_t ngx_core_module; extern ngx_module_t ngx_errlog_module; extern ngx_module_t ngx_conf_module; extern ngx_module_t ngx_emp_server_module; ... ngx_module_t *ngx_modules[] = { &ngx_core_module, &ngx_errlog_module, &ngx_conf_module, &ngx_emp_server_module, ... NULL }; 這個文件會決定所有模塊的順序,這會直接影響到最后的功能,下一小節我們將討論模塊間的順序。這個文件會加載我們的第三方模塊,這也是我們值得關注的地方: if test -n "$NGX_ADDONS"; then echo configuring additional modules for ngx_addon_dir in $NGX_ADDONS do echo "adding module in $ngx_addon_dir" if test -f $ngx_addon_dir/config; then # 執行第三方模塊的配置 . $ngx_addon_dir/config echo " + $ngx_addon_name was configured" else echo "$0: error: no $ngx_addon_dir/config was found" exit 1 fi done fi 這段代碼比較簡單,確實現了nginx很強大的擴展性,加載第三方模塊。$ngx_addon_dir變量是在configure執行時,命令行參數–add-module加入的,它是一個目錄列表,每一個目錄,表示一個第三方模塊。從代碼中,我們可以看到,它就是針對每一個第三方模塊執行其目錄下的config文件。于是我們可以在config文件里面執行我們自己的檢測邏輯,比如檢測庫依賴,添加編譯選項等。 1. auto/lib/conf 該文件會針對nginx編譯所需要的基礎庫的檢測,比如rewrite模塊需要的PCRE庫的檢測支持。 1. configure接下來定義一些宏常量,主要是是文件路徑方面的: case ".$NGX_PREFIX" in .) NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx} have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define ;; .!) NGX_PREFIX= ;; *) have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define ;; esac if [ ".$NGX_CONF_PREFIX" != "." ]; then have=NGX_CONF_PREFIX value="\"$NGX_CONF_PREFIX/\"" . auto/define fi have=NGX_SBIN_PATH value="\"$NGX_SBIN_PATH\"" . auto/define have=NGX_CONF_PATH value="\"$NGX_CONF_PATH\"" . auto/define have=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/define have=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/define have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\"" . auto/define have=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\"" . auto/define have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\"" . auto/define have=NGX_HTTP_UWSGI_TEMP_PATH value="\"$NGX_HTTP_UWSGI_TEMP_PATH\"" . auto/define have=NGX_HTTP_SCGI_TEMP_PATH value="\"$NGX_HTTP_SCGI_TEMP_PATH\"" . auto/define 1. configure最后的工作,生成編譯安裝的makefile # 生成objs/makefile文件 . auto/make # 生成關于庫的編譯選項到makefile文件 . auto/lib/make # 生成與安裝相關的makefile文件內容,并生成最外層的makefile文件 . auto/install # STUB . auto/stubs have=NGX_USER value="\"$NGX_USER\"" . auto/define have=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define # 編譯的最后階段,匯總信息 . auto/summary
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看