【问题标题】:How do I access an environment variable during compile time, when building a Java application on Windows?在 Windows 上构建 Java 应用程序时,如何在编译期间访问环境变量?
【发布时间】:2021-07-15 04:38:37
【问题描述】:

我有一个适用于 Windows 的 Java 应用程序。我希望该 Java 应用程序在运行时在磁盘上创建一个新文件,其文件名包含版本号。当我的 Azure Dev Ops (ADO) 管道正在构建 Java 应用程序时,该版本号可用作操作系统环境变量。 ADO 管道使用 CMake(运行 javac 命令)构建我的代码。

当使用 Maven 作为构建系统时,一个解决方案是 given here。我在不使用 Maven 和 pom.xml 的构建系统中找不到如何做同样的事情。使用 javac 命令行时有没有办法做同样的事情?

谢谢,

达伦

【问题讨论】:

  • ADO 可以使用 Maven 构建。 Visual Studio 支持 Maven。为什么要使用很少有项目会使用的平台特定工具?
  • CMake 在许多平台上运行,这就是我们在 ADO 管道中使用它的原因。此 Java 代码适用于 Linux、Android、iOS 和 Windows。但是,我想要进行的更改(上面讨论过)仅适用于此代码的 Widnows 版本。
  • 访问 Windows 操作系统环境变量?
  • 基本上你必须在编译时捕获变量的值。我对您的构建系统一无所知,但我建议将版本号写入文件,然后将文件作为资源包含在 jar 中,然后在运行 jar 时可用。
  • @Darren - 我并不是说它不起作用。一个汇编语言程序会付出足够的努力。但是如果你在 Java 世界中,CMAKE 不是普通的构建工具之一。逆流而上有时是有用的,但有很多很多构建工具,我只是鼓励使用在 Java 世界中更标准的东西。

标签: java environment-variables javac


【解决方案1】:

CMake 在许多平台上运行

不过,maven 运行的次数也差不多。

在构建 Java 应用程序时,该版本号可用作环境变量

javac 完全不支持预处理,也不能这样做。预处理和 IDE 最讨厌对方的胆量,这可能解释了 java 生态系统和社区非常不喜欢预处理器的概念;他们喜欢 IDE。

直接回答您的问题

因此,您将不得不寻找其他地方。例如,您可以在 java 源文件中包含一些令牌值,例如:

private static final String FULL_VERSION_ID = "{@@ INJECT_VERSION_HERE @@}";

然后,在调用javac 之前,使用sed 或其他一些搜索和替换工具。但是,这会使您的构建变得相当复杂:您必须获取该源文件(它实际上不再是实际的源文件,它现在是源文件的模板),将其复制过来(即时应用 sed 转换) ,然后编译它。这意味着源文件必须位于其他地方或具有不同的扩展名,这会对您的编辑器造成绝对破坏,因为这在 java 社区中是不“正常的”,因此没有工具支持这种事情。由于(对于 IDE)缺少文件,您的 IDE 会感到困惑并在代码中显示各种错误。

另一种解决方案是一些创造性的骇客,sed 将在飞行中修改文件:

private static final String FULL_VERSION_TEMPLATE = "{@@ INJECT_VERSION_HERE @@}1.12";
private static final String FULL_VERSION = 
  FULL_VERSION_TEMPLATE.substring(FULL_VERSION_TEMPLATE.indexOf("@@}") + 3);

然后您的 sed 工具可以“当场替换”,使用将找到整个内容的正则表达式,使 {@@ @@} 标记完好无损,只是替换 1.12 (从标记之后到第一个引号的所有内容 - 然后你需要一个规则,版本不能包含引号。我希望你能做出这个承诺,否则这会变得更加复杂。

CMake 运行文件修改时间戳,对吗?钱币。好吧,试着让它离开 80 年代后期,转而使用散列,否则这将导致不必要的重新编译。或者,如果请求的更改最终成为无操作,请尝试使 sed 不更新时间戳。

但是等等……

你确定你想进入那个又深又黑的兔子洞吗?难道你不能做更多类似 java 的、更简单的事情吗?

您可以在最终结果中添加 1 个非类文件,而不是修改源文件(我假设您的 CMake 工具最终会生成 dex 或 jar 或类似的东西)?例如,确保 version.txt 在 jar 文件的“根”中可用。在 java 中,您可以编写如下代码:“嘿,在您正在寻找构成这个应用程序的类文件的完全相同的地方查找,并给我其中一个的内容”:

public class MyApp {
  public static void main(String[] args) {
    System.out.println(readVersion());
  }
  public static String readVersion() {
    try {
      try (var in = MyApp.class.getResourceAsStream("/version.txt")) {
        return new String(in.readAllBytes(), StandardCharsets.UTF_8).trim();
      }
    } catch (IOException e) {
      throw new InternalError("version.txt not found");
    }
  }
}

这样就可以了。这似乎非常容易了:现在你的 CMake 脚本只需要确保 version.txt 有正确的版本,并且包含在 jar 中或者你的构建管道的输出是什么(我承认我'我不熟悉 ADO 是什么)。

【讨论】:

  • 感谢@rzwitserloot 非常详细的回复!这非常有帮助,我感谢您为回答我的问题所付出的努力。我喜欢插入 version.txt 文件的想法,今天将对其进行研究。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-28
  • 1970-01-01
相关资源
最近更新 更多