Makefile语法基础介绍

来源:互联网 发布:appstore安装不了软件 编辑:程序博客网 时间:2024/05/22 06:34

在Linux下,make是一个命令工具,是一个解释Makefile中指令的命令工具。make命令执行时,需要一个Makefile文件,以告诉make命令需要怎么样去编译和链接程序。

make如何工作:在默认的方式下,只输入make命令,那么:

(1)、make会在当前目录下找名字叫”Makefile”或”makefile”的文件;

(2)、如果找到,它会找文件中的第一个目标文件(target),并把这个文件作为最终的目标文件;

(3)、如果目标文件不存在,或是目标文件所依赖的后面的.o文件的修改时间要比这个目标文件新,那么,它就会执行后面所定义的命令来生成目标文件;

(4)、如果目标文件所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件;

(5)、当然,对应的.c和.h文件是存在的,于是make会生成.o文件,然后再用.o文件生成make的终极任务,也就是执行文件(目标文件)了。

Makefile里主要包含了5部分:显示规则、隐晦规则、变量定义、文件指示和注释

(1)、显示规则:显示规则说明了,如何生成一个或多个的目标文件。这是由Makefile的书写者明显指出要生成的文件,文件的依赖文件,生成的命令。

(2)、隐晦规则:由于make有自动推导的功能,所以隐晦规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。

(3)、变量定义:在Makefile中要定义一系列的变量,变量一般都是字符串。当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。

(4)、文件指示:其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样,另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样,还有就是定义一个多行的命令。

(5)、注释:Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用”#”字符,这个就像C/C++中的”//”一样。如果要在你的Makefile中使用”#”字符,可以用反斜框进行转义,如”\#”。

在Makefile中的命令,必须要以[Tab]键开始

Makefile的文件名:默认的情况下,make命令会在当前目录下按顺序找寻文件名为”GNUmakefile”、”makefile”、”Makefile”的文件,找到了解释这个文件。在这三个文件名中,最好使用”Makefile”这个文件名。最好不要用”GNUmakefile”,这个文件是GNU的make识别的。有另外一些make只对全小写的”makefile”文件名敏感,但是基本上来说,大多数的make都支持”makefile”和”Makefile”这两种默认文件名。

当然,你可以使用别的文件名来书写Makefile,比如”Make.Linux”等,如果要指定特定的Makefile,你可以使用make的”-f”和”--file”参数,如make  -f Make.Linux或make  --file  Make.Linux.

引用其它的Makefile:在Makefile使用include关键字可以把别的Makefile包含进来,被包含的文件会原模原样的放在当前文件的包含位置。

include的语法是:include filename

filename可以是当前操作系统Shell的文件模式(可以包含路径和通配符)。

在include前面可以有一些空字符,但是决不能是[Tab]键开始。include和filename可以用一个或多个空格隔开。

make命令开始时,会找寻include所指出的其它Makefile,并把其内容安置在当前的位置。如果文件都没有指定绝对路径或是相对路径的话,make会在当前目录下首先寻找,如果当前目录下没有找到,那么,make还会再下面的几个目录下找:(1)、如果make执行时,有”-I”或”--include-dir”参数,那么make就会在这个参数所指定的目录下去寻找;(2)、如果目录<prefix>/include(一般是:/usr/local/bin或/usr/include)存在的话,make也会去找。

如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或是不能读取的文件,如果还是不行,make才会出现一条致命信息。如果你想让make不理那些无法读取的文件,而继续执行,你可以在include前加一个减号”-”,如-include filename,其表示,无论include过程中出现什么错误,都不要报错继续执行。和其它版本make兼容的相关命令是sinclude,其作用和这一个是一样的。

环境变量MAKEFILES:如果你的当前环境中定义了环境变量MAKEFILES,那么,make会把这个变量中的值做一个类似于include的动作。这个变量中的值是其它的Makefile,用空格分隔。只是,它和include不同的是,从这个环境变量中引入的Makefile的”目标”不会起作用,如果环境变量中定义的文件发现错误,make也不会理。建议,不要使用这个环境变量,因为只要这个变量一被定义,那么当你使用make时,所有的Makefile都会受到它的影响。

GNU的make工作时的执行步骤

(1)、读入所有的Makefile;

(2)、读入被include的其它Makefile;

(3)、初始化文件中的变量;

(4)、推导隐晦规则,并分析所有规则;

(5)、为所有的目标文件创建依赖关系链;

(6)、根据依赖关系,决定哪些目标要重新生成;

(7)、执行生成命令。

Makefile文件书写规则

targets:  prerequisitescommand... ...
或者:

targets: prerequisites ; commandcommand... ...

targets是文件名,以空格分开,可以使用通配符。一般来说,目标基本上是一个文件,但也有可能是多个文件。

command是命令行,如果其不与”targets: prerequisites”在一行,那么,必须以[Tab]键开头,如果和prerequisites在一行,那么可以用分号作为分隔。

prerequisites也就是目标所依赖的文件(或依赖目标)。如果其中的某个文件要比目标文件要新,那么,目标就被认为是”过时的”,被认为是需要重新生成的。

如果命令太长,可以使用反斜框(‘\’)作为换行符。make对一行上有多少个字符没有限制。

在规则中使用通配符:make支持三种通配符:”*”、”?”、”[…]”。这和Unix的B-Shell是相同的。

波浪号(“~”)字符在文件名中也有比较特殊的用途。如果是”~/test”,这就表示当前用户的$HOME目录下的test目录。而”~spring/test”则表示用户spring的宿主目录下的test目录。

文件搜寻:Makefile文件中的特殊变量”VPATH”可以实现文件搜寻,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当前目录找不到的情况下,到所指定的目录中去找寻文件。

另一个设置文件搜索路径的方法是使用make的”vpath”关键字(注意,它是全小写的),这不是变量,这是一个make的关键字,它和VPATH变量很类似。它可以指定不同的文件在不同的搜索目录中。

伪目标:”伪目标”并不是一个文件,只是一个标签,由于”伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显示地指明这个”目标”才能让其生效。当然,”伪目标”的取名不能和文件名重名,不然其就失去了”伪目标”的意义了。为了避免和文件重名的这种情况,我们可以使用一个特殊的标记”.PHONY”来显示地指明一个目标是”伪目标”,向make说明,不管是否有这个文件,这个目标就是”伪目标”。

伪目标一般没有依赖的文件。但是,我们也可以为伪目标指定所依赖的文件。伪目标同样可以作为”默认目标”,只要将其放在第一个。

多目标:Makefile的规则中目标可以不止一个,其支持多目标

静态模式:可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。

自动生成依赖性:大多数的C/C++编译器都支持一个”-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。如果你使用GNU的C/C++编译器,你得用”-MM”参数,不然,”-M”参数会把一些标准库的头文件也包含进来。

书写命令:每条规则中的命令和操作系统Shell的命令行是一致的。make会按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟在依赖规则后面的分号后的。在命令行之间的空格或是空行会被忽略,但是如果该空格或空行是以[Tab]键开头的,那么make会认为其是一个空命令。

make的命令默认是被”/bin/sh”----UNIX的标准Shell解释执行的。除非你特别指定一个其它的Shell。

显示命令:通常,make会把其要执行的命令行在命令执行前输出到屏幕上。当我们用”@”字符在命令行前,那么这个命令将不被make显示出来。如果make执行时,带入make参数”-n”或”--just-print”,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的Makefile,看看我们书写的命令是执行起来是什么样子的或是什么顺序的。

命令执行:当依赖目标新于目标时,也就是当规则的目标需要被更新时,make会一条一条的执行其后的命令。需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令

#如果要让上一条命令的结果应用于下一条命令时,#应该使用分号分隔这两条命令#注意以下两者的区别exec:@cd /home/spring; pwd #希望得到的结果@cd /home/springpwd

make一般是使用环境变量SHELL中所定义的系统Shell来执行命令,默认情况下使用UNIX的标准Shell----/bin/sh来执行命令。

忽略命令的出错,我们可以在Makefile的命令行前加一个减号”-”(在Tab键之后),标记为不管命令出不出错都认为是成功的。还有一个全局的办法是,给make加上”-i”或是”--ignore-errors”参数,那么,Makefile中所有命令都会忽略错误。

嵌套执行make:可以通过export命令传递变量到下级Makefile中。需要注意的是,有两个变量,一个是SHELL,一个是MAKEFLAGS,这两个变量不管你是否export,其总是要传递到下层Makefile中,特别是MAKEFLAGS变量,其中包含了make的参数信息。但是make命令中有几个参数并不往下传递,它们是”-C”、”-f”、”-h”、”-o”和”-W”。”-w”或是”--print-directory”会在make的过程中输出一些信息,让你看到目前的工作目录。

定义命令包:如果Makefile中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量。定义这种变量序列的语法以”define”开始,以”endef”结束。

使用变量:在Makefile中定义的变量,就像是C/C++语言中的宏一样,它代表了一个文本字串,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。其与C/C++所不同的是,你可以在Makefile中改变其值。在Makefile中,变量可以使用在”目标”、”依赖目标”、”命令”或是Makefile的其它部分中。

变量的名字可以包含字符、数字、下划线(可以是数字开头),但不应该含有”:”、”#”、”=”或是空字符(空格、回车等)。变量是大小写敏感的。传统的Makefile的变量名是全大写的命名方式,但推荐使用大小写搭配的变量名,这样可以避免和系统的变量冲突,而发生意外的事情。

变量的基础:变量在声明时需要给予初值,而在使用时,需要给在变量名前加上”$”,但最好用小括号”()”或是大括号”{}”把变量给包起来。如果你要使用真实的”$”字符,那么你需要用”$$”来表示

变量中的变量:在定义变量的值时,我们可以使用其它变量来构造变量的值,在Makefile中有两种方式来用变量定义变量的值:(1)、简单的使用”=”号,在”=”左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值;(2)、使用”:=”操作符,这种方法,前面的变量不能使用后面的变量,只能使用前面已经定义好了的变量。

#变量中的变量#使用“=”,右侧的变量不一定非要是已定义好的值,其也可以使用后面定义的值foo = $(bar) hello bar = $(ugn)ugn = spring#使用":="操作符,前面的变量不能使用后面的变量,#只能使用前面已经定义好了变量,此时y的值为funy := $(x)funx := test exec:echo $(foo) #spring helloecho $(y) #fun

#定义一个变量其值是空格#但是这个例子好像并没有起到作用????   nullstring :=space := $(nullstring)#end of the lineout := spring$(space)spring#以下这个例子可以获得预期的结果dir := /bin/sh     #directorypath := $(dir)/fileexec:echo $(out) #springspringecho $(path) #/bin/sh /file

#变量值的替换#将变量foo中全部以.o字串结尾全部替换成.cfoo := a.o b.o c.obar := $(foo:.o=.c)#静态模式实现变量值的替换:依赖被替换字串中有相同模式bar1 := $(foo:%.o=%.c)#把变量的值再当成变量x = $(y)y = zz = Helloa := $($(x))exec:echo $(bar) #a.c b.c c.cecho $(bar1) #a.c b.c c.cecho $(a) #Hello

还有一个比较有用的操作符”?=”,如foo  ?=  bar,其含义是,如果foo没有被定义过,那么变量foo的值就是”bar”,如果foo先前被定义过,那么这条语句将什么也不做。

变量高级用法:(1)、变量值的替换:可以替换变量中共有的部分,其格式是”$(var:a=b)”或是”${var:a=b}”,其意思是,把变量”var”中所有以”a”字串”结尾”的”a”替换成”b”字符串。这里的”结尾”意思是”空格”或是”结束符”。另外一种变量替换的技术是以”静态模式”定义的,其格式是”$(var:%.a=%.b)”,这依赖于被替换字串中有相同的模式。(2)、把变量的值再当成变量。

追加变量值:可以使用”+=”操作符给变量追加值。如果变量之前没有定义过,那么,”+=”会自动变成”=”,如果前面有变量定义,那么”+=”会继承于前次操作的赋值符。如果前一次的是”:=”,那么”+=”会以”:=”作为起赋值符。

#追加变量值objects = main.o foo.o bar.o#下面两行语句等价#objects := $(objects) another.oobjects += another.ovariable := value#下面两行语句等价#variable := $(variable) morevariable += moreexec:echo $(objects) #main.o foo.o bar.o another.oecho $(variable) #value more

override指示符:有些变量通常是make的命令行参数设置的,那么Makefile中对这个变量的赋值会被忽略。如果想在Makefile中设置这类参数的值,那么,可以使用”override”指示符。

多行变量:使用define关键字设置变量的值可以有换行,这有利于定义一系列的命令。define指示符后面跟的是变量的名字,而重起一行定义变量的值,定义是以endef关键字结束。其工作方式和”=”操作符一样。变量的值可以包含函数、命令、文字,或是其它变量。因为命令需要以[Tab]键开头,所以如果你用define定义的命令变量中没有以[Tab]键开头,那么make就不会把其认为是命令。

环境变量:make运行时的系统环境变量可以在make开始运行时被载入到Makefile文件中,但是如果Makefile中已定义了这个变量,或是这个变量由make命令行带入,那么系统的环境变量的值将被覆盖(如果make指定了”-e”参数,那么,系统环境变量将覆盖Makefile中定义的变量)。

使用条件判断:可以让make根据运行时的不同情况选择不同的执行分支。条件表达式可以是比较变量的值,或是比较变量和常量的值:ifeq、ifneq、ifdef、ifndef。注意:make在读取Makefile时就计算条件表达式的值,并根据条件表达式的值来选择语句,所以,最好不要把自动化变量(如”$@”等)放入条件表达式中,因为自动化变量是在运行时才有的。而且,make不允许把整个条件语句分成两部分放在不同的文件中。

#使用条件判断#ifdefbar = foo = $(bar)ifdef foo    frobozz = yeselse    frobozz = noendif#ifeqifeq ($(CC), gcc)    b = gccelse    b = otherendifexec:echo $(frobozz) #yesecho $(b) 

使用函数:在Makefile中可以使用函数来处理变量。函数调用后,函数的返回值可以当作变量来使用。函数参数间以逗号”,”分隔,而函数名和参数之间以”空格”分隔。函数调用以”$”开头,以圆括号或花括号把函数名和参数括起

#使用函数#substcomma := ,empty :=  space := $(empty) $(empty)foo := a b cbar := $(subst $(space),$(comma),$(foo))#sortstr := foo bar losestr := $(sort $(str))#foreachnames := a b c dfiles := $(foreach n,$(names),$(n).o)#shelldirectory := $(shell pwd)exec:echo $(bar) #a,b,cecho $(str) #bar foo loseecho $(files) #a.o b.o c.o d.oecho $(directory)

常用的字符串处理函数有:subst、patsubst、strip、findstring、filter、filter-out、sort、word、wordlist、words、firstword。

文件名操作函数:每个函数的参数字符串都会被当作一个或是一系列的文件名来对待。常用的函数有:dir、notdir、suffix、basename、 addsuffix、addprefix、join。

foreach函数:这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照Unix标准Shell(/bin/sh)中的for语句,或是C-Shell(/bin/csh)中的foreach语句而构建的。

if函数:if函数很像GNU的make所支持的条件语句ifeq。if函数可以包含”else”部分,或是不含。即if函数的参数可以是两个,也可以是三个。

call函数:是唯一一个可以用来创建新的参数化的函数。

origin函数:它并不操作变量的值,它只是告诉你这个变量是哪里来的。

shell函数:它的参数应该就是操作系统Shell的命令,它和反引号”`”是相同的功能。这就是说,shell函数把执行操作系统命令后的输出作为函数返回。于是,可以用操作系统命令以及字符串处理命令awk、sed等命令来生成一个变量。

控制make的函数:error、warning。

make的运行:一般来说,最简单的就是直接在命令行下输入make命令,make命令会找当前目录的Makefile来执行,一切都是自动的。

make的退出码:0,表示成功执行;1,如果make运行时出现任何错误,其返回1;2,如果你使用了make的”-q”选项,并且make使得一些目标不需要更新,那么返回2.

指定Makefile:GNU make找寻默认的Makefile的规则是在当前目录下依次找三个文件----“GNUmakefile”、”makefile”和”Makefile”。其按顺序找这三个文件,一旦找到,就开始读取这个文件并执行。

我们也可以给make命令指定一个特殊名字的Makefile。要达到这个功能,要使用make的”-f”或是”--file”参数(“--makefile”参数也行)。

指定目标:一般来说,make的最终目标是makefile中的第一个目标,而其它目标一般是由这个目标连带出来的。这是make的默认行为。若要指示make,让其完成你所指定的目标,需要在make命令后直接跟目标的名字

任何在makefile中的目标都可以被指定成终极目标,但是除了以”-”打头,或是包含了”=”的目标,因为有这些字符的目标,会被解析成命令行参数或是变量

隐含规则:也就是一种惯例,make会按照这种”惯例”来运行,哪怕我们的Makefile中没有书写这样的规则。

隐含规则使用的变量:可以把隐含规则中使用的变量分成两种,一种是命令相关的,如”CC”,一种是参数相关的,如”CFLAGS”。

命令相关的变量:

(1)、AR:函数库打包程序,默认命令是”ar”;

(2)、AS:汇编语言编译程序,默认命令是”as”;

(3)、CC:C语言编译程序,默认命令是”cc”;

(4)、CXX:C++语言编译程序,默认命令是”g++”;

(5)、CO:从RCS文件中扩展文件程序,默认命令是”co”;

(6)、CPP:C程序的预处理器(输出是标准输出设备),默认命令是”$(CC)-E”;

(7)、FC:Fortran和Ratfor的编译器和预处理程序,默认命令是”f77”;

(8)、GET:从SCCS文件中扩展文件的程序,默认命令是”get”;

(9)、LEX:Lex方法分析器程序(针对于C或Ratfor),默认命令是”lex”;

(10)、PC:Pascal语言编译程序,默认命令是”pc”;

(11)、YACC:Yacc文法分析器(针对于C程序),默认命令是”yacc”;

(12)、YACCR:Yacc文法分析器(针对于Ratfor程序),默认命令是”yacc-r”;

(13)、MAKEINFO:转换Texinfo源文件(.texi)到Info文件程序,默认命令是”makeinfo”;

(14)、TEX:从TeX源文件创建TeX DVI文件的程序,默认命令是”tex”;

(15)、TEXI2DVI:从Texinfo源文件创建TeX DVI文件的程序,默认命令是”texi2dvi”;

(16)、WEAVE:转换Web到TeX的程序,默认命令是”weave”;

(17)、CWEAVE:转换C Web到TeX的程序,默认命令是”cweave”;

(18)、TANGLE:转换Web到Pascal语言的程序,默认命令是”tangle”;

(19)、CTANGLE:转换C Web到C,默认命令是”ctangle”;

(20)、RM:删除文件命令,默认命令是”rm-f”。

参数相关的变量:如果没有指明其默认值,那么其默认值都是空。

(1)、ARFLAGS:函数库打包程序AR命令的参数,默认是”rv”;

(2)、ASFLAGS:汇编语言编译器参数(当明显地调用”.s”或”.S”文件时);

(3)、CFLAGS:C语言编译器参数;

(4)、CXXFLAGS:C++语言编译器参数;

(5)、COFLAGS:RCS命令参数;

(6)、CPPFLAGS:C预处理器参数(C和Fortran编译器也会用到);

(7)、FFLAGS:Fortran语言编译器参数;

(8)、GFLAGS:SCCS “get”程序参数;

(9)、LDFLAGS:链接器参数,如”ld”;

(10)、LFLAGS:Lex文法分析器参数;

(11)、PFLAGS:Pascal语言编译器参数;

(12)、RFLAGS:Ratfor程序的Fortran编译器参数;

(13)、YFLAGS:Yacc文法分析器参数。

定义模式规则:可以使用模式规则来定义一个隐含规则,一个模式规则就好像一个一般的规则,只是在规则中,目标的定义需要有”%”字符。”%”的意思是表示一个或多个任意字符。在依赖目标中同样可以使用”%”,只是依赖目标中的”%”的取值,取决于其目标。注意:”%”的展开发生在变量和函数的展开之后,变量和函数的展开发生在make载入Makefile时,而模式规则中的”%”则发生在运行时

自动化变量:就是这种变量会把模式中所定义的一系列的文件自动地挨个取出,直至所有符合模式的文件都取完了。这种自动化变量只应出现在规则的命令中

以下是自动化变量的说明:

(1)、$@:表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,”$@”就是匹配于目标中模式定义的集合;

(2)、$%:仅当目标是函数库文件时,表示规则中的目标成员名。如果目标不是函数库文件,那么,其值为空;

(3)、$<:依赖目标中的第一个目标名字。如果依赖目标是以模式(即”%”)定义的,那么”$<”将是符合模式的一系列的文件集,注意,其是一个一个取出来的;

(4)、$?:所有比目标新的依赖目标的集合,以空格分隔;

(5)、$^:所有依赖目标的集合,以空格分隔,如果在依赖目标中有多个重复的,那么这个变量会出去重复的依赖目标,只保留一份;

(6)、$+:这个变量很像”$^”,也是所有依赖目标的集合,只是它不去除重复的依赖目标;

(7)、$*:这个变量表示目标模式中”%”及其之前的部分。如果目标是”dir/a.foo.b”,并且目标的模式是”a.%.b”,那么,”$*”的值就是”dir /a.foo”。如果目标中没有模式的定义,那么”$*”也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么”$*”就是除了后缀的那一部分。例如,如果目标是”foo.c”,因为”.c”是make所能识别的后缀名,所以,”$*”的值就是”foo”。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,应该尽量避免使用”$*”。

使用make更新函数库文件:函数库文件也就是对Object文件(程序编译的中间文件)的打包文件。在Unix下,一般是由命令”ar”来完成打包工作。

以上内容整理自陈皓的CSDN博客:http://blog.csdn.net/haoel/article/category/9198

GitHub:https://github.com/fengbingchun/Linux_Code_Test

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华为m9手机声音小怎么办 放卡的地方堵住怎么办 美图m8蓝屏了怎么办 美图m8手机蓝屏怎么办 美图m6s手机白屏怎么办 魅蓝2开不开机怎么办 魅族手机主键没反应怎么办 魅族手机主键失灵怎么办 手机4g网络不稳定怎么办 华为m9收不到手机信息怎么办 华为手机wifi信号弱怎么办 手机连接wifi信号差怎么办 华华为p10信号不好怎么办 烟没拆封受潮了怎么办 和亲儿子发生了性关系怎么办 无心磨磨出来圆度不好怎么办 中国人在越南办结婚证怎么办? 无线网被限速了怎么办 联通大王卡上传速度慢怎么办 小米手机下载视频速度慢怎么办 大疆御air脚架断了怎么办 大疆飞行器线断了怎么办 移动校园卡套餐到期后怎么办 流量年包到期了怎么办 家里无线网信号不好怎么办 无线网光信号红灯了怎么办 机顶盒获取不了lp地址怎么办 32内存卡丢了怎么办 手机上的相机找不到了怎么办 有刘鑫这样的闺蜜该怎么办 电脑开机网络初始化失败怎么办 电脑放音乐没有声音怎么办 苹果手机gprs信号弱怎么办 苹果导航gprs信号弱怎么办 au没有波形 没有声音怎么办 屏幕驱动板坏了怎么办 安吉星流量超了怎么办 网络被伪基站覆盖怎么办 骨头渣子卡嗓子里怎么办 执法仪记录仪关不了机怎么办 执法记录仪开不了机怎么办