ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

fxc不是内部或外部命令:PATH、SDK与构建配置全解析

fxc不是内部或外部命令:PATH、SDK与构建配置全解析

上周有个朋友把一个渲染小 demo 丢过来,说构建脚本跑到编译着色器那一步就红了一片,终端里只给了一句话:'fxc' 不是内部或外部命令,也不是可运行的程序或批处理文件。他电脑上进阶开发环境一应俱全,编辑器打开能正常编 C++,偏偏fxc认不出来。这类报错我这些年见过太多次,尤其是刚接触图形渲染、引擎工具链、或者自己搭构建脚本的同学,第一次撞上基本会卡半天,因为它不像语法错误那样明确告诉你哪一行写错,而是程序根本还没开始跑——命令行解释器在找人,没找到。

fxc是 HLSL 着色器编译器,全称 Effect-Compiler,我们写的.hlsl、.fx源码要靠它翻译成 GPU 能读的字节码。它不在系统默认路径里,也不属于操作系统自带组件,属于“装了 SDK 才会出现”的那一类工具。所以这条报错的本质非常朴素:当前命令行会话的搜索路径里没有fxc.exe。听起来简单,但背后的分支很多——是根本没装、装了但目录不在 PATH、PATH 里有但版本不对、位数不匹配、构建脚本用的是另一套环境……每一种对应的修法完全不同,乱改一通往往是把问题从“找不到”变成“找错了”。

下面我把这个问题从原理到落地拆开讲:先解释命令行到底是怎么找程序的,再说清 fxc 的前世今生,然后给出五条修复路线和四种可直接抄的配置,最后把这些年踩过的坑整理成速查表。刚入门的朋友可以从头看,已经在维护构建脚本的老手可以直接跳到第 3、4 节。

1. 报错先翻译:'fxc' 不是内部或外部命令到底在说什么

很多人看到这句话的第一反应是“fxc 坏了”或者“装错了版本”,其实不是。这句话是命令行解释器发出的,不是fxc自己报的。理解这一点很关键,它决定了你该往哪个方向排查:问题出在“寻址”,不出在“程序本身”。

1.1 命令行的查找规则与这条提示的准确含义

在 Windows 的命令行里敲一个不带路径的名字,解释器会按一套固定顺序去找对应的可执行文件。简化后的逻辑是:先看当前工作目录(除非系统策略禁用了这个行为),然后按PATH环境变量里的目录顺序逐个扫,每个目录里用PATHEXT列出的扩展名(.COM、.EXE、.BAT、.CMD等)依次拼上去试。全部试完都没命中,就抛出那句熟悉的提示。注意这里有个细节:PATH是按顺序匹配的,谁在前面谁先被选中,这解释了很多“明明装了新版却跑了旧版”的怪事。

还有一个常见误解:资源管理器里双击运行、或者用某些 API 启动进程时,会走注册表里的App Paths分支,那是另一套机制。但你在终端里手敲fxc,走的就是PATH,App Paths帮不上忙。所以网上有些“改注册表就能修”的教程对命令行场景是无效的,照抄只会白忙。

注意:如果你在某个 IDE 的内置终端里执行成功、切到系统终端就失败,八成不是 PATH 的问题,而是 IDE 启动时注入了一套私有环境变量。这种情况优先怀疑环境继承,而不是去改系统配置。

理解了查找规则,你就能自己推出验证方法:where fxc会按同样的顺序列出所有命中的完整路径,输出为空就说明确实没找到。这一步是我每次接手陌生环境的第一个动作,比直接翻目录快得多。

1.2 fxc 的身世:从独立 SDK 到系统 SDK 再到 dxc

fxc.exe的历史有点长,这也是它路径混乱的根源。早期它跟着一套独立的图形开发包发布,安装后落在Utilities\bin\x86这类目录下,很多人记忆里的那个路径就是那个年代的。后来这套工具被并入了 Windows SDK,从某个版本开始,它出现在Windows Kits\10\bin\<SDK版本号>\x64\fxc.exe这样的位置,并且按目标架构分了x86、x64、arm64三份。

再往后,着色器模型演进到 6.x,原来的编译器架构撑不住了,官方推出了新一代编译器dxc。现在的新 SDK 里fxc和dxc是并存的:fxc负责到着色器模型 5.1 为止的老语法,dxc负责 6.0 及以上,并且dxc也在独立仓库里单独发版,可以脱离 SDK 更新。这就造成一个非常现实的问题——同一个机器上可能同时存在三四个不同来源、不同版本的编译器,而PATH里排第一的那个决定了实际用的是谁。

我的判断习惯是:如果你维护的是老项目、目标平台是 Direct3D 11、着色器模型最高 5.1,fxc完全够用,没必要动;如果是新项目、要用到 6.0 以上的特性(比如更灵活的资源绑定、光线追踪相关的着色器),那就直接上dxc,别在fxc上浪费时间,因为它已经停止功能演进了。

1.3 为什么你装了开发环境依然没有 fxc

这是最高频的困惑:“我明明装了完整的开发环境,怎么会没有?”原因通常有三种。

第一种是安装时的组件勾选问题。那套 IDE 的安装器是按工作负载打包的,图形相关的 SDK 组件默认不一定全选,尤其是老版本的 SDK 或者某些“兼容性工具”。你选了桌面 C++ 开发,不等于把着色器编译器一起装进来了。

第二种是装了但没进 PATH。SDK 的bin目录从来不会被自动加入系统PATH,这是刻意的设计——避免不同版本的编译器互相打架。官方推荐的用法是通过开发者命令提示符启动终端,那个批处理脚本会临时把正确的目录塞进当前会话的PATH。换句话说,环境本身是好的,只是你用的终端不是“被配置过”的那个。

第三种最隐蔽:装了新版 SDK,但你的构建脚本里写死了一个旧路径,或者 CMake 缓存里存了上一次探测的结果,导致它一直在找一个已经不存在的位置。这种情况where fxc能查到,脚本仍然报错,排查方向要转向构建配置而不是系统环境。

2. 定位现场:先把 fxc.exe 找出来再谈修复

修这类问题的正确顺序是“先找文件,再决定改哪一层”。上来就改环境变量,很容易在没装的情况下白折腾半天。

2.1 三步定位法与常见安装路径清单

第一步,where fxc,看当前会话能不能找到。第二步,如果没找到,直接去 SDK 安装根目录做全盘搜索:dir /s /b "C:\Program Files (x86)\Windows Kits\10\bin\fxc.exe"。这个命令会把所有 SDK 版本、所有架构下的fxc.exe全列出来,一次看清楚机器上到底有几份。第三步,如果 SDK 目录压根不存在,那就别修了,去装组件。

下面这张表是我整理的常见落点,按出现频率排序,排查时照着翻能省不少时间:

路径形态典型来源备注
C:\Program Files (x86)\Windows Kits\10\bin\<版本>\x64\fxc.exe较新的 Windows SDK最常见,版本号形如 10.0.xxxxx.0
C:\Program Files (x86)\Windows Kits\10\bin\<版本>\x86\fxc.exe同上32 位版本,老构建脚本常指向这里
C:\Program Files (x86)\Windows Kits\8.1\bin\x86\fxc.exe较早的 SDK路径结构略有不同,没有架构子目录层
...\Utilities\bin\x86\fxc.exe独立图形开发包老项目遗留,路径里带 Utilities
...\Windows Kits\10\bin\<版本>\x64\dxc.exe新 SDK 内置新版编译器的对应位置

搜出来之后别急着复制路径,先看清楚版本号和架构。同名的fxc.exe在不同 SDK 版本下行为可能有细微差别,尤其在优化和反射信息生成上。我在一个跨平台项目里就遇到过:本机用新 SDK 编出来的字节码,在另一台用旧 SDK 的机器上重编,指令数差了将近百分之十,查了很久才发现是编译器版本不同导致的优化差异。

2.2 用 fxc /? 确认版本与着色器模型支持

找到文件后,先跑一下fxc /?,看看它输出的帮助信息和默认目标配置。这个习惯能帮你提前发现“找错编译器”的问题。输出里会列出支持的 profile 列表,比如ps_5_0、vs_5_1、cs_5_0这些。如果你传的/T参数不在这个列表里,编译器会直接告诉你 profile 无效,而不是那句“不是内部或外部命令”——这两类错误的排查方向完全不同,别混为一谈。

顺便可以编一个最小着色器验证一下整条链路通不通:

// test.hlsl float4 main(float4 pos : POSITION) : SV_POSITION { return pos; }
fxc /T vs_5_0 /E main /Fo test.cso test.hlsl

执行完看有没有生成test.cso,文件大小是否合理(几十到几百字节都正常)。这一步通过,说明编译器本身没问题,剩下的全是路径和集成问题。这个“最小可复现验证”的思路我在排查任何工具链问题时都会用,它能把“环境问题”和“代码问题”干净地切开。

2.3 查完之后怎么选:五条修复路线的取舍

确认了文件存在,接下来是选方案。我列了五条常见路线,它们的适用场景、持久性和副作用差别很大:

方案生效范围持久性适合谁主要风险
当前会话临时 set PATH当前终端关窗即失效快速验证、一次性编译无,最安全
开发者命令提示符启动当前终端会话级日常开发需要记住从哪启动
写入用户环境变量当前用户长期个人机器PATH 越滚越长、版本漂移
构建脚本内探测路径项目跟随项目团队协作、CI需要写探测逻辑
改用 dxc 并锁定版本项目跟随项目新项目语法和参数需要迁移

我个人的偏好顺序很明确:临时验证用第一条,团队项目用第四条,新项目直接跳第五条。第二条适合日常但容易被忘记,第三条看着省事其实是长期负债——你今天加进去的路径,两年后换机器、换 SDK 版本时会变成一颗定时炸弹,而且往往不是你踩,是接手的人踩。

3. 动手修:四种方案的完整配置

这一节给可以直接抄的配置。我按“从临时到永久、从手动到自动化”的顺序排,你按自己的场景挑一个就行,不需要全上。

3.1 临时注入 PATH:最快验证,也最不容易留后遗症

如果你只是想把眼前这次编译跑通,最干净的做法是在当前会话里临时追加:

set "PATH=C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64;%PATH%" fxc /T ps_5_0 /E main /Fo out.cso shader.hlsl

几个细节值得说清楚。set "PATH=..."这种把整个赋值包在引号里的写法,能避免路径里含空格时被截断;%PATH%放在后面表示“追加到现有路径之前”,这样新目录优先级最高,能盖过可能存在的旧版本。注意是set不是setx,前者只影响当前窗口,关掉就恢复,非常适合做“先验证再决定要不要永久改”的试探。

更省事的办法是用 IDE 自带的开发者命令提示符,它的启动脚本会把 SDK 的bin目录、运行时目录、各种环境变量一次性配好,你什么都不用管。我在做一次性验证时基本都用这个,比手写路径可靠得多。如果要用脚本拉起,可以这样:

call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" fxc /T ps_5_0 /E main /Fo out.cso shader.hlsl

路径里的版本号和版本类型要按你机器上的实际情况改。这个脚本执行完,PATH里会有正确的 SDK 目录,而且它还会设置一些编译相关的环境变量,对 MSBuild 场景是必需的。

注意:如果你在 32 位终端里追加了x64目录,命令行本身能启动 64 位程序,一般不会报错,但后续如果链接了位数不匹配的依赖库,问题会在运行期才冒出来。养成“终端位数、编译器位数、目标平台位数三者一致”的习惯,能省掉大量玄学问题。

3.2 永久写入环境变量:setx 的正确姿势与三个坑

确认了路径长期可用,再考虑写进环境变量。命令行里最常用的是setx,但它有几个坑必须提前知道。

第一个坑是长度限制。setx对单个值的长度有上限(大致一千字符量级),PATH一旦超过就会被静默截断,截断之后不只是fxc找不到,可能一堆别的命令也跟着失灵。所以千万不要用setx PATH "%PATH%;新路径"这种写法——%PATH%展开的是“用户变量 + 系统变量”的合并结果,你把它写回用户变量,等于把系统路径整段复制过来,一次两次还行,多来几次就爆了。

第二个坑是变量作用域。setx /M写的是系统级,需要管理员权限;不带/M写的是用户级。改系统级会影响所有用户,出问题时影响面也大,个人机器上我建议只动用户级。

第三个坑是生效时机。setx写完不会影响当前已经打开的终端,必须开新窗口才生效。很多人改完在原地重试,发现还是报错,以为没改成功,其实是没开新会话。

稳妥的做法是用 PowerShell 精确追加,先去重再拼:

$target = 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64' $current = [Environment]::GetEnvironmentVariable('Path', 'User') if ($current -notlike "*$target*") { [Environment]::SetEnvironmentVariable('Path', "$target;$current", 'User') Write-Host "已追加: $target" } else { Write-Host "已存在,跳过" }

这段脚本做了两件事:判重和追加。判重看着多余,实际上是我被坑出来的——同一个路径重复出现十几次的 PATH,阅读和维护都是灾难,而且会让排查时完全看不出哪个是有效的。

3.3 交给构建系统:CMake 与 MSBuild 里如何锁定 fxc

团队项目里最不该做的就是把路径写死在文档里让大家手动配。正确做法是让构建系统自己去找,找不到就明确报错,而不是等到编译着色器时才冒出那句让人抓瞎的提示。

CMake 里可以这样写:

# 先尝试从环境变量推断,再退回常见路径搜索 find_program(FXC_EXECUTABLE NAMES fxc HINTS "$ENV{WindowsSdkVerBinPath}/x64" "C:/Program Files (x86)/Windows Kits/10/bin/10.0.22621.0/x64" DOC "HLSL 编译器 fxc 的完整路径" ) if(NOT FXC_EXECUTABLE) message(FATAL_ERROR "未找到 fxc,请安装 Windows SDK 或在 CMake 中指定 FXC_EXECUTABLE 的路径") endif() message(STATUS "使用着色器编译器: ${FXC_EXECUTABLE}") add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/shader.cso COMMAND "${FXC_EXECUTABLE}" /nologo /T ps_5_0 /E main /Fo ${CMAKE_CURRENT_BINARY_DIR}/shader.cso ${CMAKE_CURRENT_SOURCE_DIR}/shader.hlsl DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/shader.hlsl COMMENT "编译像素着色器" )

关键点有三个:find_program会先查PATH再查HINTS,所以只要环境配好了它就能自动命中;FATAL_ERROR把“找不到编译器”这件事提前到配置阶段暴露,错误信息还带人类可读的提示;add_custom_command用DEPENDS声明依赖,改着色器才重编,避免每次全量构建。

MSBuild 场景下,如果你用的是现成的着色器编译任务,那基本不用操心路径;如果是自己写Exec或者CustomBuild,建议把路径抽成一个属性,方便 CI 覆盖:

<PropertyGroup> <FxcPath Condition="'$(FxcPath)' == ''">$(WindowsSdkDir)bin\$(WindowsTargetPlatformVersion)\x64\fxc.exe</FxcPath> </PropertyGroup> <Target Name="CompileShaders" BeforeTargets="Build"> <Error Condition="!Exists('$(FxcPath)')" Text="找不到着色器编译器: $(FxcPath)" /> <Exec Command="&quot;$(FxcPath)&quot; /nologo /T ps_5_0 /E main /Fo &quot;$(OutDir)shader.cso&quot; &quot;$(MSBuildProjectDirectory)\shader.hlsl&quot;" /> </Target>

这里用$(WindowsSdkDir)和$(WindowsTargetPlatformVersion)这两个内置属性去拼路径,能自动跟随 SDK 版本变化。加一个Exists检查是必须的,否则错误信息会非常难懂。我在一个项目里就是因为少了这一句,CI 上失败了三次才定位到是构建机的 SDK 版本和开发机不一致。

3.4 直接换 dxc:新项目的正确打开方式

如果你的项目不是维护老代码,那我强烈建议直接上dxc。它支持 6.x 的着色器模型,语法特性更完整,而且是当前在持续维护的那一支。命令行参数和fxc大体相似,迁移成本比想象中低:

用途fxc 写法dxc 写法说明
指定目标/T ps_5_0-T ps_6_0目标模型不同,不能混用
指定入口/E main-E main一致
输出文件/Fo out.cso-Fo out.dxil输出格式不同,扩展名建议区分
调试信息/Zi-Zi一致
关闭优化/Od-Od一致
剥离反射/Qstrip_reflect-Qstrip_reflect一致,体积优化常用
包含目录/I path-I path一致

参数风格上dxc同时接受/和-前缀,所以老脚本里大部分参数不用改,主要改的是目标模型和输出格式。要注意的是输出产物变了:fxc生成的是旧格式字节码,dxc生成的是新格式,运行时的加载接口也不一样,这部分改动量取决于你的资源加载代码,不是简单换个命令就能搞定。

我的建议是给新项目留一个编译开关,让它能在两条路径之间切换,这样迁移期不至于卡死在某一个编译器上:

option(USE_DXC "使用 dxc 编译着色器" ON) if(USE_DXC) find_program(SHADER_COMPILER NAMES dxc HINTS "$ENV{WindowsSdkVerBinPath}/x64") set(SHADER_TARGET "ps_6_0") else() find_program(SHADER_COMPILER NAMES fxc HINTS "$ENV{WindowsSdkVerBinPath}/x64") set(SHADER_TARGET "ps_5_0") endif()

这种写的价值在于:迁移不是一次性动作,而是一个可以回退的过程。真出问题时把开关一关就能退回老路径,心理负担小很多。

4. 踩坑实录:fxc 相关的高频异常与排查

环境配好只是一半,实际跑起来还有一堆衍生问题。下面这些是我这些年真实遇到过、并且反复在别人机器上复现的。

4.1 位宽与版本错位:编译通过了但对不上号

最典型的症状是:命令行编着色器一切正常,程序运行时加载却失败,或者画面全黑但没有任何报错。这类问题往往出在“编出来的东西不是运行时想要的”。

常见成因有两个。一是编译器版本和运行时库版本不配套,fxc生成的字节码对较老的运行时可能不可用,尤其是用了较新的语法特性时。二是目标配置写错了,比如你想编像素着色器却写了vs_5_0,或者用了 5.1 的 profile 但目标设备只支持 5.0。这两种情况编译器都不会拦你,它只管按你给的参数干活。

排查手法很直接:把编译命令的/T和程序里创建着色器时传的 profile 逐字对比一遍,再把字节码文件头里的版本标记打出来看。我现在写构建脚本时会把编译后的文件大小和哈希打进日志,一旦某次构建前后不一致,立刻能发现。

4.2 路径空格、中文目录与引号地狱

Program Files (x86)本身带空格和括号,这是路径问题的源头。命令行里不加引号,C:\Program Files就会被拆成两段,后果可能是找不到文件,也可能是找到了别的同名文件。更麻烦的是中文目录:某些老版本工具对非 ASCII 路径处理不完善,报错信息还特别含糊。

规避方式其实很简单,写命令时把所有路径参数都用双引号包起来,包括输出路径:

fxc /nologo /T ps_5_0 /E main /Fo "D:\我的工程\build\shader.cso" "D:\我的工程\shader\main.hlsl"

如果条件允许,项目根目录尽量避开中文和空格,直接用英文短路径。这个建议听着像老生常谈,但我见过至少三个项目因为路径带空格,在 CI 的 shell 转义上翻了车,修起来还很费劲。

4.3 多个 SDK 共存时的编译器漂移

一台机器上装两三个 SDK 版本是常态,问题在于PATH里排第一的决定了实际用的是哪个。症状是“我这能编,他那编出来效果不一样”,或者“昨天还好好的,今天画面对不上了”。

排查方法是把实际使用的完整路径打进构建日志。前面 CMake 里那句message(STATUS "使用着色器编译器: ...")就是干这个的。更进一步,可以在 CI 里显式指定路径而不依赖PATH搜索,把不确定性彻底消除。

注意:版本漂移带来的 bug 特别难查,因为两边代码完全一样,差异只在工具链里。凡是“本地正常、构建机异常”的问题,第一件事就是对比两边的编译器版本和完整路径,别急着怀疑代码。

4.4 运行期与编译期不是一回事:忘了带运行时库

编译成功不等于运行成功。fxc编出来的是字节码,实际运行时还要靠运行时的编译/反射组件去加载和创建管线对象。有些部署场景(比如绿色版、精简版安装包)会把相关动态库漏掉,症状是程序能起、界面能出,一到加载着色器就崩溃或者黑屏,日志里也未必有明确提示。

我的检查清单是三样:编译期工具(fxc/dxc)在不在、运行期动态库(对应的d3dcompiler系列)带没带、目标机器上的图形驱动版本够不够。三者任何一个缺位,表现出来的都可能是“着色器有问题”,但根源完全不同。把这三件事分开确认,能少走很多弯路。

4.5 常见问题速查表

现象大概率原因快速验证处理
'fxc' 不是内部或外部命令不在 PATHwhere fxc无输出注入路径或改用绝对路径
where有输出但脚本仍报错脚本里写死了旧路径打印脚本实际执行的命令改成探测或属性变量
提示 profile 无效参数写错或版本不支持fxc /?看支持列表换 profile 或换 dxc
编译成功、加载失败输出格式/运行时库不匹配检查加载接口与库文件统一工具链版本
同代码两端效果不同编译器版本漂移日志打印完整路径显式锁定版本
路径含空格后命令异常未加引号或转义错误用绝对路径加引号重试统一加引号规范

顺带说一个提升效率的小技巧:把where fxc、fxc /?的前几行、以及最终使用的绝对路径,全部写进构建脚本的日志头。下次再出问题,翻一眼日志就知道当时用的是哪套工具链,不用靠回忆。

5. 把这次报错变成资产:工具链可复现的三条经验

一句“不是内部或外部命令”,本质上暴露的是环境不可复现。修好它只是第一步,让它不再发生才是长期收益。

5.1 报错信息的翻译方法论

我现在看任何工具链报错,第一件事是分清这句话是谁说的。是操作系统、是 shell、是构建系统、还是编译器自己?这句话里的不是内部或外部命令明显是 shell 的语气,那就说明程序根本没启动,排查范围立刻收缩到“寻址”上,一行代码都不用看。

这个习惯能省掉大量无效搜索。举个反例:很多人在搜到这条报错后,会去查“着色器语法怎么写”,方向完全错了因为根本没到语法检查那一步。养成“先定位是谁在说话,再决定查什么”的反射,比记住一百个具体解决方案更有用。

5.2 版本锁定与脚本化:让下一个人不用再问同一句

团队里同一个问题被不同的人问三遍,说明环境文档失效了。我的做法是把工具链版本写进仓库:一个文本文件记录 SDK 版本号、编译器完整路径、以及一段可以直接跑的验证脚本。新人拉下代码,跑一遍脚本就知道环境齐不齐,缺什么一目了然。

脚本可以极简,但必须能一次跑完:

@echo off where fxc >nul 2>nul if errorlevel 1 ( echo [FAIL] 未在 PATH 中找到 fxc,请参考 docs/toolchain.md 配置 exit /b 1 ) echo [OK] fxc 位置: where fxc fxc /nologo /T ps_5_0 /E main /Fo "%TEMP%\probe.cso" "%~dp0probe.hlsl" if errorlevel 1 ( echo [FAIL] fxc 执行失败,请检查版本与参数 exit /b 1 ) echo [OK] 着色器编译链路正常

这种东西看着不起眼,但它把“环境是否可用”从口头约定变成了可执行检查,CI 里直接复用同一份脚本,本地和构建机的判断标准就统一了。

5.3 迁移节奏:什么时候该彻底告别 fxc

最后说个现实问题:老编译器还要用多久。我的判断标准很简单——看项目是否需要 6.x 的着色器模型特性,以及目标平台的运行时是否能加载新格式产物。如果两者都不满足,那继续用着完全没问题,它的能力范围足够覆盖绝大多数常规渲染需求。

但如果是新起项目,或者正在做一轮较大的渲染重构,那迁移窗口就在眼前。迁移时最容易低估的是资源加载链路:编译命令换了只是开头,后面的反射信息读取、管线状态创建、缓存格式都要跟着调整。我的做法是先在一个独立的小模块上跑通全链路,确认加载、绑定、渲染都正常,再批量迁移。一次改一百个着色器,出了问题根本不知道是哪一个的锅。

我个人在实际操作中的体会是,这类“命令找不到”的问题最后几乎都不是技术难题,而是环境治理问题。真正花时间的从来不是那句报错本身,而是搞清楚这台机器上到底装了几套工具链、构建脚本实际用的是哪一套、以及半年后接手的人能不能复现你今天的环境。把这几件事做扎实,比记住任何一条命令都值。

返回列表