構(gòu)建Linux筆記v1.0(第一部分)

2014-04-19 20:54:02
構(gòu)建Linux 編譯Linux BeagleBone Black

在簡書我還有個《構(gòu)建Linux筆記v1.1》饺饭,
雖然這篇發(fā)布時間靠后负蚊,但卻是先寫的酥郭。
沒什么教學(xué)性質(zhì)茵瀑,就是個筆記昆咽,沒舍得刪办悟。
這2個筆記都是 2014 年的尘奏。


由于太長了,分成了2部分:
構(gòu)建Linux筆記v1.0(第二部分)


僅供參考病蛉,我用Linux的時間較少炫加。
以下很多都是回憶,不一定準了铺然。


我構(gòu)建的目標平臺為BeagleBone Black俗孝。

交叉編譯工具為Sourcery CodeBench Lite

要構(gòu)建Linux魄健,很簡單赋铝,只有3個部分,

  1. bootloader沽瘦,即啟動引導(dǎo)程序革骨,我選擇U-Boot农尖。
  2. Linux內(nèi)核。
  3. 應(yīng)用程序良哲。

我還沒研究是什么決定了32位和64位盛卡。

我主要的資料:
Running Linux
介紹Linux的書,這才叫入門級筑凫,了解下Linux的思想即可窟扑,書的內(nèi)容可能有些過時,
這本書不是介紹怎么使用Linux的漏健。如果想知道怎么使用Linux嚎货,
可看看Linux Pocket Guide,很薄蔫浆。
鳥哥的書也不錯殖属,感覺挺詳細的,好于大部分書瓦盛,我沒看洗显。
我連shell腳本都不會寫呢,很多命令沒用過原环,這與構(gòu)建Linux關(guān)系不大挠唆。

Building Embedded Linux Systems
教構(gòu)建嵌入式Linux的,了解下思想即可嘱吗。

http://www.linuxfromscratch.org/
教構(gòu)建各種Linux的網(wǎng)站玄组,最關(guān)鍵的是網(wǎng)站給出了Linux由哪些應(yīng)用程序構(gòu)成。
我沒有用網(wǎng)站中的方式谒麦,sed那種命令不會俄讹。也是了解下思想即可。

If you can’t explain it simply, you don’t understand it well enough.
--Albert Einstein

準備SD卡

BeagleBone Black有4種啟動方式绕德,我選擇用SD卡患膛。
準備SD卡,將SD卡插到電腦中耻蛇,在我的系統(tǒng)中被識別為/dev/sdb踪蹬。

分區(qū):

# fdisk /dev/sdb

用法很簡單,輸入m臣咖,就可得到幫助跃捣。
第一個分區(qū)64M,類型為FAT32 (LBA)亡哄,加上啟動標記枝缔。
第二個分區(qū)為余下的全部,類型默認為Linux蚊惯,不必改愿卸。

參考過程是這樣的,
輸入o截型,新建一個空DOS分區(qū)表趴荸,這會清除所有分區(qū)。
輸入p宦焦,會列出分區(qū)列表发钝,此時應(yīng)該沒有。
輸入n來添加新分區(qū)波闹,直接enter酝豪,接受默認為主分區(qū),enter接受默認為第一分區(qū)精堕,
enter接受默認的開始扇區(qū)孵淘,輸入+64M,設(shè)置分區(qū)大小為64M歹篓。
輸入t瘫证,來改變分區(qū)類型,自動選擇了第一個分區(qū)庄撮,輸入l可列出所有分區(qū)列表的代碼背捌,
輸入c選擇W95 FAT32(LBA)。
輸入a洞斯,在第一分區(qū)設(shè)置可啟動標記毡庆。
輸入nenter主分區(qū)烙如,enter第二個扭仁,enter起始扇區(qū),enter結(jié)束扇區(qū)厅翔。
輸入w乖坠,將改動寫入分區(qū)表。

格式化:

# mkfs.vfat -F 32 /dev/sdb1
# mkfs.ext4 /dev/sdb2

第一個分區(qū)用來放U-Boot刀闷,板子啟動后就會找一個叫MLO的文件熊泵,
編譯U-Boot后,就會生成一個MLO甸昏,不必擔(dān)心顽分。
第二個分區(qū)用來放Linux系統(tǒng)。

sdb2被格式化后施蜜,里面自動有個lost+found卒蘸,文件系統(tǒng)的結(jié)構(gòu)中正好有一條:

/lost+found: Filesystem-specific recoverable data

我的文件系統(tǒng)目錄結(jié)構(gòu)

/
/bin             --> /usr/bin/
/boot/
/dev/
/etc/
/home/
/home/root
/lib             --> /usr/lib/
/mnt/
/proc/
/run/
/sbin            --> /usr/bin/
/sys/
/tmp
/usr/
/usr/app/
/usr/bin/
/usr/include/
/usr/lib/
/usr/sbin       --> bin/
/usr/share/
/usr/share/man/
/var/
/var/run         --> /run/

便簽

編譯時的一些配置等,我為了方便調(diào)用,放到這里缸沃。

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ export PATH=$PATH:/home/spy/Work/U-Boot/u-boot/tools
$ export CROSS_COMPILE=arm-none-linux-gnueabi-
# chown -R 0:0 
# chgrp -v tty /usr/app/util-linux/bin/wall
# chown -R spy:users 

找readelf結(jié)果中帶"Shared library"的行

readelf -ld | grep "Shared library"

以可讀寫重新掛載根文件系統(tǒng)

mount -n -o remount,rw /

放到交叉編譯器搜索庫中的程序庫
libcap恰起,pam,ncurses趾牧,gdbm检盼,db,iptables

coreutils與util-linux重復(fù)的命令翘单。
kill

shadow與util-linux重復(fù)的命令吨枉。
{login,nologin,su}

shadow與coreutils重復(fù)的命令。
groups

下面是編譯軟件的過程

U-Boot

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ export CROSS_COMPILE=arm-none-linux-gnueabi-

$ make O=../u-boot distclean
$ make O=../u-boot am335x_boneblack_config
$ make O=../u-boot all

源碼中正好有am335x_boneblack這個配置文件哄芜,對應(yīng)我的開發(fā)板貌亭,想知道可用的配置文件
看README吧,它會告訴你到另一個文件中找认臊。

忘了是編譯U-Boot還是Linux內(nèi)核的時候圃庭,提示我的系統(tǒng)中缺少bc,用你的包管理器安上就好了美尸。


摘自TI的wiki冤议,讓你了解MLO和u-boot.img是什么。
大概是AM335X芯片中的程序較小师坎,只為了4種啟動方式初始化恕酸,
然后找到MLO,運行MLO進一步初始化胯陋,如DDR3內(nèi)存蕊温。
MLO最后找到u-boot.img,運行之遏乔。u-boot.img這個名字應(yīng)該是在MLO的代碼中指定的义矛。
提示:TI的StarterWare中的2個文件叫MLO和app。

Two stage U-Boot design

This section gives an overview of the two stage U-Boot approach adopted for AM335X.

The size of the internal RAM in AM335X is 128KB out of which
18KB at the end is used by the ROM code. Also,
1 KB at the start (0x402f0000 - 0x402f0400) is secure and it cannot be accessed
This places a limit of 109KB on the size of the U-Boot binary which
the ROM code can transfer to the internal RAM and use as an initial stack
before initialization of DRAM.

Since it is not possible to squeeze in all the functionality
that is normally expected from U-Boot in < 110KB (after setting aside some space
for stack, heap etc) a two stage approach has been adopted.
Initial stage initalize only the required boot devices (NAND, MMC, I2C etc);
2nd full stage initall all other devices (ethernet, timers, clocks etc).
The 1st binary is generated MLO and the 2nd stage is generated as u-boot.img.


編譯完后盟萨,現(xiàn)在就可以找找成就感了凉翻,

  1. 將MLO和u-boot.img復(fù)制到SD卡的第一個分區(qū)里;
  2. 將串口調(diào)試用的線與計算機相連捻激,啟動串口調(diào)試程序制轰,如Putty。
  3. 將SD卡插入開發(fā)板胞谭,保持按下板子上的啟動選擇鍵垃杖,插上電源,板子會從SD卡啟動丈屹,
  4. 可以松開啟動選擇鍵了调俘。

Putty的窗口上會打印一些信息,你會看到一個1秒的倒計時,然后U-Boot會運行環(huán)境變量中
已經(jīng)設(shè)置好的一些列命令彩库,比如將Linux內(nèi)核載入內(nèi)存肤无,但此時還沒有內(nèi)核文件,U-Boot會
停留在它自己的命令行中侧巨,你可以輸入命令舅锄,如reset鞭达,這會讓板子重啟司忱,倒計時的時候
按下計算機上的任意鍵,U-Boot就不會運行環(huán)境變量中的命令了畴蹭,可玩一玩下面的演示坦仍。

給出U-Boot中的一些演示,輸入help可顯示所有命令叨襟。
help后接命令繁扎,可顯示該命令的幫助。如"help help"糊闽。

U-Boot# mmc rescan
U-Boot# mmc list
OMAP SD/MMC: 0
 OMAP SD/MMC: 1
U-Boot# mmc dev
mmc0 is current device
U-Boot# mmc part

Partition Map for MMC device 0  --   Partition Type: DOS

Part    Start Sector    Num Sectors     UUID            Type
  1     2048            131072          29942d7e-01     0c Boot
  2     133120          15390720        29942d7e-02     83
U-Boot# ls mmc 0:1
   100688   mlo
   308232   u-boot.img
      510   uenv.txt

3 file(s), 0 dir(s)

U-Boot# ls mmc 0:2
<DIR>       4096 .
<DIR>       4096 ..
<SYM>          7 bin
<DIR>       4096 boot
<DIR>       4096 dev
<DIR>       4096 etc
<DIR>       4096 home
<SYM>          7 lib
<DIR>       4096 lost+found
<DIR>       4096 mnt
<DIR>       4096 proc
<DIR>       4096 run
<SYM>          7 sbin
<DIR>       4096 sys
<DIR>       4096 tmp
<DIR>       4096 usr
<DIR>       4096 var
U-Boot# mmcinfo
Device: OMAP SD/MMC
Manufacturer ID: 3
OEM: 5344
Name: SU08G
Tran Speed: 50000000
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 7.4 GiB
Bus Width: 4-bit
U-Boot# mmc dev 1
mmc1(part 0) is current device
U-Boot# mmcinfo
Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC02
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: No
Capacity: 1.8 GiB
Bus Width: 4-bit
U-Boot# mmc dev 0
mmc0 is current device
U-Boot#

fatls,ext4ls也可以顯示文件梳玫,但對應(yīng)某種文件系統(tǒng)。

Linux

內(nèi)核配置文件我在開發(fā)板的GitHub找的右犹,
復(fù)制一份名字改.config放到O指定的目錄中提澎。
這樣就可以用make oldconfig了。
我的內(nèi)核版本是Linux-3.13.5念链,并沒有提示新的配置盼忌。
如果要修改的話,要注意systemd對內(nèi)核的配置是有要求的掂墓,我并沒有改谦纱。

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ export PATH=$PATH:/home/spy/Work/U-Boot/u-boot/tools
$ export CROSS_COMPILE=arm-none-linux-gnueabi-

$ make O=../linux ARCH=arm help
$ make O=../linux ARCH=arm mrproper
$ make O=../linux ARCH=arm oldconfig
$ make O=../linux ARCH=arm LOADADDR=0x80008000 uImage
$ make O=../linux ARCH=arm LOADADDR=0x80008000 dtbs
$ make O=../linux ARCH=arm LOADADDR=0x80008000 modules
$ make O=../linux ARCH=arm LOADADDR=0x80008000 INSTALL_MOD_PATH=/home/spy/Work/root modules_install
$ make O=../linux ARCH=arm LOADADDR=0x80008000 INSTALL_FW_PATH=/home/spy/Work/fw firmware_install
$ make O=../linux ARCH=arm LOADADDR=0x80008000 INSTALL_HDR_PATH=/home/spy/Work/root/hdr headers_install

make help是否指定ARCH,輸出內(nèi)容是不同的君编。

uImage就是壓縮后的Linux內(nèi)核跨嘉,編譯時需要mkimage這個工具,編譯U-Boot的時候會生成那個工具吃嘿,
所以我編譯內(nèi)核之前指定了該工具的目錄祠乃。

  • dts --> device tree source
  • dtb --> device tree blob
  • dtbo --> device tree blob overlay
  • dtc --> device tree compile

沒研究為什么編譯設(shè)備樹是dtbs,是在make help的幫助中看到的唠椭。

內(nèi)核的配置中指定了很多把驅(qū)動編譯成模塊的跳纳,這部分需要make modules來單獨編譯。
我構(gòu)建完的系統(tǒng)并沒有用到這些modules贪嫂,插個U盤是可用的寺庄。

編譯完成后,可在輸出文件夾的arch/arm/boot找到zImage, uImage和dts子文件夾,
dts里面有am335x-boneblack.dtb斗塘。zImage也是內(nèi)核赢织,也可以用,但我用的uImage馍盟。

最后那三個安裝目錄自己選個更好的吧于置。
modules會安在lib/moduleslib/firmware2個文件夾中。


安裝modules的時候贞岭,可能會提示depmod出問題八毯,據(jù)說正常,那不是處理交叉編譯的模塊的瞄桨。
但我還是看到了depmod后應(yīng)該出現(xiàn)的modules.dep文件话速。
depmod是用來構(gòu)建模塊依存關(guān)系的,目的是芯侥,當(dāng)用insmod裝載某模塊的時候泊交,可能會失敗,
因為這個模塊依賴的其他模塊還沒有裝入內(nèi)核柱查,depmod構(gòu)建完依賴關(guān)系后廓俭,用另外一個命令
裝載模塊,即可自動裝載模塊所依賴的其他模塊唉工。


firmware也安在lib/firmware中研乒,但與modules中的不同。我目前不知道firmware是干什么的酵紫。

headers還是需要安裝的告嘲,它就像glibc那樣,編譯程序時被調(diào)用奖地。


下面可以驗證了橄唬。
將uImage文件,dts文件夾復(fù)制到SD卡第二個分區(qū)的/boot/里参歹。
其實dts中應(yīng)該只需am335x-boneblack.dtb仰楚。

啟動開發(fā)板前應(yīng)該了解下U-Boot如何載入Linux。
U-Boot中最關(guān)鍵的環(huán)境變量

bootcmd: This variable defines a command string that is automatically executed   
         when the initial countdown is not interrupted.  
         This command is only executed when the variable bootdelay is also defined!   
bootargs: The contents of this variable are passed to the Linux kernel as boot   
          arguments (aka "command line").   

U-Boot中最關(guān)鍵的命令

run - run commands in an environment variable  

U-Boot啟動后會運行bootcmd里的命令犬庇,所以要研究的話僧界,從bootcmd開始。

提示:我的研究在后面〕敉欤現(xiàn)在可不必研究直接看我的處理捂襟。


編譯后的U-Boot是不能引導(dǎo)uImage的,通過printenv看U-Boot的環(huán)境變量欢峰,可看到
它找的是zImage葬荷,而且am335x-boneblack.dtb是在/boot/中找涨共,不是/boot/dts/。
如果將zImage和am335x-boneblack.dtb放到/boot中應(yīng)該能引導(dǎo)宠漩。

為了符合我的要求举反,要修改環(huán)境變量,可以用editenv修改環(huán)境變量后saveenv扒吁。
但還是別這么做了火鼻,我不知道它把環(huán)境變量保存到哪里去了。我以為把MLO和u-boot.img換回
原始的可以恢復(fù)默認的環(huán)境變量值雕崩,但不是這樣魁索,把SD卡格式化后也沒用。
有可能是存到eMMC中了晨逝,我想盡各種辦法破壞eMMC的數(shù)據(jù)蛾默,用了
dd if=/dev/zero of=/dev/mmcblk1也不行懦铺。
除了mmcblk1還有個mmcblk1boot捉貌,可能是存到那里了,記著那個設(shè)備比較奇怪冬念,沒有驗證趁窃。
最后用env default -a然后saveenv恢復(fù)默認了。

另一個方法是創(chuàng)建一個uEnv.txt文件急前,將它和MLO放到一起醒陆,內(nèi)容如下。
該文件中的環(huán)境變量會覆蓋掉默認的環(huán)境變量裆针。

bootfile=uImage
loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/dts/${fdtfile}
mmcloados=run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then bootm ${loadaddr} - ${fdtaddr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;
mmcroot=/dev/mmcblk0p2 rw
mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype} init=/usr/lib/systemd/systemd

一共6行刨摩,最后一行空白。
改動不是很大世吨,bootfile修改了內(nèi)核名字澡刹,
loadfdt中只是在目錄中加了“dts/”,
mmcloados主要是把bootz改成bootm耘婚。
mmcroot把只讀改成了讀寫罢浇,原因是systemd啟動后會創(chuàng)建一個machine-id到/etc中。
也許有其他辦法沐祷,如/etc/fstab文件嚷闭,但我為了簡單沒創(chuàng)建那個文件。
mmcargs只是在后面指定了init為systemd赖临,也有其他方法胞锰,如init為指向systemd的軟鏈接。

啟動BeagleBone Black兢榨,待內(nèi)核啟動后會打印很多信息嗅榕,最后你將目睹“kernel panic”挠进,
這是因為我們目前并沒有init程序,為了找到成就感誊册,你可以編譯下面
靜態(tài)鏈接的“Hello world!”领突,放到某個目錄中,然后在U-Boot的mmcargs變量中
把init指定為那個hello案怯。

hello.c

#include <stdio.h>

int main(int argc, char *argv)
{
  printf("Hello world!\n");
  sleep(999999999);
}

$ arm-none-linux-gnueabi-gcc -o hello -static hello.c

再次啟動君旦,最后你看到的將是"Hello world!"。

#我分析了U-Boot的引導(dǎo)過程嘲碱,如下金砍,再往下是我的演示。

gpio set 53;        #這個是點亮LED燈的麦锯,其實并沒有這個恕稠,是我在其他的U-Boot中看到的。
i2c mw 0x24 1 0x3e; #這個也沒有扶欣,不知干什么的鹅巍,激發(fā)下你的好奇心。
mmc dev 0;          #將設(shè)備切換到`0`料祠,即SD卡骆捧,其實一開始就是`0`,eMMC是`1`髓绽。
mmc rescan;         #應(yīng)該是檢測設(shè)備是否存在吧敛苇。

gpio set 54;
load mmc 0 0x80200000 uEnv.txt;
env import -t 0x80200000 $filesize #這2步是導(dǎo)入環(huán)境變量,filesize這個變量沒找到顺呕。

gpio set 55;
load mmc 0:2 0x80200000 /boot/uImage;

gpio set 56;
load mmc 0:2 0x80F80000 /boot/dts/am335x-boneblack.dtb;

setenv bootargs console=ttyO0,115200n8 ${optargs} root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait init=/usr/lib/systemd/systemd
bootm 0x80200000 - 0x80F80000;

#optargs這個環(huán)境變量也沒找到枫攀,在其他U-Boot中發(fā)現(xiàn)是quiet,
#作用是減少了內(nèi)核打印的信息株茶,systemd打印的信息也少了来涨。
U-Boot# mmc dev 0
mmc0 is current device
U-Boot# mmc rescan
U-Boot# load mmc 0:2 0x80200000 /boot/uImage
3894896 bytes read in 237 ms (15.7 MiB/s)
U-Boot# load mmc 0:2 0x80F80000 /boot/dts/am335x-boneblack.dtb
17911 bytes read in 213 ms (82 KiB/s)
U-Boot# setenv bootargs console=ttyO0,115200n8 root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait init=/usr/lib/systemd/systemd
U-Boot# bootm 0x80200000 - 0x80F80000
## Booting kernel from Legacy Image at 80200000 ...
   Image Name:   Linux-3.13.5
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    3894832 Bytes = 3.7 MiB
   Load Address: 80008000
   Entry Point:  80008000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 80f80000
   Booting using the fdt blob at 0x80f80000
   Loading Kernel Image ... OK
   Using Device Tree in place at 80f80000, end 80f875f6

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 3.13.5 (spy@alien) (gcc version 4.8.1 (Sourcery CodeBench Lite 2013.11-33) ) #1 SMP Sat Mar 8 20:26:55 UTC 2014

我并沒有導(dǎo)入uEnv.txt,它是下面這個樣子的忌卤。

U-Boot# load mmc 0 0x80200000 uEnv.txt
reading uEnv.txt
510 bytes read in 4 ms (124 KiB/s)
U-Boot# env import -t 0x80200000
## Info: input data size = 966 = 0x3C6

下面就是應(yīng)用程序了扫夜,可根據(jù)我的提示自行安排順序,我曾經(jīng)的順序不是這樣的驰徊。
主要的過程就是glibc笤闯,bash,coreutils,util-linux,systemd,shadow,
這些中間的都是被依賴的程序。
bash需要libgcc_s.so.1棍厂,它位于gcc中颗味,但編譯gcc時間較長,gcc還依賴5個程序。
迫不及待驗證編譯結(jié)果的話可以先把交叉編譯器中的庫復(fù)制到開發(fā)板系統(tǒng)中牺弹,
我當(dāng)初就那么做的浦马。

glibc是程序庫了时呀,幾乎動態(tài)鏈接的程序都要用到了,"Hello world"中的printf函數(shù)都需要晶默。
bash是個shell谨娜,提供了人與計算機交互的界面。
coreutils里有很多常用命令磺陡,如ls趴梢。
util-linux也是有很多命令,如mount币他,login坞靶,fdisk。
systemd是個init程序蝴悉。
shadow是和登陸相關(guān)的彰阴,主要是把/etc/passwd文件里的密碼變成“x”,
里面有l(wèi)ogin拍冠,passwd尿这,useradd等命令。
其實系統(tǒng)系統(tǒng)后的第一個程序是systemd倦微,但它的文檔較少妻味,不了解是怎么工作的,
所以先保證其他的能工作欣福,再研究。

至于怎么編譯焦履,源碼中會有README,INSTALL等文檔拓劝。

需要注意的是我構(gòu)建的系統(tǒng)與大多數(shù)Linux不同,我把所有程序都安裝在了
/usr/app/{程序}/中嘉裤。這是我改進Linux的開始郑临,咱有大計劃呀!

我的想法如下屑宠,
對于程序庫厢洞,依舊在/usr/lib/中搜索,里面除了子文件夾都是軟鏈接典奉,指向app中
相應(yīng)的程序庫躺翻。
對于/usr/bin/中的程序,也是軟鏈接卫玖。
對于/etc/中的配置文件公你,其實有些程序不在那個目錄找配置文件了,如果還在那個目錄找假瞬,
那么里面不是軟鏈接陕靠,就是傳統(tǒng)的配置文件迂尝。

glibc

/usr/local

->
<- bash, //這2個依賴和被依賴的,僅供參考剪芥,肯定不全的垄开,下面也一樣。

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ cd /home/spy/Work/sources/glibc/glibc-build

$ ../glibc-2.19/configure --prefix=/usr/app/glibc --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
$ make
$ make install install_root=/home/spy/Work/sources/glibc/glibc

源碼中并沒有makefile文件税肪,這需要運行configure來生成说榆。
通過“configure --help”查看可用的選項。
prefix為安裝目錄寸认;
build和host用來指定系統(tǒng)類型签财。可看看autoconf的手冊中“Specifying target triplets”偏塞。


build - 構(gòu)建程序的系統(tǒng)唱蒸,在該系統(tǒng)中配置和編譯程序。
host - 構(gòu)建后的程序運行在此系統(tǒng)中灸叼。
target - 編譯工具為此系統(tǒng)生成程序神汹。

這個target,配置glibc不用指定古今,有的文檔中是這樣說的屁魏。

Its for use when building compiler tools, with--hostbeing where they will run, and--targetwhat theyll produce code for.

也就是說鸥咖,通常用在構(gòu)建編譯工具的時候泊愧,舉個例子贞滨,
如果你在你的x86_64計算機中編譯gcc瑰枫,運行在你的x86_64系統(tǒng)中沟娱,讓gcc生成的程序也運行在x86_64中戈二,
這三個是這樣的(為了突出重點祥山,我簡化了等號右邊):
build=x86_64淘这,host=x86_64拟逮,target=x86_64撬统。
在Arch Linux中運行pacman -S gcc安裝的就是這種(pacman是包管理器),
前2個條件不變敦迄,如果讓gcc生成的程序運行在arm中恋追,就像我們要用的Sourcery CodeBench Lite,那么這三個是這樣的:
build=x86_64罚屋,host=x86_64苦囱,target=arm
第一個條件不變沿后,如果讓gcc運行在arm中沿彭,生成的程序也運行在arm中,就像后面我們要編譯的尖滚,這三個是這樣的:
build=x86_64喉刘,host=arm瞧柔,target=arm

等號右邊的格式如下:

cpu-company-system

system可以有以下2種格式之一

  • os
  • kernel-os

查看源碼中的config.sub文件睦裳,能看到各部分可能的值造锅。
運行configure的時候,如果沒指定的話廉邑,configure會用config.guess這個腳本
猜出build的值哥蔚。然后host默認等于build,target默認等于host蛛蒙。
config.guess通常和config.sub在一起糙箍,都可單獨運行的,有“--help”這個選項可用牵祟。

在我的系統(tǒng)中猜測出的值為“x86_64-unknown-linux-gnu”深夯。
在BeagleBone Black中,結(jié)果為“armv7l-unknow-linux-gnueabihf”诺苹。這個結(jié)果應(yīng)該是
不知道的咕晋,因為我是在BeagleBone Black已經(jīng)可用的系統(tǒng)中運行的config.guess。
而我們的系統(tǒng)還沒有構(gòu)建出來呢收奔,不可能運行config.guess掌呜。

那么我們?nèi)绾未_定host呢,難道要看config.sub坪哄?不必质蕉。
當(dāng)build和host不同的時候,configure會啟用交叉編譯模式损姜。
它會檢測以host值為前綴的編譯工具饰剥,如arm-none-linux-gnueabi-gcc,然后使用這個
帶前綴的gcc摧阅。所以我們的host指定為我們交叉編譯器中命令的前綴就好了。
我嘗試過了绷蹲,如果host是“abcdefg”這種棒卷,大概會提示無效的值;
如果是“arm-none-linux-gnueabihf”這種有效的祝钢,configure會檢測
arm-none-linux-gnueabihf-gcc比规,他是找不到的。

既然build可以猜測出來拦英,那是否還要指定呢蜒什,我開始就是沒指定,可以的疤估。但是autoconf手冊中:

“For historical reasons, whenever you specify --host, be sure
to specify --build too; this will be fixed in the future.”

看來這個“future”已經(jīng)到了灾常,但我還是指定了霎冯。

我們編譯程序是用在其他的系統(tǒng)中,如果不指定install_root钞瀑,它就要往prefix指定的目錄安了沈撞,
不要這樣,我的路徑還好雕什,如果是/usr/lib/缠俺,那就破壞了你正使用的系統(tǒng),不過我用的是普通用戶贷岸,
應(yīng)該沒權(quán)限往那個目錄安壹士。
有了install_root,就會安裝到/home/spy/Work/sources/glibc/glibc/usr/app/glibc偿警,看看
makefile文件就會明白原理躏救。
那么把prefix指定為那個完整的目錄,不使用install_root行不行呢户敬。最好別這樣落剪。
構(gòu)建完glibc,其中的ld.so并不是在/lib/或/usr/lib/中找程序庫尿庐,而是在glibc的庫
被安裝到的目錄中找忠怖,即/usr/app/glibc/lib
可見抄瑟,這個prefix會記錄到生成的程序中凡泣,所以最好別讓目錄那么長,那么亂皮假。

問題又來了鞋拟,ld.so竟然不在/usr/lib/中找程序庫,這可是傳說中的默認目錄啊惹资。
我的處理是在構(gòu)建的系統(tǒng)中運行l(wèi)dconfig贺纲,在bash中說。

gmp

/usr/local

->
<- mpfr, mpc, isl, cloog, gcc

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ cd /home/spy/Work/sources/gmp/gmp-build

$ ../gmp-5.1.3/configure --prefix=/usr/app/gmp --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
$ make
$ make install DESTDIR=/home/spy/Work/sources/gmp/gmp

這個和下面的4個都是為gcc服務(wù)的褪测。
這里的安裝目錄用的是DESTDIR猴誊,看看源代碼里的文檔吧。

libtool: install: warning: remember to run 'libtool --finish /usr/local/lib'

安裝時遇到個警告侮措,這個應(yīng)該和ldconfig這個命令有關(guān)懈叹,應(yīng)該是為了glibc的ld程序能找到這個庫,我沒執(zhí)行這一步分扎。

mpfr

/usr/local]
-> gmp,
<- mpc, gcc

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ cd /home/spy/Work/sources/mpfr/mpfr-build

$ ../mpfr-3.1.2/configure --prefix=/usr/app/mpfr --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --with-gmp=/home/spy/Work/sources/gmp/gmp/usr/app/gmp
$ make
$ make install DESTDIR=/home/spy/Work/sources/mpfr/mpfr

修改lib/libmpfr.la澄成,

# Libraries that this one depends upon.
dependency_libs=' -L/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib /usr/app/gmp/lib/libgmp.la'

# Libraries that this one depends upon.
dependency_libs=' -L/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib /home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib/libgmp.la'

也就是把目錄改成完整的,這個過程的原因見mpc。

libtool: install: warning: remember to run 'libtool --finish /usr/local/lib'

警告依舊墨状,不管他卫漫,怕他影響我正使用系統(tǒng)中的庫。

應(yīng)該還會看到其他警告歉胶,如某個.la文件被moved汛兜,答案也是見mpc。

mpc

/usr/local

-> gmp,mpfr
<- gcc

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ cd /home/spy/Work/sources/mpc/mpc-build

$ ../mpc-1.0.2/configure --prefix=/usr/app/mpc --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --with-gmp=/home/spy/Work/sources/gmp/gmp/usr/app/gmp --with-mpfr=/home/spy/Work/sources/mpfr/mpfr/usr/app/mpfr
$ make
$ make install DESTDIR=/home/spy/Work/sources/mpc/mpc

修改.la文件通今,

# Libraries that this one depends upon.
dependency_libs=` -L/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib -L/home/spy/Work/sources/mpfr/mpfr/usr/app/mpfr/lib /usr/app/mpfr/lib/libmpfr.la /usr/app/gmp/lib/libgmp.la -lm`

# Libraries that this one depends upon.
dependency_libs=` -L/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib -L/home/spy/Work/sources/mpfr/mpfr/usr/app/mpfr/lib /home/spy/Work/sources/mpfr/mpfr/usr/app/mpfr/lib/libmpfr.la /home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib/libgmp.la -lm`
libtool: install: warning: remember to run 'libtool --finish /usr/local/lib'

找不到*.la的問題

/usr/bin/sed: can't read /usr/app/gmp/lib/libgmp.la: No such file or directory
libtool: link: '/usr/app/gmp/lib/libgmp.la' is not a valid libtool archive

如果沒有我mpfr中的修改粥谬,編譯時就會出現(xiàn)這個錯誤。
編譯mpc的時候辫塌,應(yīng)該讀取了mpfr中的libmpfr.la漏策。然后根據(jù)dependency_libs中的路徑
找libgmp.la,結(jié)果找不到臼氨。
dependency_libs的前一部分掺喻,應(yīng)該是由我配置時指定的--with-gmp來確定,
而后半部分储矩,看看安裝后的gmp,也有個.la文件感耙,文件中有個libdir,

# Directory that this library needs to be installed in:
libdir='/usr/app/gmp/lib'

很明顯持隧,這個libdir是根據(jù)編譯gmp時指定的prefix確定的即硼。

如果把libdir手動改成/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib
再編譯mpfr屡拨,libmpfr.la中的dependency_libs就是只酥,

# Libraries that this one depends upon.
dependency_libs=' -L/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib /home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib/libgmp.la'

這樣也不會出現(xiàn)lib*.la文件被moved的警告。
由此可見呀狼,后半部分是由所依賴的.la文件中l(wèi)ibdir確定的裂允。
我最后沒有選擇修改libdir,雖然修改libdir也可以編譯成功哥艇,而且沒有警告绝编。

isl

/usr/local

-> gmp
<- gcc

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ cd /home/spy/Work/sources/isl/isl-build

$ ../isl-0.12.2/configure --prefix=/usr/app/isl --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --with-gmp-prefix=/home/spy/Work/sources/gmp/gmp/usr/app/gmp --with-gmp-exec-prefix=/home/spy/Work/sources/gmp/gmp/usr/app/gmp
$ make
$ make install DESTDIR=/home/spy/Work/sources/isl/isl
# Libraries that this one depends upon.
dependency_libs=' -L/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib /usr/app/gmp/lib/libgmp.la'

# Libraries that this one depends upon.
dependency_libs=' -L/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib /home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib/libgmp.la'

libtool: warning: remember to run 'libtool --finish /usr/local/lib'

cloog

/usr/local

-> isl,gmp
<- gcc

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ cd /home/spy/Work/sources/cloog/cloog-build

$ ../cloog-0.18.1/configure --prefix=/usr/app/cloog --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --with-isl=system --with-isl-prefix=/home/spy/Work/sources/isl/isl/usr/app/isl --with-isl-exec-prefix=/home/spy/Work/sources/isl/isl/usr/app/isl --with-gmp-prefix=/home/spy/Work/sources/gmp/gmp/usr/app/gmp --with-gmp-exec-prefix=/home/spy/Work/sources/gmp/gmp/usr/app/gmp

修改Makefile libcloog-isl.la:

libcloog_isl_la_LDFLAGS = -version-info 4:0:0 \
    -L/home/spy/Work/sources/isl/isl/usr/local/lib 

am_libcloog_isl_la_rpath = -rpath /home/spy/Work/sources/isl/isl/usr/app/isl/lib
$ make
$ make install DESTDIR=/home/spy/Work/sources/cloog/cloog
# Libraries that this one depends upon.
dependency_libs=' -L/home/spy/Work/sources/isl/isl/usr/app/isl/lib -L/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib /usr/app/isl/lib/libisl.la /usr/app/gmp/lib/libgmp.la'

# Libraries that this one depends upon.
dependency_libs=' -L/home/spy/Work/sources/isl/isl/usr/app/isl/lib -L/home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib /home/spy/Work/sources/isl/isl/usr/app/isl/lib/libisl.la /home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib/libgmp.la'

--with-isl=system 目的是使用之前編譯的isl,cloog源碼中有也有份isl貌踏。


編譯時錯誤undefined reference

warning: libisl.so.10, needed by ./.libs/libcloog-isl.so, not found (try using -rpath or -rpath-link)

rpath的問題瓮增,解決見make前操作。

一看和isl有關(guān)哩俭,cloog的源碼中自帶了一份isl,我配置時沒用cloog中的拳恋,
當(dāng)出現(xiàn)這個錯誤時凡资,我配置成用cloog中的,這樣編譯cloog的時候,會有編譯isl的過程隙赁,
結(jié)果編譯isl的時候就有錯誤垦藏。
看了一下cloog中的isl,版本低一些伞访。
我單獨編譯這個isl或者在isl官網(wǎng)下載同樣的版本掂骏,都是出錯,為了解決cloog的錯誤厚掷,
我決定先解決簡單一些的isl的錯誤入手弟灼。

isl-0.12.1版本的問題:

isl_polyhedron_sample
isl_polytope_scan
isl_polyhedron_detect_equalities
isl_cat
isl_closure

以上就是編譯時出現(xiàn)過的有問題的make對象。在makefile文件中冒黑,用了下面的rpath即可解決田绑。
-rpath /home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib
rpath是運行時搜索程序庫的路徑,是gcc的參數(shù)抡爹,可以寫到編譯后的程序中的掩驱。

也許還有別的對象,但都用LINK

LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
    $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
    $(AM_LDFLAGS) $(LDFLAGS) -o $@

更改 AM_LDFLAGS = -rpath /home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib
就都解決了冬竟。

但我發(fā)現(xiàn)了另一個方式欧穴,把這一個改對就可以

libisl.la: $(libisl_la_OBJECTS) $(libisl_la_DEPENDENCIES) $(EXTRA_libisl_la_DEPENDENCIES) 
    $(AM_V_CCLD)$(libisl_la_LINK) -rpath /home/spy/Work/sources/gmp/gmp/usr/app/gmp/lib $(libisl_la_OBJECTS) $(libisl_la_LIBADD) $(LIBS)

我不知道這樣做是否會出現(xiàn)什么問題,但還沒遇到泵殴,除了下面沒造成什么影響的涮帘。

按這個方式修改cloog的makefile的時候,
.la文件中袋狞,安裝路徑里出現(xiàn)的應(yīng)該是cloog啊焚辅,竟然是isl,我做了修改苟鸯,

# Directory that this library needs to be installed in:
libdir='/home/spy/Work/sources/isl/isl/usr/app/isl/lib'

改成

# Directory that this library needs to be installed in:
libdir='/usr/app/cloog/lib'

gcc

/usr/local

-> gmp,mpfr,mpc,isl,cloog
<- bash

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ cd /home/spy/Work/sources/gcc/gcc-build

$ ../gcc-4.8.2/configure --prefix=/usr/app/gcc --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --target=arm-none-linux-gnueabi --enable-shared --enable-threads --enable-languages=c --with-gmp=/home/spy/Work/sources/gmp/gmp/usr/app/gmp --with-mpfr=/home/spy/Work/sources/mpfr/mpfr/usr/app/mpfr --with-mpc=/home/spy/Work/sources/mpc/mpc/usr/app/mpc --with-isl=/home/spy/Work/sources/isl/isl/usr/app/isl --with-cloog=/home/spy/Work/sources/cloog/cloog/usr/app/cloog
$ make
$ make install DESTDIR=/home/spy/Work/sources/gcc/gcc

gcc就是編譯器了同蜻,我們編譯軟件就靠它了,gcc也包含一些庫早处,我們的bash要用到湾蔓。
gcc的配置選項太多了,我只額外用了
--enable-shared --enable-threads --enable-languages=c
也不知道是否需要砌梆。
我編譯了50分鐘默责,現(xiàn)在是2014年,我這2手筆記本比較差了咸包,
CPU 1.86GHz桃序,內(nèi)存2G的,DDR2的烂瘫,單條1G媒熊。

bash

-> glibc,gcc
<-

$ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
$ cd /home/spy/Work/sources/Bash/bash-build

$ ../bash-4.3/configure --prefix=/usr/app/bash --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --without-bash-malloc --with-installed-readline
$ make
$ make DESTDIR=/home/spy/Work/sources/Bash/bash install

--without-bash-malloc --with-installed-readline
對這2個不太了解,只是為了bash簡單點。
不知道readline干什么的芦鳍,我構(gòu)建的系統(tǒng)沒有安readline嚷往。

在這里推薦個工具,readelf柠衅,這是binutils中的一個命令皮仁。可查看二進制文件的信息菲宴,
我用它主要是為了看到所依賴的庫贷祈。

$ readelf -hld bin/bash

-a選項是打印所有的信息,我們用-hld就可以了裙顽。
看看我們編譯后的bash付燥,它需要gcc中的libgcc_s.so.1,而我電腦中的bash卻不需要那個庫愈犹。


有了shell键科,我們就可以在開發(fā)板中驗證我們編譯的結(jié)果了。
至此漩怎,我們編譯了glibc勋颖,gmp,mpfr勋锤,mpc饭玲,isl,cloog叁执,gcc茄厘,bash。
在復(fù)制到SD卡之前谈宛,我想應(yīng)該先把mpfr次哈,mpc,isl吆录,cloog中的改動改回來窑滞。
根據(jù)prefix,將編譯后的程序復(fù)制到SD卡恢筝,/usr/lib/和/usr/bin/中添加相應(yīng)的軟鏈接哀卫。
我并不是在這個時候才制作的軟鏈接,每編譯過一個程序撬槽,發(fā)現(xiàn)有bin和lib文件夾此改,
就把軟鏈接做好了,直接復(fù)制到SD卡中就可以了侄柔。
至于怎么制作带斑,我不擅長鼓寺,寫個腳本應(yīng)該比較好,但我沒學(xué)勋磕。
/etc/中不必有配置文件。

在uEnv.txt中敢靡,把bootargs的init改為/usr/bin/bash挂滓。

如果就這樣啟動的話,會提示找不到libgcc_s.so.1啸胧,因為這個庫不在ld.so的搜索路徑中赶站。
目前的搜索路徑是/usr/app/glibc/lib
所以/usr/app/glibc/lib中有個libgcc_s.so.1就可以了纺念,可以放一個軟鏈接贝椿,就像/usr/lib中的。
不要擔(dān)心陷谱,這只是臨時的烙博。

接下來我們要在開發(fā)板中運行l(wèi)dconfig,這是glibc的一部分烟逊,它會讀取ld.so.conf文件中的
路徑渣窜,然后建立一個ld.so.cache文件,這樣ld.so就能利用ld.so.cache找到那些路徑中的庫了宪躯。

ld.so.conf文件不存在乔宿,而我們構(gòu)建的系統(tǒng)還沒有文本編輯器,所以要在啟動之前建立該文件访雪。
內(nèi)容就是

/usr/lib

很多文本文件都以空行結(jié)尾详瑞,我們也這么做吧。
那么這個文件要放到哪里呢臣缀,一般是/etc/中坝橡,但在我們構(gòu)建的系統(tǒng)中,
ldconfig是到/usr/app/glibc/etc/中找肝陪,所以要放到這個目錄中驳庭。

好,可以啟動開發(fā)板了氯窍,進到shell之后饲常,運行l(wèi)dconfig。
把/usr/app/glibc/lib中的libgcc_s.so.1刪掉狼讨,重啟贝淤,看看是不是可以正常運行了?

這樣的方法并不好政供,應(yīng)該讓編譯glibc的時候可以指定ld.so的搜索路徑播聪。
其實我當(dāng)初用了更不好的方法朽基,我在內(nèi)核參數(shù)中指定了LD_LIBRARY_PATH。

雖然我們沒安什么程序离陶,但bash是有內(nèi)置命令的稼虎,比如切換目錄的cd,查看
當(dāng)前目錄的pwd招刨。


因為太長霎俩,分了2部分。
構(gòu)建Linux筆記v1.0(第二部分)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沉眶,一起剝皮案震驚了整個濱河市打却,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谎倔,老刑警劉巖柳击,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異片习,居然都是意外死亡捌肴,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進店門毯侦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哭靖,“玉大人,你說我怎么就攤上這事侈离∈杂模” “怎么了?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵卦碾,是天一觀的道長铺坞。 經(jīng)常有香客問我,道長洲胖,這世上最難降的妖魔是什么济榨? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮绿映,結(jié)果婚禮上擒滑,老公的妹妹穿的比我還像新娘。我一直安慰自己叉弦,他們只是感情好丐一,可當(dāng)我...
    茶點故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著淹冰,像睡著了一般库车。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上樱拴,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天柠衍,我揣著相機與錄音洋满,去河邊找鬼。 笑死珍坊,一個胖子當(dāng)著我的面吹牛牺勾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播垫蛆,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼禽最,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了袱饭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤呛占,失蹤者是張志新(化名)和其女友劉穎虑乖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晾虑,經(jīng)...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡疹味,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了帜篇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糙捺。...
    茶點故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖笙隙,靈堂內(nèi)的尸體忽然破棺而出洪灯,到底是詐尸還是另有隱情,我是刑警寧澤竟痰,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布签钩,位于F島的核電站,受9級特大地震影響坏快,放射性物質(zhì)發(fā)生泄漏铅檩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一莽鸿、第九天 我趴在偏房一處隱蔽的房頂上張望昧旨。 院中可真熱鬧,春花似錦祥得、人聲如沸兔沃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽粘拾。三九已至,卻和暖如春创千,著一層夾襖步出監(jiān)牢的瞬間缰雇,已是汗流浹背入偷。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留械哟,地道東北人疏之。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像暇咆,于是被迫代替她去往敵國和親锋爪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,937評論 2 361