书签 分享 收藏 举报 版权申诉 / 39
上传文档赚钱

类型嵌入式系统原理与技术课件:makefile的编写.ppt

  • 上传人(卖家):罗嗣辉
  • 文档编号:2046063
  • 上传时间:2022-01-21
  • 格式:PPT
  • 页数:39
  • 大小:701KB
  • 【下载声明】
    1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
    2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
    3. 本页资料《嵌入式系统原理与技术课件:makefile的编写.ppt》由用户(罗嗣辉)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
    4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
    5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
    配套讲稿:

    如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。

    特殊限制:

    部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。

    关 键  词:
    嵌入式 系统 原理 技术 课件 makefile 编写
    资源描述:

    1、Makefile编写目的:掌握 make 的基本语法,使用make编译程序。8.1.1Make 概述w makefile定义整个工程的编译规则w一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。w 自动化编译 w只需要一个make命令,整个工程完全自动编译 ;wmake是一个命令工具,是一个解释makefile中指令的命令工具;一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C+的nmake,Linux下GNU的

    2、make。可见,makefile都成为了一种在工程方面的编译方法。Makefile里主要有什么w 显式规则、隐晦规则、变量定义、文件指示和注释。w w1、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。w w2、隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。w w3、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的

    3、引用位置上。w w4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。w w5、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“#”。8.1.2关于程序的编译和链接 w 无论是C、C+,首先要把源文件编译成中间代码文件,在Windows下是 .obj

    4、 文件,UNIX下是 .o 文件,即目标文件,这个动作叫做编译(compile)。w 然后再把大量的目标文件链接成执行文件,这个动作叫作链接(link)。w 编译编译时,编译器检查语法,函数与变量的声明是否正确。对于声明,通常需要你告诉编译器头文件所在的位置(头文件中应该只是声明,而定义应该放在源文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件可以生成一个中间目标文件(.o文件或是.obj文件)。关于程序的编译和链接 w 链接链接时,主要是找到函数和全局变量的定义。w 链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File)。在大多数时候

    5、,由于源文件太多,编译生成的目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件 或.sow 下面是一个包含三个文件的工程8.1.3准备文件file1.c#include #include file2.hint main() printf(print file1n); File2Print(); return 0;返回返回准备文件file2.c#include file2.hvoid Fil

    6、e2Print() printf(Print file2n);返回返回准备文件file2.h#ifndef FILE2_H_#define FILE2_H_#includevoid File2Print();#endif返回返回8.1.4Makefile里的主要规则target . : prerequisites .command.1.target是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(伪目标) 。2.prerequisites是要生成那个target所需要的文件或是目标。mand也就是make需要执行的命令。(任意的Shell命令)文件的依赖关系,也

    7、就是说,target是需要生成的一个或多个文件,它们依赖于 prerequisites.中列出的文件,通过执行command来生成target.。一个规则可以有多个命令行,每一条命令占一行。 注意:每一个命令行必须以Tab字符开始,Tab字符告诉 make 此行是一个命令行。make按照命令完成相应的动作。这也是书写 Makefile 中容易产生,而且比较隐蔽的错误。这就是Makefile的规则,也是Makefile中最核心的内容。helloworld:file1.o file2.ogcc file1.o file2.o -o helloworldfile1.o:file1.c file2.h

    8、gcc -c file1.c -o file1.ofile2.o:file2.c file2.hgcc -c file2.c -o file2.oclean:rm -rf *.o helloworld编写Makefile文件详细解读Makefile文件helloworld : file1.o file2.ogcc file1.o file2.o -o helloworld helloworld依赖file1.o file2.o两个文件编译出helloworld可执行文件。-o表示指定 的目标文件名。 若file1.o和file2.o都存在,但是其中一个比helloworld新或hellowor

    9、ld不存在时,执行下面的gcc命令。 若file1.o和file2.o有任意一个不存在,假设是file1.o,会先找到file1.o的生成关系,生成file1.o后,再执行下面的gcc命令。详细解读Makefile文件(续)file1.o : file1.c file2.hgcc -c file1.c -o file1.o file1.o依赖file1.c 和file2.h这两个文件,编译出file1.o文件。 若依赖文件中有任意一个文件不存在或比file1.o新,都会重新执行下面的gcc命令。 -c表示gcc 只把给它的文件编译成.o文件,用源码文件的文件名命名但把其后缀由“.c” 变成“.

    10、o”。在这句中,可以省略-o file1.o,编译器默认生成file1.o文件,这就是-c的作用。file2.o : file2.c file2.h gcc -c file2.c -o file2.o这两句的功能同上。返回返回详细解读Makefile文件(续)clean: rm -rf *.o helloworld#当用户输入make clean命令时,会执行rm指令,其功能是删除*.o 和helloworld文 件。 写好Makefile文件,在命令行中直接键入make命令,就会执行Makefile中的内容了 返回返回w 假设一个工程有3个头文件,和8个源文件,我们按照那三个规则写出的mak

    11、efile应该是下面的这个样子的。w w edit :main.o kbd.o command.o display.o w insert.o search.o files.o utils.ow cc -o edit main.o kbd.o command.o display.o w insert.o search.o files.o utils.ow main.o : main.c defs.hw cc -c main.cw kbd.o : kbd.c defs.h command.hw cc -c kbd.cw command.o : command.c defs.h command.hw

    12、 cc -c command.cw display.o : display.c defs.h buffer.hw cc -c display.cw insert.o : insert.c defs.h buffer.hw cc -c insert.cw search.o : search.c defs.h buffer.hw cc -c search.cw files.o : files.c defs.h buffer.h command.hw cc -c files.cw utils.o : utils.c defs.hw cc -c utils.cw clean :w rm edit ma

    13、in.o kbd.o command.o display.o w insert.o search.o files.o utils.ow 在这个makefile中,w 目标文件(target)包含:执行文件edit和中间目标文件(*.o)。依赖文件(prerequisites)就是冒号后面的那些 .c 文件和 .h文件。w 每一个 .o 文件都有一组依赖文件,而这些 .o 文件又是执行文件 edit 的依赖文件。w 依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。 make如何工作在默认的方式下,也就是我们只输入make命令。那么:w 1、make会在当前

    14、目录下找名字叫“Makefile”或“makefile”的文件。w 2、默认的情况下,make执行的是Makefile中的第一个规则。此规则的第一个目标称之为“最终目的”或者“终极目标”。在上面的例子中,它会找文件中的第一个目标文件(target),即“edit”这个文件,并把这个文件作为最终的目标文件。w 3、如果edit文件不存在,或是edit所依赖的后面的 .o 文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。w 4、如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为该.o文件的依赖规则,如果找到则再根据那一个规则生

    15、成.o文件。(这有点像一个栈的过程)w 5、前提你的.c文件和.h文件是存在make如何工作w 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。w 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。w 通过上述分析,我们知道,像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令“make clean”,以此来清除所有的目标文件,以便重编译。 使用变量w 取得变量

    16、值的方式:$(变量名)或 $变量名 w 定义变量w =n使用时展开w :=n定义时即展开(只能使用已经定义好的变量)w +=n变量追加w ?=n若未定义则定义,若已定义则不执行此定义w 例如:例如:w objects = main.o kbd.o command.o display.o w insert.o search.o files.o utils.ow 于是,我们就可以很方便地在我们的makefile中以“$(objects)”的方式来使用这个变量了变量基础w objects = program.o foo.o utils.ow program : $(objects)w cc -o p

    17、rogram $(objects) 或者:cc $ -o $ $和$属于自动化变量 $ 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,$就是匹配于目标中模式定义的集合。这里是 program$所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。 这里是$(objects)w $(objects) : defs.h 变量会在使用它的地方精确地展开,就像C/C+中的宏一样Makefile里使用变量OBJS = file1.o file2.oCC = gccCFLAGS = -Wall -O g-Wall:输出所有的警告信息;-

    18、O:在编译时进行优化;-g:表示编译debug版本。helloworld : $(OBJS)$(CC) $(OBJS) -o helloworldfile1.o : file1.c file2.h$(CC) $(CFLAGS) -c file1.c -o file1.ofile2.o : file2.c file2.h$(CC) $(CFLAGS) -c file2.c -o file2.oclean:rm -rf *.o helloworld返回返回自动推导-隐晦规则?w GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个.o文件后都写上类似的命

    19、令,因为,我们的make会自动识别,并自己推导命令。w w 只要make看到一个.o文件,它就会自动的把.c文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。并且 gcc -c whatever.c 也会被推导出来,于是,我们的makefile再也不用写得这么复杂。我们的是新的makefile又出炉了。自动推导-隐晦规则?前面的makefile可以这么写:w objects = main.o kbd.o command.o display.o w insert.o search.o files.o utils.ow e

    20、dit : $(objects)w cc -o edit $(objects)w main.o : defs.hw kbd.o : defs.h command.hw command.o : defs.h command.hw display.o : defs.h buffer.hw insert.o : defs.h buffer.hw search.o : defs.h buffer.hw files.o : defs.h buffer.h command.hw utils.o : defs.hw .PHONY : cleanw clean :w rm edit $(objects)w M

    21、ake又是如何实现自动推导的呢?在隐含规则中的命令中,基本上都是使用了一些预先设置的变量。你可以在你的makefile中改变这些变量的值。w 比如,编译C程序的隐含规则的命令是:$(CC) c $(CFLAGS) $(CPPFLAGS)w Make默认的编译命令是“cc”,如果你把变量“$(CC)”重定义成 “gcc”,把变量“$(CFLAGS)”重定义成“-g”,那么,隐含规则中的命令全部会以“gcc c -g $(CPPFLAGS)”的样子来执行了。 我们可以把隐含规则中使用的变量分成两种:一种是命令相关的,如“CC”;一种是参数相的关,如“CFLAGS”。w 下面是C/C+隐含规则中会用

    22、到的变量: w 关于命令的变量:AR 函数库打包程序。默认命令是“ar”。 AS 汇编语言编译程序。默认命令是“as”。CXX C+语言编译程序。默认命令是“g+”。CC C语言编译程序。默认命令是“cc”。 CPP C程序的预处理器(输出是标准输出设备)。默认命令是$(CC) Ew 关于命令参数的变量。下面的这些变量都是相关上面的命令的参数。如果没有指明其默认值,那么其默认值都是空。ARFLAGS 函数库打包程序AR命令的参数。默认值是“rv”。 ASFLAGS 汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时)CFLAGS C语言编译器参数。 CXXFLAGS C+语言编译器参数

    23、。 LDFLAGS 链接器参数。 (例如:LDFLAGS += -L ./. ltest )CPPFLAGS C预处理器参数。( C 和 Fortran 编译器也会用到)。 另类Makefile?w 如何把重复的buffer.h去掉?w 这个对于make来说很容易,它提供了自动推导命令和文件的功能呢?来看看最新风格的makefile吧。 objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) :

    24、defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h .PHONY : clean clean : rm edit $(objects) 不推荐这种风格:一是文件的依赖关系看不清楚:二是如果文件一多,要加入几个新的.o文件,那就理不清楚了清空目标文件的规则w每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,这不仅便于重编译,也很利于保持文件的清洁。w clean:w rm edit $(objects)w w更为稳健的做法是:w .PHONY :

    25、cleanw clean :w -rm edit $(objects)w w.PHONY意思表示意思表示clean是一个是一个“伪目标伪目标”。w而在命令前面加了一个小减号的意思就是,即便该命令执行出错,而在命令前面加了一个小减号的意思就是,即便该命令执行出错,make也也不管。对于不管。对于rm命令,意思是也许某些文件出现问题,但不要管,继续做后命令,意思是也许某些文件出现问题,但不要管,继续做后面的事。当然,面的事。当然,clean的规则不要放在文件的开头,不然,这就会变成的规则不要放在文件的开头,不然,这就会变成make的默认目标。不成文的规矩是的默认目标。不成文的规矩是“clean从来

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

    27、你可以使用别的文件名来书写Makefile,比如:“Make.Linux”,“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“-file”参数,如:make -f Make.Linux或make -file Make.AIX。w 引用其它的Makefilew在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。include的语法是:winclude w wfilename可以是当前操作系统Shell的文件模式(可以保含路

    28、径和通配符)w w在在include前面可以有一些空字符,但是绝不能是前面可以有一些空字符,但是绝不能是Tab键开始键开始。include和可以用一个或多个空格隔开。举个例子,你有这样几个Makefile:a.mk、b.mk、c.mk,还有一个文件叫foo.make,以及一个变量$(bar),其包含了e.mk和f.mk,那么,下面的语句:w winclude foo.make *.mk $(bar)书写规则w 规则包含两个部分,一个是依赖关系,一个是生成目标的方法。w w 在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出

    29、来的,所以一定要让make知道你的最终目标是什么。w 一般来说,定义在定义在Makefile中的目标可能会有很多,但中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。是第一条规则中的目标将被确立为最终的目标。如果第如果第一条规则中的目标有很多个一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。make所完成的也就是这个目标。w 语法规则wtargets : prerequisitescommand.w wtargets是文件名,以空格分开,可以使用通配符。一般来说,我们的目标基本上是一个文件,但也有可能是多个文件。w wcommand是命令行,如果其不与“target

    30、 prerequisites”在一行,那么,必须以Tab键开头,如果和prerequisites在一行,那么可以用分号做为分隔。w wprerequisites也就是目标所依赖的文件(或依赖目标)。如果其中的某个文件要比目标文件要新,那么,目标就被认为是“过时的”,被认为是需要重生成的。这个在前面已经讲过了。w w如果命令太长,你可以使用反斜框()作为换行符。make对一行上有多少个字符没有限制。规则告诉make两件事,文件的依赖关系和如何成成目标文件。w w一般来说,make会以Linux的标准Shell,也就是/bin/bash来执行命令。伪目标w前面我们看到如下规则,通过.PHONY告诉

    31、make,clean是个伪目标w.PHONY : cleanwclean :w-rm edit $(objects)w “伪目标”并不是一个文件,只是一个标签,所以通常,make无法生成它的依赖关系和决定它是否要执行,只能通过显示地指明这个“目标”才能让其生效。“伪目标”的取名不能和文件名重名。 w 为了避免和文件重名的这种情况,可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标” w 伪目标一般没有依赖的文件,但也可以为伪目标指定所依赖的文件。 w 伪目标同样可以作为“默认目标”,只要将其放在第一个。 w如果你的M

    32、akefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性:wall : prog1 prog2 prog3w.PHONY : allw prog1 : prog1.o utils.owcc -o prog1 prog1.o utils.ow prog2 : prog2.owcc -o prog2 prog2.ow prog3 : prog3.o sort.o utils.owcc -o prog3 prog3.o sort.o utils.ow 我们知道,Makefile中的第一个目标会被

    33、作为其默认目标。我们声明了一个“all”的伪目标,其依赖于其它三个目标。执行 make时,目标“all”被作为终极目标。为了完成对它的更新,make会创建(不存在)或者重建(已存在)目标“all”的所有依赖文件(prog1、prog2 和 prog3) 。这就达到了我们一口气生成多个目标的目的。w “.PHONY : all”声明了“all”这个目标为“伪目标”。w 从前面的例子我们可以看出,目标可以成为依赖。伪目标同样也可成为依赖。看下面的例子: .PHONY: cleanall cleanobj cleandiff cleanall : cleanobj cleandiff rm prog

    34、ram cleanobj : rm *.o cleandiff : rm *.diff “make clean”将清除所有要被清除的文件。“cleanobj”和“cleandiff”这两个伪目标有点像“子程序”的意思。我们可以输入“make cleanall”和“make cleanobj”和“make cleandiff”命令来达到清除不同种类文件的目的。静态模式w 静态模式规则是这样一个规则:规则存在多个目标,并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。w 静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。我们还是先来看一下语法:w : : w

    35、w .w targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。目标中的%定义表示对文件名的匹配w target-parrtern是指明了targets的模式,也就是的目标集模式。如果“%”定义在目标中,那么,目标中的“%”的值决定了依赖目标中的“%”的值w prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。静态模式w 举个例子:w 如果我们的定义成“%.o”,意思是我们的集合中都是以“.o”结尾的,而如果我们的定义成“%.c”,意思是对所形成的目标集进行二次定义,其计算方法是,取模式中的“%”(也就是去掉了

    36、.o这个结尾),并为其加上.c这个结尾,形成的新集合。w 所以,我们的“目标模式”或是“依赖模式”中都应该有“%”这个字符,如果你的文件名中有“%”那么你可以使用反斜杠“”进行转义,来标明真实的“%”字符。看一个例子: w objects = foo.o bar.ow all: $(objects)w $(objects): %.o: %.cw $(CC) -c $(CFLAGS) $ -o $w 例子中,指明了我们的目标从$(object)中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.

    37、o”的“%”,也就是“foo bar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.c bar.c”。而命令中的 “$”表示所有的依赖目标集(也就是“foo.c bar.c”),“$”表示目标集(也就是“foo.o bar.o”)。左边的规则展开后等价于下面的规则:foo.o : foo.c$(CC) -c $(CFLAGS) foo.c -o foo.obar.o : bar.c$(CC) -c $(CFLAGS) bar.c -o bar.ow 如果我们的“%.o”有几百个,那种我们只要用这种很简单的“静态模式规则”就可以写完一堆规则。“静态模式规则”的用法很灵活,如果用得

    38、好,那会一个很强大的功能。w 再看一个例子: files = foo.elc bar.o lose.o $(filter %.o,$(files): %.o: %.c $(CC) -c $(CFLAGS) $ -o $ $(filter %.elc,$(files): %.elc: %.el emacs -f batch-byte-compile $ $(filter %.o,$(files)表示调用Makefile的filter函数,过滤“$filter”集,只要其中模式为“%.o”的内容。这个例子展示了Makefile中更大的弹性。 (函数这里不讲了,make有一些自带的函数可供调用,如需要可查看相关教程)GNU的make工作方式总结w GNU的make工作时的执行步骤如下: 1、读入所有的Makefile。 2、读入被include的其它Makefile。 3、初始化文件中的变量。 4、推导隐晦规则,并分析所有规则。 5、为所有的目标文件创建依赖关系链。 6、根据依赖关系,决定哪些目标要重新生成。 7、执行生成命令。

    展开阅读全文
    提示  163文库所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
    关于本文
    本文标题:嵌入式系统原理与技术课件:makefile的编写.ppt
    链接地址:https://www.163wenku.com/p-2046063.html

    Copyright@ 2017-2037 Www.163WenKu.Com  网站版权所有  |  资源地图   
    IPC备案号:蜀ICP备2021032737号  | 川公网安备 51099002000191号


    侵权投诉QQ:3464097650  资料上传QQ:3464097650
       


    【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。

    163文库