在windows上构建java应用程序时,如何在编译时访问环境变量?

ijnw1ujt  于 2021-07-09  发布在  Java
关注(0)|答案(1)|浏览(198)

我有一个windows的java应用程序。我希望java应用程序在运行时在磁盘上创建一个新文件,文件名中包含版本号。当java应用程序由myazuredevops(ado)管道构建时,该版本号作为os环境变量可用。ado管道使用cmake(运行javac命令)构建我的代码。
当使用maven作为构建系统时,这里给出了一个解决方案。我在我的构建系统中找不到同样的方法,它不使用maven和pom.xml。在使用javac命令行时,有没有同样的方法?
谢谢,
达伦

btqmn9zl

btqmn9zl1#

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工具就可以“就地替换”,使用regexp来查找整个内容,这就留下了 {@@ @@} 标记完好无损,它只是取代了1.12(从标记之后到第一个引号的所有内容),然后您需要一个规则,即版本不能包含引号。我希望你能做出承诺,否则事情会变得更复杂。
cmake运行文件修改时间戳,对吗?噢。好吧,试着让它离开80年代后期,改用散列,否则会导致不必要的重新编译。或者,如果请求的更改最终是禁止操作的,则尝试使sed不更新时间戳。

但是等等。。。

你确定你要下到那个又深又黑的兔子洞里去吗?你不能做一件更像java的,更简单的事情吗?
不是修改源文件,而是向最终结果添加一个非类文件(我假设您的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是什么)。

相关问题