From 43c60417aed900f61d22952d2e1c9e69a5490488 Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Mon, 31 Aug 2026 20:19:14 +0000 Subject: [PATCH] :bug: Fix C++ shared linker configuration, fixes #3363 Set LDCXXSHARED globally from the Android C++ compiler and shared linker flags so setuptools cannot inherit macOS bundle options. Remove the equivalent Greenlet, Kiwisolver, and Material You Color workarounds, and cover both compiler flag modes in architecture tests. --- pythonforandroid/archs.py | 1 + pythonforandroid/recipes/greenlet/__init__.py | 5 --- .../recipes/kiwisolver/__init__.py | 3 +- .../recipes/materialyoucolor/__init__.py | 5 --- tests/recipes/test_greenlet.py | 32 ------------------- tests/test_archs.py | 10 ++++++ 6 files changed, 12 insertions(+), 44 deletions(-) delete mode 100644 tests/recipes/test_greenlet.py diff --git a/pythonforandroid/archs.py b/pythonforandroid/archs.py index d09cee0ba9..5aec926065 100644 --- a/pythonforandroid/archs.py +++ b/pythonforandroid/archs.py @@ -209,6 +209,7 @@ def get_env(self, with_flags_in_cc=True): # Custom linker options env['LDSHARED'] = env['CC'] + ' ' + ' '.join(self.common_ldshared) + env['LDCXXSHARED'] = env['CXX'] + ' ' + ' '.join(self.common_ldshared) # Host python (used by some recipes) hostpython_recipe = Recipe.get_recipe( diff --git a/pythonforandroid/recipes/greenlet/__init__.py b/pythonforandroid/recipes/greenlet/__init__.py index f69ea053a0..11542b7abc 100644 --- a/pythonforandroid/recipes/greenlet/__init__.py +++ b/pythonforandroid/recipes/greenlet/__init__.py @@ -7,10 +7,5 @@ class GreenletRecipe(PyProjectRecipe): depends = ['setuptools'] call_hostpython_via_targetpython = False - def get_recipe_env(self, arch, **kwargs): - env = super().get_recipe_env(arch, **kwargs) - env['LDCXXSHARED'] = env['CXX'] + ' -shared' - return env - recipe = GreenletRecipe() diff --git a/pythonforandroid/recipes/kiwisolver/__init__.py b/pythonforandroid/recipes/kiwisolver/__init__.py index 3ccfc2d432..2501af29f5 100644 --- a/pythonforandroid/recipes/kiwisolver/__init__.py +++ b/pythonforandroid/recipes/kiwisolver/__init__.py @@ -9,12 +9,11 @@ class KiwiSolverRecipe(PyProjectRecipe): need_stl_shared = True def get_recipe_env(self, arch, **kwargs): - """Override compile and linker flags, refs: #3115 and #3122""" + """Add the Python include path, refs: #3115.""" env = super().get_recipe_env(arch, **kwargs) flags = " -I" + self.ctx.python_recipe.include_root(arch.arch) env["CFLAGS"] += flags env["CPPFLAGS"] += flags - env["LDFLAGS"] += " -shared" return env diff --git a/pythonforandroid/recipes/materialyoucolor/__init__.py b/pythonforandroid/recipes/materialyoucolor/__init__.py index abbc2d7b39..09dc779bf5 100644 --- a/pythonforandroid/recipes/materialyoucolor/__init__.py +++ b/pythonforandroid/recipes/materialyoucolor/__init__.py @@ -6,10 +6,5 @@ class MaterialyoucolorRecipe(PyProjectRecipe): version = "2.0.10" url = "https://github.com/T-Dynamos/materialyoucolor-python/releases/download/v{version}/materialyoucolor-{version}.tar.gz" - def get_recipe_env(self, arch, **kwargs): - env = super().get_recipe_env(arch, **kwargs) - env['LDCXXSHARED'] = env['CXX'] + ' -shared' - return env - recipe = MaterialyoucolorRecipe() diff --git a/tests/recipes/test_greenlet.py b/tests/recipes/test_greenlet.py deleted file mode 100644 index 6d5aaa9533..0000000000 --- a/tests/recipes/test_greenlet.py +++ /dev/null @@ -1,32 +0,0 @@ -import unittest -from unittest.mock import patch - -from tests.recipes.recipe_ctx import RecipeCtx - - -class TestGreenletRecipe(RecipeCtx, unittest.TestCase): - - recipe_name = "greenlet" - - def test_get_recipe_env_sets_target_cxx_shared_linker(self): - parent_env = { - 'CXX': ( - '/ndk/bin/aarch64-linux-android24-clang++ ' - '--target=aarch64-linux-android24' - ), - 'LDCXXSHARED': 'clang++ -bundle -undefined dynamic_lookup', - 'CFLAGS': '-DANDROID', - } - - with patch( - 'pythonforandroid.recipe.PyProjectRecipe.get_recipe_env', - return_value=parent_env, - ) as get_recipe_env: - env = self.recipe.get_recipe_env(self.arch) - - get_recipe_env.assert_called_once_with(self.arch) - self.assertEqual( - env['LDCXXSHARED'], - parent_env['CXX'] + ' -shared', - ) - self.assertEqual(env['CFLAGS'], '-DANDROID') diff --git a/tests/test_archs.py b/tests/test_archs.py index 58530886ff..1e701341b3 100644 --- a/tests/test_archs.py +++ b/tests/test_archs.py @@ -25,6 +25,7 @@ "CC", "CXX", "LDSHARED", + "LDCXXSHARED", "STRIP", "MAKE", "READELF", @@ -62,6 +63,7 @@ def setUp(self): recipes=["python3", "kivy"], archs=[self.TEST_ARCH], ) + self.ctx.recipe_build_order = self.ctx.bootstrap.distribution.recipes self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx) # Here we define the expected compiler, which, as per ndk >= r19, # should be the same for all the tests (no more gcc compiler) @@ -134,6 +136,10 @@ def test_arch_arm(self, mock_ensure_dir, mock_shutil_which): # check gcc compilers self.assertEqual(env["CC"].split()[0], self.expected_compiler) self.assertEqual(env["CXX"].split()[0], self.expected_compiler + "++") + self.assertEqual( + env["LDCXXSHARED"], + env["CXX"] + " " + " ".join(arch.common_ldshared), + ) # check android binaries self.assertEqual( env["STRIP"].split()[0], @@ -159,6 +165,10 @@ def test_arch_arm(self, mock_ensure_dir, mock_shutil_which): self.ctx.ccache = "/usr/bin/ccache" env = arch.get_env(with_flags_in_cc=False) self.assertNotIn(env["CFLAGS"], env["CC"]) + self.assertEqual( + env["LDCXXSHARED"], + env["CXX"] + " " + " ".join(arch.common_ldshared), + ) self.assertEqual(env["USE_CCACHE"], "1") self.assertEqual(env["NDK_CCACHE"], "/usr/bin/ccache")