Makefile学习之路详解

嵌入式学习之Makefile入门 本文会带你Makefile入门 阅读详情

看懂Makefile

什么是Makefile

makefile是一种说明编译规则的文件,带来的好处就是自动化编译,极大提高开发的效率

关于编译和链接

无论是C耗时C++都需要把源文件编译成中间件,这个过程叫做编译

然后将这些大量的中间文件链接合成一个可执行文件,这个过程叫做链接

Makefile文件命名和规则

  1. 文件命名

文件命名必须是Makefile或是makefile只能是这两种

  1. Makefile规则: 文件中可以有一个或多个规则
目标 ... : 依赖 ...
	命令(shell命令)
	...
	...
	...
  • 目标: 最终要生成的文件(伪目标除外),可以使.o .i .s文件,也可以是可执行文件

  • 依赖: 生成目标锁依赖的文件或者目标

  • 命令: 通过执行命令对依赖进行操作生成目标

Makefile中的掐规则一般都是为第一条规则服务的

\是换行符方便阅读

基本原理

  1. 再命令执行前会检查依赖是否存在

    a. 如果存在,执行命令

    b. 如果不存在,向下检查其他规则,检查有没有一个规则用来生成这个依赖的,如果找到了,则执行该规则中的命令

  2. 检查更新

    a.如果依赖的时间比目标时间晚,需要重新生成目标

    b.如果依赖的时间比目标早,目标不需要进行更新,对应规则中的命令就不需要执行

变量、模式匹配、函数

可以参考这个链接

Makefile支持三个通配符==* ? ~==与shell是一样的

自动变量

链接

简单使用时目标和依赖文件都是一系例的文件,那么我们如何书写一个命令来完成从不同的依赖文件生成相应的目标?因为在每一次的对模式规则的解析时,都会是不同的目标和依赖文件。自动化变量就是完成这个功能的

  • $@:表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
  • $%:仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么," %"就是"bar.o"," @“就是"foo.a”。如果目标不是函数库文件(Unix 下是[.a],Windows 下是[.lib]),那么,其值为空。
  • $<:依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
  • $?:所有比目标新的依赖目标的集合。以空格分隔。
  • $^:所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
  • $+:这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
  • $*:这个变量表示目标模式中"%“及其之前的部分。如果目标是"dir/a.foo.b”,并且目标的模式是"a.%.b",那么," ∗ " 的 值 就 是 " d i r / a . f o o " 。 这 个 变 量 对 于 构 造 有 关 联 的 文 件 名 是 比 较 有 较 。 如 果 目 标 中 没 有 模 式 的 定 义 , 那 么 " *"的值就是"dir/a.foo"。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么" ∗"的值就是"dir/a.foo"。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么"“也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么” ∗ " 就 是 除 了 后 缀 的 那 一 部 分 。 例 如 : 如 果 目 标 是 " f o o . c " , 因 为 " . c " 是 m a k e 所 能 识 别 的 后 缀 名 , 所 以 , " *"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"是make所能识别的后缀名,所以," ∗"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"是make所能识别的后缀名,所以,"“的值就是"foo”。这个特性是GNUmake的,很有可能不兼容于其它版本的 make,所以,你应该尽量避免使用" ∗ " , 除 非 是 在 隐 含 规 则 或 是 静 态 模 式 中 。 如 果 目 标 中 的 后 缀 是 m a k e 所 不 能 识 别 的 , 那 么 " *",除非是在隐含规则或是静态模式中。如果目标中的后缀是 make 所不能识别的,那么" ∗",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么"*"就是空值。
  • $(@D):表示 “ @ " 的 目 录 部 分 ( 不 以 斜 杠 作 为 结 尾 ) , 如 果 " @"的 目录 部 分( 不以斜杠作 为结尾 ), 如 果" @"的目录部分(不以斜杠作为结尾),如果"@“值是"dir/foo.o”,那么” ( @ D ) " 就 是 " d i r " , 而 如 果 " (@D)"就是"dir",而如果" (@D)"就是"dir",而如果"@“中没有包含斜杠的话,其值就是”."(当前目录)。
  • $(@F):表示" @ " 的 文 件 部 分 , 如 果 " @"的文件部分,如果" @"的文件部分,如果"@“值是"dir/foo.o”,那么" ( @ F ) " 就 是 " f o o . o " , " (@F)"就是"foo.o"," (@F)"就是"foo.o","(@F)“相当于函数”$(notdir $@)"。
  • $(*D):和上面所述的同理,也是取文件的目录部分。对于上面的那个例子,"$(*D)“返回"dir”。
  • $(*F):和上面所述的同理,也是取文件的文件部分。对于上面的那个例子,"$(*F)“返回"foo”。
  • $(%D):表示了函数包文件成员的目录部分。这对于形同"archive(member)"形式的目标中的"member"中包含了不同的目录很有用。
  • $(%F):表示了函数包文件成员的文件部分。这对于形同"archive(member)"形式的目标中的"member"中包含了不同的目录很有用。
  • $(<D):表示依赖文件的目录部分。
  • $(<F):表示依赖文件的文件部分。
  • $(^D):表示所有依赖文件的目录部分。(无相同的)
  • $(^F):表示所有依赖文件的文件部分。(无相同的)
  • $(+D):表示所有依赖文件的目录部分。(可以有相同的)
  • $(+F):所有依赖文件的文件部分。(可以有相同的)
  • $(?D):表示被更新的依赖文件的目录部分。
  • $(?F):表示被更新的依赖文件的文件部分。
    最后,对于" < " , 为 了 避 免 产 生 不 必 要 的 麻 烦 , 最 好 给 <",为了避免产生不必要的麻烦,最好给 <",为了避免产生不必要的麻烦,最好给后面的那个特定字符都加上圆括号,比如," ( < ) " 就 要 比 " (< )"就要比" (<)"就要比"<"要好一些。

伪目标

最早先的一个例子中,我们提到过一个“clean”的目标,这是一个“伪目标”,

clean:
    rm *.o temp

正像我们前面例子中的“clean”一样,既然我们生成了许多文件编译文件,我们也应该提供一个清除它们的“目标”以备完整地重编译而用。 (以“make clean”来使用该目标)

因为,我们并不生成“clean”这个文件。“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显式地指明这个“目标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义了。

当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显式地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。

.PHONY : clean

只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”这样。于是整个过程可以这样写:

.PHONY : clean
clean :
    rm *.o temp

伪目标一般没有依赖的文件。但是,我们也可以为伪目标指定所依赖的文件。伪目标同样可以作为“默认目标”,只要将其放在第一个。一个示例就是,如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性:

all : prog1 prog2 prog3
.PHONY : all

prog1 : prog1.o utils.o
    cc -o prog1 prog1.o utils.o

prog2 : prog2.o
    cc -o prog2 prog2.o

prog3 : prog3.o sort.o utils.o
    cc -o prog3 prog3.o sort.o utils.o

我们知道,Makefile中的第一个目标会被作为其默认目标。我们声明了一个“all”的伪目标,其依赖于其它三个目标。由于默认目标的特性是,总是被执行的,但由于“all”又是一个伪目标,伪目标只是一个标签不会生成文件,所以不会有“all”文件产生。于是,其它三个目标的规则总是会被决议。也就达到了我们一口气生成多个目标的目的。 .PHONY : all 声明了“all”这个目标为“伪目标”。(注:这里的显式“.PHONY : all” 不写的话一般情况也可以正确的执行,这样make可通过隐式规则推导出, “all” 是一个伪目标,执行make不会生成“all”文件,而执行后面的多个目标。建议:显式写出是一个好习惯。)

随便提一句,从上面的例子我们可以看出,目标也可以成为依赖。所以,伪目标同样也可成为依赖。看下面的例子:

.PHONY : cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff
    rm program

cleanobj :
    rm *.o

cleandiff :
    rm *.diff

“make cleanall”将清除所有要被清除的文件。“cleanobj”和“cleandiff”这两个伪目标有点像“子程序”的意思。我们可以输入“make cleanall”和“make cleanobj”和“make cleandiff”命令来达到清除不同种类文件的目的。

编译的过程

编译的过程分为

链接

Makefile示例

app:sub.c add.c mult.c div.c main.c
	gcc sub.c add.c mult.c div.c main.c -o app

这里生成app目标, 依赖的是.c文件 命令是gcc命令

app:sub.o add.o mult.o div.o main.o
	gcc sub.o add.o mult.o div.o main.o -o app

sub.o:sub.c
	gcc -c sub.c -o sub.o

add.o:add.c
	gcc -c add.c -o add.o

mult.o:mult.c
	gcc -c mult.c -o mult.o

div.o:div.c
	gcc -c div.c -o div.o

main.o:main.c
	gcc -c main.c -o main.o

# 依赖.o文件没有向下寻找生成.o文件的规则
#定义变量
src=sub.o add.o mult.o div.o main.o
target=app
$(target):$(src)
	$(CC) $(src) -o $(target)

sub.o:sub.c
	gcc -c sub.c -o sub.o

add.o:add.c
	gcc -c add.c -o add.o

mult.o:mult.c
	gcc -c mult.c -o mult.o

div.o:div.c
	gcc -c div.c -o div.o

main.o:main.c
	gcc -c main.c -o main.o

#定义变量
src=sub.o add.o mult.o div.o main.o
target=app
$(target):$(src)
	$(CC) $(src) -o $(target)

%.o:%.c
	$(CC) -c $< -o $@
# 使用变量和自动变量
​​​​​​​嵌入式学习笔记(9) Makefile文件详解 读取到BL1后会做Checksum(需要校验的内存区域16KB-16Bytes中,所有内存中的内容按照字节为单位来进行相加,最终相加的和极为校验和,mkv210_image.c将校验和放在BL1头文件第3个字(即0xd0020008--0xd002000c)中,BL0也会计算校验和。通过BL0计算的校验和和BL1头文件中的校验和对比即可得知BL1是否正确),判断BL1是否正确,如果正确则加载BL1到iRAM运行BL1程序(这里的BL1程序指的是16个字节的BL1头文件+我们写的程序+空0) 阅读详情

相关推荐

四.ARM裸机学习之Makefile和mkv210_image.c文件详解

一.Makefile的简单使用 2017/10/30 22:00 Makefile是用来管理工程的 事先编写好一个可执行的.c文件 编写创建的Makefile 再此输入一下命令,看图 Makefile的基本工作原理 其一,当我们执行 make xx 的时候,Makefile会自动执行xx这个目标下面的命令语句。 其二,当我们make xx的时候

Mr.Wang的博客 953

makefile的使用和基础知识

makefile的使用和基础知识 文章目录**makefile的使用和基础知识**makefile的引入及规则makefile的语法makefile函数 makefile的引入及规则 makefile的语法 makefile函数 ####放的地方

weixin_47180249的博客 595

C和C++混合编程的Makefile的编写!_makefile c c++混编

2.c源文件放到CFILES宏后面, cpp文件放到C++Files宏后面,第三方库放到LIBS宏后面,头文件的包含路径放到INCLUDES后面,库文件的包含路径放到使用-L./等表达式放到LIBS中的开头即可。1.如果LIBS的位置放置不对,这几个基础库将不会编进so中。3.这里严格区分c和cpp文件的目的是,c文件使用gcc编译,而cpp文件会使用g++编译,它们必须严格区分开。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人**下面是依据上面Makefile编译后得到的正确的截图。

2401_85012446的博客 873

嵌入式之Makefile的学习

本文章适用于从事嵌入式uboot移植,和驱动开发的工程师阅读,涉及到的知识点比较基础,涉及内容不是那么深入。 首先Makefile是管理一个大型项目必须的文件,当一个项目中涉及到多个C语言程序,和.h头文件程序,这种情况下就必须使用到Makefile进行项目的编译和链接。Makefile文件的格式: 目标:依赖 TAB命令 命令前面是一个Tab键,当且仅当是Tab按键,不能是空格,必须是一...

qq_35480173的博客 764

caffe 学习笔记之Makefile.config注释

github上源码 ubuntu下执行一下命令得到Makefile.configcp Makefile.config.example Makefile.config以下注释为在博客的基础上进行修改而成。## Refer to http://caffe.berkeleyvision.org/installation.html # Contributions simplifying and impro

learning notes 4393

实战解析:如何利用MDFEND与Weibo21数据集构建多领域假新闻检测系统

本文实战解析了如何利用MDFEND模型与Weibo21数据集构建多领域假新闻检测系统。文章深入剖析了MDFEND的领域门控与专家混合机制,并提供了从数据预处理、模型理解到训练部署的完整指南,旨在解决通用模型在不同领域新闻检测中的性能衰减问题,提升检测的准确性与适应性。

vulkan6gpu的博客 580

嵌入式系统——Makefile基础知识

Makefile基础知识,库文件的编译和链接

weixin_43229184的博客 1032

Android车载应用开发:Kotlin与Automotive OS深度实践

Android Automotive OS(AAOS)是Google专为车辆设计的操作系统,直接运行于车机硬件,提供完整的车载信息娱乐系统(IVI)。与Android Auto不同,AAOS允许开发者深度集成车辆硬件功能,如空调控制和传感器数据读取,同时遵循严格的驾驶安全规范。Kotlin作为开发语言,具备空安全设计、扩展函数和协程支持等优势,简化了开发流程。开发环境配置包括Android Studio、AAOS模拟器和Gradle配置,核心组件如CarAppService、Screen与模板系统,以及车辆

时小雨的专栏 3444

5_嵌入式Linux驱动开发篇_Makefile的初步使用_语法|变量|自动化变量|伪目标_一个案例让你搞懂Makefile_笔记

Makefile

qq_45083790的博客 2117

【Qt】QML-01:使用QtCreator10创建QML工程,并讲解第一个程序:Hello World

QML第一讲:创建QML工程、详解QML第一个程序Hello World

郭老二 7796

从OFED到rdma-core:手把手带你搞定Linux下RDMA开发环境的选型与搭建

本文详细介绍了在Linux系统下搭建RDMA开发环境的完整流程,涵盖OFED与rdma-core的选型对比及分步安装指南。针对高性能计算和分布式存储需求,解析RDMA技术栈的核心组件,提供环境验证与性能测试方法,帮助开发者快速构建稳定高效的开发环境。特别适合需要优化网络性能的工程师参考。

weixin_26905487的博客 225

Makefile详解--学习linux下Gtk开发看到的一篇详细的讲解Makefile的文章,转来分享

Makefile详解<br />概述<br />—— <br />什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和 professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解 HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完 成大型工程的

Terry_zhao软件技术专栏 2519

Chkdsk误删文件?5步教你从FOUND.000文件夹找回重要数据(附工具推荐)

本文详细介绍了当Chkdsk误删文件后,如何从FOUND.000文件夹中找回重要数据的5个步骤。包括理解Chkdsk与FOUND.000的关系、定位与访问FOUND.000文件夹、手动恢复CHK文件的技巧、使用UnCHK工具自动化恢复以及预防数据丢失的关键措施。适用于Windows用户解决数据丢失问题,特别是NTFS文件系统下的文件恢复。

weixin_30687051的博客 391

学习笔记——文件传输工具配置与Makefile详解

本文详细介绍了Ubuntu FTP服务配置和Makefile编译流程。FTP配置部分包含安装vsftpd、修改配置文件、设置权限掩码等关键步骤,并提供了安全建议。Makefile解析部分展示了ARM交叉编译的完整流程:从汇编文件编译为目标文件(.o),链接为可执行文件(.elf),提取二进制文件(.bin),并生成反汇编文件(.dis),重点说明了-Ttext指定运行地址的重要性。文章还提供了开发环境准备清单和常见问题解决方案,形成了一套完整的嵌入式开发工作流程,涵盖代码编写、编译、传输和烧录全过程。

2301_78295956的博客 737

ElectrolyteGPT:首个电池电解液逆向设计的生成式 AI 系统 —— 算法原理与复现解析

数据驱动的重要性:1100 万→100 万的精心筛选,比单纯增大模型更有效领域适配:fLine 表示法、正则分词、化学感知的数据增强(SMILES randomization)都是关键小模型的力量:6M 参数在特定化学空间的表现,远超通用大模型在相同任务上的零样本能力条件生成的极限:10 维条件导致模型崩溃,提示我们需要更好的条件编码策略(如 diffusion guidance、RLHF-style 偏好优化)未来方向配方实验验证。

ASKCOS博客 123

基于Flink的流式数据降维实现方案

理解为何实时场景需要降维(解决维度灾难)掌握Flink流处理与降维算法的结合方式学会用Flink实现一个可落地的流式降维系统覆盖内容包括:Flink流处理基础、降维算法选择(侧重在线算法)、Flink与降维的集成方案、实战代码示例,以及工业级场景的应用经验。本文从“为什么需要流式降维”出发,用“快递分拣”的生活案例引出核心概念;接着拆解Flink流处理、数据降维的底层逻辑;然后重点讲解“在线PCA”这一适合流式场景的降维算法,并用Flink实现一个完整的流式降维管道;

AI 领航者的博客 567

C语言学习(三)Makefile基础学习详解

所谓工程管理器,顾名思义,是指管理较多的文件的。试想一下,有一个上百个文件的代码构成的项目,如果其中只有一个或少数几个文件进行了修改,按照之前所学的Gcc 编译工具,就(第一个缺点)不得不把这所有的文件重新编译一遍,因为编译器并不知道哪些文件是最近更新的,而只知道需要包含这些文件才能把源代码编译成可执行文件,于是,(第二个缺点)程序员就不能不再重新输入数目如此庞大的文件名以完成最后的编译工作。  ...

ls_dashang的博客 1491

第11节:GPU 线程层级:线程、线程块、网格

层级标识变量功能线程threadIdx执行单元,处理数据线程块blockIdx管理多个线程,提供共享内存网格管理多个 blockGPU 编程中,合理安排线程层级,是提升性能的关键。

yumeiguo的博客 211

Makefile详解 && Makefile中文文档

Makefile详解 && Makefile中文文档 去发现同类优质开源项目:https://gitcode.com/ 此压缩文件包含Makefile详解和Makefile中文文档,适合想要深入学习Makefile的读者。文件内容详尽,系统性地介绍了Makefile的基本概念、编写规则以及在实际项目中的应用。通过阅读此文档,您将能够掌握Makefile的核心知识,提高项目构建和管理...

gitblog_06724的博客 279

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Linux -【新手必看】Makefile完全指南:4种写法详解+基础语法+变量与函数全解析

本文以简单计算器项目为例,详解了四种常见 Makefile 写法及其区别。第一种直接编译所有源文件,简单但效率低;第二种显式写出每个目标文件的编译规则,效率高但规则繁琐;第三种利用隐式规则简化命令,保持增量编译且更简洁;第四种结合变量、通配符和自动变量,灵活且易维护,是推荐写法。文章还系统介绍了 Makefile 基础语法、变量分类(自定义变量与内置变量)、自动变量($@、$^、$<)、显示规则与隐式规则区别,以及常用函数(wildcard、patsubst、shell)

欢迎来到Petter_Deng的博客 1162

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

makefile实现自动化编译 学习资料整理 初学者看过来

首先看正月点灯笼的入门视频,知道简单的makefile文件命令: https://www.bilibili.com/video/BV1Mx411m7fm?from=search&seid=17761668290792883688 然后看makefile详解(不看第一个,对于初学者来说,这里面的例子会看不懂,我之前就是= =、): https://blog.youkuaiyun.com/freeking101/article/details/51610782/?utm_medium=distribute.p

qihuazhuozhuo的博客 204

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Makefile Tutor v1详解:最简单C项目的Makefile构建实战

Makefile Tutor是一个专注于清晰讲解Makefile构建流程的开源项目,通过逐步演进的版本设计,帮助新手掌握从简单到复杂项目的构建技巧。本文将以v1版本为例,详细解析最简单C项目的Makefile构建实战,让你快速入门Makefile的核心概念和基础用法。 ## 一、v1项目结构概览 v1版本作为Makefile Tutor的起点,采用了最精简的C项目结构,主要包含两个核心文件:

gitblog_00967的博客 474

Makefile学习

介绍以下两个学习makefile的网站

qq_55345521的博客 1291

makefile

Reference from:https://www.bilibili.com/video/BV18p4y167Md?p=71&spm_id_from=pageDriver p70 And: Sorry about myChinglish cuz there has not a chinese input language in ubuntu os...XD **** original version 1: **** mytool:main.o tool1.o tool2.o g...

qq_40529035的博客 192

Makefile详解

一、Makefile规则格式 Makefile是由一系列的单一规则指令组合起来: 目标XX1:依赖文件 <TAB>命令1 <TAB>命令2 目标XX2:依赖文件 <TAB>命令1 <TAB>命令2 ... ... 指令1: 命令1 命令2 指令2: 命令1 命令2 ... ... 示例: Tag:a....

qq_34968572的博客 3万+

makefile详解

想要掌握makefile,首先需要了解两个概念,⼀个是⽬标(target),另⼀个就是依赖(dependency)。⽬标就是指要⼲什么,或说运⾏ make 后⽣成什么,⽽依赖是告诉 make 如何去做以实现⽬标。在 Makefile 中,⽬标和依赖是通过规则(rule)来表达的。 上面Makefile 中的 all 就是我们 的⽬标,⽬标放在‘:’的前⾯,其名字可以是由字⺟和下划线‘_’组成 。echo “Hello World”就是⽣成⽬标的命令,这些命令可以是任何你可以在你的环境中运⾏的命令以及 mak

szembed的博客 5928
上一篇: 编译的详细过程
下一篇: c++ 不完全类型
黑猫爱小鹿
博客等级 码龄8年 1万+粉丝 205原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值