iOS 編譯與鏈接四:靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)

一:靜態(tài)鏈接庫(kù)

1.制作.a文件
.a文件即 static library

library和framework

創(chuàng)建library,project的配置對(duì)最終產(chǎn)物.a文件基本沒(méi)有影響,只需要關(guān)注target的配置

copy files會(huì)在product文件夾生成include文件夾,里面就是cpoy file


copy files

Header會(huì)在product文件夾生成一個(gè)usr/local/include/文件夾,里面是暴露的.h文件


Header

除了默認(rèn)的架構(gòu),還可以添加其他架構(gòu),不過(guò)需要對(duì)應(yīng)上iOS版本號(hào)


架構(gòu)支持

iOS版本

接下來(lái)運(yùn)行,運(yùn)行出來(lái)的有四種product:
Debug-iphoneos
Release-iphoneos
Debug-iphonesimulator
Release-iphonesimulator
我們需要考慮2個(gè)問(wèn)題,
第一是使用靜態(tài)庫(kù)的時(shí)候通常并不區(qū)分debug和release,這要看具體需求,如果debug和release的配置不同,則需要分別處理;
第二是包的體積大小,實(shí)質(zhì)就是這個(gè)靜態(tài)庫(kù)支持的架構(gòu)是不是都需要的.比支持iOS12以上的情況下,ipa里的這個(gè)靜態(tài)庫(kù)只需要arm64就行了,但是模擬器需要考慮mac的架構(gòu),并且模擬器不需要關(guān)心包體積.
因此要結(jié)合實(shí)際情況合并和拆分架構(gòu).
有相同架構(gòu)的包是不能直接合并的,要把其中一個(gè)去除掉.
lipo -info (絕對(duì)路徑或相對(duì)路徑) 查看架構(gòu)
lipo -output (新文件絕對(duì)路徑或相對(duì)路徑) -remove (架構(gòu)) (舊文件絕對(duì)路徑或相對(duì)路徑) 移除架構(gòu)
lipo -output (新文件絕對(duì)路徑或相對(duì)路徑) -create (舊文件絕對(duì)路徑或相對(duì)路徑1) (舊文件絕對(duì)路徑或相對(duì)路徑2) 合并架構(gòu)

最終生成一個(gè)包含armv7 armv7s i386 x86_64 arm64 的.a

Architectures in the fat file: TestStatic.a are: armv7 armv7s i386 x86_64 arm64 

2..a的特性
用machOView看一下這個(gè).a,(關(guān)于Mach-O)

Fat Binary

.o

靜態(tài)鏈接庫(kù)指的是參與靜態(tài)鏈接,通常.a文件就是.o的集合,是編譯的產(chǎn)物,并非鏈接的產(chǎn)物;
因此本身是不經(jīng)過(guò)靜態(tài)鏈接的,compile source里有多少個(gè)文件,就有多少個(gè).o;

所以只要能編譯通過(guò),就可以生成靜態(tài)鏈接庫(kù),.h文件不參與編譯,所以只聲明沒(méi)實(shí)現(xiàn)的類(lèi)和方法會(huì)被作為外部符號(hào)引用,等到項(xiàng)目真正鏈接的時(shí)候,再去決議和重定位.

3.制作靜態(tài)framework

之前的MakeLibrary2里面是這樣的

#import "MakeLibrary2.h"
#import "MakeLibrary/MakeLibrary.h"

@implementation MakeLibrary2

- (instancetype)init{
    if(self = [super init]){
        NSLog(@"MakeLibrary2 init");
        
        MakeLibrary *m = [[MakeLibrary alloc]init];
    }
    return self;
}

@end

MakeLibrary2使用了MakeLibrary,但是制作MakeLibrary2.a的時(shí)候沒(méi)有引入MakeLibrary.a,也就是說(shuō)MakeLibrary2.a里沒(méi)有MakeLibrary符號(hào).

新建一個(gè)framework的target,在build setting -> linking 中有個(gè)mach-o type, 默認(rèn)是dynamic Library, 改成static Library,然后把MakeLibrary2.a放進(jìn)來(lái)


image.png

然后引用makeLibrary2類(lèi)

#import "FrameClass.h"
#import "MakeLibrary2.h"

@implementation FrameClass

- (instancetype)init{
    if(self = [super init]){
        NSLog(@"FrameClass init");
        
        MakeLibrary2 *m = [[MakeLibrary2 alloc]init];
    }
    return self;
}

@end

添加Headers


build phases -> Header

添加Link Binary With Libraries


build phases -> Link Binary With Libraries

然后運(yùn)行,生成的framework里面是這樣的


image.png

用machOView查看這個(gè)MakeFramework,和.a沒(méi)區(qū)別,是.o文件的集合,這里只有一個(gè)x86_64架構(gòu),所以沒(méi)有Fat Binary.


image.png

引入到UseLibrary中,使用

#import "ViewController.h"
#import "FrameClass.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    FrameClass *fc = [[FrameClass alloc]init];
}

@end

運(yùn)行,輸出

FrameClass init
MakeLibrary2 init
MakeLibrary init
Make FirstObj init
  • 總結(jié)

再生成時(shí):靜態(tài)鏈接庫(kù)的生成過(guò)程不包含靜態(tài)鏈接,所做的事主要是編譯,而符號(hào)解析重定位都沒(méi)有做,引用的符號(hào)是不是真的存在,是不是有重復(fù)的符號(hào)都不重要,要做的只有編譯,然后把目標(biāo)文件打包起來(lái).最終.a里可能會(huì)有重復(fù)的.o(指的是同一架構(gòu)內(nèi)).

在使用時(shí):在靜態(tài)庫(kù)是參與靜態(tài)鏈接的,靜態(tài)鏈接時(shí)會(huì)合并mach-o,因此對(duì)于主程序來(lái)說(shuō),編譯之后,靜態(tài)庫(kù)里的目標(biāo)文件被復(fù)制并且合并到了主程序的mach-o中,而靜態(tài)庫(kù)本身不會(huì)發(fā)生變化.

用命令行工具libtool可以拆分和組合static Library的.o并生成新的static Library
比如合并

 libtool -static -o 輸出文件 staticLibraryA  staticLibraryB

二.動(dòng)態(tài)鏈接庫(kù)

1.制作動(dòng)態(tài)framework
動(dòng)態(tài)鏈接庫(kù)經(jīng)過(guò)了靜態(tài)鏈接,已經(jīng)沒(méi)有.o文件在了,會(huì)進(jìn)行符號(hào)解析.
可以驗(yàn)證一下

接下來(lái)運(yùn)行,打算生成framework.結(jié)果報(bào)錯(cuò)了,因?yàn)镸akeLibrary2里引用了MakeLibrary,但是實(shí)際上現(xiàn)在這個(gè)target里沒(méi)有這個(gè)類(lèi).


沒(méi)找到MakeLibrary

把MakeLibrary2 *m = [[MakeLibrary2 alloc]init];這行注釋,就可以運(yùn)行成功,得到framework,可以看到它被系統(tǒng)標(biāo)記為可執(zhí)行文件


image.png

然后用MachOView查看這個(gè)可執(zhí)行文件,它是一個(gè)Shared Libray, file type是dylib,可以看到已經(jīng)沒(méi)有.o了


image.png

2.制作一個(gè)動(dòng)態(tài)的.a

創(chuàng)建target選擇static Library時(shí),這項(xiàng)默認(rèn)是static Library,但是也可以手動(dòng)改成dynamic Library


image.png

運(yùn)行,然后machOView查看.a文件,果真是dylib,和上面的framework一樣,甚至如果把.a擴(kuò)展名刪掉,會(huì)被標(biāo)記為可執(zhí)行文件


image.png

image.png

實(shí)際上生成的就是一個(gè)動(dòng)態(tài)庫(kù),可以直接使用
  • 總結(jié)

在生成時(shí):動(dòng)態(tài)鏈接庫(kù)在生成時(shí)會(huì)執(zhí)行靜態(tài)鏈接,把目標(biāo)文件,包括依賴(lài)的靜態(tài)庫(kù)里的目標(biāo)文件合并到dylib中,這個(gè)過(guò)程還包括符號(hào)解析和重定位,這時(shí)根據(jù)不同的依賴(lài)關(guān)系和鏈接策略進(jìn)行檢查并拋出異常.后面具體說(shuō)明.

在使用時(shí):靜態(tài)鏈接時(shí)會(huì)把引用自動(dòng)態(tài)鏈接庫(kù)的符號(hào)進(jìn)行標(biāo)記,設(shè)置占位地址,真正的符號(hào)重定位需要在運(yùn)行時(shí)由dyld來(lái)做,因此動(dòng)態(tài)庫(kù)是不是真的定義了這個(gè)符號(hào),需要運(yùn)行時(shí)才知道.

embedded framework會(huì)被復(fù)制到.app里面的framework文件夾中.

三.依賴(lài)關(guān)系

build setting -> linking可以配置鏈接的選項(xiàng).這些就會(huì)影響依賴(lài)關(guān)系.
比如靜態(tài)鏈接時(shí),鏈接器ld64會(huì)進(jìn)行dead code striping,此時(shí)就需要解析依賴(lài)關(guān)系,然后剝離未被引用的符號(hào).
比如ohter link flags.

制作靜態(tài)庫(kù)的時(shí)候,靜態(tài)庫(kù)本身經(jīng)常需要訪(fǎng)問(wèn)外部文件,比如依賴(lài)別的靜態(tài)庫(kù),或者直接引用外部的文件.

首先創(chuàng)建一個(gè)新項(xiàng)目,創(chuàng)建時(shí)選擇app target,叫做UseLibrary用來(lái)使用靜態(tài)庫(kù)
然后再添加一個(gè)target,選擇Static Library 叫做makeLibrary用來(lái)生成靜態(tài)庫(kù).


image.png

1.靜態(tài)庫(kù)引用外部文件
這個(gè)MakeLibrary封裝了一些功能,并且需要引用UseLibrary里的一個(gè)叫做FirstObj的類(lèi).
直接import并且使用,是可以編譯通過(guò)的.

#import "FirstObj.h"

@implementation FirstObj

- (instancetype)init{
    if(self = [super init]){
        NSLog(@"FirstObj init");
    }
    return self;
}

@end


#import "MakeLibrary.h"
#import "FirstObj.h"

@implementation MakeLibrary

- (instancetype)init{
    if(self = [super init]){
        NSLog(@"MakeLibrary init");
        
        FirstObj *f = [[FirstObj alloc]init];
    }
    return self;
}

@end

接下來(lái)生成.a文件,然后添加到UseLibrary


image.png

然后在viewcontroller中使用


#import "ViewController.h"
#import "MakeLibrary.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    MakeLibrary *m = [[MakeLibrary alloc]init];
}


@end

切換target運(yùn)行,輸出

MakeLibrary init
FirstObj init

如果用MachOView打開(kāi)這個(gè).a,去查看這個(gè)MakeLibrary.o的符號(hào)表,我們會(huì)看到一個(gè)叫FirstObj的外部符號(hào)

未定義符號(hào)

當(dāng)UseLibrary編譯的時(shí)候,在靜態(tài)鏈接的過(guò)程中會(huì)把這個(gè)符號(hào)的地址給重定位.
所以如果刪除UseLibrary中的FirstObj這個(gè)類(lèi),就會(huì)在編譯時(shí)報(bào)下面這個(gè)錯(cuò):
報(bào)錯(cuò)

clang報(bào)錯(cuò):在libMakeLibrary.a里的x86_64里的MakeLibrary.o中,引用了一個(gè)OBJC_CLASS$_FirstObj符號(hào),這個(gè)符號(hào)沒(méi)能成功重定位,也就是沒(méi)找到.

2.靜態(tài)庫(kù)引用靜態(tài)庫(kù)
再創(chuàng)建一個(gè)target叫做MakeLibrary2,這個(gè)MakeLibrary2會(huì)引用MakeLibrary

#import "MakeLibrary2.h"
#import "MakeLibrary/MakeLibrary.h"

@implementation MakeLibrary2

- (instancetype)init{
    if(self = [super init]){
        NSLog(@"MakeLibrary2 init");
        
        MakeLibrary *m = [[MakeLibrary alloc]init];
    }
    return self;
}

@end

image.png

生成之后,在Viewcontroller中使用MakeLibrary2

#import "ViewController.h"
#import "MakeLibrary2.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    MakeLibrary2 *m = [[MakeLibrary2 alloc]init];
}


@end

運(yùn)行輸出

MakeLibrary2 init
MakeLibrary init
FirstObj init

3.靜態(tài)庫(kù)和靜態(tài)庫(kù)(或主程序)包含重復(fù)符號(hào)
創(chuàng)建一個(gè)新的target叫MakeLibrary3, 然后直接把libMakeLibrary.a扔進(jìn)去

image.png

#import "MakeLibrary3.h"
#import "MakeLibrary.h"

@implementation MakeLibrary3

- (instancetype)init{
    if(self = [super init]){
        NSLog(@"MakeLibrary2 init");
        
        MakeLibrary *m = [[MakeLibrary alloc]init];
    }
    return self;
}


@end

制作出libMakeLibrary3.a,查看結(jié)構(gòu),可以看到.a無(wú)非就是.o文件的集合,就算套再多層,靜態(tài)鏈接也會(huì)重組結(jié)構(gòu),合并成新的Mach-o,把.o排列在一起.
需要注意的是,制作靜態(tài)庫(kù)時(shí)引入其他靜態(tài)庫(kù),如果沒(méi)有引用頭文件,是不會(huì)被打包進(jìn)來(lái)的.或者在build phases -> Link Binary With Libraries中添加需要一起打包的靜態(tài)庫(kù)


Link Binary With Libraries
ilibMakeLibrary3.a

然后把libMakeLibrary3.a放到UseLibrary中使用


image.png
#import "ViewController.h"
#import "MakeLibrary3.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    MakeLibrary3 *m = [[MakeLibrary3 alloc]init];
}

@end

運(yùn)行輸出

MakeLibrary2 init
MakeLibrary init
FirstObj init

現(xiàn)在UseLibrary其實(shí)有兩份MakeLibrary.o,運(yùn)行起來(lái)沒(méi)有問(wèn)題,也沒(méi)有警告,
即便兩個(gè)相同的.o有著不同的實(shí)現(xiàn),運(yùn)行的時(shí)候總是只有一個(gè)被鏈接.

注意這個(gè)引用了重復(fù)的.a還能正常運(yùn)行,前提是ohter link flags什么都不設(shè)置.
ld自行進(jìn)行了取舍,假如設(shè)置了-ObjC,或者-all_load或者-force_load,就會(huì)報(bào)錯(cuò) duplicated symbols

image.png

-all_load一般不考慮;
添加-ObjC報(bào)錯(cuò)重復(fù),如果是和主target里的文件重復(fù),那么可以考慮去掉-ObjC,給靜態(tài)庫(kù)單獨(dú)一個(gè)個(gè)的添加-force_load,如果兩個(gè)靜態(tài)庫(kù)互相重復(fù),那就麻煩了,如果二選一-force_load不能解決,那就只能重新制作靜態(tài)庫(kù).

4.動(dòng)態(tài)庫(kù)包含靜態(tài)庫(kù)
制作動(dòng)態(tài)庫(kù)的時(shí)候,包含一個(gè)靜態(tài)庫(kù),動(dòng)態(tài)庫(kù)生成需要經(jīng)過(guò)靜態(tài)鏈接,最終靜態(tài)庫(kù)會(huì)被拷貝合并進(jìn)去,叫做吸附性.
需要設(shè)置link Binary with libraries

5.動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)(或主程序)包含重復(fù)符號(hào)
在主程序和動(dòng)態(tài) Framework中分別創(chuàng)建一個(gè)類(lèi)都叫FirstObj

//主程序的FirstObj
- (instancetype)init{
    if(self = [super init]){
        NSLog(@"common FirstObj init");
    }
    return self;
}

//動(dòng)態(tài)Framework的FirstObj
- (instancetype)init{
    if(self = [super init]){
        NSLog(@"Make2 FirstObj init");
    }
    return self;
}

//在主程序分別調(diào)用
#import <MakeFramework2/MakeLibrary2.h>
#import "FirstObj.h"

///這個(gè)是Framework的類(lèi),init里面會(huì)調(diào)用[[FirstObj alloc]init];
MakeLibrary2 *m = [[MakeLibrary2 alloc]init];

FirstObj *f = [[FirstObj alloc]init];

運(yùn)行:
控制臺(tái)會(huì)報(bào)警告:One of the two will be used. Which one is undefined.
然后輸出
MakeLibrary2 init
Make2 FirstObj init
common FirstObj init

說(shuō)明分別創(chuàng)建了不同的FirstObj,這是因?yàn)閯?dòng)態(tài)庫(kù)的獨(dú)立性,有獨(dú)立的命名空間,動(dòng)態(tài)庫(kù)會(huì)使用動(dòng)態(tài)庫(kù)的本地符號(hào).
另外與頭文件無(wú)關(guān),即便是下面這樣

#import <MakeFramework2/FirstObj.h>,
FirstObj *f = [[FirstObj alloc]init];

輸出的依然是 common FirstObj init

6.動(dòng)態(tài)庫(kù)和動(dòng)態(tài)庫(kù)包含重復(fù)符號(hào)

安裝makeFramework2的文件給makeFramework來(lái)一遍
運(yùn)行輸出
One of the two will be used. Which one is undefined.
MakeLibrary init
Make FirstObj init
MakeLibrary2 init
Make2 FirstObj init

即便與上一條相同,會(huì)警告,但是各用個(gè)的.

7.在動(dòng)態(tài)庫(kù)中引用動(dòng)態(tài)庫(kù)
在makeFramework2中拖一個(gè)makeFramework進(jìn)去

image.png

設(shè)置上embed和link
image.png

然后運(yùn)行,生成成功
可以看到在MakeFramework2.framework中被包含了一個(gè)framework文件夾
image.png

放到工程里是可以正常運(yùn)行,相當(dāng)于分別引入兩個(gè)framework.

四.embedded framework和tbd

framework可以理解為框架,是一個(gè)文件夾,是mach-o+資源文件+描述文件+簽名
在info.plist中可以設(shè)置當(dāng)前framework的版本,兼容的最低系統(tǒng)版本等等描述信息,資源文件可以直接放進(jìn)來(lái),也可以打包成bundle.

framework可以是static Library 也可以是shared Library;
通過(guò)Xcode -> Framework-> dynamic Library生成的叫做 embedded framework,它也是通過(guò)dyld在運(yùn)行時(shí)動(dòng)態(tài)鏈接,但是和系統(tǒng)的Framework不同.系統(tǒng)的Framework才是真正只有一份在硬盤(pán)或內(nèi)存中.
使用是需要設(shè)置為embed


embed

.tbd文件是文本文件,其中包含架構(gòu)信息劫樟,以及在真實(shí)運(yùn)行時(shí)候二進(jìn)制所在的位置,以及包含了動(dòng)態(tài)庫(kù)的符號(hào)表還有類(lèi)的一些信息,目的是不把動(dòng)態(tài)庫(kù)放在Xcode中;
系統(tǒng)tbd的位置:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks
這里面全是.tbd,而tbd文本里面指向了這樣一個(gè)路徑/System/Library/Frameworks/,這里面仍然沒(méi)有mach-O,真正的二進(jìn)制文件被合成一個(gè)很大的文件,在手機(jī)上保存在/System/Library/Caches/com.apple.dyld中.

五:XCFramework

為什么模擬器會(huì)報(bào)錯(cuò)找不到第三方庫(kù)
在M1芯片之前,模擬器是x86_64架構(gòu)(更早的是i386),真機(jī)是arm系列,armv7,armv7s,arm64,arm64e這些.
制作靜態(tài)庫(kù)的時(shí)候,分別制作了模擬器和真機(jī),Intel芯片制作的模擬器版本靜態(tài)庫(kù)是x86_64,而M1是arm64,
通常會(huì)把模擬器和真機(jī)的用lipo命令合在一起,并且合并的時(shí)候相同的架構(gòu)是需要去掉一個(gè)的,通常我們?nèi)サ裟M器的arm64,因?yàn)槿サ粽鏅C(jī)的,手機(jī)就不能編譯了.
現(xiàn)在M1的mac制作的模擬器版本是arm64,真機(jī)也有arm64,就無(wú)法合并了,本來(lái)m1的模擬器就需要arm64的架構(gòu),現(xiàn)在刪掉模擬器的arm64導(dǎo)致m1上的模擬器無(wú)法使用這個(gè)合并后的靜態(tài)庫(kù).
那為什么真機(jī)的arm64模擬器不能用呢,因?yàn)閷?shí)際上這倆還是不一樣的.

現(xiàn)在有兩種解決方案,一是把模擬器和Xcode設(shè)置為Rosetta模式(只是運(yùn)行app project的話(huà),只設(shè)置模擬器也行),這樣的話(huà)模擬器就使用x86_64的架構(gòu).
同時(shí)記得在Excluded Architecture中添加arm64.


image.png

第二種方案就是wwdc19新增的XCFramework.
還是合并,只不過(guò)使用新的指令,這樣的話(huà)就不用刪除模擬器的arm64了

1.合并.a
xcodebuild -create-xcframework -library <path> [-headers <path>] [-library <path> [-headers <path>]...] -output <path>

xcodebuild -create-xcframework -library youpath/TestFramework.a -headers youpath/TestFramework -library youpath/TestFramework.a -headers youpath/TestFramework -output youpath/TestFramework.xcframework

2.合并.framework
xcodebuild -create-xcframework -framework <path> [-framework <path>...] -output <path>

xcodebuild -create-xcframework -framework Release-iphoneos/TestFramework.framework -framework Release-iphonesimulator/TestFramework.framework -output TestFramework.xcframework
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宽闲,一起剝皮案震驚了整個(gè)濱河市林螃,隨后出現(xiàn)的幾起案子歪赢,更是在濱河造成了極大的恐慌廉涕,老刑警劉巖睬澡,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異磕谅,居然都是意外死亡私爷,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)膊夹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)衬浑,“玉大人,你說(shuō)我怎么就攤上這事放刨」ぶ龋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵进统,是天一觀的道長(zhǎng)助币。 經(jīng)常有香客問(wèn)我,道長(zhǎng)螟碎,這世上最難降的妖魔是什么眉菱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮抚芦,結(jié)果婚禮上倍谜,老公的妹妹穿的比我還像新娘迈螟。我一直安慰自己叉抡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布答毫。 她就那樣靜靜地躺著褥民,像睡著了一般。 火紅的嫁衣襯著肌膚如雪洗搂。 梳的紋絲不亂的頭發(fā)上消返,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天载弄,我揣著相機(jī)與錄音,去河邊找鬼撵颊。 笑死宇攻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倡勇。 我是一名探鬼主播逞刷,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼妻熊!你這毒婦竟也來(lái)了夸浅?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤扔役,失蹤者是張志新(化名)和其女友劉穎帆喇,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體亿胸,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坯钦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了侈玄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片葫笼。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拗馒,靈堂內(nèi)的尸體忽然破棺而出路星,到底是詐尸還是另有隱情,我是刑警寧澤诱桂,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布洋丐,位于F島的核電站,受9級(jí)特大地震影響挥等,放射性物質(zhì)發(fā)生泄漏友绝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一肝劲、第九天 我趴在偏房一處隱蔽的房頂上張望迁客。 院中可真熱鬧,春花似錦辞槐、人聲如沸掷漱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)卜范。三九已至,卻和暖如春鹿榜,著一層夾襖步出監(jiān)牢的瞬間海雪,已是汗流浹背锦爵。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奥裸,地道東北人险掀。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像湾宙,于是被迫代替她去往敵國(guó)和親迷郑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

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