跳到内容

第 0 卷 / 第 5 章 / 第 5 课

5.5 依赖与构建工具综合实验 ​

前置知识:本章前四页

预计时间:25~35 分钟

练习环境:Bash、Python 3、Node/npm 与 Java;Maven、Gradle 分别需要本机工具和离线缓存

完成标志:能在临时目录完成可用工具的实验,并解释离线构建因缓存缺项而失败的原因

依赖、清单和版本规则已经分清。本实验使用 mktemp 创建的临时工作区,不修改仓库或全局配置。Python 与 npm 实验不安装第三方依赖;Maven/Gradle 只使用本机工具和已有缓存。缺少工具时跳过对应小节,不要为了完成教程临时改全局软件源。

1. Python 虚拟环境 ​

先执行前两行创建 $workdir;即使跳过 Python 部分,后续实验仍需要这个目录变量。其余命令要求 Python 已提供 venv 和 pip。

bash
workdir=$(mktemp -d)
mkdir -p "$workdir/py-demo"
python3 -m venv "$workdir/py-demo/.venv"
. "$workdir/py-demo/.venv/bin/activate"
python -m pip --version
python -m pip list
python -c 'import sys; print(sys.prefix != sys.base_prefix)'
deactivate

最后一行 Python 输出应为 True。PowerShell 激活脚本位于 .venv\Scripts\Activate.ps1。

2. npm 清单与空依赖 lock ​

bash
(
mkdir -p "$workdir/node-demo"
cd "$workdir/node-demo"
npm_config_cache="$workdir/npm-cache"
export npm_config_cache
npm init -y
npm pkg set scripts.check="node -e \"console.log('ok')\""
npm install --package-lock-only --ignore-scripts --offline --no-audit --no-fund
npm run check
test -f package.json
test -f package-lock.json
)

圆括号让这组命令在子 Shell 中运行,退出后不保留 npm 缓存变量和目录变化。预期 npm run check 打印 ok。这一步没有第三方依赖。package-lock.json 仍记录根项目,npm 的日志与缓存也被定向到临时目录。真实项目新增包时需要访问配置的 npm registry。

3. 最小 Maven 项目 ​

如果 command -v mvn 能找到 Maven 3.6.3+,且 mvn --version 显示使用 JDK 17,再创建项目:

bash
mkdir -p "$workdir/maven-demo/src/main/java/example"
cat > "$workdir/maven-demo/pom.xml" <<'XML'
<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>example.workshop</groupId>
  <artifactId>maven-demo</artifactId>
  <version>1.0.0</version>
  <properties>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.14.1</version>
      </plugin>
    </plugins>
  </build>
</project>
XML
cat > "$workdir/maven-demo/src/main/java/example/App.java" <<'JAVA'
package example;

public final class App {
    public static void main(String[] args) {
        System.out.println("build tool ok");
    }
}
JAVA
cd "$workdir/maven-demo"
mvn -o package
java -cp target/classes example.App

这里固定了支持 maven.compiler.release 的编译插件,成功编译后应输出 build tool ok。-o 禁止 Maven 解析器访问远程仓库;它不是对任意插件代码的网络沙箱。若本地 Maven 缓存没有构建插件,命令会失败;删除 -o 会访问 POM 和设置中配置的仓库。项目正式使用时应生成并提交 Maven Wrapper。

4. 最小 Gradle 项目 ​

如果 command -v gradle 能找到 与本机 JDK 兼容的 Gradle 7 或更高版本,就建立一份独立项目。即使上一节因 Maven 不可用而跳过,这里也能运行:

bash
mkdir -p "$workdir/gradle-demo/src/main/java/example"
cat > "$workdir/gradle-demo/src/main/java/example/App.java" <<'JAVA'
package example;

public final class App {
    public static void main(String[] args) {
        System.out.println("build tool ok");
    }
}
JAVA
cat > "$workdir/gradle-demo/build.gradle" <<'GRADLE'
plugins {
    id 'java'
    id 'application'
}

application {
    mainClass = 'example.App'
}
GRADLE
cd "$workdir/gradle-demo"
gradle --offline --no-daemon build
gradle --offline --no-daemon run

--offline 要求 Gradle 发行包、插件和依赖已经可用;缺项时不要把缓存问题误判成 Java 编译错误。--no-daemon 避免保留长期后台进程;JVM 参数不匹配时仍可能启动一个构建结束就退出的单次 daemon。Gradle 会读写用户缓存,临时项目目录不会隔离这些缓存,见 Gradle Daemon 文档。真实项目应提交 Gradle Wrapper,并用 ./gradlew 代替本机 gradle。

排障 ​

  1. 打印运行时和工具版本,确认执行的是项目预期版本。
  2. 区分网络/认证、版本无解、校验、编译和运行时 classpath 错误。
  3. 查看依赖树与引入路径,不先删 lock。
  4. 镜像属于供应链配置。不要把教程镜像永久写进全局配置,也不要把凭据提交。
  5. 清缓存前记录路径;缓存损坏并不是所有安装错误的原因。

清理 ​

bash
cd
ls -ld -- "$workdir"
rm -r -- "$workdir"

临时目录清理后,真正需要留下的是三类证据:项目声明了什么、解析器选中了什么、构建使用了什么工具链。下一章从一份失败日志的退出码、stderr 和堆栈开始排错。

→ 下一章:读错误与日志

Built with VitePress | Software Systems Atlas