简体   繁体   中英

How do I access an environment variable during compile time, when building a Java application on Windows?

I have a Java application for Windows. I would like that Java application, when run, to create a new file on disk with a file name that includes a version number. That version number is available as an OS environment variable while the Java application is being built by my Azure Dev Ops (ADO) pipeline. The ADO pipeline builds my code using CMake (which runs the javac command).

A solution is given here when using Maven as the build system. I could not find how to do the same in my build system, which does not use Maven and pom.xml. Is there a way to do the same when using javac command line?

Thanks,

Darren

CMake runs on many platforms

maven runs on about just as many, though.

That version number is available as an environment variable while the Java application is being built

javac has absolutely no support for preprocessing and cannot do this, period. preprocessing and IDEs mostly hate each others guts, which probably explains the java ecosystem and communities extremely strong dislike of the notion of a preprocessor; they like IDEs.

Answering your question directly

Thus, you'll have to look elsewhere. For example, you can include some token value in your java source file, such as:

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

and then, before invoking javac , use sed or some other search and replace tool. However, this complicates your build considerably: You'd have to take that source file (which is really no longer an actual source file, it's a template to a source file now), copy it over (applying the sed transformation on the fly), and then compile that. That means the source file has to live elsewhere or have a different extension and that plays absolute havoc with your editor, because this is not 'normal' in the java community, so no tools support this sort of thing. Your IDE will get confused and show all sorts of errors in your code due to the (to the IDE) missing file.

Another solution is some creative hackery, where sed will modify the file in flight:

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);

And then your sed tool can just 'replace on the spot', using a regexp that will find the whole thing, which leaves the {@@ @@} marker intact, and which just replaces the 1.12 (everything from after the marker up to the first quotation mark - and then you need a rule that versions cannot ever contain quotation marks. I hope you can make that promise or this gets even more complicated.

CMake runs off of file modification timestamps, right? Oof. Well, try to make it leave the late 80s and work off of hashes instead, or this is going to cause needless recompilation. Alternatively, try to make sed not update the time stamp if the requested change ends up being a no-op.

But wait...

Are you sure you want to go down that deep, dark rabbit hole? Can't you do this much more java-esque, much simpler thing?

Instead of modifying a source file, can you instead add 1 non-class file to the end result (I assume your CMake tool ends up making a dex or jar or something similar)? For example, ensure that version.txt is available in the 'root' of the jar file. In java, you can write code that goes: "Hey, look in the exact same place you're looking for the very class files that compose this very application, and gimme the contents of one of em":

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");
    }
  }
}

That'll do the job. This seems much easier: Now your CMake script just needs to make sure version.txt has the right version in it and is included in the jar or whatever the output of your build pipeline is (I admit I'm not familiar with what ADO is).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM