-
Notifications
You must be signed in to change notification settings - Fork 506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8264449: Enable reproducible builds with SOURCE_DATE_EPOCH #446
Conversation
👋 Welcome back jgneff! A progress list of the required criteria for merging this PR into |
Webrevs
|
I think there might be a Skara bug. The pre-submit builds on Linux, macOS, and Windows completed immediately. I think that's because the first of the two commits in this pull request includes the Java Bug ID from another pending pull request, because this pull request is a continuation of that one. I can squash the two commits and force-push the changes, if that would help. |
No, no bug. Sorry about that. I just don't know how GitHub works. |
/reviewers 2 |
@kevinrushforth |
I recommend trying this with the following gradle flags, to match the settings for production builds:
where Note that this will build the native media libraries and the native webkit library. |
Thanks, Kevin. Good news so far. I'm posting the Linux results while I run the macOS and Windows builds. LinuxI ran the following commands twice, moving the $ bash gradlew clean
$ bash gradlew -PCONF=Release -PPROMOTED_BUILD_NUMBER=5 \
-PHUDSON_BUILD_NUMBER=101 -PHUDSON_JOB_NAME=jfx \
-PCOMPILE_WEBKIT=true -PCOMPILE_MEDIA=true \
-PBUILD_LIBAV_STUBS=true sdk jmods javadoc Then I changed the Hudson job number with The first result is as hoped, and the second result is as expected: $ diff -qr build1 build2
$ diff -qr build2 build3
Files build2/jmods/javafx.base.jmod
and build3/jmods/javafx.base.jmod
differ
Files build2/modular-sdk/modules/javafx.base/com/sun/javafx/runtime/VersionInfo.class
and build3/modular-sdk/modules/javafx.base/com/sun/javafx/runtime/VersionInfo.class
differ
Files build2/modular-sdk/modules_src/javafx.base/com/sun/javafx/runtime/VersionInfo.java
and build3/modular-sdk/modules_src/javafx.base/com/sun/javafx/runtime/VersionInfo.java
differ
Files build2/publications/javafx.base-linux.jar
and build3/publications/javafx.base-linux.jar
differ
Files build2/sdk/lib/javafx.base.jar
and build3/sdk/lib/javafx.base.jar
differ
Files build2/sdk/lib/src.zip
and build3/sdk/lib/src.zip
differ You have to appreciate the irony of adding all this information to the build — the time, the path, even the job number — so that we can uniquely identify a build by its output. Meanwhile, if we didn't add this information, our builds could be uniquely identified by a single Git tag. |
There's good news and bad news. Good news first. macOSThe two comparisons of the three builds on macOS were similar to those on Linux: $ diff -qr build1 build2
$ diff -qr build2 build3
Files build2/jmods/javafx.base.jmod
and build3/jmods/javafx.base.jmod
differ
Files build2/modular-sdk/modules/javafx.base/com/sun/javafx/runtime/VersionInfo.class
and build3/modular-sdk/modules/javafx.base/com/sun/javafx/runtime/VersionInfo.class
differ
Files build2/modular-sdk/modules_src/javafx.base/com/sun/javafx/runtime/VersionInfo.java
and build3/modular-sdk/modules_src/javafx.base/com/sun/javafx/runtime/VersionInfo.java
differ
Files build2/publications/javafx.base-mac.jar
and build3/publications/javafx.base-mac.jar
differ
Files build2/sdk/lib/javafx.base.jar
and build3/sdk/lib/javafx.base.jar
differ
Files build2/sdk/lib/src.zip
and build3/sdk/lib/src.zip
differ WindowsThe Windows build, on the other hand, failed to produce identical copies of the media and WebKit shared libraries: $ diff -qr build1 build2
Files build1/jmods/javafx.media.jmod
and build2/jmods/javafx.media.jmod
differ
Files build1/jmods/javafx.web.jmod
and build2/jmods/javafx.web.jmod
differ
Files build1/modular-sdk/modules_libs/javafx.media/fxplugins.dll
and build2/modular-sdk/modules_libs/javafx.media/fxplugins.dll
differ
Files build1/modular-sdk/modules_libs/javafx.media/glib-lite.dll
and build2/modular-sdk/modules_libs/javafx.media/glib-lite.dll
differ
Files build1/modular-sdk/modules_libs/javafx.media/gstreamer-lite.dll
and build2/modular-sdk/modules_libs/javafx.media/gstreamer-lite.dll
differ
Files build1/modular-sdk/modules_libs/javafx.media/jfxmedia.dll
and build2/modular-sdk/modules_libs/javafx.media/jfxmedia.dll
differ
Files build1/modular-sdk/modules_libs/javafx.web/jfxwebkit.dll
and build2/modular-sdk/modules_libs/javafx.web/jfxwebkit.dll
differ
Files build1/publications/javafx.media-win.jar
and build2/publications/javafx.media-win.jar
differ
Files build1/publications/javafx.web-win.jar
and build2/publications/javafx.web-win.jar
differ
Files build1/sdk/bin/fxplugins.dll
and build2/sdk/bin/fxplugins.dll
differ
Files build1/sdk/bin/glib-lite.dll
and build2/sdk/bin/glib-lite.dll
differ
Files build1/sdk/bin/gstreamer-lite.dll
and build2/sdk/bin/gstreamer-lite.dll
differ
Files build1/sdk/bin/jfxmedia.dll
and build2/sdk/bin/jfxmedia.dll
differ
Files build1/sdk/bin/jfxwebkit.dll
and build2/sdk/bin/jfxwebkit.dll
differ I didn't bother running the third build with |
@kevinrushforth I found the Makefiles building the media libraries for Windows. I can fix those, but there's also
They both state at the top, "There should never be a need to modify anything below this line." Are those files directly from their upstream sources? If so, what's our policy on patching them while waiting for fixes? |
The WebKit build is complicated (to say the least). All of the WebKit components, including the additional third-party dependencies in @arun-joseph might be able to comment on that. |
I should add that if changes are needed to the |
It would be better to add the flag in |
Ideally the latter, if feasible, so that the logic to handle |
Enable reproducible builds of the native media shared libraries for Windows when SOURCE_DATE_EPOCH is defined. The libraries are: fxplugins.dll glib-lite.dll gstreamer-lite.dll jfxmedia.dll
IMHO, it would make sense to merge any clear improvement of the status-quo and debug+fix more in a later PR. "Perfect is the enemy of good." Regarding Webkit, I know of |
Given the level of effort to test this, I would recommend minimizing the number of separate fixes for this enhancement. If WebKit turns out to be too big a can of worms, then it might make sense to do everything else with this fix and file a follow-on for WebKit.
Right, we aren't nearly that old. We just updated WebKit a little over 2 months ago with recent sources (we update WebKit every six months). |
I agree that we will have to draw the line somewhere, but right now I'm down to just one file on one operating system out of 10,633 files in the build output! (It's just I would, though, like to postpone tests of static builds and builds for Android and iOS. My priorities for this pull request are:
I would be happy to satisfy just the first group, but we might be close to getting all three. |
/contributor add Bernhard M. Wiedemann javabmw@lsmod.de |
@bmwiedemann Only the author (@jgneff) is allowed to issue the |
@sashamatveev Can you look at the changes to the media Makefiles? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Media makefiles look fine.
Mailing list message from Eric Bresie on openjfx-dev: Silly question, is the difference with Windows just the nature of the native support on each platform (Unix based vs Windows) and libraries used as part of that? Eric Bresie |
I reverted the version timestamp to the original format. The version looks like this for "release" early-access builds: $ cat build5/sdk/lib/javafx.properties
javafx.version=21-ea
javafx.runtime.version=21-ea+12
javafx.runtime.build=12 and like this for developer builds: $ cat build1/sdk/lib/javafx.properties
javafx.version=21-internal
javafx.runtime.version=21-internal+0-2023-04-06-232926
javafx.runtime.build=0 The only difference is that the timestamp is localized to UTC, while before it was in the local time of the build machine. The // Parses the format in the current JavaFX release
var currentFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HHmmss");
var localTime = LocalDateTime.parse(timestamp, currentFormatter);
// Parses the ISO 8601 basic format
var basicFormatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX");
var zonedTime = ZonedDateTime.parse(timestamp, basicFormatter); |
For the record, here's the latest version of my program that tests the timestamp formats: import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class Timestamp {
private static final String OPT = "([-a-zA-Z0-9.]+)";
private static final String OK = " (OK)";
private static final String NOT_OK = " (FAILED)";
public static void main(String[] args) {
var buildInstant = Instant.now().truncatedTo(ChronoUnit.SECONDS);
// Creates the timestamp in the ISO 8601 extended format
String extended = buildInstant.toString();
// Creates the timestamp in the current non-stnadard format
var zonedTime = ZonedDateTime.ofInstant(buildInstant, ZoneOffset.UTC);
var currentFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HHmmss");
String current = zonedTime.format(currentFormatter);
// Creates the timestamp in the ISO 8601 basic format
zonedTime = ZonedDateTime.ofInstant(buildInstant, ZoneOffset.UTC);
var basicFormatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX");
String basic = zonedTime.format(basicFormatter);
// Prints the timestamps and checks them for the version OPT field
System.out.print("ISO 8601 extended format = " + extended);
System.out.println(extended.matches(OPT) ? OK : NOT_OK);
System.out.print("Current JavaFX format = " + current);
System.out.println(current.matches(OPT) ? OK : NOT_OK);
System.out.print("ISO 8601 basic format = " + basic);
System.out.println(basic.matches(OPT) ? OK : NOT_OK);
System.out.println();
// Parses the timestamp in the ISO 8601 extended format
zonedTime = ZonedDateTime.parse(extended);
System.out.println("Parsed extended time = " + zonedTime);
// Parses the timestamp in the current non-standard format
var localTime = LocalDateTime.parse(current, currentFormatter);
System.out.println("Parsed current time = " + localTime);
// Parses the timestamp in the ISO 8601 basic format
zonedTime = ZonedDateTime.parse(basic, basicFormatter);
System.out.println("Parsed basic time = " + zonedTime);
}
} Below is a sample of its output: $ java Timestamp
ISO 8601 extended format = 2023-04-07T16:01:16Z (FAILED)
Current JavaFX format = 2023-04-07-160116 (OK)
ISO 8601 basic format = 20230407T160116Z (OK)
Parsed extended time = 2023-04-07T16:01:16Z
Parsed current time = 2023-04-07T16:01:16
Parsed basic time = 2023-04-07T16:01:16Z |
Your solution using two formatted date strings looks good to me. Thanks for the additional detail. |
I solved the build failure occurring on Windows by downgrading to Visual Studio 2022 Build Tools version 17.1.0, dated February 15, 2022, from the prior version 17.5.4 that I was using. I opened a bug report, linked below, as a heads-up for when we upgrade Visual Studio. I'm now using the following versions of the tools: Toolchains
Build Tools
My latest test results are:
where:
I created bug reports to track each of the remaining potential problems:
|
I forgot the original remaining problem! It's listed as item 4 under Fixes in the description at the top of this pull request and now described by the following bug report:
|
@jgneff This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
Now that the compiler updates are in, I'll resume reviewing and testing this. I'd like to get it in soon. @jgneff Can you merge in the latest master? This will pick up the recent compiler updates along with any other recent changes. I'll do that anyway when testing, but that way we'll get a GHA run on Mac and Linux with the latest compilers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I finished all my testing. This looks good to me, and I have no further questions or concerns. There is some follow-up work that is needed, but that can be done after we get this in.
Here are the results of my testing. I did 3 CI builds as well as a few local builds on all three desktop OS platforms. All of my testing was done using the latest compiler devkits and the kevinrushforth:test-pr-446 branch, which is the latest branch from this PR with the latest upstream master merged in.
For the first test, I ran without setting SOURCE_DATE_EPOCH
and compared the results of a build from test-pr-446
with a build from master
. All is as expected.
For the second test, I compared the results of two builds using the same SOURCE_DATE_EPOCH
timestamp on the same platform. Except for the native WebKit library on Windows and macOS, everything was identical.
For the third test, I compared the results of a local build with the results of a CI build using the same SOURCE_DATE_EPOCH
timestamp. There were some differences on Windows and Linux in the native binaries that should be followed-up on.
macOS
Two different CI builds on the same system:
- Only
libjfxwebkit.dylib
is different
Two different builds (CI and local) each on a different macOS 13.x system:
libjfxwebkit.dylib
is different.bss
files differ due to known issue where the absolute file path is recorded in the.bss
files
Linux
Two different CI builds on the same system:
* All artifacts are identical
Two different builds (CI and local) each on a different OS platform (Oracle Linux 7.x versus Ubuntu 16.04) with devkit:
* All .so
files are different
* .bss
files differ due to file path issues
Windows
Two different builds on the same system:
* Only jfxwebkit.dll
is different
Two different builds (CI and local) each on a different OS platform (Windows 10 versus Windows Server 2016) with devkit:
* All .dll
files are different
* .bss
files differ due to file path issues
NOTE: Please merge in the latest master and I'll reapprove.
Thank you, Kevin, for your patience while I was away on vacation. I'll also give this another test, at least on Linux, as my own final review. |
I upgraded Visual Studio 2022 to version 17.5.5 on Windows and CMake to version 3.26.4 on all of the platforms, so now I'm using the following tools: Toolchains
Build Tools
I ran the builds as described in the jgneff/jfxbuild repository. The results are shown below. LinuxOnly the file ubuntu@openjfx:~/src/jfx$ for n in 1,2 3,4 5,6; do (set -x; diff -qr build[$n]); done
+ diff -qr build1 build2
+ diff -qr build3 build4
+ diff -qr build5 build6
Files build5/jmods/javafx.web.jmod and build6/jmods/javafx.web.jmod differ
Files build5/modular-sdk/modules_libs/javafx.web/libjfxwebkit.so and build6/modular-sdk/modules_libs/javafx.web/libjfxwebkit.so differ
Files build5/publications/javafx.web-linux.jar and build6/publications/javafx.web-linux.jar differ
Files build5/sdk/lib/libjfxwebkit.so and build6/sdk/lib/libjfxwebkit.so differ macOSOnly the file john@macwifi:~/src/jfx$ for n in 1,2 3,4 5,6; do (set -x; diff -qr build[$n]); done
+ diff -qr build1 build2
Files build1/jmods/javafx.graphics.jmod and build2/jmods/javafx.graphics.jmod differ
Files build1/modular-sdk/modules_libs/javafx.graphics/libjavafx_iio.dylib and build2/modular-sdk/modules_libs/javafx.graphics/libjavafx_iio.dylib differ
Files build1/publications/javafx.graphics-mac.jar and build2/publications/javafx.graphics-mac.jar differ
Files build1/sdk/lib/libjavafx_iio.dylib and build2/sdk/lib/libjavafx_iio.dylib differ
+ diff -qr build3 build4
+ diff -qr build5 build6 WindowsOnly the file john@windows:~/src/jfx$ for n in 1,2 3,4 5,6; do (set -x; diff -qr build[$n]); done
+ diff -qr build1 build2
+ diff -qr build3 build4
+ diff -qr build5 build6
Files build5/jmods/javafx.web.jmod and build6/jmods/javafx.web.jmod differ
Files build5/modular-sdk/modules_libs/javafx.web/jfxwebkit.dll and build6/modular-sdk/modules_libs/javafx.web/jfxwebkit.dll differ
Files build5/publications/javafx.web-win.jar and build6/publications/javafx.web-win.jar differ
Files build5/sdk/bin/jfxwebkit.dll and build6/sdk/bin/jfxwebkit.dll differ I found another build failure on Windows when running the latest Visual Studio 2022 Build Tools version 17.6.3, dated June 13, 2023. I opened the bug report, "JDK-8310161: Error C2666 compiling ICU 73.1 with VS 2022 17.6," as a heads-up for when we upgrade Visual Studio. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good step towards 100% reproducible builds.
I am slightly worried about the added complexity to the build.gradle but I don't see a real alternative.
/reviewers 2 |
@kevinrushforth |
@jgneff This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 4 new commits pushed to the
Please see this link for an up-to-date comparison between the source branch of this pull request and the ➡️ To integrate this PR with the above commit message to the |
Please see all three of the following pull requests for a complete history of these changes:
|
/integrate |
Going to push as commit 0d9dcf3.
Your commit was automatically rebased without conflicts. |
This pull request allows for reproducible builds of JavaFX on Linux, macOS, and Windows by defining the
SOURCE_DATE_EPOCH
environment variable. For example, the following commands create a reproducible build:The three commands:
The third command won't be necessary once Gradle can build the JMOD archives or the
jmod
tool itself has the required support. For more information on the environment variable, see theSOURCE_DATE_EPOCH
page. For more information on the command to recreate the JMOD files, see thestrip-nondeterminism
repository. I'd like to propose that we allow for reproducible builds in JavaFX 17 and consider making them the default in JavaFX 18.Fixes
There are at least four sources of non-determinism in the JavaFX builds:
Build timestamp
The class
com.sun.javafx.runtime.VersionInfo
in the JavaFX Base module stores the time of the build. Furthermore, for builds that don't run on the Hudson continuous integration tool, the class adds the build time to the system propertyjavafx.runtime.version
.Modification times
The JAR, JMOD, and ZIP archives store the modification time of each file.
File ordering
The JAR, JMOD, and ZIP archives store their files in the order returned by the file system. The native shared libraries also store their object files in the order returned by the file system. Most file systems, though, do not guarantee the order of a directory's file listing.
Build path
The class
com.sun.javafx.css.parser.Css2Bin
in the JavaFX Graphics module stores the absolute path of its.css
input file in the corresponding.bss
output file, which is then included in the JavaFX Controls module.This pull request modifies the Gradle and Groovy build files to fix the first three sources of non-determinism. A later pull request can modify the Java files to fix the fourth.
Progress
Issues
Reviewers
Contributors
<javabmw@lsmod.de>
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/446/head:pull/446
$ git checkout pull/446
Update a local copy of the PR:
$ git checkout pull/446
$ git pull https://git.openjdk.org/jfx.git pull/446/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 446
View PR using the GUI difftool:
$ git pr show -t 446
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/446.diff
Webrev
Link to Webrev Comment