Skip to content

Reproducible build #400

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

Closed
IzzySoft opened this issue Mar 18, 2025 · 54 comments
Closed

Reproducible build #400

IzzySoft opened this issue Mar 18, 2025 · 54 comments
Labels
fdroid issue with fdroid builds or RB has failed

Comments

@IzzySoft
Copy link

Just wondering: you've created a Github action to build the release APK, but you're obviously not using it for release builds (at least your latest APK was built on a Windows machine). Which unfortunately makes Reproducible Builds impossible, as the build paths are embedded into the libraries – and on Linux, we cannot match Windows paths:

Image

If you'd use your Github action instead, it would be possible to establish reproducible builds – at least at IzzyOnDroid (see e.g. Reproducible Builds, special client support and more at IzzyOnDroid for some background on this).

So no pressure, but just asking: would that be something you'd consider? One big win of having your app confirmed as RB is that this clearly shows your APKs have been built from exactly the source code they claim to, with nothing added or taken away, and thus pushes up the trust level a level or two. No guarantee we succeed there – but given an example APK built with your Github action, we could take a look and see.

Thanks in advance for considering!

@Hamza417
Copy link
Owner

So no pressure, but just asking: would that be something you'd consider?

Yes, I'll try to complete the actions setup right away. I remember getting multiple OutOfMemoryError building the APK in the GitHub server, causing me to fall back to my local machine for building the APK files.

@IzzySoft
Copy link
Author

Ah, thanks! That explains my confusion.

I was able to build the app with our setup here (if you have a Linux machine or VM at hand, you can establish that environment in probably less than 5 minutes using our rbuilder_setup scripts, which we already successfully tested on Debian systems (Debian bookworm/bullseye and Ubuntu jammy/noble) and have a PR ready for testing on RPM based ones (RHEL, Fedora, Rocky & Co) – I gladly share my build recipe with you for that).

@Hamza417
Copy link
Owner

I do have a local Linux server and your provided repo would be a great start for it, thanks for that!!

@IzzySoft
Copy link
Author

What distribution is the Linux server running? And, I'd be very very glad & thankful for feedback shared about the setup (and operation then). We're still working on making the latter easier (my next steps will be improving the rbhelper package which the installer offers to set up as well, and then to update/create proper documentation). Feedback "from outside" would be very valuable for that!

@IzzySoft
Copy link
Author

Here's my build recipe for Inure:

---
repository: https://github.com/Hamza417/Inure.git
updates: releases
versions:
  - tag: build103.1.1
    apks:
      - apk_pattern: app-github-release\.apk
        apk_url: https://github.com/Hamza417/Inure/releases/download/build103.1.1/app-github-release.apk
        build:
          - chmod +x gradlew
          - ./gradlew assembleGithubRelease
          - mv app/build/outputs/apk/github/release/*unsigned.apk /outputs/unsigned.apk
        build_cpus:
        build_home_dir: /home/runner
        build_repo_dir: /home/runner/work/Inure/Inure
        build_timeout:
        build_user: build
        provisioning:
          android_home: /opt/sdk
          build_tools:
          cmake:
          cmdline_tools:
            version: '12.0'
            url: https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
            sha256: 2d2d50857e4eb553af5a6dc3ad507a17adf43d115264b1afc116f95c92e5e258
          extra_packages: []
          image: ubuntu:noble
          jdk: openjdk-17-jdk-headless
          ndk:
          platform:
          platform_tools:
          tools:
          verify_gradle_wrapper: true

(empty values using defaults; I'm keeping those declarations in to have them easily available in case they are needed, e.g. with a later release. And I've set build_home_dir plus build_repo_dir to match the GH action; defaults are /build and /buils/repo)

@Hamza417
Copy link
Owner

Hamza417 commented Mar 19, 2025

I have updated the actions file, and the build should now be generated in a Linux environment from now on.

Also, yes I did set up and ran your scripts in my Ubuntu server (noble) and found the process of setting it up a breeze, and it helped me a lot into finding the source of the issue. I haven't formed any opinion about it, but yeah, using trydiffoscope was troublesome because the server kept timing out on my request and I had to set up the diffoscope locally and compare the APKs. Other than that, it was good. Thanks for helping me out on this one :)

I did a thorough study on this and managed to make the Inure fully reproducible, or at least that's what my result says. Could you please check the diffoscope report and let me know if it's identical now? I had compared two signed APKs, so the signature mismatched (expected) but classes and resources are identical on two separate builds.

@IzzySoft
Copy link
Author

I have updated the actions file, and the build should now be generated in a Linux environment from now on.

Wonderful!

I did set up and ran your scripts in my Ubuntu server (noble) and found the process of setting it up a breeze, and it helped me a lot into finding the source of the issue.

🤩 Thanks for that lovely feedback! Much appreciated. Glad to see a goal achieved 🥳

using trydiffoscope was troublesome because the server kept timing out on my request

So it's not only me… It worked fine a while ago, but lately seems to permanently time out.

I had to set up the diffoscope locally

You've seen the note about the diffoscope image for Podman and how to operate that? Maybe we should make that more obvious, if you missed it.

Could you please check the diffoscope report and let me know if it's identical now?

It looks like it is. To be absolutely sure, could you provide me an APK and name the corresponding commit? You can attach the APK here after renaming it to *.zip (the usual MS logic: a file is bad if the extension is .apk, but if you just rename it to *.zip it is fine – same for *.sql, *.diff etc when renamed to *.txt 🙈)

Btw: the builder should show you whether the file was RB. Well, time to get the documentation up to sniff I guess, but we cannot do everything at the same time unfortunately…

@Hamza417
Copy link
Owner

app-github-release.zip

It's built on this commit: f2b7d66

@IzzySoft
Copy link
Author

Funny. Looks like now signing is enforced even if the keystore does not exist (I didn't place any):

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:packageGithubRelease'.
> A failure occurred while executing com.android.build.gradle.tasks.PackageAndroidArtifact$IncrementalSplitterRunnable
   > SigningConfig "release" is missing required property "storeFile".

which is strange, as this line should take care the corresponding block is not even called when the file does not exist. Guess it should be set to null then? 🤷‍♂

Adding sed -r '/signingConfigs.release/d' -i app/build.gradle to my recipe and trying again… OK, builds now, but not RB. The libs do not match:

- -rw-r--r--  0.0 unx     7264 b-     7264 stor 1981-01-01 01:01:02 2747909b lib/arm64-v8a/libinure_su.so
- -rw-r--r--  0.0 unx  1388080 b-  1388080 stor 1981-01-01 01:01:02 7c7ae7e2 lib/arm64-v8a/libinure_terminal_emulator.so
+ -rw-r--r--  0.0 unx     7192 b-     7192 stor 1981-01-01 01:01:02 f5b5a084 lib/arm64-v8a/libinure_su.so
+ -rw-r--r--  0.0 unx  1387720 b-  1387720 stor 1981-01-01 01:01:02 0931087b lib/arm64-v8a/libinure_terminal_emulator.so
  -rw-r--r--  0.0 unx   387256 b-   387256 stor 1981-01-01 01:01:02 c14c01f1 lib/arm64-v8a/librenderscript-toolkit.so
- -rw-r--r--  0.0 unx     5692 b-     5692 stor 1981-01-01 01:01:02 a6b77094 lib/armeabi-v7a/libinure_su.so
- -rw-r--r--  0.0 unx   810664 b-   810664 stor 1981-01-01 01:01:02 6176f3ed lib/armeabi-v7a/libinure_terminal_emulator.so
+ -rw-r--r--  0.0 unx     5620 b-     5620 stor 1981-01-01 01:01:02 d18ddcf6 lib/armeabi-v7a/libinure_su.so
+ -rw-r--r--  0.0 unx   810304 b-   810304 stor 1981-01-01 01:01:02 3e1d62c8 lib/armeabi-v7a/libinure_terminal_emulator.so
  -rw-r--r--  0.0 unx   251596 b-   251596 stor 1981-01-01 01:01:02 cbd89bb1 lib/armeabi-v7a/librenderscript-toolkit.so
- -rw-r--r--  0.0 unx     5784 b-     5784 stor 1981-01-01 01:01:02 42e41388 lib/x86/libinure_su.so
- -rw-r--r--  0.0 unx  1049384 b-  1049384 stor 1981-01-01 01:01:02 4c457021 lib/x86/libinure_terminal_emulator.so
+ -rw-r--r--  0.0 unx     5712 b-     5712 stor 1981-01-01 01:01:02 6256a591 lib/x86/libinure_su.so
+ -rw-r--r--  0.0 unx  1049024 b-  1049024 stor 1981-01-01 01:01:02 9f7d23fd lib/x86/libinure_terminal_emulator.so
  -rw-r--r--  0.0 unx   321232 b-   321232 stor 1981-01-01 01:01:02 4e1d41d2 lib/x86/librenderscript-toolkit.so
- -rw-r--r--  0.0 unx     6920 b-     6920 stor 1981-01-01 01:01:02 c0a01cc3 lib/x86_64/libinure_su.so
- -rw-r--r--  0.0 unx  1243896 b-  1243896 stor 1981-01-01 01:01:02 553134ad lib/x86_64/libinure_terminal_emulator.so
+ -rw-r--r--  0.0 unx     6848 b-     6848 stor 1981-01-01 01:01:02 57aeea86 lib/x86_64/libinure_su.so
+ -rw-r--r--  0.0 unx  1243576 b-  1243576 stor 1981-01-01 01:01:02 7619ae3a lib/x86_64/libinure_terminal_emulator.so
  -rw-r--r--  0.0 unx   354768 b-   354768 stor 1981-01-01 01:01:02 9f8e8758 lib/x86_64/librenderscript-toolkit.so

Which cmake version are you using? Without specifying any, here it uses 3.22.1. I guess you didn't use my above recipe for building that APK? I'm just trying again now with OpenJDK 21 – but as that installs the very same cmake, I don't expect any difference. And nope, there is none…

@Hamza417
Copy link
Owner

I did use the same recipe, and It's built using the same CMake version

 > Task :app:configureCMakeRelWithDebInfo[arm64-v8a]
Checking the license for package CMake 3.22.1 in /usr/local/lib/android/sdk/licenses
License for package CMake 3.22.1 accepted.
Preparing "Install CMake 3.22.1 v.3.22.1".
"Install CMake 3.22.1 v.3.22.1" ready.
Installing CMake 3.22.1 in /usr/local/lib/android/sdk/cmake/3.22.1
"Install CMake 3.22.1 v.3.22.1" complete.
"Install CMake 3.22.1 v.3.22.1" finished.

What's interesting is if .so files are what's breaking the RB, then why is lib/**/librenderscript-toolkit.so RB, but others are not. And, RBs work as long as the APK is checked against another built on the same machine but breaks when the machine changes. I'll check it.

Hamza417 added a commit that referenced this issue Mar 20, 2025
@IzzySoft
Copy link
Author

IzzySoft commented Mar 20, 2025

And, RBs work as long as the APK is checked against another built on the same machine but breaks when the machine changes.

Image

BuildIDs differ. Because:

Image

Different build path. I could match that by setting android_home: /usr/local/lib/android/sdk, let me try…

PS: I see you found the same already. I'll revert my change after verifying. I just want to make sure it's not something else in addition.

@Hamza417
Copy link
Owner

Image

I tested the actions build against the rblog and finally passed the RB 🥳🎈

@Hamza417
Copy link
Owner

Hamza417 commented Mar 20, 2025

It's interesting that actions used /usr/local/** dir as SDK path but in your recipe you have specified as /opt/sdkand that is the main reason why the RBs were failing in your machine but passing in mine. I updated the actions script to use /opt/sdk as ANDROID_HOME, but may I know the reason for going with /opt/sdk?

Here's the build recipe I used, I changed the path to /usr/local/lib/android/sdk and RB passed after that:

---
repository: https://github.com/Hamza417/Inure.git
updates: releases
versions:
  - tag: build103.1.1
    apks:
      - apk_pattern: app-github-release\.apk
        apk_url: https://github.com/Hamza417/Inure/releases/download/build103.1.1/app-github-release.apk
        build:
          - chmod +x gradlew
          - ./gradlew assembleGithubRelease
          - mv app/build/outputs/apk/github/release/*unsigned.apk /outputs/unsigned.apk
        build_cpus:
        build_home_dir: /home/runner
        build_repo_dir: /home/runner/work/Inure/Inure
        build_timeout:
        build_user: build
        provisioning:
          android_home: /usr/local/lib/android/sdk
          build_tools:
          cmake:
          cmdline_tools:
            version: '12.0'
            url: https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
            sha256: 2d2d50857e4eb553af5a6dc3ad507a17adf43d115264b1afc116f95c92e5e258
          extra_packages: []
          image: ubuntu:noble
          jdk: openjdk-21-jdk-headless
          ndk:
          platform:
          platform_tools:
          tools:
          verify_gradle_wrapper: true

@IzzySoft
Copy link
Author

/opt/sdk is the default we use. And I forgot to adjust that according to your action, my bad. Confirmed here: matching them, the build is RB. Just let me know what path you want to go with then.

@Hamza417
Copy link
Owner

Hamza417 commented Mar 20, 2025

I have updated the actions workflow to use /opt/sdk in this 64c2720, so I guess nothing needs to be changed now? I'll run a few more checks against actions build to make sure RB passes in different conditions before the next release, your script is really handy :)

I think it's safe to close #399 now as well.

@Hamza417 Hamza417 added the fdroid issue with fdroid builds or RB has failed label Mar 20, 2025
@IzzySoft
Copy link
Author

OK, so we stay with /opt/sdk then – and I wait for the next release to establish Inure with RB here?

@Hamza417 Hamza417 reopened this Mar 20, 2025
@Hamza417
Copy link
Owner

OK, so we stay with /opt/sdk then – and I wait for the next release to establish Inure with RB here?

Yes, next release should be RB, can you do what is necessary if Inure needs to be marked reproducible on F-Droid?

@licaon-kter
Copy link

licaon-kter commented Mar 20, 2025

@Hamza417 note that this will cover @IzzySoft's repo only

for F-Droid... since users already have your app, to switch, they'll need to uninstall and reainstall the newer RB versions. There's no "upgrade" path

you'd want that?

/LE: first of all they'd need to find out they have to do this, while we announce these in https://f-droid.org/news/ (RSS too) and https://floss.social/@fdroidorg our reach is still rather limited. There are ideas about integrating this is Client, but no concrete proposals

@Hamza417
Copy link
Owner

you'd want that?

It'd be an inconvenience for them for sure, unless the signature is changed on F-Droid, why'd the users need to uninstall before installing? I am a bit lost here, so could you explain this please, and what is the best course of action here?

/LE: first of all they'd need to find out they have to do this, while we announce these in https://f-droid.org/news/ (RSS too) and https://floss.social/@fdroidorg our reach is still rather limited. There are ideas about integrating this is Client, but no concrete proposals

I can also notify the users through my ends like notifying about this in the group and through the app's GitHub repo.

@licaon-kter
Copy link

right now, in F-Droid, the APK is signed by F-Droid.

with reproducible builds (if confirmed verified), we'll host your own signed APK (eg. https://github.com/Hamza417/Inure/releases/tag/build103.1.1 -> app-github-release.apk ) per the graph in https://f-droid.org/docs/Reproducible_Builds/ branches YES - YES

Android security protection does not allow updating a package with a different signature.

@IzzySoft
Copy link
Author

Summing up:

  • no signing changes at IzzyOnDroid, as we always ship the APKs signed by the developers
  • at F-Droid.org, a signature change would be required to have the APK shipped RB there, as currently Inure is signed with a key generated by F-Droid.org itself, which would need to be switched to yours
  • the fact that your APKs will have the "green shield" at IzzyOnDroid, certifying it was built RB – and that it is well known that F-Droid builds from the very same source, could be a good compromise if you do not want people having to uninstall/reinstall

@Hamza417
Copy link
Owner

Understandable! It'd be best to keep the signature consistent throughout the repositories. I'll mention this in changelogs and notify everyone about this beforehand.

@IzzySoft
Copy link
Author

Sounds good to me. @licaon-kter what do you think? How much "preparation time" on your end so @Hamza417 doesn't send out the notification "too early"? Or maybe just mention it "for the next release", once LK confirmed F-Droid has their RB recipe ready?

@licaon-kter
Copy link

"for the next release" sounds good enough 👍

@IzzySoft
Copy link
Author

@Hamza417 missed to reply to your comment, apologies! Asking @licaon-kter / @linsui to correct me should that have been fixed already, but at F-Droid.org it will be difficult to remove screenshots later. You can replace them there easily with new variants using the exact same names, but should you later reduce their number, some of the "old once" will stick there.

At IzzyOnDroid, screenshots will be optimized at import (resized if too large, and also compressed). Still, the resulting screenshot files sum up to over 1 MB – which will be downloaded to each client looking at the app details. Considering bandwidth (especially for devices on "low-end plans", but also in general considering the environment), this still might pose an issue.

To not get me wrong: I don't try to "regulate" here, I'm just "voicing concerns". Decision remains yours. I just feel the need to advise, so you can make an informed decision 😉

@linsui
Copy link

linsui commented Mar 28, 2025

is it a problem at your end? If it's impossible (or hard) for you to apply, I could/should consider that for future recommendations then.

Yep, it's harder to change the path. We need to move things around. Not difficule but verbose and ugly. And I prefer to have less requirement for reproducible build. It's better if we can make it reproducible with any folder layout.

at F-Droid.org it will be difficult to remove screenshots later

It needs to be removed manually.

@linsui
Copy link

linsui commented Mar 28, 2025

There is a folder name in .cxx is different. According to the hash_key.txt file in it:

# Values used to calculate the hash in this folder name.
# Should not depend on the absolute path of the project itself.
#   - AGP: 8.9.1.
#   - $NDK is the path to NDK 25.2.9519653.
#   - $PROJECT is the path to the parent folder of the root Gradle build file.
#   - $ABI is the ABI to be built with. The specific value doesn't contribute to the value of the hash.
#   - $HASH is the hash value computed from this text.
#   - $CMAKE is the path to CMake 3.22.1.
#   - $NINJA is the path to Ninja.
-H$PROJECT/app/src/main/jni
-DCMAKE_SYSTEM_NAME=Android
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_SYSTEM_VERSION=23
-DANDROID_PLATFORM=android-23
-DANDROID_ABI=$ABI
-DCMAKE_ANDROID_ARCH_ABI=$ABI
-DANDROID_NDK=$NDK
-DCMAKE_ANDROID_NDK=$NDK
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake
-DCMAKE_MAKE_PROGRAM=$NINJA
-DCMAKE_C_FLAGS=-ffile-prefix-map=$PROJECT=/home/runner/work/Inure/Inure -ffile-prefix-map=/opt/android-sdk=/usr/local/lib/android/sdk -Wl,--hash-style=gnu
-DCMAKE_CXX_FLAGS=-ffile-prefix-map=$PROJECT=/home/runner/work/Inure/Inure -ffile-prefix-map=/opt/android-sdk=/usr/local/lib/android/sdk -Wl,--hash-style=gnu
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=$PROJECT/app/build/intermediates/cxx/RelWithDebInfo/$HASH/obj/$ABI
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=$PROJECT/app/build/intermediates/cxx/RelWithDebInfo/$HASH/obj/$ABI
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-B$PROJECT/app/.cxx/RelWithDebInfo/$HASH/$ABI

If I understand it correctly, if we put the cFlags in gradle this hash is affected so we should put it in the cmake file instead.

Hamza417 added a commit that referenced this issue Mar 28, 2025
- Added `-ffile-prefix-map` to remove absolute paths from debug info.
- Enabled `--hash-style=gnu` for improved ELF symbol lookup performance.
- Disabled `--build-id` to ensure fully reproducible builds.
@linsui
Copy link

linsui commented Mar 28, 2025

You can add them with add_compile_options and add_link_options. Not sure if there is any difference. Anyway, can you build an apk so that we can check if the changes work? :)

@Hamza417
Copy link
Owner

Hamza417 commented Mar 28, 2025

Yes, you can get the APK from here: https://github.com/Hamza417/Inure/actions/runs/14134722583
Please check it, building on my local server is broken for some reason, and I am not able to test the RB.

Starting a Gradle Daemon (subsequent builds will be faster)
Calculating task graph as no cached configuration is available for tasks: assembleGithubRelease

Session terminated, killing shell... ...killed.

EDIT: rebooting the server fixed it, I am building an APK now in rblog.

@Hamza417
Copy link
Owner

I checked it did not work, and the RB failed, I'll look into it more and see If something works.

Decision remains yours. I just feel the need to advise, so you can make an informed decision

@IzzySoft If it can be removed as @linsui stated above, I'll replace them with the play store screenshots.

Hamza417 added a commit that referenced this issue Mar 28, 2025
- Added `-ffile-prefix-map` to remove absolute paths from debug info.
- Enabled `--hash-style=gnu` for improved ELF symbol lookup performance.
- Disabled `--build-id` to ensure fully reproducible builds.
@linsui
Copy link

linsui commented Mar 28, 2025

I thought it should be

add_compile_options("-ffile-prefix-map=${CMAKE_SOURCE_DIR}= -ffile-prefix-map=$ENV{ANDROID_HOME}=")
add_link_options("LINKER:--hash-style=gnu,--build-id=none")

Not sure if it works without the quotes.

@linsui
Copy link

linsui commented Mar 28, 2025

It works but it's not enough... We need to replace the root path of this repo because some paths are not in CMAKE_SOURCE_DIR. I guess we need to use https://cmake.org/cmake/help/latest/command/cmake_path.html#get-parent-path.

@IzzySoft
Copy link
Author

Yep, it's harder to change the path.

Thanks for clarification, @linsui – added that to our notes with a link to your comment. Please update me if it turns out that needs to be adjusted, so I can then replace it with the final variant. (And following the discussion, I'm not sure where it's harder to change the path: in the YAML, or with cmake 🙊 💨)

If it can be removed as @linsui stated above, I'll replace them with the play store screenshots.

@Hamza417 I'll leave that to you and linsui then. At IoD, currently all screenshots have been pulled – but they will be cleaned automatically when you remove them on your end. Only exception where that currently fails on our end is if you only change the file extension (e.g. 01.jpg => 01.png leads to both being present here and we need to cleanup manually).

@linsui
Copy link

linsui commented Mar 28, 2025

Please update me if it turns out that needs to be adjusted, so I can then replace it with the final variant.

I hope we can make the build path configurable soon.

And following the discussion, I'm not sure where it's harder to change the path: in the YAML, or with cmake

This is new to me... Generally it's enough to add flags in gradle. Still, I thought it's better to make it reproducible even in a different build environment. :)

Hamza417 added a commit that referenced this issue Mar 28, 2025
- Added `-ffile-prefix-map` to remove absolute paths from debug info.
- Enabled `--hash-style=gnu` for improved ELF symbol lookup performance.
- Disabled `--build-id` to ensure fully reproducible builds.
Hamza417 added a commit that referenced this issue Mar 28, 2025
- Dynamically determine the project root using `cmake_path(GET ... PARENT_PATH)`.
- Added `-ffile-prefix-map` to remove absolute paths from debug info.
- Enabled `--hash-style=gnu` for improved ELF symbol lookup performance.
- Disabled `--build-id` to ensure fully reproducible builds.
@IzzySoft
Copy link
Author

@linsui yeah, and life's a bitch sometimes, adding unexpected things to reality unfortunately. How was that old Chinese curse: "May you live in interesting times?" Well, I sometimes wish for boring ones now…

So yeah, wherever the course goes. Wish you luck there. If that path ends at a wall, a configurable path (as rbtlog supports it) would be the way to go. Though I agree, "reproducible even in a different build environment" would be good – hope the price isn't too high there…

Hamza417 added a commit that referenced this issue Mar 28, 2025
- Added `-ffile-prefix-map` and `-fdebug-prefix-map` flags.
- Added linker flags to strip debug symbols from the final release build.
@Hamza417
Copy link
Owner

It works but it's not enough... We need to replace the root path of this repo because some paths are not in CMAKE_SOURCE_DIR. I guess we need to use https://cmake.org/cmake/help/latest/command/cmake_path.html#get-parent-path.

#get-parent-path block doesn't exist on the landing page? Anyway, I did some adjustments and stripped many things out of the .so files. I think I have achieved the env independent RB because in my diffoscope report after comparing against two build, one from windows and other from Linux did not flag any CMake files. Doing also brought down the APK size by 4 megabytes, so it's a triple win?

You can check the report: report.zip w.apk is windows one and l.ap is what I had built in GitHub actions (Ubuntu)

The permission.txt is something happened first time, probably by how line separators works in different build environments? That's something I can deal with a little bit more investigation.

You can get the new APK file from here: https://github.com/Hamza417/Inure/actions/runs/14139120293

Please check it now 🤞🏻

Hamza417 added a commit that referenced this issue Mar 29, 2025
@Hamza417 Hamza417 changed the title Build workflow Reproducible build Mar 29, 2025
@linsui
Copy link

linsui commented Mar 29, 2025

It works. :) Thanks! Yep, strip helps a lot.

@IzzySoft
Copy link
Author

Confirmed here as well, without any changes to the recipe on our end:

  {
    "upstream_signed_apk_sha256": "bbfed552e71f1eb8268b1bdd544371328891680fc4112c499b5191ab9a30a0ac",
    "built_unsigned_apk_sha256": "fc967bf2afd87b455e44ef14adafdf6fd5243d938af2ce33cdfb0d9f389aba80",
    "signature_copied_apk_sha256": "bbfed552e71f1eb8268b1bdd544371328891680fc4112c499b5191ab9a30a0ac"
  }

@IzzySoft
Copy link
Author

PS: could someone please sum up what changes were needed in the end, so we can document that properly? Would be good if we can suggest a "one fits all" solution (as we've shown, we all pull the same rope here 😉).

@linsui
Copy link

linsui commented Mar 29, 2025

Besides the known tricks in https://f-droid.org/docs/Reproducible_Builds/, strip can remove lots of unreproducible bits.

@IzzySoft
Copy link
Author

OK, so making my question a little more precise:


Different build paths

If there are differences in embedded paths, this is what one should start with. Having used the defaults of our recipes, one most likely used build_repo_dir: /build/repo – which one will see for the *unsigned.apk. This is what then usually needs to be adjusted in the recipe. For apps built via CI by e.g. Github Actions this mostly means:

        build_home_dir: /home/runner
        build_repo_dir: /home/runner/work/<repoName>/<repoName>
        build_user: runner
        provisioning:
          android_home: /usr/local/lib/android/sdk

For other variables used in GH images, see e.g. here. Also check the .github/workflows/* in the app's repo for details, where one usually also finds which image and JDK version was being used.

linsui points out that the embedded android_home path can also be „mapped“ via build.gradle, which seems to be what F-Droid.org prefers:

        externalNativeBuild {
            cmake {
                cFlags "-ffile-prefix-map=${rootDir}= -ffile-prefix-map=${System.getenv("ANDROID_HOME")}= -Wl,--hash-style=gnu,--build-id=none"
                cppFlags "-ffile-prefix-map=${rootDir}= -ffile-prefix-map=${System.getenv("ANDROID_HOME")}= -Wl,--hash-style=gnu,--build-id=none"
            }
        }

Build IDs

...

This is from the documentation I'm currently writing on analyzing/fixing RBs with our builder setup. The last block with "linsui points out" is what I've added from here. Is that sufficient for this part, or what extra steps were taken? If we want to include that approach, it should have all steps. For our builders, the first variant suffices – but it would be nice to have the second variant to fit yours as well, don't you agree? 😉

@linsui
Copy link

linsui commented Mar 29, 2025

I prefer to remove those bits depending on the build environment, which is mainly embeded absolute path. And the build-id is also affected by the build path which is a hash of them. The absolute path can be removed by -ffile-prefix-map and the build-id can be disabled by --build-id=none. And there are more info in our document. :) For example the hash style is different here. It's a difference between different distros. Maybe you can use different image but F-Droid only builds on Debian. And strip can remove lots of debug info which makes reproducible build easier.

@IzzySoft
Copy link
Author

And there are more info in our document

I know – in ours as well 😉 E.g. build-id comes in the next section, as you can see. And yes, hash style is mentioned as well. (And yes, I know that different build paths can lead to different build IDs, too.) Above quote was just a little piece of the documentation I'm currently preparing 😉

So -Wl,--hash-style=gnu,--build-id=none is clear (and covered in our documentation as well). From your above example, I'll adopt the -ffile-prefix-map=OLD=NEW (which I understand for the ANDROID_HOME, but do not know what rootDir refers to: the projectRoot?).

In above text, I've just added before the "Build IDs" header:

This uses the -ffile-prefix-map=OLD=NEW compiler options to remove parts of the embedded paths, and thus works in general (not depending on the build environment) – but must be implemented with the source code by the app's author(s).

And this is why both are mentioned: if you want to confirm an APK from a project where the maintainer(s) left, there is nobody to fix the "upstream APK". That leaves only things you can do locally on your builder then. Our builders are intended "for general use", not specific to our repo or yours, so we need both options there 😉

PS: My question here was mostly to confirm that this adjustment was "the complete one" – or what other "learnings" I might have missed. Thanks for enlighting me as well, linsui 🙇‍♂

@Hamza417
Copy link
Owner

Hamza417 commented Apr 1, 2025

It works. :) Thanks! Yep, strip helps a lot.

Nice to know :)

I'll publish a patch release soon after fixing some minor issues.

@Hamza417 Hamza417 closed this as completed Apr 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fdroid issue with fdroid builds or RB has failed
Projects
None yet
Development

No branches or pull requests

4 participants