这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@acozzette
Copy link

@acozzette acozzette commented Sep 4, 2025

Credit goes to @robertkirkman for doing most of the hard work of actually getting this to build! I largely copied Robert's changes with permission.

Fixes #20259.

@acozzette
Copy link
Author

This is my first attempt to add or modify a Termux package, so sorry in advance if I screwed something up!

I wasn't exactly sure how to handle the license field, because has different files under different licenses: https://github.com/Gnucash/gnucash/blob/stable/LICENSE So I just marked the license as custom.

Copy link
Member

@TomJo2000 TomJo2000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good for a first time contribution.
I've left you a couple pointers as review comments.

@robertkirkman
Copy link
Member

Package 'libsecret-1' not found

try adding libsecret to TERMUX_PKG_DEPENDS to resolve this

@robertkirkman
Copy link
Member

The patch removes a reference to the Boost system component, and this was necessary to get CMake to run successfully. I'm not exactly sure why this is necessary, but I see that some other packages needed the same fix to work with Boost 1.89.0.

I approve of your patch and I believe it is correct. Eventually, a similar change will also be made in upstream Gnucash, which you could open a PR for as well, but since the necessary change is very small in this case, I expect that it will probably be straightforward for upstream to make the change on their own without too much trouble.

@robertkirkman
Copy link
Member

robertkirkman commented Sep 4, 2025

I wasn't exactly sure how to handle the license field, because has different files under different licenses: https://github.com/Gnucash/gnucash/blob/stable/LICENSE So I just marked the license as custom.

Others can clarify the Termux package license policies in more detail if needed, but I believe that what you have done (specifying "custom" and adding a comment that lists the licenses) is one acceptable way,

but if you wanted to, there is also another way to specify license in Termux packages that can actually distribute the license files with the package itself in the folder $PREFIX/share/licenses/gnucash, including as many licenses as you believe apply.

I believe that this other package where I have done that serves as a good example of how to do it, in case you would like to try:

The paths which are listed in TERMUX_PKG_LICENSE_FILE are relative to the root of the source code folder of the package, and should specify locations within the package's source code where each relevant license is stored.

TERMUX_PKG_LICENSE="BSD 3-Clause, Apache-2.0, ZLIB, Public Domain, BSD 2-Clause, OpenSSL, MirOS, BSD"
TERMUX_PKG_LICENSE_FILE="
bionic/libc/NOTICE
system/core/NOTICE
external/zlib/NOTICE
external/lzma/NOTICE
external/icu/NOTICE
external/boringssl/NOTICE
external/mksh/NOTICE
external/toybox/NOTICE
external/iputils/NOTICE
"

if some licenses are originally stored in files with the same names (like in my example), Termux will automatically rename each additional license that conflicts with one of the other license filenames as the same name but with ".$num" appended, like"NOTICE.1" "NOTICE.2", "NOTICE.3", etc. during packaging.

@TomJo2000
Copy link
Member

TomJo2000 commented Sep 4, 2025

[...]
but if you wanted to, there is also another way to specify license in Termux packages that can actually distribute the license files with the package itself in the folder $PREFIX/share/licenses/gnucash, including as many licenses as you believe apply.
[...]

This is what I proposed in #25962 (comment),
GPL-2.0-or-later should be sufficiently close to the licensing situation given that we ship the LICENSE file from gnucash's repo instead of linking to the generic GPLv2 license file from termux-licenses.

As a tangent, here's the code that handles installation of multiple license files.

if some licenses are originally stored in files with the same names (like in my example), Termux will automatically rename each additional license that conflicts with one of the other license filenames as the same name but with ".$num" appended, like"NOTICE.1" "NOTICE.2", "NOTICE.3", etc. during packaging.

They're installed as copyright, copyright.2, etc.

for FILE in "${COMMON_LICENSE_FILES[@]}" "${EXTRA_LICENSE_FILES[@]}"; do
[[ -f "$TERMUX_PKG_SRCDIR/$FILE" ]] && {
if (( COUNTER )); then
cp -f "${TERMUX_PKG_SRCDIR}/$FILE" "${TERMUX_PREFIX}/share/doc/${TERMUX_PKG_NAME}/copyright.${COUNTER}"
else
cp -f "${TERMUX_PKG_SRCDIR}/$FILE" "${TERMUX_PREFIX}/share/doc/${TERMUX_PKG_NAME}/copyright"
fi
(( ++COUNTER, ++FROM_SOURCES ))
}
done

Though it appears that aosp-libs is a non-standard case here as it's license files are in fact named NOTICE.$COUNT.
I assume this is because the codepath for explicitly specified license locations doesn't rename them to copyright.$COUNT
COUNTER=1
local LICENSE_FILEPATH
local -A INSTALLED_LICENSES=()
while read -r LICENSE; do
# Skip empty lines
[[ -z "${LICENSE}" ]] && continue
# Check that the license file exists in the source files
[[ -f "$TERMUX_PKG_SRCDIR/$LICENSE" ]] || {
termux_error_exit "$TERMUX_PKG_SRCDIR/$LICENSE does not exist"
}
LICENSE_FILEPATH="$(basename "$LICENSE")"
if [[ -n ${INSTALLED_LICENSES[${LICENSE_FILEPATH}]:-} ]]; then
# We have already installed a license file named $(basename $LICENSE) so add a suffix to it
TARGET="$TERMUX_PREFIX/share/doc/${TERMUX_PKG_NAME}/${LICENSE_FILEPATH}.$((COUNTER++))"
else
TARGET="$TERMUX_PREFIX/share/doc/${TERMUX_PKG_NAME}/${LICENSE_FILEPATH}"
# shellcheck disable=SC2190 # this is a valid way to assign key value pairs
INSTALLED_LICENSES+=("${LICENSE_FILEPATH}" 'already installed')
fi
cp -f "${TERMUX_PKG_SRCDIR}/${LICENSE}" "$TARGET"
done <<< "${TERMUX_PKG_LICENSE_FILE//,/$'\n'}"

@acozzette
Copy link
Author

@TomJo2000 @robertkirkman Thank you for all the information and feedback! I made all your suggested changes. Now I'm just trying to figure out what's going on with the Could not determine Guile prefix error. I never hit this error when I was building on my phone, but I'm going to try with Docker and see if I can reproduce the error there.

@TomJo2000
Copy link
Member

@TomJo2000 @robertkirkman Thank you for all the information and feedback! I made all your suggested changes. Now I'm just trying to figure out what's going on with the Could not determine Guile prefix error.

I am assuming there is a missing build option along the lines of -DGUILE_PREFIX=$TERMUX_PREFIX, or something to that effect, that's missing from the TERMUX_PKG_EXTRA_CONFIGURE_ARGS.
But I haven't combed through gnucash's build scripts to find it.

I never hit this error when I was building on my phone, but I'm going to try with Docker and see if I can reproduce the error there.

Builds in the package build container and on-device can sometimes have different behavior.
The setup for the container is documented at;
https://github.com/termux/termux-packages/wiki/Build-environment#docker-container
if you have any issues with it please feel free to ask.
You should be able to run a local build on a PC using:

./scripts/run-docker.sh ./build-package.sh -I -f gnucash

@robertkirkman
Copy link
Member

robertkirkman commented Sep 5, 2025

I'm going to try to make a solution to the next problem in CI, CMake Error at common/cmake_modules/GncAddSchemeTargets.cmake, because it seems like an interesting problem to me.

I believe that if given the choice, Tomjo2000 will prefer solutions involving the addition of the build dependency aosp-libs to this package and the insertion of calls to termux-proot-run.

however, I still like to write things the way that does not involve use of those things, sometimes.

I believe that I would like to show acozzette both ways.

@TomJo2000
Copy link
Member

I believe that if given the choice, Tomjo2000 will prefer solutions involving the addition of the build dependency aosp-libs to this package and the insertion of calls to termux-proot-run.

Whatever gets the job done.
The termux-proot-run approach has a proven track record, but I agree that it may be the wrong approach for this.

@robertkirkman
Copy link
Member

I believe that if given the choice, Tomjo2000 will prefer solutions involving the addition of the build dependency aosp-libs to this package and the insertion of calls to termux-proot-run.

Whatever gets the job done. The termux-proot-run approach has a proven track record, but I agree that it may be the wrong approach for this.

Just would like to give an update that after checking some things, it absolutely will be much easier and less code to use termux-proot-run (or, for related examples, things like termux-on-gha or TUR-on-device PRs which are even easier) for this package than the other way, but I will still try to make an example of both because I think it's a software that could serve as a really good learning example for both.

@robertkirkman
Copy link
Member

robertkirkman commented Sep 5, 2025

An additional update is: I have now successfully built gnucash targeting Termux entirely inside the termux-package-builder container, in the way that does not use aosp-libs+termux-proot-run, and my resulting gnucash package is working when I install and test it on my device.

Therefore, if you are very eager to see a solution ASAP and don't want to wait longer, please let me know and I can immediately upload and show my first solution so that you don't have to wait.

However, at the moment, unfortunately I would be embarrassed to show my first version that is messy. Now that I know both ways of building gnucash in the termux-package-builder are possible, I'd like to write as good of an example as I can for both ways, because there currently aren't really any examples of both ways implemented for a single package, which I think would be really helpful for teaching how to do both ways. Next I would like to:

  • clean up my current build and get it ready to upload
  • implement the same build a second time, but in the other way that does make use of aosp-libs and termux-proot-run
  • finish writing my document explaining the steps of how to write both ways and comparing them, which might be helpful as a reference in the future to help do either way in future packages

@robertkirkman
Copy link
Member

robertkirkman commented Sep 6, 2025

The two possible methods for fixing the error "CMake Error at common/cmake_modules/GncAddSchemeTargets.cmake..." in gnucash

Method 1 for fixing packages that build on-device but fail in termux-packages CI

Note

Older method that could be described as "traditional cross-compilation"
Advantages:

  • High-performance, fast re-builds (after any hostbuild-steps have been cached) and no issues with ARM targets
  • More easily-portable to non-Termux Android projects
  • Builds cleanly in the container on any Docker PC without any special settings external to Docker needed

Disadvantages:

  • More lines of code and more time-consuming and tedious to write
  • Higher risk of breaking during version bumps due to upstream changes
  • Usually, testsuites cannot be run at build-time
expand to view method 1
  1. Find commands that the build system of the software runs that don't perform the correct behavior unless run inside Termux, not Ubuntu
builder@b24c3740d7a6:~/.termux-build/gnucash/src$ grep -rn . -e find_one_guile_dir
./common/cmake_modules/GncAddSchemeTargets.cmake:50:function(find_one_guile_dir _DIRCLASS _DIRCMD _PREFIX)
./common/cmake_modules/GncAddSchemeTargets.cmake:75:    find_one_guile_dir("prefix" "(display (assoc-ref %guile-build-info 'prefix))" "")
./common/cmake_modules/GncAddSchemeTargets.cmake:77:    find_one_guile_dir("datadir" "(display (%package-data-dir))" ${GUILE_PREFIX})
./common/cmake_modules/GncAddSchemeTargets.cmake:79:    find_one_guile_dir("libdir" "(display (%library-dir))" ${GUILE_PREFIX})
./common/cmake_modules/GncAddSchemeTargets.cmake:81:    find_one_guile_dir("ccachedir" "(display (assoc-ref %guile-build-info 'ccachedir))" ${GUILE_PREFIX})
./common/cmake_modules/GncAddSchemeTargets.cmake:83:    find_one_guile_dir("sitedir" "(display (%site-dir))" ${GUILE_PREFIX})
./common/cmake_modules/GncAddSchemeTargets.cmake:85:    find_one_guile_dir("siteccachedir" "(display (%site-ccache-dir))" ${GUILE_PREFIX})
builder@b24c3740d7a6:~/.termux-build/gnucash/src$ grep -rn . -e Python3_EXECUTABLE
./bindings/python/tests/CMakeLists.txt:10:  add_test(NAME python-bindings COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/runTests.py.in)
./CMakeLists.txt:531:    COMMAND ${Python3_EXECUTABLE} -c "from sysconfig import get_path; print(get_path('platlib', 'posix_prefix', {'platbase': '${CMAKE_INSTALL_PREFIX}'}))"
  1. Refactor out and run those commands in Bash inside Termux on an Android device, and record the results
~$ guile -c "(display (assoc-ref %guile-build-info 'prefix))" && echo
/data/data/com.termux/files/usr
~ $ guile -c "(display (%package-data-dir))" && echo
/data/data/com.termux/files/usr/share/guile
~ $ guile -c "(display (%library-dir))" && echo
/data/data/com.termux/files/usr/share/guile/3.0
~ $ guile -c "(display (assoc-ref %guile-build-info 'ccachedir))" && echo
/data/data/com.termux/files/usr/lib/guile/3.0/ccache
~ $ guile -c "(display (%site-dir))" && echo
/data/data/com.termux/files/usr/share/guile/site/3.0
~ $ guile -c "(display (%site-ccache-dir))" && echo
/data/data/com.termux/files/usr/lib/guile/3.0/site-ccache
~ $ python -c "from sysconfig import get_path; print(get_path('platlib', 'posix_prefix', {'platbase': '${PREFIX}'}))"
/data/data/com.termux/files/usr/lib/python3.12/site-packages
~ $
  1. Rewrite the resulting needed results from the commands into a patch that entirely replaces all attempts of the software's build system to run commands during the build that don't behave correctly unless run inside Termux, with new lines that apply the same command results in some way that doesn't involve running commands inside Android to get them
--- a/common/cmake_modules/GncAddSchemeTargets.cmake
+++ b/common/cmake_modules/GncAddSchemeTargets.cmake
@@ -82,17 +82,33 @@ endfunction()
 # datadir, libdir, sitedir, ccachedir and siteccachedir
 macro(find_guile_dirs)
     # Get GUILE_PREFIX and GUILE_UNIX_PREFIX
-    find_one_guile_dir("prefix" "(display (assoc-ref %guile-build-info 'prefix))" "")
+    set(GUILE_PREFIX "@TERMUX_PREFIX@")
+    set(GUILE_UNIX_PREFIX "@TERMUX_PREFIX@")
     # Get GUILE_DATADIR, GUILE_UNIX_DATADIR, GUILE_REL_DATADIR, GUILE_REL_UNIX_DATADIR
-    find_one_guile_dir("datadir" "(display (%package-data-dir))" ${GUILE_PREFIX})
+    set(GUILE_DATADIR "@TERMUX_PREFIX@/share/guile")
+    set(GUILE_UNIX_DATADIR "@TERMUX_PREFIX@/share/guile")
+    set(GUILE_REL_DATADIR "share/guile")
+    set(GUILE_REL_UNIX_DATADIR "share/guile")
     # Get GUILE_LIBDIR, GUILE_UNIX_LIBDIR, GUILE_REL_LIBDIR, GUILE_REL_UNIX_LIBDIR
-    find_one_guile_dir("libdir" "(display (%library-dir))" ${GUILE_PREFIX})
+    set(GUILE_LIBDIR "@TERMUX_PREFIX@/share/guile/3.0")
+    set(GUILE_UNIX_LIBDIR "@TERMUX_PREFIX@/share/guile/3.0")
+    set(GUILE_REL_LIBDIR "share/guile/3.0")
+    set(GUILE_REL_UNIX_LIBDIR "share/guile/3.0")
     # Get GUILE_CCACHEDIR, GUILE_UNIX_CCACHEDIR, GUILE_REL_CCACHEDIR, GUILE_REL_UNIX_CCACHEDIR
-    find_one_guile_dir("ccachedir" "(display (assoc-ref %guile-build-info 'ccachedir))" ${GUILE_PREFIX})
+    set(GUILE_CCACHEDIR "@TERMUX_PREFIX@/lib/guile/3.0/ccache")
+    set(GUILE_UNIX_CCACHEDIR "@TERMUX_PREFIX@/lib/guile/3.0/ccache")
+    set(GUILE_REL_CCACHEDIR "lib/guile/3.0/ccache")
+    set(GUILE_REL_UNIX_CCACHEDIR "lib/guile/3.0/ccache")
     # Get GUILE_SITEDIR, GUILE_UNIX_SITEDIR, GUILE_REL_SITEDIR, GUILE_REL_UNIX_SITEDIR
-    find_one_guile_dir("sitedir" "(display (%site-dir))" ${GUILE_PREFIX})
+    set(GUILE_SITEDIR "@TERMUX_PREFIX@/share/guile/site/3.0")
+    set(GUILE_UNIX_SITEDIR "@TERMUX_PREFIX@/share/guile/site/3.0")
+    set(GUILE_REL_SITEDIR "share/guile/site/3.0")
+    set(GUILE_REL_UNIX_SITEDIR "share/guile/site/3.0")
     # Get GUILE_SITECCACHEDIR, GUILE_UNIX_SITECCACHEDIR, GUILE_REL_SITECCACHEDIR, GUILE_REL_UNIX_SITECCACHEDIR
-    find_one_guile_dir("siteccachedir" "(display (%site-ccache-dir))" ${GUILE_PREFIX})
+    set(GUILE_SITECCACHEDIR "@TERMUX_PREFIX@/lib/guile/3.0/site-ccache")
+    set(GUILE_UNIX_SITECCACHEDIR "@TERMUX_PREFIX@/lib/guile/3.0/site-ccache")
+    set(GUILE_REL_SITECCACHEDIR "lib/guile/3.0/site-ccache")
+    set(GUILE_REL_UNIX_SITECCACHEDIR "lib/guile/3.0/site-ccache")
     string(REGEX REPLACE "[/\\]*${GUILE_EFFECTIVE_VERSION}$" "" GUILE_REL_TOP_SITEDIR ${GUILE_REL_SITEDIR})
     string(REGEX REPLACE "[/]*${GUILE_EFFECTIVE_VERSION}$" "" GUILE_REL_UNIX_TOP_SITEDIR ${GUILE_REL_UNIX_SITEDIR})
 
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -311,8 +311,8 @@ if (GUILE3_FOUND) # found guile-3.0
   set(GUILE_EFFECTIVE_VERSION 3.0)
   set(GUILE_INCLUDE_DIRS ${GUILE3_INCLUDE_DIRS})
   set(GUILE_LDFLAGS ${GUILE3_LDFLAGS})
-  pkg_get_variable (GUILD_EXECUTABLE guile-3.0 guild)
-  pkg_get_variable (GUILE_EXECUTABLE guile-3.0 guile)
+  set(GUILD_EXECUTABLE @GUILD_EXECUTABLE@)
+  set(GUILE_EXECUTABLE @GUILE_EXECUTABLE@)
   if (NOT GUILD_EXECUTABLE)
     find_program (GUILD_EXECUTABLE NAMES guild3.0 guild)
   endif()
@@ -527,17 +527,7 @@ if (WITH_PYTHON)
   endif()
 
   # Determine where to install the python libraries.
-  execute_process(
-    COMMAND ${Python3_EXECUTABLE} -c "from sysconfig import get_path; print(get_path('platlib', 'posix_prefix', {'platbase': '${CMAKE_INSTALL_PREFIX}'}))"
-    RESULT_VARIABLE PYTHON_SYSCONFIG_RESULT
-    OUTPUT_VARIABLE PYTHON_SYSCONFIG_OUTPUT
-    ERROR_VARIABLE PYTHON_SYSCONFIG_ERROR
-    OUTPUT_STRIP_TRAILING_WHITESPACE
-    ERROR_STRIP_TRAILING_WHITESPACE
-  )
-  if (PYTHON_SYSCONFIG_RESULT)
-    message(SEND_ERROR "Could not determine Python site-package directory:\n${PYTHON_SYSCONFIG_ERROR}")
-  endif()
+  set(PYTHON_SYSCONFIG_OUTPUT "@TERMUX_PYTHON_HOME@/site-packages")
   string(REPLACE ${CMAKE_INSTALL_PREFIX} ${CMAKE_BINARY_DIR} PYTHON_SYSCONFIG_BUILD ${PYTHON_SYSCONFIG_OUTPUT})
 endif()
 
  1. Disable any hardcoded testsuites, since without the presence of an Android device, they cannot be effectively run
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -3,7 +3,6 @@
 # The subdirectories
 add_subdirectory (cmake_modules)
 add_subdirectory (debug)
-add_subdirectory (test-core)
 
 set(common_EXTRA_DIST
         base-typemaps.i
  1. If the software's build system attempts to build binaries from its own code, load them, and run them during the build at any point where, unlike testsuites, they are actually required for a usable build, which could manifest as many different error messages, but in this case manifests as libgnucash-guile.so: cannot open shared object file: No such file or directory, this is an indicator that a temporary build of the software at the same version for Ubuntu that can be imported and run during the build targeting Android is likely necessary. In Termux, this temporary build is referred to as a "hostbuild" and is performed in the function termux_step_host_build().
TERMUX_PKG_HOSTBUILD=true
termux_step_host_build() {
    ...
export LD_LIBRARY_PATH="${HOSTBUILD_ROOTFS}/usr/lib/x86_64-linux-gnu"
LD_LIBRARY_PATH+=":${HOSTBUILD_ROOTFS}/usr/lib"
LD_LIBRARY_PATH+=":${HOSTBUILD_ROOTFS}/usr/lib/$TERMUX_PKG_NAME"
  1. When targeting 64-bit Android-x86, additional errors can occur that do not occur when building for other targets, which can look like this, which should be identifiable as subtly different from the similar error messages that are possible when building for other targets, because unlike other error messages, they will mention libdl.so. This is interpretable as an indication that Ubuntu GNU/Linux is attempting, and failing, to load a shared library file that was built for 64-bit Android-x86:
In procedure dlopen: file "libgnucash-guile.so", message "libdl.so: cannot open shared object file: No such file or directory"

This happens because unfortunately, 64-bit x86 Ubuntu GNU/Linux treats 64-bit Android-x86 libraries differently from any other incompatible type of libraries and unsuccessfully attempts to load them more aggressively than the libraries of other targets. In the case of gnucash, this can be worked around by intercepting the build system's handling of LD_LIBRARY_PATH to forcibly hide the newly-built libraries for the target platform.

@@ -268,7 +268,7 @@ function(gnc_add_scheme_targets _TARGET)
         set(LIBRARY_PATH "PATH=${BINDIR_BUILD};${fpath}")
         make_win32_path_list(LIBRARY_PATH)
       else()
-        set (LIBRARY_PATH "LD_LIBRARY_PATH=${LIBDIR_BUILD}:${LIBDIR_BUILD}/gnucash:$ENV{LD_LIBRARY_PATH}")
+        set (LIBRARY_PATH "LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}")
       endif()
       if (APPLE)
         set (LIBRARY_PATH "DYLD_LIBRARY_PATH=${LIBDIR_BUILD}:${LIBDIR_BUILD}/gnucash:$ENV{DYLD_LIBRARY_PATH}")

Full code of this method for gnucash: robertkirkman@a33e816

Build log of this example in termux-packages GitHub Actions CI: https://github.com/robertkirkman/termux-packages/actions/runs/17513848454/job/49748891215

Total package source code length, not including imported code that is shared between multiple termux packages: 636 lines

Method 2 for fixing packages that build on-device but fail in termux-packages CI

Note

Newer method that could be described as "running a headless Android nested pseudocontainer at build-time"
Advantages:

  • Fewer lines of code and less time-consuming and tedious to write
  • Lower risk of breaking due to upstream changes during version bumps
  • Sometimes, it can even allow enabling testsuites during the build

Disadvantages:

  • For the ARM targets, negative performance impact affecting build duration and, rarely, compatibility problems. Severity of this problem increases the more intensive the commands that need to run at build-time inside Android are.
  • Less easily-portable to non-Termux Android projects
  • In some cases, can sometimes require and/or be affected by settings outside of Docker that some people might not want to or might not be able to configure in their Docker server. One example
expand to view method 2
  1. Add aosp-libs to TERMUX_PKG_BUILD_DEPENDS
TERMUX_PKG_BUILD_DEPENDS="aosp-libs, boost-headers, googletest"
  1. Add a call to termux_setup_proot to the start of termux_step_pre_configure()
termux_step_pre_configure() {
    ...
	termux_setup_proot
  1. Add termux-proot-run wrappers below that in termux_step_pre_configure() of all the binary programs from which the software's build system will need to get the results of running them on an Android device, and add them to PATH, making sure to customize them to explicitly pass through any needed environment variables set up by the build system, which can be tedious to track down (for example, in this case, the software-specific environment variables GUILE_LOAD_PATH and GUILE_LOAD_COMPILED_PATH had to be manually identified, learned and passed through explicitly)
	export LD_LIBRARY_PATH="$TERMUX_PKG_BUILDDIR/lib:$TERMUX_PKG_BUILDDIR/lib/$TERMUX_PKG_NAME"
	mkdir -p "$TERMUX_PKG_TMPDIR/bin"
	for tool in python guile; do
		# proot will append its own LD_LIBRARY_PATH which is incompatible with bionic
		cat > "$TERMUX_PKG_TMPDIR/bin/$tool" <<-HERE
			#!$(command -v bash)
			LD_LIBRARY_PATH=$LD_LIBRARY_PATH
			exec $(command -v termux-proot-run) env LD_PRELOAD= LD_LIBRARY_PATH=\$LD_LIBRARY_PATH GUILE_LOAD_PATH=\$GUILE_LOAD_PATH GUILE_LOAD_COMPILED_PATH=\$GUILE_LOAD_COMPILED_PATH $TERMUX_PREFIX/bin/$tool "\$@"
		HERE
	done
	chmod +x "$TERMUX_PKG_TMPDIR/bin"/*
	ln -sf "$TERMUX_PREFIX/bin/guild" "$TERMUX_PKG_TMPDIR/bin/guild"
	PATH="$TERMUX_PKG_TMPDIR/bin:$PATH"
  1. Patch the build system of the software to find the wrappers, instead of attempting to continue to use the executables from the $TERMUX_PREFIX/bin path directly
Hide the original Termux guild and guile from the build system
so that the wrappers will be detected and used instead
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -311,8 +311,6 @@ if (GUILE3_FOUND) # found guile-3.0
   set(GUILE_EFFECTIVE_VERSION 3.0)
   set(GUILE_INCLUDE_DIRS ${GUILE3_INCLUDE_DIRS})
   set(GUILE_LDFLAGS ${GUILE3_LDFLAGS})
-  pkg_get_variable (GUILD_EXECUTABLE guile-3.0 guild)
-  pkg_get_variable (GUILE_EXECUTABLE guile-3.0 guile)
   if (NOT GUILD_EXECUTABLE)
     find_program (GUILD_EXECUTABLE NAMES guild3.0 guild)
   endif()
  1. Disable the testsuite, since unfortunately, while the testsuite might pass on device, for the time being I wasn't able to get it to pass inside termux-proot-run (which is more limited than standard Termux)

[!NOTE]
I skipped implementing it here for now because the process can be extremely time-consuming and tedious, but if you would like to see the a complete and stable example of a package's full testsuite passing during CI inside of the termux-proot-run container, fully realizing the testsuite-enabling potential of termux-proot-run, you can take a look at my package of SBCL in Termux (which took me about 2 weeks of work to fully complete):

# run test suite inside proot
termux-proot-run env LD_PRELOAD= LD_LIBRARY_PATH= \
CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" LINKFLAGS="$LDFLAGS" \
TMPDIR="$TERMUX_PREFIX/tmp" \
sh run-tests.sh

Full code of this method for gnucash: robertkirkman@edd2202

Build log of this example in termux-packages GitHub Actions CI: https://github.com/robertkirkman/termux-packages/actions/runs/17515294855/job/49752007407

Total package source code length, not including imported code that is shared between multiple termux packages: 344 lines

@robertkirkman
Copy link
Member

Both methods are available to use and you can feel free to copy and paste them from the commits I uploaded and linked. You can feel free to decide which method is more appealing to you after reading the information and code I have provided and testing them as you see fit.

@acozzette
Copy link
Author

@robertkirkman Wow, that's awesome! Thanks so much for doing all this. Your explanations help a lot to understand the build issues involved.

I think I'm leaning toward preferring your Method 2, since the necessary changes look a bit less invasive and since this method offers the ability of potentially getting the tests working. If I can find time this weekend then I'll try to start from your commit and see if I can get the tests to run.

Do you think it's important to enable Python support? I'm just curious because I would be slightly inclined to leave it turned off. I don't personally plan on using it and thought it might simplify things a little bit to leave it disabled.

@robertkirkman
Copy link
Member

robertkirkman commented Sep 6, 2025

Do you think it's important to enable Python support? I'm just curious because I would be slightly inclined to leave it turned off.

not really, i just enabled it because it's not difficult to do so and usually we do enable python support in other packages. if you want to leave it off you can.

I think I'm leaning toward preferring your Method 2, since the necessary changes look a bit less invasive and since this method offers the ability of potentially getting the tests working. If I can find time this weekend then I'll try to start from your commit and see if I can get the tests to run.

sure, I found the errors that happen when enabling the testsuite difficult, but I can also try helping with that and i understand the importance of it, since enabling the tests in another package SBCL did help identify and fix multiple bugs in that software that only appeared when it was built for Android and especially Android-x86 that would not really have been possible to fix otherwise. I think that these two topics will probably be relevant for getting the tests to pass in CI: debugging and troubleshooting Scheme code and the guile binary, and adjusting the settings or packages installed within termux-proot-run until its behavior gets close enough to the behavior of real Termux for it to run the on-device-only parts of gnucash's build system and tests the same exact way.

@acozzette
Copy link
Author

@robertkirkman Sorry for taking forever to get back to this. I haven't forgotten about it but have just been busy with other things.

I was thinking that since you did almost all the real work of getting this working, you should feel free to submit your own PR if you want. If not then I will try to get back to it soon, but probably won't be able to work on it for another week at least.

@robertkirkman
Copy link
Member

@robertkirkman Sorry for taking forever to get back to this. I haven't forgotten about it but have just been busy with other things.

I was thinking that since you did almost all the real work of getting this working, you should feel free to submit your own PR if you want. If not then I will try to get back to it soon, but probably won't be able to work on it for another week at least.

That's ok, and sure, I have also been planning to eventually try some more to get the tests to work. Part of my plan involves writing code that would simplify running build-time tests like what gnucash has, in a way that would be easier to generalize to many packages, rather than dependent on large, package-specific patches. That plan could be described as adding a "third" build method, distinct from the other two build methods that I have showed examples of here so far.

This PR is a blocker for me to make progress on that third method, so I'm waiting for reviews on it. If approved, eventually it would allow me to implement the third method of building, which should be much more easily compatible with build-time testsuites and much easier to maintain.

@acozzette acozzette changed the title addpkg(x11/gnucash): 5.12 addpkg(x11/gnucash): 5.13 Oct 21, 2025
@acozzette
Copy link
Author

I finally got back to this and updated my PR. I copied Robert's termux-proot changes and also upgraded to Gnucash 5.13 since that has been released in the meantime. I was able to build the package successfully in Docker and install and run it on my device, so hopefully this is now ready to merge.

@robertkirkman
Copy link
Member

Hm, it looks like the builds for 32-bit targets failed. I will take a look and see if I can fix that or not.

@robertkirkman
Copy link
Member

robertkirkman commented Oct 21, 2025

When I test building gnucash for 32-bit Android in non-cross-compilation mode (meaning, building on a real Android device with a real 32-bit CPU), unfortunately the same problem happens, with identical warnings and errors. That narrows down the problem to something going wrong on specifically 32-bit Android with either gnucash itself, or with the 32-bit Termux build of the guile package, which is being used during the gnucash build (and eliminates the possibility of the problem being caused by cross-compiling gnucash or using termux-proot-run with the gnucash package).

It's acceptable as a last resort to disable the 32-bit targets in Termux packages and implement the package only for 64-bit targets, but if at all possible it's desirable to make packages work on 32-bit targets, since otherwise people who have 32-bit devices won't be able to get them, so I will continue trying.

@robertkirkman
Copy link
Member

I have figured out that this error when running the 32-bit build of guile only happens when using guile 3.0.10 and it does not seem to happen when using guile 3.0.9.

This also explains why I didn't see this error when I originally wrote the build script for gnucash that you are trying to use - at that time, Termux guile was version 3.0.9.

It was only later that I upgraded the Termux guile to version 3.0.10, in this:

however, while doing that fixed a bug elsewhere, it seems like it might have introduced a bug that prevents building gnucash for 32-bit targets.

I could start bisecting the issue, but I've also noticed that Debian's guile package is one that has a huge number of patches applied to it, including some patches related to 32-bit support that Termux's package doesn't have, and among them are patches that weren't added until after the release of guile 3.0.10.

https://sources.debian.org/src/guile-3.0/3.0.10%2Breally3.0.10-6/debian/patches

I'll probably try applying the Debian patches to Termux's guile package first and check if that helps, and if that doesn't help, then after that I will start bisecting the commit in guile which causes 3.0.10 to have an error when 3.0.9 does not.

@robertkirkman
Copy link
Member

robertkirkman commented Oct 23, 2025

After a lot of testing, I have collected the following information:

  • Unfortunately, none of the patches from Debian's current guile 3.0.10 package I found in https://sources.debian.org/src/guile-3.0/3.0.10%2Breally3.0.10-6/debian/patches are able to prevent this error, which indicates that for some reason, it has probably not yet been encountered by Debian developers building for 32-bit Debian targets.

  • However, I have managed to reproduce the same error on 32-bit GNU/Linux (not Android) by performing a relatively contrived series of steps, which indicates that the issue does not technically require the presence of Android to reproduce, therefore I will also eventually try to report this issue upstream if I can manage to write down a working MRE for it that reproduces the error in GNU/Linux without the presence of Android.

  • I have managed to bisect the error to this commit in guile: https://cgit.git.savannah.gnu.org/cgit/guile.git/commit/?id=d579848cb5d65440af5afd9c8968628665554c22 Unfortunately I don't understand the Scheme code which is changed in that commit, but dozens of tests firmly confirm it in my environment: all commits of guile before that commit do not produce the error, and that commit and all commits after it produce the error (including the current development branch newer than version 3.0.10)

  • I have opened this PR which, if applied to Termux, will allow you to successfully build gnucash using this gnucash PR's build.sh unchanged if you rebase this PR after I merge my PR. It works by reverting the bisected problematic upstream commit in guile with no other changes, and I have tested it locally and confirmed that for me, it allows the command scripts/run-docker.sh ./build-package.sh -I -f -a arm guile gnucash to complete successfully. fix(main/guile): revert commit which causes crashes on 32-bit devices and environments #26977

  • I might try to write and submit my report of the bug to upstream before I merge my PR to Termux reverting the commit, because if upstream is informed, they might know how to quickly provide a condensed or improved patch to fix the problem that would be more refined than just completely reverting the bisected commit would be.

@acozzette
Copy link
Author

Wow, well thanks for doing all this work to debug the problem! I'll hold off for now and wait for your fix to land.

@robertkirkman
Copy link
Member

Ok, @acozzette I have merged my PR now which fixed the 32-bit Termux guile packages, so if you rebase this PR on master and try to build it in CI again, it should now succeed for all architectures without errors.

@acozzette
Copy link
Author

@robertkirkman Great, thank you! I just rebased this PR onto master.

@robertkirkman
Copy link
Member

I can see that there is now another, different error, which definitely was not happening 3 days ago when I thought I tested the exact PR I merged combined with this PR locally. I must not have tested it as completely as I thought I did, though, because when I test again, I can reproduce the new error when only the first bisected commit is reverted, but not when using a development snapshot of the entire Guile project at the commit right before the bisected commit.

I really was sure that I tested the final version of my recent Termux guile PR with the current version of this Gnucash PR, but testing again today indicates that I must not have.

There is a way to reproduce that first error on GNU/Linux, which I documented in full in my recent issue associated with my Termux guile PR, but in that reproduction environment, that first error actually does completely go away and allow building with no errors when the individual commit is reverted.

However, it appears that there might be more commits necessary to revert than just that one in order to build gnucash successfully for 32-bit Android, which is a different situation.

The additional commits necessary to revert are definitely somewhere in between the commit that caused the first error and the final release of Guile 3.0.10, because this second error is definitely not reproducible with the upstream commit of Guile immediately before the commit that caused the first error, I have just tested that again to reconfirm that today.

I will now find the additional commit or commits in guile 3.0.10 that are responsible for the second error and any further errors.

@robertkirkman
Copy link
Member

robertkirkman commented Oct 26, 2025

I've written and, this time, I believe fully tested all the necessary additional changes to the guile 3.0.10 package in order to fix all of the remaining errors in the 32-bit builds of this PR, and I've placed them in my next PR,

I did bisect the second error to several other upstream Guile commits, however, this time, I tried again one of the workarounds that doesn't involve reverting commits which I tried on the first error that didn't work at the time, and now that the first error is fixed, that same workaround is now able to work and this time it's actually helping since it appears to fix the second error, meaning that I probably don't need to revert any additional commits, but instead only add all that additional code to the guile package.

When I test repeatedly building both guile and gnucash with this second guile PR, I am no longer seeing any more errors, so I will merge it soon and then I believe there won't be any more errors in the CI of this PR.

robertkirkman added a commit that referenced this pull request Oct 27, 2025
- Fixes multiple malformations in the 32-bit builds of `guile` 3.0.10, including but not limited to this MRE of a `WARNING`:

```
~ $ cat hello.scm
!#
(display "Hello, world!")
(newline)
~ $ ./hello.scm
;;; WARNING: compilation of /data/data/com.termux/files/home/./hello.scm failed:
;;; In procedure load-thunk-from-memory: ELF file does not have native word size
Hello, world!
~ $
```

- Necessary after these three upstream Guile commits and other commits which depend on them:
  - https://cgit.git.savannah.gnu.org/cgit/guile.git/commit/?id=137b0e85b956a7b7e7c9bc0029d09fe6868e5b17
  - https://cgit.git.savannah.gnu.org/cgit/guile.git/commit/?id=c758c99b5e37408e48dc1b22c73d6ec35d9de866
  - https://cgit.git.savannah.gnu.org/cgit/guile.git/commit/?id=88e0933450ed9f1cc96858641e0756ffa44c53c6

- Tangentially related follow-up to #26977, but **that PR is still necessary also, this PR does not replace it**.

- Necessary to complete #25962
termux-pacman-bot added a commit to termux-pacman/termux-packages that referenced this pull request Oct 27, 2025
- Fixes multiple malformations in the 32-bit builds of `guile` 3.0.10, including but not limited to this MRE of a `WARNING`:

```
~ $ cat hello.scm
!#
(display "Hello, world!")
(newline)
~ $ ./hello.scm
;;; WARNING: compilation of /data/data/com.termux/files/home/./hello.scm failed:
;;; In procedure load-thunk-from-memory: ELF file does not have native word size
Hello, world!
~ $
```

- Necessary after these three upstream Guile commits and other commits which depend on them:
  - https://cgit.git.savannah.gnu.org/cgit/guile.git/commit/?id=137b0e85b956a7b7e7c9bc0029d09fe6868e5b17
  - https://cgit.git.savannah.gnu.org/cgit/guile.git/commit/?id=c758c99b5e37408e48dc1b22c73d6ec35d9de866
  - https://cgit.git.savannah.gnu.org/cgit/guile.git/commit/?id=88e0933450ed9f1cc96858641e0756ffa44c53c6

- Tangentially related follow-up to termux/termux-packages#26977, but **that PR is still necessary also, this PR does not replace it**.

- Necessary to complete termux/termux-packages#25962
Credit goes to @robertkirkman for doing most of the hard work of actually
getting this to build! I largely copied Robert's changes with permission.

Fixes termux#20259.
Copy link
Member

@robertkirkman robertkirkman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's ready, I will merge it in 24 hours if no additional problems are found.

@robertkirkman robertkirkman merged commit 2cd112e into termux:master Oct 28, 2025
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Package]: gnucash

3 participants