QEMU 構(gòu)建系統(tǒng)架構(gòu)

這份文檔旨在幫助開發(fā)者理解 QEMU 構(gòu)建系統(tǒng)的架構(gòu)硼身。正如使用 GNU autotools 的項(xiàng)目一樣缓艳,QEMU 構(gòu)建系統(tǒng)有兩個(gè)階段菠镇,第一步開發(fā)者運(yùn)行 configure 腳本確定本地構(gòu)建環(huán)境特性稻励,然后執(zhí)行 make 構(gòu)建整個(gè)項(xiàng)目椎瘟。與 GNU autotools 的相似之處僅此而已覆致,因此請(qǐng)忘掉你已知關(guān)于它們的東西。

第一步:configure

QEMU 配置腳本是直接用 shell 寫的肺蔚,且應(yīng)該與任何 POSIX shell 兼容煌妈,因此它使用 #!/bin/sh。這種做法的一個(gè)重要影響是,在以 bash 為主 host 的開發(fā)平臺(tái)上避免使用 bash-isms 很重要璧诵。

與 autoconf 腳本相反汰蜘,QEMU 的配置在檢查功能特性時(shí)是靜默的。只有在出錯(cuò)時(shí)它才顯示輸出腮猖,或者在完成時(shí)展示最后啟用的功能特性總結(jié)鉴扫。

為配置腳本添加新的檢查項(xiàng)通常包括如下任務(wù):

  • 初始化一個(gè)或多個(gè)包含默認(rèn)狀態(tài)的變量赞枕。
    理想的功能特性應(yīng)該自動(dòng)檢查它們是否存在澈缺,因此要努力避免通過(guò)硬編碼初始狀態(tài)來(lái)啟用或禁用,那樣強(qiáng)迫用戶在每次調(diào)用 configure 時(shí)傳入一個(gè) --enable-XXX / --disable-XXX 標(biāo)記炕婶。

  • 為命令行參數(shù)解析器添加支持來(lái)處理功能特性 XXX 所需要的新的 --enable-XXX / --disable-XXX 標(biāo)記姐赡。

  • 為幫助輸出消息添加信息以報(bào)告新的功能特性標(biāo)記。

  • 添加代碼執(zhí)行實(shí)際的功能特性檢查柠掂。如上面看到的那樣项滑,努力完全動(dòng)態(tài)地檢查啟用/禁用。

  • 添加代碼在完成時(shí)的配置總結(jié)中打印功能特性狀態(tài)涯贞。

  • 在完成時(shí)為 $config_host_mak 添加新的 makefile 變量枪狂。

以在 configure 中探測(cè) gnutls (一個(gè)簡(jiǎn)化版本)為例,我們有如下的片段:

  # Initial variable state
  gnutls=""

  ..snip..

  # Configure flag processing
  --disable-gnutls) gnutls="no"
  ;;
  --enable-gnutls) gnutls="yes"
  ;;

  ..snip..

  # Help output feature message
  gnutls          GNUTLS cryptography support

  ..snip..

  # Test for gnutls
  if test "$gnutls" != "no"; then
     if ! $pkg_config --exists "gnutls"; then
        gnutls_cflags=`$pkg_config --cflags gnutls`
        gnutls_libs=`$pkg_config --libs gnutls`
        libs_softmmu="$gnutls_libs $libs_softmmu"
        libs_tools="$gnutls_libs $libs_tools"
        QEMU_CFLAGS="$QEMU_CFLAGS $gnutls_cflags"
        gnutls="yes"
     elif test "$gnutls" = "yes"; then
        feature_not_found "gnutls" "Install gnutls devel"
     else
        gnutls="no"
     fi
  fi

  ..snip..

  # Completion feature summary
  echo "GNUTLS support    $gnutls"

  ..snip..

  # Define make variables
  if test "$gnutls" = "yes" ; then
     echo "CONFIG_GNUTLS=y" >> $config_host_mak
  fi

輔助函數(shù)

配置腳本提供了大量的輔助函數(shù)來(lái)幫助開發(fā)者檢查系統(tǒng)功能特性:

  • do_cc $ARGS...
    嘗試運(yùn)行系統(tǒng) C 編譯器并給它傳遞 $ARGS...

  • do_cxx $ARGS...
    嘗試運(yùn)行系統(tǒng) C++ 編譯器并給它傳遞 $ARGS...

  • compile_object $CFLAGS
    嘗試以系統(tǒng) C 編譯器使用 $CFLAGS 編譯一個(gè)測(cè)試程序宋渔。測(cè)試程序必須已經(jīng)在前面寫入了稱為 $TMPC 的文件州疾。

  • compile_prog $CFLAGS $LDFLAGS
    嘗試以系統(tǒng) C 編譯器使用 $CFLAGS 編譯一個(gè)測(cè)試程序,并以系統(tǒng)鏈接器用 $LDFLAGS 進(jìn)行鏈接皇拣。測(cè)試程序必須已經(jīng)在前面寫入了稱為 $TMPC 的文件严蓖。

  • has $COMMAND
    確定當(dāng)前環(huán)境中是否存在 $COMMAND,可以是一個(gè) shell 內(nèi)建命令或可執(zhí)行二進(jìn)制文件氧急,成功時(shí)返回 0颗胡。

  • path_of $COMMAND
    返回 $COMMAND 的完全限定路徑,將它打印到 stdout吩坝,成功時(shí)返回 0毒姨。

  • check_define $NAME
    檢查系統(tǒng) C 編譯器是否定義了宏 $NAME。

  • check_include $NAME
    檢查 $NAME 頭文件對(duì)系統(tǒng) C 編譯器是否可用钉寝。

  • write_c_skeleton
    向 $TMPC 指向的臨時(shí)文件寫入一個(gè)最小的 C 程序 main() 函數(shù)手素。

  • feature_not_found $NAME $REMEDY
    功能特性 $NAME 在系統(tǒng)上不可用時(shí)向 stderr 打印一條消息,提示用戶嘗試 $REMEDY 定位問(wèn)題瘩蚪。

  • error_exit $MESSAGE $MORE...
    向 stderr 打印 $MESSAGE泉懦,后面跟 $MORE... ,然后以非零狀態(tài)碼從配置腳本中退出疹瘦。

  • query_pkg_config $ARGS...
    以 $ARGS 為參數(shù)運(yùn)行 pkg-config崩哩。如果 QEMU 正在執(zhí)行靜態(tài)構(gòu)建,則 --static 將被自動(dòng)地加進(jìn) $ARGS

第二步:makefiles

QEMU 構(gòu)建系統(tǒng)需要使用 GNU make邓嘹。

盡管源碼分布于多個(gè)子目錄下酣栈,構(gòu)建系統(tǒng)本質(zhì)上應(yīng)該被認(rèn)為是非遞歸的,與在 automake 中看到的通常的實(shí)踐相反汹押。有一些 make 的遞歸調(diào)用矿筝,但這與要構(gòu)建的東西有關(guān),而不是源碼目錄的結(jié)構(gòu)棚贾。

QEMU 當(dāng)前支持 VPATH 和非 VPATH 構(gòu)建窖维,因此有三種通用方式調(diào)用 configure 并執(zhí)行構(gòu)建。

  • VPATH妙痹,完全在 QEMU 源碼樹之外構(gòu)建產(chǎn)品
$ cd ../
$ mkdir build
$ cd build
$ ../qemu/configure
$ make
  • VPATH铸史,在 QEMU 源碼樹的一個(gè)子目錄中構(gòu)建產(chǎn)品
$ mkdir build
$ cd build
$ ../configure
$ make
  • 非 VPATH,在任何地方構(gòu)建產(chǎn)品
$ ./configure
$ make

QEMU 的維護(hù)者通常建議開發(fā)者使用 VPATH 構(gòu)建怯伊。QEMU 的補(bǔ)丁期待確保 VPATH 構(gòu)建依然有效琳轿。

模塊結(jié)構(gòu)

QEMU 構(gòu)建系統(tǒng)有大量的重要輸出:

  • 工具 - qemu-img,qemu-nbd耿芹,qga (guest agent)崭篡,等等
  • 系統(tǒng)模擬器 - qemu-system-$ARCH
  • 用戶空間模擬器 - qemu-$ARCH
  • 單元測(cè)試

源碼是高度模塊化的,分割多個(gè)文件吧秕,以便盡可能少地重復(fù)編譯所有這些組件琉闪。可以認(rèn)為是兩個(gè)不同的文件組寇甸,那些獨(dú)立于 QEMU 仿真目標(biāo)的文件和依賴于
QEMU 仿真目標(biāo)的文件組塘偎。

獨(dú)立于仿真目標(biāo)的文件集合中是各種通用輔助代碼,比如錯(cuò)誤處理基礎(chǔ)設(shè)施拿霉,標(biāo)準(zhǔn)數(shù)據(jù)結(jié)構(gòu)吟秩,平臺(tái)移植性封裝函數(shù),等等绽淘。這些代碼可以只被編譯一次涵防,而把它們的 .o 文件鏈接到所有的輸出二進(jìn)制文件。

依賴于仿真目標(biāo)的文件集合中是 CPU 模擬沪铭,設(shè)備模擬和許多膠水代碼壮池。這有時(shí)還不得不編譯多次,為每個(gè)目標(biāo)編譯一次杀怠。

所有二進(jìn)制文件都用到的實(shí)用代碼被編譯為一個(gè)稱為 libqemuutil.a 靜態(tài)包椰憋,它會(huì)被鏈接進(jìn)所有的二進(jìn)制文件。為了提供只有一部分二進(jìn)制文件需要的鉤子赔退,libqemuutil.a 中的代碼可能依賴于其它不完全由所有 QEMU 二進(jìn)制實(shí)現(xiàn)的函數(shù)橙依。為了處理這種情況证舟,還有另一個(gè)稱為 libqemustub.a 的庫(kù),它為所有這些函數(shù)提供了 dummy stubs窗骑。如果沒(méi)有真實(shí)的實(shí)現(xiàn)女责,則它們將被延遲鏈接進(jìn)二進(jìn)制中备埃。以這種方式丁屎,libqemustub.a 靜態(tài)庫(kù)可以被看作一個(gè)弱符號(hào)概念的可移植實(shí)現(xiàn)。所有的二進(jìn)制文件應(yīng)該同時(shí)鏈接 libqemuutil.a 和 libqemustub.a阳啥。比如

 qemu-img$(EXESUF): qemu-img.o ..snip.. libqemuutil.a libqemustub.a

Windows 平臺(tái)可移植性

在 Windows 平臺(tái)上软族,所有的二進(jìn)制文件都有后綴 '.exe'刷喜,因此所有創(chuàng)建二進(jìn)制文件的 Makefile 規(guī)則都必須在二進(jìn)制文件名中包含 $(EXESUF) 變量。比如互订,

 qemu-img$(EXESUF): qemu-img.o ..snip..

這在 Windows 平臺(tái)上展開為 '.exe'吱肌,或者在其它平臺(tái)上為 ''痘拆。

系統(tǒng)模擬器二進(jìn)制文件的另一重復(fù)雜性是需要生成兩個(gè)單獨(dú)的二進(jìn)制文件仰禽。主二進(jìn)制文件(例如 qemu-system-x86_64.exe)與 Windows 控制臺(tái)運(yùn)行時(shí)子系統(tǒng)鏈接。這些預(yù)期將從命令提示符窗口運(yùn)行纺蛆,因此吐葵,將 stderr 打印到啟動(dòng)它們的控制臺(tái)。

生成的第二個(gè)二進(jìn)制文件在它們的名字的最后有一個(gè) 'w' (比如 qemu-system-x86_64w.exe )桥氏,它們與 Windows 圖形運(yùn)行時(shí)子系統(tǒng)鏈接温峭。這些預(yù)計(jì)將直接從桌面運(yùn)行,且將打開一個(gè)專門的終端窗口用于 stderr 輸出字支。

Makefile.target 將首先為圖形子系統(tǒng)生成二進(jìn)制文件凤藏,然后使用 objcopy 重新與終端子系統(tǒng)鏈接生成第二個(gè)二進(jìn)制文件。

目標(biāo)變量命名

QEMU 約定是用于定義變量來(lái)列出不同的目標(biāo)文件組的堕伪。它們的命名約定為 $PREFIX-obj-y揖庄。比如,libqemuutil.a 文件將與變量 util-obj-y 列出的所有目標(biāo)文件鏈接欠雌。因此蹄梢,比如,util/Makefile.obj 將包含一系列看起來(lái)像這樣的定義:

  util-obj-y += bitmap.o bitops.o hbitmap.o
  util-obj-y += fifo8.o
  util-obj-y += acl.o
  util-obj-y += error.o qemu-error.o

當(dāng)有一個(gè)目標(biāo)文件需要基于主機(jī)系統(tǒng)的一些特性有條件地構(gòu)建時(shí)富俄,配置腳本將為條件定義一個(gè)變量禁炒。比如,在 Windows 上它將定義 $(CONFIG_POSIX) 指為 'n'霍比,而 $(CONFIG_WIN32) 值為 'y'∧桓ぃ現(xiàn)在可以在列出目標(biāo)文件時(shí)使用配置變量了。比如悠瞬,

  util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
  util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o

在 Windows 上被擴(kuò)展為

  util-obj-y += oslib-win32.o qemu-thread-win32.o
  util-obj-n += oslib-posix.o qemu-thread-posix.o

由于 libqemutil.a 被鏈接進(jìn) $(util-obj-y) 们豌,在 Windows 平臺(tái)構(gòu)建中,$(util-obj-n) 中列出的 POSIX 特有文件被忽略。

CFLAGS / LDFLAGS / LIBS 處理

有許多不同的二進(jìn)制文件為了不同目的而構(gòu)建玛痊,其中一些甚至可能是通過(guò)git子模塊拉入的第三方庫(kù)汰瘫。因此通常在 QEMU 中要避免使用全局的 CFLAGS 變量,由于它將應(yīng)用于太多的構(gòu)建目標(biāo)擂煞。

所有的 QEMU 代碼(比如混弥,除了 GIT子模塊工程)需要的標(biāo)記都被放進(jìn)了 $(QEMU_CFLAGS) 變量。對(duì)于鏈接器標(biāo)志对省,有時(shí)會(huì)使用 $(LIBS) 變量蝗拿,但是優(yōu)先選擇幾個(gè)更有針對(duì)性的變量。$(libs_softmmu) 用于必須鏈接到系統(tǒng)模擬器的庫(kù)蒿涎,$(LIBS_TOOLS) 用于像 qemu-img哀托,qemu-nbd,等等的工具劳秋,$(LIBS_QGA) 用于 QEMU guest agent仓手。當(dāng)前沒(méi)有專門用于用戶空間模擬器的變量作為全局 $(LIBS),或者下面顯示的更有針對(duì)性的變量就足夠了玻淑。

除了這些變量嗽冒,可以針對(duì)各個(gè)源代碼文件提供 cflags 和 libs,通過(guò)以 $FILENAME-cflags 和 $FILENAME-libs 的形式定義變量补履。比如添坊,curl 塊驅(qū)動(dòng)需要鏈接 libcurl 庫(kù),于是 block/Makefile 定義了一些變量:

  curl.o-cflags      := $(CURL_CFLAGS)
  curl.o-libs        := $(CURL_LIBS)

這兩個(gè)變量的影響范圍有一點(diǎn)不同箫锤。當(dāng)鏈接任何包含 curl.o 目標(biāo)文件的二進(jìn)制文件時(shí) libs 都會(huì)被用到贬蛙,而 cflags 只有在編譯 curl.c 時(shí)被用到。

靜態(tài)定義的文件

下面的重要文件是在源碼樹中靜態(tài)定義的谚攒,以構(gòu)建 QEMU 所需的規(guī)則進(jìn)行阳准。它們的行為受稍后列出的動(dòng)態(tài)創(chuàng)建的文件影響。

  • Makefile
    調(diào)用 make 構(gòu)建 QEMU 的所有組件的主入口點(diǎn)五鲫。默認(rèn)的 'all' target 自然地構(gòu)建每一個(gè)組件溺职。各種工具和輔助二進(jìn)制文件直接通過(guò)一個(gè)非遞歸的規(guī)則集合構(gòu)建。
    每個(gè)系統(tǒng)/用戶空間模擬器需要一些稍有不同的 make 規(guī)則/變量位喂。因此浪耘,make 將為每個(gè)模擬器遞歸地調(diào)用。
    遞歸調(diào)用將最終處理頂層的 Makefile.target 文件(稍后再說(shuō))塑崖。

  • */Makefile.objs
    由于源碼分布于多個(gè)目錄下七冲,每個(gè)文件的規(guī)則類似地都被模塊化了。因此规婆,每個(gè)子目錄包含 .c 文件的也將常常包含一個(gè) Makefile.objs 文件澜躺。這些文件不直接由一個(gè)遞歸的 make 調(diào)用蝉稳,而是被導(dǎo)入到頂層的 Makefile 和/或 Makefile.target。
    每個(gè) Makefile.objs 通常只聲明一系列變量列出當(dāng)前目錄下需要從源碼文件構(gòu)建的 .o 文件掘鄙。它們還定義任何定制的鏈接器或編譯器標(biāo)志耘戚。比如在 block/Makefile.objs 中:

  block-obj-$(CONFIG_LIBISCSI) += iscsi.o
  block-obj-$(CONFIG_CURL) += curl.o

  ..snip...

  iscsi.o-cflags     := $(LIBISCSI_CFLAGS)
  iscsi.o-libs       := $(LIBISCSI_LIBS)
  curl.o-cflags      := $(CURL_CFLAGS)
  curl.o-libs        := $(CURL_LIBS)

如果 Makefile.objs 文件定義了規(guī)則,則它們都應(yīng)該使用 $(obj) 作為 target 的前綴操漠,比如:

  $(obj)/generated-tcg-tracers.h: $(obj)/generated-tcg-tracers.h-timestamp
  • Makefile.target
    這個(gè)文件提供了構(gòu)建每個(gè)獨(dú)立的系統(tǒng)或用戶空間模擬器 target 的入口點(diǎn)收津。每個(gè)開啟的 target 擁有它自己的子目錄。比如如果 configure 以參數(shù) '--target-list=x86_64-softmmu' 運(yùn)行浊伙,則將創(chuàng)建 'x86_64-softmu' 子目錄撞秋,包含一個(gè) 'Makefile',符號(hào)鏈接回 Makefile.target嚣鄙。
    因此當(dāng)調(diào)用遞歸的 '$(MAKE) -C x86_64-softmmu' 時(shí)吻贿,它將最終使用 Makefile.target 構(gòu)建規(guī)則。

  • rules.mak
    這個(gè)文件為調(diào)用構(gòu)建工具提供了通用的輔助規(guī)則哑子,特別是編譯器和鏈接器舅列。這也包含了用于將源樹中所有 Makefile.objs 的變量定義合并到主 Makefile 上下文中的magic(hairy)'unnest-vars' 函數(shù)。

  • default-configs/*.mak
    default-configs/ 下的文件控制每個(gè) QEMU 系統(tǒng)和用戶空間模擬器內(nèi)置什么模擬的硬件赵抢。它們僅僅包含長(zhǎng)長(zhǎng)的配置變量定義列表剧蹂。比如声功,default-configs/x86_64-softmmu.mak 有:

  include pci.mak
  include sound.mak
  include usb.mak
  CONFIG_QXL=$(CONFIG_SPICE)
  CONFIG_VGA_ISA=y
  CONFIG_VGA_CIRRUS=y
  CONFIG_VMWARE_VGA=y
  CONFIG_VIRTIO_VGA=y
  ...snip...

這些文件幾乎不需要修改烦却,除非為一個(gè)特定的系統(tǒng)/用戶空間模擬器啟用新的設(shè)備/硬件。

  • tests/Makefile
    編譯單元測(cè)試的規(guī)則先巴。這個(gè)文件直接被包含進(jìn)頂層的 Makefile其爵,因此這個(gè)文件中定義的任何東西將影響整個(gè)構(gòu)建系統(tǒng)。當(dāng)為測(cè)試編寫規(guī)則時(shí)需要小心伸蚯,確保它們只應(yīng)用于單元測(cè)試的執(zhí)行/構(gòu)建摩渺。

  • tests/docker/Makefile.include
    Docker 測(cè)試的規(guī)則。像 tests/Makefile 一樣剂邮,這個(gè)文件直接被包含進(jìn)頂層的 Makefile摇幻,這個(gè)文件中定義的任何東西將影響整個(gè)構(gòu)建系統(tǒng)。

  • po/Makefile
    從文本 .po 文件源構(gòu)建和安裝二進(jìn)制消息目錄的規(guī)則挥萌。它幾乎從不需要因任何原因而修改绰姻。

動(dòng)態(tài)創(chuàng)建的文件

下面的文件是由 configure 動(dòng)態(tài)生成,來(lái)控制靜態(tài)定義的 makefiles 的行為的引瀑。這使得 QEMU makefiles 無(wú)需像在 autotools 中看到的做預(yù)處理狂芋,其中 Makefile.am 生成 Makefile.in 生成 Makefile。

  • config-host.mak
    當(dāng) configure 已經(jīng)確定了構(gòu)建主機(jī)的特性時(shí)憨栽,它將向 config-host.mak 文件寫入一個(gè)長(zhǎng)長(zhǎng)的變量列表帜矾。這提供了各種安裝目錄翼虫,編譯器/鏈接器標(biāo)記和大量與啟用的可選功能特性有關(guān)的 CONFIG_* 變量。它被頂層的 Makefile 引入以裁剪構(gòu)建輸出屡萤。
    這里定義的變量適用于所有的 QEMU 構(gòu)建輸出珍剑。每個(gè)模擬器目標(biāo)文件可能不同的變量定義在下一個(gè)文件. . .
    它還被用作一個(gè)獨(dú)立的檢查機(jī)制。如果 make 看到 configure 的修改時(shí)間戳比 config-host.mak 的更新死陆,則 configure 將重新運(yùn)行次慢。

  • config-host.h
    源碼使用 config-host.h 文件來(lái)確定啟用了那些功能特性。它是使用 scripts/create_config 程序根據(jù) config-host.mak 的內(nèi)容生成的翔曲。它提取所有的 CONFIG_* 變量迫像,大部分 HOST_* 變量和其它一些來(lái)自于 config-host.mak 的雜項(xiàng)變量,以 C 預(yù)處理器宏格式化它們瞳遍。

  • $TARGET-NAME/config-target.mak
    TARGET-NAME 是系統(tǒng)或用戶空間模擬器的名字闻妓,比如 x86_64-softmmu 表示 x86_64 架構(gòu)的系統(tǒng)模擬器。這個(gè)文件包含在每個(gè)模擬器上需要變化的變量掠械。比如由缆,它將指出是否為目標(biāo)文件啟用 KVM 或 Xen,及鏈接目標(biāo)文件所需的其它潛在的定制庫(kù)猾蒂。

  • $TARGET-NAME/config-devices.mak
    TARGET-NAME 是系統(tǒng)或用戶空間模擬器的名字均唉。config-devices.mak 文件是 make 使用 scripts/make_device_config.sh 程序自動(dòng)生成的,以 default-configs/$TARGET-NAME 文件作為輸入肚菠。

  • $TARGET-NAME/Makefile
    這是 make 遞歸地構(gòu)建單獨(dú)的系統(tǒng)或用戶空間模擬器時(shí)所使用的入口點(diǎn)舔箭。它僅僅是到頂層的 Makefile.target 的符號(hào)鏈接。

譯自 qemu 官方文檔 qemu/docs/build-system.txt 蚊逢。

Done层扶。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市烙荷,隨后出現(xiàn)的幾起案子镜会,更是在濱河造成了極大的恐慌,老刑警劉巖终抽,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戳表,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡昼伴,警方通過(guò)查閱死者的電腦和手機(jī)匾旭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)亩码,“玉大人季率,你說(shuō)我怎么就攤上這事∶韫担” “怎么了飒泻?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵鞭光,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我泞遗,道長(zhǎng)惰许,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任史辙,我火速辦了婚禮汹买,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘聊倔。我一直安慰自己晦毙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布耙蔑。 她就那樣靜靜地躺著见妒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪甸陌。 梳的紋絲不亂的頭發(fā)上须揣,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音钱豁,去河邊找鬼耻卡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛牲尺,可吹牛的內(nèi)容都是我干的卵酪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼秸谢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼凛澎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起估蹄,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沫换,沒(méi)想到半個(gè)月后臭蚁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡讯赏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年垮兑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漱挎。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡系枪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出磕谅,到底是詐尸還是另有隱情私爷,我是刑警寧澤雾棺,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站衬浑,受9級(jí)特大地震影響捌浩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜工秩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一尸饺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧助币,春花似錦浪听、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至倍谜,卻和暖如春迈螟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尔崔。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工答毫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人季春。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓洗搂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親载弄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耘拇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容