Anroid 编译过程分析

 

 

 

 

Anroid 编译过程分析


该文档主要是在mtk android L 6582 基础上面来介绍编译过程.

一.如何编译

1.初始化编译环境

执行source build/envsetup.sh 命令 或者 . build/envsetup.sh.这一点mtk 和google 原生的编译方式是一致的

2.选择要编译的工程

执行lunch 命令,由于我们拿到的mtk source 里面可以编译的工程不只一个,所以我们需要选择一个工程名字.输入lunch 命令之后会看到下面待选的工程列表,具体选择哪一个更具实际需要.针对mtk 6582 来说,我们如果编译工程版本的话选择full_aeon6582_wt_l-eng ,编译用户版本的选择full_aeon6582_wt_l-user

 

3.开始编译

执行命令: make -j36 2>&1 | tee build.log

 

如果是编译原生的代码使用以上命令,如果是mtk 的代码不需要加-j36

         其中-j36 表示开启36个进程来编译,主要是为了加快编译速度.

其中2>&1 | tee build.log  关于shell 命令部分如果有不明白的地方,可以查看后面的解释.这里我们可以理解为它只是对编译log进行的一个处理动作.

这份文档里面涉及到几个重要的shell命令我会统一放到第3章,可以直接点击上面的链接直接查看.

 

4.查看系统效果

由于没有样机,所以只能启动Android 模拟器来看效果

4.1创建Android虚拟机

android create avd -n <name> -t <targetID> [-<option> <value>] ...

例如,我们输入android create avd -n Android5 -t 1并回车,出现以下提示:

提示是否自定义硬件配置。如果直接回车或者输入n再回车,则会创建默认的模拟器:

 

4.2启动一个Android模拟器

emulator -avd <avd_name>

具体命令操作的截图如下:

 

二.编译过程分析

以上只是介绍了如何如编译一个通用的系统,但是没有介绍具体过程

 

1.source build/envsetup.sh

执行source build/envsetup.sh 命令之后会输出一下内容:

2. envsetup.sh其主要作用:

2.1加载了编译时使用到的函数命令:

如:help,lunch,m,mm,mmm等

                   全部的函数列表如下:

addcompletions

add_lunch_combo #添加Android编译选项

cgrep           # 查找c/cpp文件

check_product  检查product

check_variant   检查variant

choosecombo    # 设置variant

chooseproduct  # 设置product

choosetype   # 设置type

choosevariant    # 设置variant

cproj

croot  查找makefile

findmakefile   # 查找makefile

gdbclient

gdbwrapper

get_abs_build_var

getbugreports

get_build_var

getdriver

getlastscreenshot

get_make_command

getprebuilt

getscreenshotpath

getsdcardpath

get_symbols_directory

gettargetarch

gettop

ggrep

godir #跳到指定目录

hmm

is

isviewserverstarted jgrep key_back key_home

key_menu

lunch  配置lunch

_lunch

m  #基本上同make命令

make  #编译命令

mangrep

mgrep

mm  #编译命令,编译当前目录下面的源码

mma  #编译命令,可以在Android 其他目录编译

mmm  #编译命令

mmma

pez

pid

printconfig

print_lunch_menu  打印lunch列表

qpid

resgrep

runhat

runtest

sepgrep

set_java_home  #设置java jdk 相关的环境变量

setpaths

set_sequence_number

set_stuff_for_environment

settitle设置标题

sgrep smoketest

stacks

startviewserver

stopviewserver

systemstack

tapas       功能同choosecombo

tracedmdump

treegrep

 

 

m make

make: 编译所有的模块,mtk 之前的./mk new 是一样的.

mm:编译当前目录下的模块,当前目录下要有Android.mk文件

mmm:编译指定路径下的模块,指定路径下要有Android.mk文件

2.2 查找vendor和  device 目录下的vendorsetup.sh,如果存在的话,加载执行它,添加厂商自己定义产品的编译选项

 其实,上述第2条是向编译系统添加了厂商自己定义产品的编译选项,里面的代码就是:add_lunch_combo xxx-xxx。

 

根据上面的内容,可以推测出,如果要想定义自己的产品编译项,简单的办法是直接在envsetup.sh最后,

添加上add_lunch_combo myProduct-eng,当然这么做,不太符合上面代码最后的本意,

我们还是老实的在vendor或者 device 目录下创建自己公司名字,然后在公司目录下创建一个新的vendorsetup.sh,在里面添加上自己的产品编译项.现在连mtk 在Android L 上面也是按照google 的意图来添加自己研发的相关的功能

具体的代码分析(红色部分为新加的注释)

#检查bash 环境

if [ "x$SHELL" != "x/bin/bash" ]; then

case `ps -o command -p $$` in

*bash*)

            ;;

*)

            echo "WARNING: Only bash is supported, use of other shell would lead to erroneous results"

            ;;

esac

fi

 

# Execute the contents of any vendorsetup.sh files we can find.

device  vendor 目录下面查找vendorsetup.sh 文件,子文件夹深度最大为4

for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null` \

`test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null`

do

echo "including $f"

. $f   # 执行找到的脚本,其实里面就是厂商自己定义的编译选项

done

unset f

 

初始化化adb 命令

addcompletions

 

关于for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null` \

`test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null`

中的test –d 和find –L  及2> /dev/null 请分别参考第三章 1.test命令 , 2.find 命令3.2>/dev/null

 

function addcompletions()

{

local T dir f

 

# Keep us from trying to run in something that isn't bash.

if [ -z "${BASH_VERSION}" ]; then

return

fi

#检查bash 版本是否是比较新的版本

# Keep us from trying to run in bash that's too old.

if [ ${BASH_VERSINFO[0]} -lt 3 ]; then

return

fi

#sdk/bash_completion 目录下找bash 文件并执行

dir="sdk/bash_completion"

if [ -d ${dir} ]; then

for f in `/bin/ls ${dir}/[a-z]*.bash 2> /dev/null`; do

            echo "including $f"

            . $f   # 执行文件

done

fi

}

3. lunch<project>

执行 :lunch full_aeon6582_wt_l-eng

function lunch()

{

local answer

#$1 是我们在lunch 后面输入第一个参数

if [ "$1" ] ; then

answer=$1

else

         #如果lunch命令后面没有跟参数就打印可以选择的project,并等待继续输入内容

print_lunch_menu

echo -n "Which would you like? [aosp_arm-eng] "

read answer

fi

 

local selection=

 

         #判断answer 是否存在值也就是判断是否有输入值

if [ -z "$answer" ]

then

          #如果用户在菜单中没有选择,直接回车,则为系统缺省的 aosp_arm-eng

selection=aosp_arm-eng

elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$") #输入值字符是否为空

then

                   如果answer是选择菜单的数字,则获取该数字对应的字符串

if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]

then

            selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}

fi

         如果answer是选择菜单的数字,则获取该数字对应的字符串

elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")

then

selection=$answer

fi

 

if [ -z "$selection" ]

then

echo

echo "Invalid lunch combo: $answer"

return 1

fi

 

export TARGET_BUILD_APPS=

 

local product=$(echo -n $selection | sed -e "s/-.*$//")

#full_aeon6582_wt_l-eng 替换full_aeon6582_wt_l

         检查之,调用关系 check_product()->get_build_var()->build/core/config.mk,很复杂

check_product $product

if [ $? -ne 0 ]

then

echo

echo "** Don't have a product spec for: '$product'"

echo "** Do you have the right repo manifest?"

product=

fi

 

local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")

check_variant $variant

if [ $? -ne 0 ]

then

echo

echo "** Invalid variant: '$variant'"

echo "** Must be one of ${VARIANT_CHOICES[@]}"

variant=

fi

 

if [ -z "$product" -o -z "$variant" ]

then

echo

return 1

fi

         #设置3个环境变量

export TARGET_PRODUCT=$product

export TARGET_BUILD_VARIANT=$variant

export TARGET_BUILD_TYPE=release

 

 echo

         #设置到环境变量

set_stuff_for_environment

         打印一些主要的变量调用关系 printconfig()->get_build_var()->build/core/config.mk->build/core/envsetup.mk

printconfig}

 

3.1 add_lunch_combo 方法

该方法是用来添加我们自己加入的project的.

unset LUNCH_MENU_CHOICES

function add_lunch_combo()

{

local new_combo=$1

local c

for c in ${LUNCH_MENU_CHOICES[@]} ; do

if [ "$new_combo" = "$c" ] ; then

            return

fi

done

LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)

}

 

比如以下操作将加入默认的几个project:

# add the default one here

add_lunch_combo aosp_arm-eng

add_lunch_combo aosp_arm64-eng

add_lunch_combo aosp_mips-eng

add_lunch_combo aosp_mips64-eng

add_lunch_combo aosp_x86-eng

add_lunch_combo aosp_x86_64-eng

 

其中full_aeon6582_wt_l-eng 又是怎么加进去的呢?可以回头看一下2.2 中device  vendor 目录下面查找vendorsetup.sh 文件介绍.由于之前已经找到并执行了device/eastaeon/aeon6582_wt_l/vendorsetup.sh 脚本,这个脚本会执行add_lunch_combo来添加full_aeon6582_wt_l-eng.具体如下:

device/eastaeon/aeon6582_wt_l/vendorsetup.sh 文件内容:

add_lunch_combo full_aeon6582_wt_l-eng

add_lunch_combo full_aeon6582_wt_l-userdebug

add_lunch_combo full_aeon6582_wt_l-user

 

由上面分析可知,lunch命令可以带参数和不带参数,最终导出一些重要的环境变量,从而影响编译系统的编译结果。导出的变量如下

============================================

PLATFORM_VERSION_CODENAME=REL

PLATFORM_VERSION=5.0

TARGET_PRODUCT=full_aeon6582_wt_l

TARGET_BUILD_VARIANT=eng

TARGET_BUILD_TYPE=release

TARGET_BUILD_APPS=

TARGET_ARCH=arm

TARGET_ARCH_VARIANT=armv7-a-neon

TARGET_CPU_VARIANT=cortex-a7

TARGET_2ND_ARCH=

TARGET_2ND_ARCH_VARIANT=

TARGET_2ND_CPU_VARIANT=

HOST_ARCH=x86_64

HOST_OS=linux

HOST_OS_EXTRA=Linux-3.2.0-72-generic-x86_64-with-Ubuntu-12.04-precise

HOST_BUILD_TYPE=release

BUILD_ID=LRX21M

OUT_DIR=out

============================================

4.make 编译

4.1 执行Makefile 文件

make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。

### DO NOT EDIT THIS FILE ###

include build/core/main.mk

### DO NOT EDIT THIS FILE ###

 

关于makefile有不明白的地方可以打开以下链接来学习一下http://blog.csdn.net/edisonlg/article/details/7171641

 

4.2 build/core/main.mk

文件里引入下面几个主要的文件,关于每个文件的作用,文档中默认已经有解释.

 

# Targets that provide quick help on the build system.

Line 89: include $(BUILD_SYSTEM)/help.mk

 

# Set up various standard variables based on configuration

# and host information.

Line 93: include $(BUILD_SYSTEM)/config.mk

 

# This allows us to force a clean build - included after the config.mk

# environment setup is done, but before we generate any dependencies.  This

# file does the rm -rf inline so the deps which are all done below will

# be generated correctly

Line 99: include $(BUILD_SYSTEM)/cleanbuild.mk

 

# Bring in standard build system definitions.

#定义了很多全局变量与函数

Line 260: include $(BUILD_SYSTEM)/definitions.mk

 

# Bring in dex_preopt.mk

Line 263: include $(BUILD_SYSTEM)/dex_preopt.mk

 

# Now with all Android.mks loaded we can do post cleaning steps.

Line 525: include $(BUILD_SYSTEM)/post_clean.mk

 

#添加所有预先构建的模块,google不建议我们修改这个文件

Line 531: include $(BUILD_SYSTEM)/legacy_prebuilts.mk

 

#加载其他makefiel文件

Line 797: include $(BUILD_SYSTEM)/Makefile

 

其中上面BUILD_SYSTEM变量的值,在main.mk中也有定义.

即BUILD_SYSTEM := $(TOPDIR)build/core.

关于上面标红色的config.mk 等文件作用后面会介绍.

 

关于main.mk 文件的整体结构如下图,后面会再具体介绍,这里先整体了解一下.

4.3. build/core/config.mk

This is included by the top-level Makefile.It sets up standard variables based on the current configuration and platform, whichare not specific to what is being built.

 以上是官方提供的英文说明,其实他的以上也就是说这个文件是用来设置编译相关的环境变量和平台相关的变量,而不是用来指定哪些应用需要编译哪些不需要编译的.

 

# TODO: Enforce some kind of layering; only add include paths

#when a module links against a particular library.

# TODO: See if we can remove most of these from the global list.

SRC_HEADERS := \

         $(TOPDIR)system/core/include \

         $(TOPDIR)hardware/libhardware/include \

         $(TOPDIR)hardware/libhardware_legacy/include \

         $(TOPDIR)hardware/ril/include \

         $(TOPDIR)libnativehelper/include \

         $(TOPDIR)frameworks/native/include \

         $(TOPDIR)frameworks/native/opengl/include \

         $(TOPDIR)frameworks/av/include \

         $(TOPDIR)frameworks/base/include

SRC_HOST_HEADERS:=$(TOPDIR)tools/include

SRC_LIBRARIES:= $(TOPDIR)libs

SRC_SERVERS:= $(TOPDIR)servers

SRC_TARGET_DIR := $(TOPDIR)build/target

SRC_API_DIR := $(TOPDIR)prebuilts/sdk/api

SRC_SYSTEM_API_DIR := $(TOPDIR)prebuilts/sdk/system-api

比如定义了以上编译环境相关变量:

 

# Various mappings to avoid hard-coding paths all over the place

include $(BUILD_SYSTEM)/pathmap.mk

 

# ###############################################################

# Build system internal files

# ###############################################################

 

BUILD_COMBOS:= $(BUILD_SYSTEM)/combo

 

CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk

BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk

BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk

BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk

BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk

BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk

BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk

BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk

BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk

BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk

BUILD_PHONY_PACKAGE:= $(BUILD_SYSTEM)/phony_package.mk

BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk

BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk

BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk

BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk

BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk

BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk

BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk

BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk

BUILD_NATIVE_TEST := $(BUILD_SYSTEM)/native_test.mk

BUILD_HOST_NATIVE_TEST := $(BUILD_SYSTEM)/host_native_test.mk

 

BUILD_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/shared_test_lib.mk

BUILD_HOST_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/host_shared_test_lib.mk

BUILD_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/static_test_lib.mk

BUILD_HOST_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/host_static_test_lib.mk

 

BUILD_NOTICE_FILE := $(BUILD_SYSTEM)/notice_files.mk

BUILD_HOST_DALVIK_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_java_library.mk

BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_static_java_library.mk

 

上述命令变量其实是对应的mk文件名,所有的Android.mk文件里基本上都包含上述命令变量,如:

CLEAR_VARS:用来清除之前定义的环境变量

BUILD_SHARED_LIBRARY:用来指定编译动态库过程

 

同时config.mk 还加入几个.mk文件

4.3.1. build/core/envsetup.mk

其中envsetup.mk 的说明如下:

# Define most of the global variables.  These are the ones that

# are specific to the user's build configuration.

include $(BUILD_SYSTEM)/envsetup.mk

 

而envsetup.mk文件主要指定了编译时要输出的所有文件的OUT目录.同时加入下面这2个文件


A.其中version_defaults.mk 主要是定义以下变量

#PLATFORM_VERSION

#PLATFORM_SDK_VERSION

#PLATFORM_VERSION_CODENAME

#DEFAULT_APP_TARGET_SDK

#BUILD_ID

#BUILD_NUMBER

 

 

B. product_config.mk 文件

首先我们就会看到它又包括了以下文件.

 

# ---------------------------------------------------------------

# Include the product definitions.

# We need to do this to translate TARGET_PRODUCT into its

# underlying TARGET_DEVICE before we start defining any rules.

#

include $(BUILD_SYSTEM)/node_fns.mk

include $(BUILD_SYSTEM)/product.mk

include $(BUILD_SYSTEM)/device.mk

 

ifneq ($(strip $(TARGET_BUILD_APPS)),)

# An unbundled app build needs only the core product makefiles.

all_product_configs := $(call get-product-makefiles,\

    $(SRC_TARGET_DIR)/product/AndroidProducts.mk)

else

# Read in all of the product definitions specified by the AndroidProducts.mk

# files in the tree.

all_product_configs := $(get-all-product-makefiles)

endif

上面中的product.mk文件和AndroidProducts.mk 就是获取系统定义的哪些需要编译的部分.

 

product_config.mk 文件主要作用就是加载系统里面定义的哪些需要编译进来的应用.

 

product.mk 文件的中的get-product-makefiles 方法就是根据AndroidProducts.mk 里面定义的PRODUCT_MAKEFILES 变量来获取已经定义好需编译的模块的名字.

 

#

# Returns the list of all AndroidProducts.mk files.

# $(call ) isn't necessary.

vendor device 目录下面查找AndroidProducts.mk 文件

define _find-android-products-files

$(shell test -d device && find device -maxdepth 6 -name AndroidProducts.mk) \

$(shell test -d vendor && find vendor -maxdepth 6 -name AndroidProducts.mk) \

$(SRC_TARGET_DIR)/product/AndroidProducts.mk

endef

 

#

# Returns the sorted concatenation of PRODUCT_MAKEFILES

# variables set in the given AndroidProducts.mk files.

# $(1): the list of AndroidProducts.mk files.

#根据AndroidProducts.mk 文件里面定义的PRODUCT_MAKEFILES中包含的路径来加载其他.mk文件

define get-product-makefiles

$(sort \

$(foreach f,$(1), \

$(eval PRODUCT_MAKEFILES :=) \

$(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \

$(eval include $(f)) \

$(PRODUCT_MAKEFILES) \

) \

$(eval PRODUCT_MAKEFILES :=) \

$(eval LOCAL_DIR :=) \

 )

endef

 

 

总结:

如果想增加自己的产品,应该有以下流程,包含上一节内容:

1. 创建公司目录

#mkdir vendor/aeon

 

2. 创建一个vendorsetup.sh文件,将当前产品编译项添加到lunch里,让lunch能找到用户个性定制编译项

#echo "add_lunch_combo fs100-eng" > vendor/aeon/vendorsetup.sh

 

3. 仿着Android示例代码,在公司目录下创建products目录

#mkdir -p vendor/aeon/products

 

4. 仿着Android示例代码,在products目录下创建两个mk文件

#touch vendor/aeon/products/AndroidProduct.mk vendor/aeon/products/products.mk

 

4.4执行shell 脚本中的function make()

编译完成之后将执行envsetup.sh的function make()中为完成部分,最后会统计这一次编译花费了多久的时间.

function make()

{

local start_time=$(date +"%s")

    $(get_make_command) "$@"

local ret=$?

local end_time=$(date +"%s")

local tdiff=$(($end_time-$start_time))

local hours=$(($tdiff / 3600 ))

local mins=$((($tdiff % 3600) / 60))

local secs=$(($tdiff % 60))

echo

if [ $ret -eq 0 ] ; then

echo -n -e "#### make completed successfully "

else

echo -n -e "#### make failed to build some targets "

fi

if [ $hours -gt 0 ] ; then

printf "(%02g:%02g:%02g (hh:mm:ss))" $hours $mins $secs

elif [ $mins -gt 0 ] ; then

printf "(%02g:%02g (mm:ss))" $mins $secs

elif [ $secs -gt 0 ] ; then

printf "(%s seconds)" $secs

fi

echo -e " ####"

echo

return $ret

}

 

 

三.编译中使用到的shell 命令介绍

1.    test 命令

功能:检查文件和比较值

关于比较值这里不做介绍

test 文件运算符

 

判断文件

test  File1 –ef  File2 两个文件具有同样的设备号和i结点号

test  File1 –nt  File2 文件1比文件2 新

test  File1 –ot  File2 文件1比文件2 旧

test –b File 文件存在并且是块设备文件

test –c File 文件存在并且是字符设备文件

test –d File 文件存在并且是目录

test –e File 文件存在

test –f File  文件存在并且是正规文件

test –g File 文件存在并且是设置了组ID

test –G File 文件存在并且属于有效组ID

test –h File 文件存在并且是一个符号链接(同-L)

test –k File 文件存在并且设置了sticky位

test –b File 文件存在并且是块设备文件

test –L File 文件存在并且是一个符号链接(同-h)

test –o File 文件存在并且属于有效用户ID

test –p File 文件存在并且是一个命名管道

test –r File 文件存在并且可读

test –s File 文件存在并且是一个套接字

test –t FD 文件描述符是在一个终端打开的

test –u File 文件存在并且设置了它的set-user-id位

test –w File 文件存在并且可写

test –x File 文件存在并且可执行

 

 

2.    find 命令

find命令的一般格式为:

find [-H] [-L] [-P] [path...] [expression]

 

其中,'-H' '-L' '-P'三个选项主要是用来处理符号连接,

'-H'表示只跟随命令行中指定的符号连接,

'-L'表示跟随所有的符号连接,

'-P'是默认的选项,表示不跟随符号连接。

 

具体参考: http://pipal.iteye.com/blog/307127

3.2> /dev/null

 shell中可能经常能看到:>/dev/null 2>&1

命令的结果可以通过%>的形式来定义输出

分解这个组合:“>/dev/null 2>&1” 为五部分。

1代表重定向到哪里,例如:echo "123" > /home/123.txt
2
/dev/null 代表空设备文件
3
2> 表示stderr标准错误
4
表示等同于的意思,2>&1,表示2的输出重定向等同于1
5
表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 "1>/dev/null"

因此,>/dev/null 2>&1也可以写成“1> /dev/null 2> &1”

那么本文标题的语句执行过程为:
1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,说白了就是不显示任何信息。
2>&1 :接着,标准错误输出重定向到 标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。

说清楚了吗,大家理解下吧!

顺便对比述说下这么用的好处!

   最常用的方式有:

command > file 2>file  command > file 2>&1

它们 有什么不同的地方吗?


首先command > file 2>file 的意思是将命令所产生的标准输出信息,和错误的输出信息送到file 中.command  > file 2>file 这样的写法,stdout和stderr都直接送到file中, file会被打开两次,这样stdout和stderr会互相覆盖,这样写相当使用了FD1和FD2两个同时去抢占file 的管道。
而command >file 2>&1 这条命令就将stdout直接送向file, stderr 继承了FD1管道后,再被送往file,此时,file 只被打开了一次,也只使用了一个管道FD1,它包括了stdout和stderr的内容。
从IO效率上,前一条命令的效率要比后面一条的命令效率要低,所以在编写shell脚本的时候,较多的时候我们会command > file 2>&1 这样的写法。

以上内容可以查看:http://ppp1013.blog.51cto.com/927700/271043

4.    If 语句中的-z –d等

-d :判断制定的是否为目录

-z:判断制定的变量是否存在值

-f:判断制定的是否为文件

-L:判断制定的是否为符号链接

-n :判断字符是否为空

-r:判断制定的是否可读

-s:判断存在的对象长度是否为0

-w:判断制定的是否可写

-x:判断存在的对象是否可以执行

!:测试条件的否定符号

-lt,小于

-le,小于等于

-eq,等于

-ge,大于等于

-gt,大于

-ne,不等于

 

5.    sed

sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换、删除、新增、选取等特定工作,下面先了解一下sed的用法

sed命令行格式为:

sed [-nefri] ‘command’输入文本       

常用选项:

-n∶使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN的资料一般都会被列出到萤幕上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。

-e∶直接在指令列模式上进行 sed 的动作编辑;

-f∶直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的sed 动作;

-r∶sed 的动作支援的是延伸型正规表示法的语法。(预设是基础正规表示法语法)

-i∶直接修改读取的档案内容,而不是由萤幕输出。      

常用命令:

a   ∶新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~

c   ∶取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!

d   ∶删除,因为是删除啊,所以 d 后面通常不接任何咚咚;

i   ∶插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);

p  ∶列印,亦即将某个选择的资料印出。通常 p 会与参数 sed -n 一起运作~

s  ∶取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!

举例:(假设我们有一文件名为ab)

     删除某行

[root@localhost ruby] # sed '1d' ab              #删除第一行

[root@localhost ruby] # sed '$d' ab              #删除最后一行

[root@localhost ruby] # sed '1,2d' ab           #删除第一行到第二行

[root@localhost ruby] # sed '2,$d' ab           #删除第二行到最后一行

  显示某行

.[root@localhost ruby] # sed -n '1p' ab           #显示第一行

[root@localhost ruby] # sed -n '$p' ab           #显示最后一行

[root@localhost ruby] # sed -n '1,2p' ab        #显示第一行到第二行

[root@localhost ruby] # sed -n '2,$p' ab        #显示第二行到最后一行

  使用模式进行查询

[root@localhost ruby] # sed -n '/ruby/p' ab    #查询包括关键字ruby所在所有行

[root@localhost ruby] # sed -n '/\$/p' ab        #查询包括关键字$所在所有行,使用反斜线\屏蔽特殊含义

  增加一行或多行字符串

[root@localhost ruby]# cat ab

Hello!

ruby is me,welcome to my blog.

end

[root@localhost ruby] # sed '1a drink tea' ab  #第一行后增加字符串"drink tea"

Hello!

drink tea

ruby is me,welcome to my blog.

end

[root@localhost ruby] # sed '1,3a drink tea' ab #第一行到第三行后增加字符串"drink tea"

Hello!

drink tea

ruby is me,welcome to my blog.

drink tea

end

drink tea

[root@localhost ruby] # sed '1a drink tea\nor coffee' ab   #第一行后增加多行,使用换行符\n

Hello!

drink tea

or coffee

ruby is me,welcome to my blog.

end

  代替一行或多行

[root@localhost ruby] # sed '1c Hi' ab                #第一行代替为Hi

Hi

ruby is me,welcome to my blog.

end

[root@localhost ruby] # sed '1,2c Hi' ab             #第一行到第二行代替为Hi

Hi

end

  替换一行中的某部分

  格式:sed 's/要替换的字符串/新的字符串/g'   (要替换的字符串可以用正则表达式)

[root@localhost ruby] # sed -n '/ruby/p' ab | sed 's/ruby/bird/g'    #替换ruby为bird

   [root@localhost ruby] # sed -n '/ruby/p' ab | sed 's/ruby//g'        #删除ruby

     插入

[root@localhost ruby] # sed -i '$a bye' ab         #在文件ab中最后一行直接输入"bye"

[root@localhost ruby]# cat ab

Hello!

ruby is me,welcome to my blog.

end

bye

6. tee 命令详解

 

功能说明:读取标准输入的数据,并将其内容输出成文件。

语  法:tee [-ai][--help][--version][文件...]

补充说明:tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。

 

参  数:

 -a或--append  附加到既有文件的后面,而非覆盖它.

 -i-i或--ignore-interrupts  忽略中断信号。

 --help  在线帮助。

 --version  显示版本信息。

 

四.总结

Android 编译系统很复杂,涉及的东西太多,想要详细的了解,是需要大量的时间和足够的耐心,同时需要了解Makefile和shell脚本.因为这次发现mtk 释放的Android L source 居然可以使用google 推荐的命令来编译,所以就想了解一下这个编译过程,在学习的过程中,遇到了很多不懂地方,自己或许还是会继续加强自己这方面的知识.

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值