nixpkgs 中的 Maven 打包实战:buildMavenPackage、离线构建、可执行 JAR 与 Maven 4 实践
2026/9/17 15:30:02 网站建设 项目流程

nixpkgs 中的 Maven 打包实战:buildMavenPackage、离线构建、可执行 JAR 与 Maven 4 实践

【免费下载链接】nixpkgsNix Packages collection & NixOS项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgs

Maven 是 Java 生态中事实标准的构建工具,但它依赖远程仓库动态解析依赖的特性,与 Nix 构建系统的沙盒化、可复现构建存在天然冲突。本文基于 nixpkgs 官方手册中的 Maven 章节,系统讲解在 nixpkgs 中将 Maven 项目(或任何可导出为 Maven 坐标的 JVM 语言项目)打包为 Nix 包的推荐方案与备选方案:包括核心的maven.buildMavenPackage助手、overrideMavenAttrs属性覆写、buildOffline离线构建优化、Maven 4 的maven_4包,以及已不推荐但仍广泛存量的mvn2nix/buildMaven、双调用(Double Invocation)仓库固定模式,最后给出将构建产物 JAR 变为可直接执行的可执行文件的 CLASSPATH 与 MANIFEST 两种做法。

为什么 Maven 项目难以直接融入 Nix 构建

Maven 的标准工作流是:构建时在线访问中央仓库,按pom.xml声明的依赖坐标(groupId/artifactId/version)动态解析并下载 jar 与 pom 文件,填充本地仓库(传统位置为~/.m2/repository)。而 Nix 的nix-build默认在沙盒中运行、没有互联网连接,且要求构建输出可复现(output hash 稳定)。因此在 nixpkgs 中打包 Maven 项目,核心问题只有一个:如何把“Maven 仓库里到底有哪些依赖、哪些文件”变成构建的一个确定性输入

官方文档给出的整体答案分两代:

  • 现代推荐路径:maven.buildMavenPackage,把整个 Maven 依赖仓库作为一个固定输出派生(fixed-output derivation)来下载,并用一个mvnHash锁定依赖集合;
  • 历史路径:buildMaven(基于mvn2nix-maven-plugin生成 lock 文件)与 Double Invocation(整个仓库当单一源下载)。

从顶层属性定义看,maven属性集是这些功能的统一入口:pkgs/top-level/all-packages.nix 中可见maven3 = maven;以及inherit (maven) buildMaven;,即buildMaven同样由maven属性集导出;同时 pkgs/top-level/java-packages.nix 中保留了mavenfod的弃用声明(throw "'mavenfod' is renamed to/replaced by 'maven.buildMavenPackage'"),印证了buildMavenPackage取代旧入口的演进方向。

首选方案:maven.buildMavenPackage

jd-cli(一个 JD Core Java 反编译器的命令行封装)为例,完整的推荐打包写法如下:

{ lib, fetchFromGitHub, jre, makeWrapper, maven, }: maven.buildMavenPackage (finalAttrs: { pname = "jd-cli"; version = "1.2.1"; src = fetchFromGitHub { owner = "intoolswetrust"; repo = "jd-cli"; tag = "jd-cli-${finalAttrs.version}"; hash = "sha256-rRttA5H0A0c44loBzbKH7Waoted3IsOgxGCD2VM0U/Q="; }; mvnHash = "sha256-kLpjMj05uC94/5vGMwMlFzLKNFOKeyNvq/vmB6pHTAo="; nativeBuildInputs = [ makeWrapper ]; installPhase = '' runHook preInstall mkdir -p $out/bin $out/share/jd-cli install -Dm644 jd-cli/target/jd-cli.jar $out/share/jd-cli makeWrapper ${jre}/bin/java $out/bin/jd-cli \ --add-flags "-jar $out/share/jd-cli/jd-cli.jar" runHook postInstall ''; meta = { description = "Simple command line wrapper around JD Core Java Decompiler project"; homepage = "https://github.com/intoolswetrust/jd-cli"; license = lib.licenses.gpl3Plus; maintainers = with lib.maintainers; [ majiir ]; }; })

这个包通过maven.buildMavenPackage完成大部分工作。与stdenv.mkDerivation相比,它的关键差异在于mvnHash属性:它是整个 Maven 依赖集合(即固定输出派生下载下来的$out/.m2仓库)的哈希。Nix 用mvnHash保证:只要项目依赖树不变,依赖下载结果就不变;依赖一旦变化(升级版本、换插件),mvnHash失配会立刻暴露,迫使维护者显式更新,这正是 Maven 动态依赖问题被收敛为静态输入的方式。

文档中同时给出了一条通用建议:设置好buildMavenPackage之后,安装环节遵循标准的 Java.jar安装惯例——把.jar放到$out/share/java(示例中按项目需要放到了$out/share/jd-cli),再用makeWrapper包装一个可执行入口。关于 Java 应用的通用打包信息,可参考同目录的 Java 语言章节。

overrideMavenAttrs覆写包属性

buildMavenPackage的返回对象携带一个overrideMavenAttrs属性,其签名为:

overrideMavenAttrs :: (AttrSet -> Derivation) | ((AttrSet -> Attrset) -> Derivation) -> Derivation

它接受以下两种形式的参数之一,并基于“旧参数 + 新参数合并”的结果返回新的 derivation:

  1. 任意一个buildMavenPackage允许传入属性的子集(AttrSet);
  2. 一个函数,形如(old: ...)old是上一次buildMavenPackage调用所用的参数(按惯例命名),函数返回一个可传给buildMavenPackage的属性集。

它的语义类似于普通的overrideAttrs,但有一个重要区别:不允许访问传给buildMavenPackage的参数的最终值(即拿不到finalAttrs形式的全量结果)。

overrideMavenAttrs实战示例

官方示例演示了如何构建jd-cli的 1.2.0 旧版本并禁用若干不稳定的测试:

jd-cli.overrideMavenAttrs (old: rec { version = "1.2.0"; src = fetchFromGitHub { owner = old.src.owner; repo = old.src.repo; tag = "${old.pname}-${version}"; # old source hash of 1.2.0 version hash = "sha256-US7j6tQ6mh1libeHnQdFxPGoxHzbZHqehWSgCYynKx8="; }; # tests can be disabled by prefixing it with `!` # see Maven documentation for more details: # https://maven.apache.org/surefire/maven-surefire-plugin/examples/single-test.html#Multiple_Formats_in_One mvnParameters = lib.escapeShellArgs [ "-Dsurefire.failIfNoSpecifiedTests=false" "-Dtest=!JavaDecompilerTest#basicTest,!JavaDecompilerTest#patternMatchingTest" ]; # old mvnHash of 1.2.0 maven dependencies mvnHash = "sha256-N9XC1pg6Y4sUiBWIQUf16QSXCuiAPpXEHGlgApviF4I="; })

这个示例有三个可复用的技巧:

  • old.src.owner/old.src.repo让覆写尽量小,只改必须改的字段;
  • surefire 插件支持用-Dtest=!TestClass#method,!...语法按类/方法粒度禁用 flaky 测试,-Dsurefire.failIfNoSpecifiedTests=false则避免“指定了测试但某模块没有该测试”时构建直接失败;
  • 换版本意味着依赖树变化,mvnHash必须一并换成对应旧版本的值,否则固定输出派生会哈希失配。

离线构建:buildOffline = true

默认情况下buildMavenPackage的执行流程是两步:

  1. 在依赖的固定输出派生中运行mvn package -Dmaven.repo.local=$out/.m2 ${mvnParameters}
  2. 在主 derivation 中再次运行mvn package -o -nsu "-Dmaven.repo.local=$mvnDeps/.m2" ${mvnParameters}

也就是说,测试会被执行两次:第一次在下载依赖的固定输出派生里(因为mvn package本身就包含测试阶段),第二次在主构建里。这带来两个代价:一是双倍测试耗时;二是任何一次测试失败都会触发固定输出派生的重新实化(re-realise),进而把全部依赖重新下载一遍。对于大型 Maven 项目,这会造成很长的调试反馈循环。

设置buildOffline = true后,行为变为:

  1. 在固定输出派生中运行mvn de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies -Dmaven.repo.local=$out/.m2 ${mvnDepsParameters}
  2. 在主 derivation 中运行mvn package -o -nsu "-Dmaven.repo.local=$mvnDeps/.m2" ${mvnParameters}

此时所有依赖在步骤 1 一次性下载,测试只在步骤 2 执行一次。测试失败只会触发步骤 2 的重建,因为步骤 1 的依赖产物未变化、可以直接复用——反馈循环显著缩短。

注意:动态测试依赖需要手动补充

go-offline 插件无法处理所谓“动态依赖”(dynamic dependencies),测试依赖不会在步骤 1 被下载,因此在步骤 2 中很可能因缺失这些依赖而构建失败。此时必须用manualMvnArtifacts手动列出这些坐标:

maven.buildMavenPackage { manualMvnArtifacts = [ # add dynamic test dependencies here "org.apache.maven.surefire:surefire-junit-platform:3.1.2" "org.junit.platform:junit-platform-launcher:1.10.0" ]; }

稳定 Maven 插件版本:避免升级 Maven 时的连锁手工劳动

Maven 为其核心插件定义了默认版本(例如maven-compiler-plugin)。如果你的项目没有显式声明这些插件版本,那么升级 Maven 就会改变实际使用的插件版本,进而改变构建产物与mvnHash

这带来一个维护上的连锁反应:每当maven包升级,所有受影响包的mvnHash都要人工更新,否则构建会基于旧插件的依赖派生进行、因找不到请求的插件而失败。这实际上阻止了 Maven 的自动升级——任何想要推进升级的维护者都要在整个 nixpkgs 中做一遍手工劳动。

文档给出的建议是:让包显式声明所有插件版本。可以在(父)POM 中加入maven-enforcer-pluginrequirePluginVersions规则来强制校验:

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <id>enforce-plugin-versions</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requirePluginVersions /> </rules> </configuration> </execution> </executions> </plugin>

一旦有插件漏声明版本,enforcer 会在构建期直接报错,把问题提前到上游暴露。

Maven 4:maven_4

除了默认的maven包(最新的 Maven 3 发行版),nixpkgs 还提供了一个maven_4包,封装 Maven 4 发行线。maven_4是一个独立的 derivation,可以在任何使用maven的地方作为直接替代品(drop-in replacement)。例如用 Maven 4 构建同一个jd-cli

{ lib, fetchFromGitHub, jre, makeWrapper, maven_4, }: maven_4.buildMavenPackage (finalAttrs: { pname = "jd-cli"; version = "1.2.1"; src = fetchFromGitHub { owner = "intoolswetrust"; repo = "jd-cli"; tag = "jd-cli-${finalAttrs.version}"; hash = "sha256-rRttA5H0A0c44loBzbKH7Waoted3IsOgxGCD2VM0U/Q="; }; mvnHash = ""; nativeBuildInputs = [ makeWrapper ]; installPhase = '' runHook preInstall mkdir -p $out/bin $out/share/jd-cli install -Dm644 jd-cli/target/jd-cli.jar $out/share/jd-cli makeWrapper ${jre}/bin/java $out/bin/jd-cli \ --add-flags "-jar $out/share/jd-cli/jd-cli.jar" runHook postInstall ''; meta = { description = "Simple command line wrapper around JD Core Java Decompiler project"; homepage = "https://github.com/intoolswetrust/jd-cli"; license = lib.licenses.gpl3Plus; maintainers = with lib.maintainers; [ majiir ]; }; })

maven_4暴露了与maven相同的buildMavenPackage助手,因此本文前面所有模式同等适用。需要特别注意一点:Maven 4 解析出的依赖集合与 Maven 3 不同(Maven 4 在依赖解析语义上有变化),因此在两者之间切换时必须重新计算mvnHash

历史方案一:mvn2nix/buildMaven(已不推荐)

官方文档明确标注:这条路线已不再推荐,应优先使用上面的buildMavenPackage。本节内容用于理解存量包与 lock-file 思路。

为了完整演示,文档使用一个极简 Maven 项目。其pom.xml只声明一个依赖emoji-java

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>io.github.fzakaria</groupId> <artifactId>maven-demo</artifactId> <version>1.0</version> <packaging>jar</packaging> <name>NixOS Maven Demo</name> <dependencies> <dependency> <groupId>com.vdurmont</groupId> <artifactId>emoji-java</artifactId> <version>5.1.1</version> </dependency> </dependencies> </project>

主类Main.java使用emoji-java解析表情符号:

import com.vdurmont.emoji.EmojiParser; public class Main { public static void main(String[] args) { String str = "NixOS :grinning: is super cool :smiley:!"; String result = EmojiParser.parseToUnicode(str); System.out.println(result); } }

文档以emoji-java5.1.1 为唯一直接依赖构造该 demo 项目,其完整源码仓库为nixos-maven-example(文中示例文件如build-maven-repository.nixdouble-invocation-repository.nixbuild-jar.nixrunnable-jar.nix均来自该项目)。

生成依赖锁定文件

buildMaven是一条模仿其他语言 lock-file 思路的路线,它依赖mvn2nix-maven-plugin这个 Maven 插件。首先在项目源码仓库内部(或指定pom.xml位置)运行插件,生成project-info.json

# run this step within the project's source repository ❯ mvn org.nixos.mvn2nix:mvn2nix-maven-plugin:mvn2nix ❯ cat project-info.json | jq | head { "project": { "artifactId": "maven-demo", "groupId": "org.nixos", "version": "1.0", "classifier": "", "extension": "jar", "dependencies": [ { "artifactId": "maven-resources-plugin",

然后把该文件交给buildMaven函数,它返回两个属性:

  • repo:一个 Maven 仓库 derivation,实质是project-info.json中所有依赖的 symlink farm(链接农场);
  • build:一个依次执行mvn compilemvn package的简单 derivation,用于构建 JAR,可以作为更复杂 derivation 的参考骨架。

构建 Maven 仓库的最小调用:

{ pkgs ? import <nixpkgs> { }, }: with pkgs; (buildMaven ./project-info.json).repo

它与下面要讲的“双调用”相比的优势在于:/nix/store条目是每个构件一个链接的 linkFarm 结构,依赖集合的小幅变化不会导致从头重新下载全部构件。实际产物结构如下:

❯ tree $(nix-build --no-out-link build-maven-repository.nix) | head /nix/store/g87va52nkc8jzbmi1aqdcf2f109r4dvn-maven-repository ├── antlr │ └── antlr │ └── 2.7.2 │ ├── antlr-2.7.2.jar -> /nix/store/d027c8f2cnmj5yrynpbq2s6wmc9cb559-antlr-2.7.2.jar │ └── antlr-2.7.2.pom -> /nix/store/mv42fc5gizl8h5g5vpywz1nfiynmzgp2-antlr-2.7.2.pom ├── avalon-framework │ └── avalon-framework │ └── 4.1.3 │ ├── avalon-framework-4.1.3.jar -> /nix/store/iv5fp3955w3nq28ff9xfz86wvxbiw6n9-avalon-framework-4.1.3.jar

双调用(Double Invocation)模式

官方注记:这是最简单的方式,但可能因为 output hash 变化引发不必要的重建。

双调用绕过了“nix-build沙盒内无网络”的问题:把整个 Maven 仓库当成一个整体源来下载,依赖 Maven 自身的依赖解析满足固定输出哈希。它和fetchgit等 fetcher 的思路类似——只是要确定下载内容,必须先实际跑一次 Maven 构建。

第一步是把 Maven 项目作为固定输出派生来构建,以此收集 Maven 仓库。传统上 Maven 仓库位于~/.m2/repository,这里被覆写为$out目录:

{ lib, stdenv, maven, }: stdenv.mkDerivation { name = "maven-repository"; buildInputs = [ maven ]; src = ./.; # or fetchFromGitHub, cleanSourceWith, etc buildPhase = '' runHook preBuild mvn package -Dmaven.repo.local=$out runHook postBuild ''; # keep only *.{pom,jar,sha1,nbm} and delete all ephemeral files with lastModified timestamps inside installPhase = '' runHook preInstall find $out -type f \ -name \*.lastUpdated -or \ -name resolver-status.properties -or \ -name _remote.repositories \ -delete runHook postInstall ''; # don't do any fixup dontFixup = true; outputHashAlgo = null; outputHashMode = "recursive"; # replace this with the correct SHA256 outputHash = lib.fakeHash; }

首次构建会失败,并打印出应填入的outputHash;填入正确哈希后,构建产出的/nix/store条目即为完整的 Maven 仓库:

❯ tree $(nix-build --no-out-link double-invocation-repository.nix) | head /nix/store/8kicxzp98j68xyi9gl6jda67hp3c54fq-maven-repository ├── backport-util-concurrent │ └── backport-util-concurrent │ └── 3.1 │ ├── backport-util-concurrent-3.1.pom │ └── backport-util-concurrent-3.1.pom.sha1 ├── classworlds │ └── classworlds │ ├── 1.1 │ │ ├── classworlds-1.1.jar

两个工程细节值得注意:

  • installPhase中删除*.lastUpdatedresolver-status.properties_remote.repositories这些临时文件,是为了避免后续运行中它们携带的时间戳类内容让 output hash 漂移;
  • 若项目使用SNAPSHOT 依赖版本区间(version ranges),随时间推移解析结果可能变化,output hash 会随之改变——这是该方式不如buildMaven推荐的根本原因。

构建 JAR:三种仓库策略共用的最终步骤

无论上文选择哪种仓库固定策略,构建 JAR 这一步都是相同的:

{ stdenv, maven, callPackage, }: let # pick a repository derivation, here we will use buildMaven repository = callPackage ./build-maven-repository.nix { }; in stdenv.mkDerivation (finalAttrs: { pname = "maven-demo"; version = "1.0"; src = fetchTarball "https://github.com/fzakaria/nixos-maven-example/archive/main.tar.gz"; buildInputs = [ maven ]; buildPhase = '' runHook preBuild echo "Using repository ${repository}" mvn --offline -Dmaven.repo.local=${repository} package; runHook postBuild ''; installPhase = '' runHook preInstall install -Dm644 target/${finalAttrs.pname}-${finalAttrs.version}.jar $out/share/java runHook postInstall ''; })

这里的关键点是mvn --offline -Dmaven.repo.local=${repository}:完全离线、指向已固定的仓库 derivation。产物结构为:

❯ tree $(nix-build --no-out-link build-jar.nix) /nix/store/7jw3xdfagkc2vw8wrsdv68qpsnrxgvky-maven-demo-1.0 └── share └── java └── maven-demo-1.0.jar 2 directories, 1 file

文档中有一条与 nixpkgs Java 工具链强相关的设计注记:把库放进$out/share/java,是因为 JDK 包携带一个stdenv setup hook,它会自动把所有 build input 的share/java目录下的 JAR 追加到 CLASSPATH 环境变量——这就是 nixpkgs 中 Java 包之间“声明buildInputs即自动获得类路径依赖”的底层机制。

可执行 JAR:两种比 UberJar 更 Nix 化的做法

上面构建出的jar文件本身不可直接执行,必须用java -jar $out/share/java/output.jar并自行提供 classpath 依赖。传统的解决方式是打一个 UberJar(fat jar),但文档指出下面两种方法比 UberJar 更贴合 Nix 的依赖模型,并都通过makeWrapper让 derivation 产出一个可执行入口。两种方式都复用前面构建的仓库(无论buildMaven还是双调用产物)。

方式一:CLASSPATH(适合为 nixpkgs 提供包、不想改动pom.xml

思路是读取 Maven 仓库、展平为 jar 文件列表,用 CLASSPATH 分隔符拼接成完整 classpath,再交给makeWrapper

{ stdenv, maven, callPackage, makeWrapper, jre, }: let repository = callPackage ./build-maven-repository.nix { }; in stdenv.mkDerivation (finalAttrs: { pname = "maven-demo"; version = "1.0"; src = fetchTarball "https://github.com/fzakaria/nixos-maven-example/archive/main.tar.gz"; nativeBuildInputs = [ makeWrapper ]; buildInputs = [ maven ]; buildPhase = '' runHook preBuild echo "Using repository ${repository}" mvn --offline -Dmaven.repo.local=${repository} package; runHook postBuild ''; installPhase = '' runHook preInstall mkdir -p $out/bin classpath=$(find ${repository} -name "*.jar" -printf ':%h/%f'); install -Dm644 target/maven-demo-${finalAttrs.version}.jar $out/share/java # create a wrapper that will automatically set the classpath # this should be the paths from the dependency derivation makeWrapper ${jre}/bin/java $out/bin/maven-demo \ --add-flags "-classpath $out/share/java/maven-demo-${finalAttrs.version}.jar:''${classpath#:}" \ --add-flags "Main" runHook postInstall ''; })

细节解析:find ... -printf ':%h/%f'生成:目录/文件名形式的列表;''${classpath#:}在 shell 中剥掉首个多余的冒号;-classpath参数把主 JAR 与全部依赖 JAR 合并为一条类路径,Main是主类名。这样产出的$out/bin/maven-demo是一个已注入类路径的 wrapper 脚本。

方式二:MANIFEST 文件(适合项目所有者、可以修改pom.xml

作为上游项目维护者,可以直接在pom.xml里通过maven-jar-plugin生成带 classpath 信息的 MANIFEST:

<build> <plugins> <plugin> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>../../repository/</classpathPrefix> <classpathLayoutType>repository</classpathLayoutType> <mainClass>Main</mainClass> </manifest> <manifestEntries> <Class-Path>.</Class-Path> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build>

该配置让 JAR 按 Maven 仓库的目录布局,到相对路径lib/风格的repository/文件夹中查找依赖。生成的 MANIFEST 内容形如:

❯ unzip -q -c $(nix-build --no-out-link runnable-jar.nix)/share/java/maven-demo-1.0.jar META-INF/MANIFEST.MF Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Built-By: nixbld Class-Path: . ../../repository/com/vdurmont/emoji-java/5.1.1/emoji-java-5.1.1.jar ../../repository/org/json/json/20170516/json-20170516.jar Created-By: Apache Maven 3.6.3 Build-Jdk: 1.8.0_265 Main-Class: Main

注意classpathPrefix../../repository/,因此 Nix 侧的 derivation 需要在installPhase中把仓库软链进产物,使 JAR 在运行时能沿相对路径找到依赖:

{ stdenv, maven, callPackage, makeWrapper, jre, }: let # pick a repository derivation, here we will use buildMaven repository = callPackage ./build-maven-repository.nix { }; in stdenv.mkDerivation (finalAttrs: { pname = "maven-demo"; version = "1.0"; src = fetchTarball "https://github.com/fzakaria/nixos-maven-example/archive/main.tar.gz"; nativeBuildInputs = [ makeWrapper ]; buildInputs = [ maven ]; buildPhase = '' runHook preBuild echo "Using repository ${repository}" mvn --offline -Dmaven.repo.local=${repository} package; runHook postBuild ''; installPhase = '' runHook preInstall mkdir -p $out/bin # create a symbolic link for the repository directory ln -s ${repository} $out/repository install -Dm644 target/maven-demo-${finalAttrs.version}.jar $out/share/java # create a wrapper that will automatically set the classpath # this should be the paths from the dependency derivation makeWrapper ${jre}/bin/java $out/bin/maven-demo \ --add-flags "-jar $out/share/java/maven-demo-${finalAttrs.version}.jar" runHook postInstall ''; })

文档特别指出一个 closure 控制细节:脚本刻意依赖jre而非jdk,以限制运行应用所必需的运行时闭包(runtime closure)体积。最终产物与运行结果:

❯ tree $(nix-build --no-out-link runnable-jar.nix) /nix/store/8d4c3ibw8ynsn01ibhyqmc1zhzz75s26-maven-demo-1.0 ├── bin │ └── maven-demo ├── repository -> /nix/store/g87va52nkc8jzbmi1aqdcf2f109r4dvn-maven-repository └── share └── java └── maven-demo-1.0.jar ❯ $(nix-build --no-out-link --option tarball-ttl 1 runnable-jar.nix)/bin/maven-demo NixOS 😀 is super cool 😃!

相关实现文件与模式选择小结

围绕本文内容,仓库内可直接查证的相关文件包括:

  • Maven 手册章节:本文主体来源;
  • Java 手册章节:Java 应用通用打包信息(.jar安装与 wrapper 惯例);
  • pkgs/top-level/all-packages.nix:maven3 = maven别名与buildMaven属性导出;
  • pkgs/top-level/java-packages.nix:mavenfod已弃用并指向maven.buildMavenPackage
  • pkgs/top-level/all-packages.nix:fetchMavenArtifact导出,用于按需获取单个 Maven 构件;
  • pkgs/build-support/release/maven-build.nix:从源码结构看,n

【免费下载链接】nixpkgsNix Packages collection & NixOS项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询