clang driver

clang不止是前端編譯器,更是連接了LLVM整個(gè)編譯過程和其他工具的一個(gè)驅(qū)動(dòng)程序性宏。

clang/include/clang/Basic 目錄下定義了眾多td模版文件滥壕,例如DiagnosticDriverKinds.td就是Driver的相關(guān)診斷信息丑婿。對(duì)應(yīng)的類型則是在 clang/include/clang/Basic/DiagnosticIDs.h 文件中定義了6個(gè)類型:

/// Used for handling and querying diagnostic IDs.
///
/// Can be used and shared by multiple Diagnostics for multiple translation units.
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
public:
  /// The level of the diagnostic, after it has been through mapping.
  enum Level {
    Ignored, Note, Remark, Warning, Error, Fatal
  };

clang driver

clang Driver 負(fù)責(zé)拼接編譯器命令和 ld 命令。

他的處理原理如下:

  1. Parse:解析傳入的參數(shù)
  2. Pipeline:根據(jù)每個(gè)輸入的文件和類型留拾,組建action,具體類型可以查看ActionClass枚舉類型鲫尊,對(duì)應(yīng)到具體的JobAction
  3. Bind:根據(jù)action選擇對(duì)應(yīng)的工具和文件名信息痴柔,具體可以通過 clang -ccc-print-bindings 進(jìn)行查看
  4. Translate:將輸入的參數(shù)轉(zhuǎn)換為不同的tool的參數(shù)。如clang -cc1 -arch arm64疫向,在clang中使用的是-triple arm64-apple-ios14竞帽,而ld則會(huì)使用-arch arm64
  5. Execute:調(diào)用tool執(zhí)行任務(wù)。該步驟會(huì)通過創(chuàng)建子進(jìn)程方式調(diào)用tool鸿捧。

舉個(gè)實(shí)例:

/Test ? xcrun -l clang test.c -v -O2 -o Test                                                                             n14637@GIH-D-21687
env SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang test.c -v -O2 -o Test
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.15.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -emit-obj -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test.c -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=all -fno-strict-return -masm-verbose -munwind-tables -target-sdk-version=10.15.6 -fcompatibility-qualified-id-block-type-checking -target-cpu penryn -dwarf-column-info -debugger-tuning=lldb -target-linker-version 609.8 -v -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -I/usr/local/include -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/local/include -internal-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0/include -internal-externc-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -O2 -Wno-reorder-init-list -Wno-implicit-int-float-conversion -Wno-c99-designator -Wno-final-dtor-non-final-class -Wno-extra-semi-stmt -Wno-misleading-indentation -Wno-quoted-include-in-framework-header -Wno-implicit-fallthrough -Wno-enum-enum-conversion -Wno-enum-float-conversion -fdebug-compilation-dir /Test -ferror-limit 19 -fmessage-length 164 -stack-protector 1 -fstack-check -mdarwin-stkchk-strong-link -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fobjc-runtime=macosx-10.15.0 -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -vectorize-loops -vectorize-slp -o /var/folders/71/830m4bcj2_v1ly5qbtsbhxm4w50c2h/T/test-72900e.o -x c test.c
clang -cc1 version 12.0.0 (clang-1200.0.32.29) default target x86_64-apple-darwin19.6.0
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/local/include"
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/System/Library/Frameworks (framework directory)
End of search list.
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -dynamic -arch x86_64 -platform_version macos 10.15.0 10.15.6 -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -o Test -L/usr/local/lib /var/folders/71/830m4bcj2_v1ly5qbtsbhxm4w50c2h/T/test-72900e.o -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0/lib/darwin/libclang_rt.osx.a

可以看到屹篓,執(zhí)行xcrun之后,實(shí)際上clang構(gòu)造了兩個(gè)job匙奴,一個(gè)是編譯任務(wù)堆巧,一個(gè)是鏈接任務(wù),最后根據(jù)job創(chuàng)建兩個(gè)進(jìn)程執(zhí)行任務(wù)。

看到源碼部分谍肤,在driver.cpp:

    //解析參數(shù)啦租,該方法會(huì)調(diào)用DriverOptTable中的getDriverOptTable方法判斷clang driver支持的所有參數(shù)類型
    //其內(nèi)部的OptTable::Info InfoTable[]是通過clang/Driver/Options.inc生成的,而inc是由tablegen將optins.td轉(zhuǎn)換的
  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
      CreateAndPopulateDiagOpts(argv);
    //診斷引擎綁定到一個(gè)翻譯單元和一個(gè)SourceManager荒揣。
    DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
    //并將diagnostics傳遞給DiagnosticConsumer篷角,以便向用戶報(bào)告
  if (!DiagOpts->DiagnosticSerializationFile.empty()) {
    auto SerializedConsumer =
        clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
                                        &*DiagOpts, /*MergeChildRecords=*/true);
    Diags.setClient(new ChainedDiagnosticConsumer(
        Diags.takeClient(), std::move(SerializedConsumer)));
  }
    ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
    //創(chuàng)建driver實(shí)例
    Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
  SetInstallDir(argv, TheDriver, CanonicalPrefixes);
  TheDriver.setTargetAndMode(TargetAndMode);
    //xxx
    //1.構(gòu)造需要執(zhí)行的命令,跳轉(zhuǎn)到最下面的方法??
  std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));

    //2.構(gòu)建action
  if (TC.getTriple().isOSBinFormatMachO())
    BuildUniversalActions(*C, C->getDefaultToolChain(), Inputs);
  else
    BuildActions(*C, C->getArgs(), Inputs, C->getActions());
    //3.構(gòu)建jobs
  BuildJobs(*C);

    //4.執(zhí)行任務(wù)
  Driver::ExecuteCompilation -> Compilation::ExecuteJobs -> Compilation::ExecuteCommand-> Command::Execute -> llvm::sys::ExecuteAndWait


    
    Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
        //xxx
        //1.1.根據(jù)命令行指定的參數(shù)進(jìn)行解析
      CLOptions = std::make_unique<InputArgList>(
      ParseArgStrings(ArgList.slice(1), IsCLMode(), ContainsError));
        //1.2.獲取triple并通過gettoolchain獲取對(duì)應(yīng)的toolchain
      const ToolChain &TC = getToolChain(
      *UArgs, computeTargetTriple(*this, TargetTriple, *UArgs));
            //1.3.Compilation類接管參數(shù)
        Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs,
                                   ContainsError);
        //1.4.獲取輸入文件進(jìn)行編譯系任,該方法會(huì)通過輸入的文件擴(kuò)展后綴獲取文件類型
      BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs);
  }

    //1.1.1.
    InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
                                     bool IsClCompatMode,
                                     bool &ContainsError) {
        //調(diào)用getOpts獲取支持的所有參數(shù)恳蹲,然后調(diào)用parseArgs對(duì)命令行參數(shù)進(jìn)行解析
        //解析的規(guī)則則是通過調(diào)用OptTable的ParseOneArg方法對(duì)字符串進(jìn)行遍歷解析
        //ParseOneArg內(nèi)部調(diào)用了accept方法,該方法對(duì)參數(shù)別名會(huì)進(jìn)行判斷和特殊處理俩滥,如下:
      InputArgList Args =
      getOpts().ParseArgs(ArgStrings, MissingArgIndex, MissingArgCount,
                          IncludedFlagsBitmask, ExcludedFlagsBitmask);
            //判斷參數(shù)是否支持嘉蕾,是否支持通過Optins.td文件進(jìn)行查找,否則拋出異常
          for (const Arg *A : Args) {
                if (A->getOption().hasFlag(options::Unsupported)) {
              DiagID = diag::err_drv_unsupported_opt;
                    Diag(DiagID) << ArgString;
            }
  }
    
    Arg *Option::accept(const ArgList &Args,
                    unsigned &Index,
                    unsigned ArgSize) const {
    //解析參數(shù)
          std::unique_ptr<Arg> A(acceptInternal(Args, Index, ArgSize));
  if (!A)
    return nullptr;
    //判斷是否有別名
      const Option &UnaliasedOption = getUnaliasedOption();
  if (getID() == UnaliasedOption.getID())
    return A.release();
    //從unalias選項(xiàng)中獲取拼寫霜旧,對(duì)應(yīng)的關(guān)系在Optins.td中有聲明
      StringRef UnaliasedSpelling = Args.MakeArgString(
      Twine(UnaliasedOption.getPrefix()) + Twine(UnaliasedOption.getName()));
  }
    
    void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC,
                                   const InputList &BAInputs) const {
        //2.1.根據(jù)-arch參數(shù)生成需要處理的的Archs错忱,構(gòu)建actions
        DerivedArgList &Args = C.getArgs();
        ActionList &Actions = C.getActions();
          for (Arg *A : Args) {
    if (A->getOption().matches(options::OPT_arch)) {
      //xxx
      if (ArchNames.insert(A->getValue()).second)
        Archs.push_back(A->getValue());
    }
    }
    //如果沒有傳入 -arch 參數(shù),則獲取 triple 對(duì)應(yīng)的架構(gòu)
     if (!Archs.size())
        Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName()));
      ActionList SingleActions;
        //調(diào)用 Driver::handleArguments 方法對(duì)參數(shù)進(jìn)行處理
          BuildActions(C, Args, BAInputs, SingleActions);
    
      // 構(gòu)建 offloading actions.
        OffloadingActionBuilder OffloadBuilder(C, Args, Inputs);

        // 構(gòu)造要執(zhí)行的actions
        HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr;
          ActionList LinkerInputs;
          ActionList MergerInputs;

        for (auto &I : Inputs) {
            types::ID InputType = I.first;
            const Arg *InputArg = I.second;
            //根據(jù)輸入源碼文件inputs獲取需要處理的 phase 數(shù)組
      //phase其實(shí)就是一個(gè)枚舉類型挂据,包含Preprocess Precompile Compile Backend Assemble Link IfsMerge
      //在 Types.def 文件維護(hù)了不同文件類型默認(rèn)情況下需要經(jīng)歷的 phase
        llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL;
      types::getCompilationPhases(*this, Args, InputType, PL);
        if (PL.empty())
        continue;
            //xxx
  }

//2.2.
void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
                          const InputList &Inputs, ActionList &Actions) const {
        //將每個(gè)phase轉(zhuǎn)化為一個(gè)action
    for (phases::ID Phase : PL) {
      //xxx
      // Otherwise construct the appropriate action.
      //該方法內(nèi)部根據(jù)Phase的類型進(jìn)行action的構(gòu)建以清,詳情在個(gè)下方法:
      Action *NewCurrent = ConstructPhaseAction(C, Args, Phase, Current);
      if (auto *HMA = dyn_cast<HeaderModulePrecompileJobAction>(NewCurrent))
        HeaderModuleAction = HMA;
      Current = NewCurrent;
      // Use the current host action in any of the offloading actions, if
      // required.
      if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg))
        break;
      if (Current->getType() == types::TY_Nothing)
        break;
    }
}
  
    Action *Driver::ConstructPhaseAction(
    Compilation &C, const ArgList &Args, phases::ID Phase, Action *Input,
    Action::OffloadKind TargetDeviceOffloadKind) const {
      switch (Phase) {
  case phases::Preprocess: {
        //通過 Input 和 OutputTy 構(gòu)建 PreprocessJobAction
    return C.MakeAction<PreprocessJobAction>(Input, OutputTy);
  }
    return C.MakeAction<PrecompileJobAction>(Input, OutputTy);
  }
  case phases::Compile: {
    return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
  }
      case phases::Backend: {
    if (isUsingLTO() && TargetDeviceOffloadKind == Action::OFK_None) {
      types::ID Output =
          Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
      return C.MakeAction<BackendJobAction>(Input, Output);
    }
    if (Args.hasArg(options::OPT_emit_llvm)) {
      types::ID Output =
          Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC;
      return C.MakeAction<BackendJobAction>(Input, Output);
    }
    return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm);
  }
  case phases::Assemble:
    return C.MakeAction<AssembleJobAction>(std::move(Input), types::TY_Object);
  }
  }
    
  //3.構(gòu)建jobs
  void Driver::BuildJobs(Compilation &C) const {
        //1.收集需要處理的架構(gòu)
      llvm::StringSet<> ArchNames;
  if (C.getDefaultToolChain().getTriple().isOSBinFormatMachO())
    for (const Arg *A : C.getArgs())
      if (A->getOption().matches(options::OPT_arch))
        ArchNames.insert(A->getValue());
        //2.緩存action和inputinfo的映射
        //BuildJobsForAction 方法會(huì)先查找緩存,如果緩存中不存在則再調(diào)用 BuildJobsForActionNoCache 方法創(chuàng)建 InputInfo
      std::map<std::pair<const Action *, std::string>, InputInfo> CachedResults;
        BuildJobsForAction(C, A, &C.getDefaultToolChain(),
                       /*BoundArch*/ StringRef(),
                       /*AtTopLevel*/ true,
                       /*MultipleArchs*/ ArchNames.size() > 1,
                       /*LinkingOutput*/ LinkingOutput, CachedResults,
                       /*TargetDeviceOffloadKind*/ Action::OFK_None);       
  }
    
 InputInfo Driver::BuildJobsForActionNoCache(
    Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch,
    bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput,
    std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults,
    Action::OffloadKind TargetDeviceOffloadKind) const {
            
     if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) {
    const ToolChain *TC;
    StringRef ArchName = BAA->getArchName();
        //3.通過 computeTargetTriple 計(jì)算 triple崎逃,然后獲取合適的工具鏈
    // computeTargetTriple會(huì)獲取-target參數(shù)更新TargetTriple字符串玖媚,然后根據(jù)其生產(chǎn)Triple實(shí)例
    if (!ArchName.empty())
      TC = &getToolChain(C.getArgs(),
                         computeTargetTriple(*this, TargetTriple,
                                             C.getArgs(), ArchName));
    else
      TC = &C.getDefaultToolChain();
        //4.隨后會(huì)以 BindArchAction 持有的第一個(gè) input(類型是 LinkJobAction)為參數(shù)再次調(diào)用 BuildJobsForAction 方法
    return BuildJobsForAction(C, *BAA->input_begin(), TC, ArchName, AtTopLevel,
                              MultipleArchs, LinkingOutput, CachedResults,
                              TargetDeviceOffloadKind);
  }

   //5.獲取 LinkJobAction 的 Inputs
     ActionList Inputs = A->getInputs();

  const JobAction *JA = cast<JobAction>(A);
  ActionList CollapsedOffloadActions;
    //6.創(chuàng)建 ToolSelector 的實(shí)例 TS,并調(diào)用 ToolSelector::getTool 獲取支持 link 的工具
  ToolSelector TS(JA, *TC, C, isSaveTempsEnabled(),
                  embedBitcodeInObject() && !isUsingLTO());
  const Tool *T = TS.getTool(Inputs, CollapsedOffloadActions);
   
     //7.通過 BuildJobsForAction 處理 Inputs
     for (const auto *OA : CollapsedOffloadActions)
    cast<OffloadAction>(OA)->doOnEachDependence(
        /*IsHostDependence=*/BuildingForOffloadDevice,
        [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) {
          OffloadDependencesInputInfo.push_back(BuildJobsForAction(
              C, DepA, DepTC, DepBoundArch, /* AtTopLevel */ false,
              /*MultipleArchs=*/!!DepBoundArch, LinkingOutput, CachedResults,
              DepA->getOffloadingDeviceKind()));
        });
     //xxx
       //調(diào)用 Compilation::getArgsForToolChain 進(jìn)行參數(shù)轉(zhuǎn)換
     llvm::Triple EffectiveTriple;
  const ToolChain &ToolTC = T->getToolChain();
  const ArgList &Args =
      C.getArgsForToolChain(TC, BoundArch, A->getOffloadingDeviceKind());
   //xxx
       if (UnbundlingResults.empty())
         //調(diào)用 darwin::Linker 的 ConstructJob 方法構(gòu)建 Job
      T->ConstructJob(
          C, *JA, Result, InputInfos,
          C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()),
          LinkingOutput);
    else
      T->ConstructJobMultipleOutputs(
          C, *JA, UnbundlingResults, InputInfos,
          C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()),
          LinkingOutput);
 }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末婚脱,一起剝皮案震驚了整個(gè)濱河市今魔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌障贸,老刑警劉巖错森,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異篮洁,居然都是意外死亡涩维,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門袁波,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓦阐,“玉大人,你說我怎么就攤上這事篷牌∷” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵枷颊,是天一觀的道長(zhǎng)戳杀。 經(jīng)常有香客問我该面,道長(zhǎng),這世上最難降的妖魔是什么信卡? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任隔缀,我火速辦了婚禮,結(jié)果婚禮上傍菇,老公的妹妹穿的比我還像新娘猾瘸。我一直安慰自己,他們只是感情好丢习,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布牵触。 她就那樣靜靜地躺著,像睡著了一般泛领。 火紅的嫁衣襯著肌膚如雪荒吏。 梳的紋絲不亂的頭發(fā)上敛惊,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天渊鞋,我揣著相機(jī)與錄音,去河邊找鬼瞧挤。 笑死锡宋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的特恬。 我是一名探鬼主播执俩,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼癌刽!你這毒婦竟也來了役首?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤显拜,失蹤者是張志新(化名)和其女友劉穎衡奥,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體远荠,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡矮固,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了譬淳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片档址。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖邻梆,靈堂內(nèi)的尸體忽然破棺而出守伸,到底是詐尸還是另有隱情,我是刑警寧澤浦妄,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布含友,位于F島的核電站替裆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏窘问。R本人自食惡果不足惜辆童,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惠赫。 院中可真熱鬧把鉴,春花似錦、人聲如沸儿咱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)混埠。三九已至怠缸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钳宪,已是汗流浹背揭北。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吏颖,地道東北人搔体。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓半醉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親呆奕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子衬吆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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