From 9aa5d780d695d58ab44eab2e40911153a2da9c8e Mon Sep 17 00:00:00 2001 From: bbhtt Date: Tue, 10 Mar 2026 09:31:09 +0530 Subject: [PATCH 1/3] builder-options: Return NULL from get_flags when override is set When an override property is set in the manifest along with sdk default flags set but no explicit flags, builder_options_get_flags would return an empty string instead of NULL, causing a `--env=CFLAGS=` (and equivalent) being passed to the build. Return NULL in this case as well, which should not set the env var at all. Buildsystems might interpret this differently but the override properties as documented are not meant to affect the buildsystem's own internal handlings of the flags, rather only clear the accumulated flags of f-b. --- src/builder-options.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/builder-options.c b/src/builder-options.c index 8602a284..2daaa3d1 100644 --- a/src/builder-options.c +++ b/src/builder-options.c @@ -884,7 +884,10 @@ builder_options_get_flags (BuilderOptions *self, gboolean override = G_STRUCT_MEMBER (gboolean, o, override_field_offset); if (override && flags) - g_string_truncate (flags, 0); + { + g_string_free (flags, TRUE); + flags = NULL; + } if (flag) { From 761a3a1cb0b260e5dcebc7ce6a0c48608342381d Mon Sep 17 00:00:00 2001 From: bbhtt Date: Sat, 7 Mar 2026 20:20:35 +0530 Subject: [PATCH 2/3] builder-options: Set CGO build flags in builder environment Set CGO_CFLAGS, CGO_CXXFLAGS and CGO_LDFLAGS in the build environment. By default these inherit the values of cflags, cxxflags and ldflags respectively, unless overridden in the manifest. Fixes: https://github.com/flatpak/flatpak-builder/issues/694 --- NEWS | 1 + data/flatpak-manifest.schema.json | 24 +++++ doc/flatpak-manifest.xml | 24 +++++ src/builder-options.c | 160 ++++++++++++++++++++++++++++++ src/builder-options.h | 6 ++ tests/meson.build | 1 + tests/test-builder-flags.sh | 147 +++++++++++++++++++++++++++ 7 files changed, 363 insertions(+) create mode 100755 tests/test-builder-flags.sh diff --git a/NEWS b/NEWS index 94c034e9..d8bf427c 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ TBD * Support setting state-dir for run * Default to builddir true for cmake and cmake-ninja buildsystems * Handle case-insensitive YAML boolean and null scalars +* Support setting CGO buildflags in builder environment Changes in 1.4.6 ================ diff --git a/data/flatpak-manifest.schema.json b/data/flatpak-manifest.schema.json index b9bb8be4..714b5db9 100644 --- a/data/flatpak-manifest.schema.json +++ b/data/flatpak-manifest.schema.json @@ -26,6 +26,14 @@ "description": "If this is true, clear cflags from previous build options before adding it from these options.", "type": "boolean" }, + "cgo-cflags": { + "description": "This is set in the environment variable CGO_CFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces. If unset, defaults to the value of cflags.", + "type": "string" + }, + "cgo-cflags-override": { + "description": "If this is true, clear cgo-cflags from previous build options before adding it from these options. If set without cgo-cflags, CGO_CFLAGS will not be set.", + "type": "boolean" + }, "cppflags": { "description": "This is set in the environment variable CPPFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces.", "type": "string" @@ -42,6 +50,14 @@ "description": "If this is true, clear cxxflags from previous build options before adding it from these options.", "type": "boolean" }, + "cgo-cxxflags": { + "description": "This is set in the environment variable CGO_CXXFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces. If unset, defaults to the value of cxxflags.", + "type": "string" + }, + "cgo-cxxflags-override": { + "description": "If this is true, clear cgo-cxxflags from previous build options before adding it from these options. If set without cgo-cxxflags, CGO_CXXFLAGS will not be set.", + "type": "boolean" + }, "ldflags": { "description": "This is set in the environment variable LDFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces.", "type": "string" @@ -50,6 +66,14 @@ "description": "If this is true, clear ldflags from previous build options before adding it from these options.", "type": "boolean" }, + "cgo-ldflags": { + "description": "This is set in the environment variable CGO_LDFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces. If unset, defaults to the value of ldflags.", + "type": "string" + }, + "cgo-ldflags-override": { + "description": "If this is true, clear cgo-ldflags from previous build options before adding it from these options. If set without cgo-ldflags, CGO_LDFLAGS will not be set.", + "type": "boolean" + }, "prefix": { "description": "The build prefix for the modules (defaults to /app for applications and /usr for runtimes).", "type": "string" diff --git a/doc/flatpak-manifest.xml b/doc/flatpak-manifest.xml index 4c9dddcd..7d3b530c 100644 --- a/doc/flatpak-manifest.xml +++ b/doc/flatpak-manifest.xml @@ -316,6 +316,14 @@ (boolean) If this is true, clear cflags from previous build options before adding it from these options. + + (string) + This is set in the environment variable CGO_CFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces. If unset, defaults to the value of cflags. + + + (boolean) + If this is true, clear cgo-cflags from previous build options before adding it from these options. If set without cgo-cflags, CGO_CFLAGS will not be set. + (string) This is set in the environment variable CPPFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces. @@ -332,6 +340,14 @@ (boolean) If this is true, clear cxxflags from previous build options before adding it from these options. + + (string) + This is set in the environment variable CGO_CXXFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces. If unset, defaults to the value of cxxflags. + + + (boolean) + If this is true, clear cgo-cxxflags from previous build options before adding it from these options. If set without cgo-cxxflags, CGO_CXXFLAGS will not be set. + (string) This is set in the environment variable LDFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces. @@ -340,6 +356,14 @@ (boolean) If this is true, clear ldflags from previous build options before adding it from these options. + + (string) + This is set in the environment variable CGO_LDFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces. If unset, defaults to the value of ldflags. + + + (boolean) + If this is true, clear cgo-ldflags from previous build options before adding it from these options. If set without cgo-ldflags, CGO_LDFLAGS will not be set. + (string) The build prefix for the modules (defaults to /app for diff --git a/src/builder-options.c b/src/builder-options.c index 2daaa3d1..86d1c00f 100644 --- a/src/builder-options.c +++ b/src/builder-options.c @@ -41,12 +41,18 @@ struct BuilderOptions gboolean no_debuginfo_compression; char *cflags; gboolean cflags_override; + char *cgo_cflags; + gboolean cgo_cflags_override; char *cppflags; gboolean cppflags_override; char *cxxflags; gboolean cxxflags_override; + char *cgo_cxxflags; + gboolean cgo_cxxflags_override; char *ldflags; gboolean ldflags_override; + char *cgo_ldflags; + gboolean cgo_ldflags_override; char *append_path; char *prepend_path; char *append_ld_library_path; @@ -80,12 +86,18 @@ enum { PROP_0, PROP_CFLAGS, PROP_CFLAGS_OVERRIDE, + PROP_CGO_CFLAGS, + PROP_CGO_CFLAGS_OVERRIDE, PROP_CPPFLAGS, PROP_CPPFLAGS_OVERRIDE, PROP_CXXFLAGS, PROP_CXXFLAGS_OVERRIDE, + PROP_CGO_CXXFLAGS, + PROP_CGO_CXXFLAGS_OVERRIDE, PROP_LDFLAGS, PROP_LDFLAGS_OVERRIDE, + PROP_CGO_LDFLAGS, + PROP_CGO_LDFLAGS_OVERRIDE, PROP_PREFIX, PROP_LIBDIR, PROP_ENV, @@ -116,9 +128,12 @@ builder_options_finalize (GObject *object) BuilderOptions *self = (BuilderOptions *) object; g_free (self->cflags); + g_free (self->cgo_cflags); g_free (self->cxxflags); + g_free (self->cgo_cxxflags); g_free (self->cppflags); g_free (self->ldflags); + g_free (self->cgo_ldflags); g_free (self->append_path); g_free (self->prepend_path); g_free (self->append_ld_library_path); @@ -158,6 +173,14 @@ builder_options_get_property (GObject *object, g_value_set_boolean (value, self->cflags_override); break; + case PROP_CGO_CFLAGS: + g_value_set_string (value, self->cgo_cflags); + break; + + case PROP_CGO_CFLAGS_OVERRIDE: + g_value_set_boolean (value, self->cgo_cflags_override); + break; + case PROP_CPPFLAGS: g_value_set_string (value, self->cppflags); break; @@ -174,6 +197,14 @@ builder_options_get_property (GObject *object, g_value_set_boolean (value, self->cxxflags_override); break; + case PROP_CGO_CXXFLAGS: + g_value_set_string (value, self->cgo_cxxflags); + break; + + case PROP_CGO_CXXFLAGS_OVERRIDE: + g_value_set_boolean (value, self->cgo_cxxflags_override); + break; + case PROP_LDFLAGS: g_value_set_string (value, self->ldflags); break; @@ -182,6 +213,14 @@ builder_options_get_property (GObject *object, g_value_set_boolean (value, self->ldflags_override); break; + case PROP_CGO_LDFLAGS: + g_value_set_string (value, self->cgo_ldflags); + break; + + case PROP_CGO_LDFLAGS_OVERRIDE: + g_value_set_boolean (value, self->cgo_ldflags_override); + break; + case PROP_APPEND_PATH: g_value_set_string (value, self->append_path); break; @@ -287,6 +326,15 @@ builder_options_set_property (GObject *object, self->cflags_override = g_value_get_boolean (value); break; + case PROP_CGO_CFLAGS: + g_clear_pointer (&self->cgo_cflags, g_free); + self->cgo_cflags = g_value_dup_string (value); + break; + + case PROP_CGO_CFLAGS_OVERRIDE: + self->cgo_cflags_override = g_value_get_boolean (value); + break; + case PROP_CXXFLAGS: g_clear_pointer (&self->cxxflags, g_free); self->cxxflags = g_value_dup_string (value); @@ -296,6 +344,15 @@ builder_options_set_property (GObject *object, self->cxxflags_override = g_value_get_boolean (value); break; + case PROP_CGO_CXXFLAGS: + g_clear_pointer (&self->cgo_cxxflags, g_free); + self->cgo_cxxflags = g_value_dup_string (value); + break; + + case PROP_CGO_CXXFLAGS_OVERRIDE: + self->cgo_cxxflags_override = g_value_get_boolean (value); + break; + case PROP_CPPFLAGS: g_clear_pointer (&self->cppflags, g_free); self->cppflags = g_value_dup_string (value); @@ -314,6 +371,15 @@ builder_options_set_property (GObject *object, self->ldflags_override = g_value_get_boolean (value); break; + case PROP_CGO_LDFLAGS: + g_clear_pointer (&self->cgo_ldflags, g_free); + self->cgo_ldflags = g_value_dup_string (value); + break; + + case PROP_CGO_LDFLAGS_OVERRIDE: + self->cgo_ldflags_override = g_value_get_boolean (value); + break; + case PROP_APPEND_PATH: g_clear_pointer (&self->append_path, g_free); self->append_path = g_value_dup_string (value); @@ -448,6 +514,20 @@ builder_options_class_init (BuilderOptionsClass *klass) "", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_CGO_CFLAGS, + g_param_spec_string ("cgo-cflags", + "", + "", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_CGO_CFLAGS_OVERRIDE, + g_param_spec_boolean ("cgo-cflags-override", + "", + "", + FALSE, + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_CXXFLAGS, g_param_spec_string ("cxxflags", @@ -462,6 +542,20 @@ builder_options_class_init (BuilderOptionsClass *klass) "", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_CGO_CXXFLAGS, + g_param_spec_string ("cgo-cxxflags", + "", + "", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_CGO_CXXFLAGS_OVERRIDE, + g_param_spec_boolean ("cgo-cxxflags-override", + "", + "", + FALSE, + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_CPPFLAGS, g_param_spec_string ("cppflags", @@ -490,6 +584,20 @@ builder_options_class_init (BuilderOptionsClass *klass) "", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_CGO_LDFLAGS, + g_param_spec_string ("cgo-ldflags", + "", + "", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_CGO_LDFLAGS_OVERRIDE, + g_param_spec_boolean ("cgo-ldflags-override", + "", + "", + FALSE, + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_APPEND_PATH, g_param_spec_string ("append-path", @@ -924,6 +1032,16 @@ builder_options_get_cflags (BuilderOptions *self, BuilderContext *context) get_sdk_flags (self, context, builder_sdk_config_get_cflags)); } +char * +builder_options_get_cgo_cflags (BuilderOptions *self, BuilderContext *context) +{ + g_autofree char *cflags = builder_options_get_cflags (self, context); + return builder_options_get_flags (self, context, + G_STRUCT_OFFSET (BuilderOptions, cgo_cflags), + G_STRUCT_OFFSET (BuilderOptions, cgo_cflags_override), + cflags); +} + char * builder_options_get_cxxflags (BuilderOptions *self, BuilderContext *context) { @@ -932,6 +1050,17 @@ builder_options_get_cxxflags (BuilderOptions *self, BuilderContext *context) get_sdk_flags (self, context, builder_sdk_config_get_cxxflags)); } +char * +builder_options_get_cgo_cxxflags (BuilderOptions *self, BuilderContext *context) +{ + g_autofree char *cxxflags = builder_options_get_cxxflags (self, context); + return builder_options_get_flags (self, context, + G_STRUCT_OFFSET (BuilderOptions, cgo_cxxflags), + G_STRUCT_OFFSET (BuilderOptions, cgo_cxxflags_override), + cxxflags); +} + + char * builder_options_get_cppflags (BuilderOptions *self, BuilderContext *context) { @@ -948,6 +1077,16 @@ builder_options_get_ldflags (BuilderOptions *self, BuilderContext *context) get_sdk_flags (self, context, builder_sdk_config_get_ldflags)); } +char * +builder_options_get_cgo_ldflags (BuilderOptions *self, BuilderContext *context) +{ + g_autofree char *ldflags = builder_options_get_ldflags (self, context); + return builder_options_get_flags (self, context, + G_STRUCT_OFFSET (BuilderOptions, cgo_ldflags), + G_STRUCT_OFFSET (BuilderOptions, cgo_ldflags_override), + ldflags); +} + static char * builder_options_get_appended_path (BuilderOptions *self, BuilderContext *context, const char *initial_value, size_t append_field_offset, size_t prepend_field_offset) { @@ -1138,9 +1277,12 @@ builder_options_get_env (BuilderOptions *self, BuilderContext *context) int i; char **envp = NULL; g_autofree char *cflags = NULL; + g_autofree char *cgo_cflags = NULL; g_autofree char *cppflags = NULL; g_autofree char *cxxflags = NULL; + g_autofree char *cgo_cxxflags = NULL; g_autofree char *ldflags = NULL; + g_autofree char *cgo_ldflags = NULL; envp = builder_context_extend_env_pre (context, envp); @@ -1148,6 +1290,10 @@ builder_options_get_env (BuilderOptions *self, BuilderContext *context) if (cflags) envp = g_environ_setenv (envp, "CFLAGS", cflags, FALSE); + cgo_cflags = builder_options_get_cgo_cflags (self, context); + if (cgo_cflags) + envp = g_environ_setenv (envp, "CGO_CFLAGS", cgo_cflags, FALSE); + cppflags = builder_options_get_cppflags (self, context); if (cppflags) envp = g_environ_setenv (envp, "CPPFLAGS", cppflags, FALSE); @@ -1156,10 +1302,18 @@ builder_options_get_env (BuilderOptions *self, BuilderContext *context) if (cxxflags) envp = g_environ_setenv (envp, "CXXFLAGS", cxxflags, FALSE); + cgo_cxxflags = builder_options_get_cgo_cxxflags (self, context); + if (cgo_cxxflags) + envp = g_environ_setenv (envp, "CGO_CXXFLAGS", cgo_cxxflags, FALSE); + ldflags = builder_options_get_ldflags (self, context); if (ldflags) envp = g_environ_setenv (envp, "LDFLAGS", ldflags, FALSE); + cgo_ldflags = builder_options_get_cgo_ldflags (self, context); + if (cgo_ldflags) + envp = g_environ_setenv (envp, "CGO_LDFLAGS", cgo_ldflags, FALSE); + /* We traverse in reverse order because the list is "last first" */ for (l = g_list_last (options); l != NULL; l = l->prev) { @@ -1395,12 +1549,18 @@ builder_options_checksum (BuilderOptions *self, builder_cache_checksum_str (cache, BUILDER_OPTION_CHECKSUM_VERSION); builder_cache_checksum_str (cache, self->cflags); builder_cache_checksum_compat_boolean (cache, self->cflags_override); + builder_cache_checksum_str (cache, self->cgo_cflags); + builder_cache_checksum_compat_boolean (cache, self->cgo_cflags_override); builder_cache_checksum_str (cache, self->cxxflags); builder_cache_checksum_compat_boolean (cache, self->cxxflags_override); + builder_cache_checksum_str (cache, self->cgo_cxxflags); + builder_cache_checksum_compat_boolean (cache, self->cgo_cxxflags_override); builder_cache_checksum_str (cache, self->cppflags); builder_cache_checksum_compat_boolean (cache, self->cppflags_override); builder_cache_checksum_str (cache, self->ldflags); builder_cache_checksum_compat_boolean (cache, self->ldflags_override); + builder_cache_checksum_str (cache, self->cgo_ldflags); + builder_cache_checksum_compat_boolean (cache, self->cgo_ldflags_override); builder_cache_checksum_str (cache, self->prefix); builder_cache_checksum_compat_str (cache, self->libdir); builder_cache_checksum_strv (cache, self->env); diff --git a/src/builder-options.h b/src/builder-options.h index 3eec8e35..9a8b6a49 100644 --- a/src/builder-options.h +++ b/src/builder-options.h @@ -39,12 +39,18 @@ GType builder_options_get_type (void); char *builder_options_get_cflags (BuilderOptions *self, BuilderContext *context); +char *builder_options_get_cgo_cflags (BuilderOptions *self, + BuilderContext *context); char *builder_options_get_cxxflags (BuilderOptions *self, BuilderContext *context); +char *builder_options_get_cgo_cxxflags (BuilderOptions *self, + BuilderContext *context); char *builder_options_get_cppflags (BuilderOptions *self, BuilderContext *context); char *builder_options_get_ldflags (BuilderOptions *self, BuilderContext *context); +char *builder_options_get_cgo_ldflags (BuilderOptions *self, + BuilderContext *context); const char *builder_options_get_prefix (BuilderOptions *self, BuilderContext *context); const char *builder_options_get_libdir (BuilderOptions *self, diff --git a/tests/meson.build b/tests/meson.build index c1fda2cb..ff701571 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -12,6 +12,7 @@ test_names = [ 'test-builder', 'test-builder-deprecated', 'test-builder-python', + 'test-builder-flags', ] tap_test = find_program( diff --git a/tests/test-builder-flags.sh b/tests/test-builder-flags.sh new file mode 100755 index 00000000..c8f09bdb --- /dev/null +++ b/tests/test-builder-flags.sh @@ -0,0 +1,147 @@ +#!/bin/bash +# +# Copyright (C) 2026 Boudhayan Bhattacharya +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_fuse + +echo "1..4" + +setup_repo +install_repo +setup_sdk_repo +install_sdk_repo + +cd "$TEST_DATA_DIR" + +run_build () { + local manifest=$1 + ${FLATPAK_BUILDER} --force-clean appdir "$manifest" >&2 +} + +# Default: CGO_CFLAGS=$CFLAGS (inherited from SDK or set explicitly) +# The test SDK does not ship with defaults so it is set here +# via cflags explicitly. +cat > test-cgo-default.json <<'EOF' +{ + "app-id": "org.test.CgoDefault", + "runtime": "org.test.Platform", + "sdk": "org.test.Sdk", + "build-options": { + "cflags": "-O2 -g" + }, + "modules": [{ + "name": "test", + "buildsystem": "simple", + "build-commands": [ + "echo $CFLAGS > /app/cflags_out", + "echo $CGO_CFLAGS > /app/cgo_cflags_out" + ] + }] +} +EOF + +run_build test-cgo-default.json + +assert_file_has_content appdir/files/cflags_out '\-O2 \-g' +assert_file_has_content appdir/files/cgo_cflags_out '\-O2 \-g' + +echo "ok cgo-cflags defaults to cflags" + +# Explicit cgo-cflags set and no cgo-cflags-override: CGO_CFLAGS=$CFLAGS+explicit +cat > test-cgo-set.json <<'EOF' +{ + "app-id": "org.test.CgoSet", + "runtime": "org.test.Platform", + "sdk": "org.test.Sdk", + "build-options": { + "cflags": "-O2 -g", + "cgo-cflags": "-O0" + }, + "modules": [{ + "name": "test", + "buildsystem": "simple", + "build-commands": [ + "echo $CGO_CFLAGS > /app/cgo_cflags_out" + ] + }] +} +EOF + +run_build test-cgo-set.json + +assert_file_has_content appdir/files/cgo_cflags_out '\-O2 \-g \-O0' + +echo "ok explicit cgo-cflags is additive to cflags" + +# Explicit cgo-cflags set and `cgo-cflags-override: true`: CGO_CFLAGS=explicit +cat > test-cgo-set-with-override.json <<'EOF' +{ + "app-id": "org.test.CgoSetWithOverride", + "runtime": "org.test.Platform", + "sdk": "org.test.Sdk", + "build-options": { + "cflags": "-O2 -g", + "cgo-cflags": "-O0", + "cgo-cflags-override": true + }, + "modules": [{ + "name": "test", + "buildsystem": "simple", + "build-commands": [ + "echo $CFLAGS > /app/cflags_out", + "echo $CGO_CFLAGS > /app/cgo_cflags_out" + ] + }] +} +EOF + +run_build test-cgo-set-with-override.json + +assert_file_has_content appdir/files/cgo_cflags_out '\-O0' + +echo "ok cgo-cflags with override has only explicit flags" + +# Only `cgo-cflags-override: true`: CGO_CFLAGS is unset +cat > test-cgo-only-override.json <<'EOF' +{ + "app-id": "org.test.CgoOnlyOverride", + "runtime": "org.test.Platform", + "sdk": "org.test.Sdk", + "build-options": { + "cflags": "-O2 -g", + "cgo-cflags-override": true + }, + "modules": [{ + "name": "test", + "buildsystem": "simple", + "build-commands": [ + "echo ${CGO_CFLAGS:-unset} > /app/cgo_cflags_out" + ] + }] +} +EOF + +run_build test-cgo-only-override.json + +assert_file_has_content appdir/files/cgo_cflags_out '^unset$' + +echo "ok only cgo-cflags-override clears CGO_CFLAGS" From 31f6869c1e3b880b707fd01c60f775251662fdaf Mon Sep 17 00:00:00 2001 From: bbhtt Date: Sun, 8 Mar 2026 07:51:49 +0530 Subject: [PATCH 3/3] builder-options: Set RUSTFLAGS in builder environment This inherits the SDK provided rustflags by default Fixes: https://github.com/flatpak/flatpak-builder/issues/693 --- NEWS | 2 +- data/flatpak-manifest.schema.json | 8 +++ doc/flatpak-manifest.xml | 8 +++ src/builder-options.c | 52 ++++++++++++++++++ src/builder-options.h | 2 + src/builder-sdk-config.c | 25 +++++++++ src/builder-sdk-config.h | 1 + tests/test-builder-flags.sh | 87 ++++++++++++++++++++++++++++++- 8 files changed, 183 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index d8bf427c..d6e32167 100644 --- a/NEWS +++ b/NEWS @@ -11,7 +11,7 @@ TBD * Support setting state-dir for run * Default to builddir true for cmake and cmake-ninja buildsystems * Handle case-insensitive YAML boolean and null scalars -* Support setting CGO buildflags in builder environment +* Support setting CGO buildflags and RUSTFLAGS in builder environment Changes in 1.4.6 ================ diff --git a/data/flatpak-manifest.schema.json b/data/flatpak-manifest.schema.json index 714b5db9..85e5560a 100644 --- a/data/flatpak-manifest.schema.json +++ b/data/flatpak-manifest.schema.json @@ -74,6 +74,14 @@ "description": "If this is true, clear cgo-ldflags from previous build options before adding it from these options. If set without cgo-ldflags, CGO_LDFLAGS will not be set.", "type": "boolean" }, + "rustflags": { + "description": "This is set in the environment variable RUSTFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces.", + "type": "string" + }, + "rustflags-override": { + "description": "If this is true, clear rustflags from previous build options before adding it from these options.", + "type": "boolean" + }, "prefix": { "description": "The build prefix for the modules (defaults to /app for applications and /usr for runtimes).", "type": "string" diff --git a/doc/flatpak-manifest.xml b/doc/flatpak-manifest.xml index 7d3b530c..1b5e08f9 100644 --- a/doc/flatpak-manifest.xml +++ b/doc/flatpak-manifest.xml @@ -364,6 +364,14 @@ (boolean) If this is true, clear cgo-ldflags from previous build options before adding it from these options. If set without cgo-ldflags, CGO_LDFLAGS will not be set. + + (string) + This is set in the environment variable RUSTFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatenated, separated by spaces. + + + (boolean) + If this is true, clear rustflags from previous build options before adding it from these options. + (string) The build prefix for the modules (defaults to /app for diff --git a/src/builder-options.c b/src/builder-options.c index 86d1c00f..f8e070ba 100644 --- a/src/builder-options.c +++ b/src/builder-options.c @@ -53,6 +53,8 @@ struct BuilderOptions gboolean ldflags_override; char *cgo_ldflags; gboolean cgo_ldflags_override; + char *rustflags; + gboolean rustflags_override; char *append_path; char *prepend_path; char *append_ld_library_path; @@ -98,6 +100,8 @@ enum { PROP_LDFLAGS_OVERRIDE, PROP_CGO_LDFLAGS, PROP_CGO_LDFLAGS_OVERRIDE, + PROP_RUSTFLAGS, + PROP_RUSTFLAGS_OVERRIDE, PROP_PREFIX, PROP_LIBDIR, PROP_ENV, @@ -134,6 +138,7 @@ builder_options_finalize (GObject *object) g_free (self->cppflags); g_free (self->ldflags); g_free (self->cgo_ldflags); + g_free (self->rustflags); g_free (self->append_path); g_free (self->prepend_path); g_free (self->append_ld_library_path); @@ -221,6 +226,14 @@ builder_options_get_property (GObject *object, g_value_set_boolean (value, self->cgo_ldflags_override); break; + case PROP_RUSTFLAGS: + g_value_set_string (value, self->rustflags); + break; + + case PROP_RUSTFLAGS_OVERRIDE: + g_value_set_boolean (value, self->rustflags_override); + break; + case PROP_APPEND_PATH: g_value_set_string (value, self->append_path); break; @@ -380,6 +393,15 @@ builder_options_set_property (GObject *object, self->cgo_ldflags_override = g_value_get_boolean (value); break; + case PROP_RUSTFLAGS: + g_clear_pointer (&self->rustflags, g_free); + self->rustflags = g_value_dup_string (value); + break; + + case PROP_RUSTFLAGS_OVERRIDE: + self->rustflags_override = g_value_get_boolean (value); + break; + case PROP_APPEND_PATH: g_clear_pointer (&self->append_path, g_free); self->append_path = g_value_dup_string (value); @@ -598,6 +620,20 @@ builder_options_class_init (BuilderOptionsClass *klass) "", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_RUSTFLAGS, + g_param_spec_string ("rustflags", + "", + "", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_RUSTFLAGS_OVERRIDE, + g_param_spec_boolean ("rustflags-override", + "", + "", + FALSE, + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_APPEND_PATH, g_param_spec_string ("append-path", @@ -1087,6 +1123,15 @@ builder_options_get_cgo_ldflags (BuilderOptions *self, BuilderContext *context) ldflags); } +char * +builder_options_get_rustflags (BuilderOptions *self, BuilderContext *context) +{ + return builder_options_get_flags (self, context, + G_STRUCT_OFFSET (BuilderOptions, rustflags), + G_STRUCT_OFFSET (BuilderOptions, rustflags_override), + get_sdk_flags (self, context, builder_sdk_config_get_rustflags)); +} + static char * builder_options_get_appended_path (BuilderOptions *self, BuilderContext *context, const char *initial_value, size_t append_field_offset, size_t prepend_field_offset) { @@ -1283,6 +1328,7 @@ builder_options_get_env (BuilderOptions *self, BuilderContext *context) g_autofree char *cgo_cxxflags = NULL; g_autofree char *ldflags = NULL; g_autofree char *cgo_ldflags = NULL; + g_autofree char *rustflags = NULL; envp = builder_context_extend_env_pre (context, envp); @@ -1314,6 +1360,10 @@ builder_options_get_env (BuilderOptions *self, BuilderContext *context) if (cgo_ldflags) envp = g_environ_setenv (envp, "CGO_LDFLAGS", cgo_ldflags, FALSE); + rustflags = builder_options_get_rustflags (self, context); + if (rustflags) + envp = g_environ_setenv (envp, "RUSTFLAGS", rustflags, FALSE); + /* We traverse in reverse order because the list is "last first" */ for (l = g_list_last (options); l != NULL; l = l->prev) { @@ -1561,6 +1611,8 @@ builder_options_checksum (BuilderOptions *self, builder_cache_checksum_compat_boolean (cache, self->ldflags_override); builder_cache_checksum_str (cache, self->cgo_ldflags); builder_cache_checksum_compat_boolean (cache, self->cgo_ldflags_override); + builder_cache_checksum_str (cache, self->rustflags); + builder_cache_checksum_compat_boolean (cache, self->rustflags_override); builder_cache_checksum_str (cache, self->prefix); builder_cache_checksum_compat_str (cache, self->libdir); builder_cache_checksum_strv (cache, self->env); diff --git a/src/builder-options.h b/src/builder-options.h index 9a8b6a49..8efa5eba 100644 --- a/src/builder-options.h +++ b/src/builder-options.h @@ -51,6 +51,8 @@ char *builder_options_get_ldflags (BuilderOptions *self, BuilderContext *context); char *builder_options_get_cgo_ldflags (BuilderOptions *self, BuilderContext *context); +char *builder_options_get_rustflags (BuilderOptions *self, + BuilderContext *context); const char *builder_options_get_prefix (BuilderOptions *self, BuilderContext *context); const char *builder_options_get_libdir (BuilderOptions *self, diff --git a/src/builder-sdk-config.c b/src/builder-sdk-config.c index d7601974..f99973d4 100644 --- a/src/builder-sdk-config.c +++ b/src/builder-sdk-config.c @@ -30,6 +30,7 @@ struct BuilderSdkConfig { char *cflags; char *cxxflags; char *ldflags; + char *rustflags; }; typedef struct @@ -49,6 +50,7 @@ builder_sdk_config_finalize (GObject *object) g_free (self->cflags); g_free (self->cxxflags); g_free (self->ldflags); + g_free (self->rustflags); G_OBJECT_CLASS (builder_sdk_config_parent_class)->finalize (object); } @@ -60,6 +62,7 @@ enum { PROP_CFLAGS, PROP_CXXFLAGS, PROP_LDFLAGS, + PROP_RUSTFLAGS, LAST_PROP }; @@ -93,6 +96,10 @@ builder_sdk_config_get_property (GObject *object, g_value_set_string (value, self->ldflags); break; + case PROP_RUSTFLAGS: + g_value_set_string (value, self->rustflags); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -132,6 +139,11 @@ builder_sdk_config_set_property (GObject *object, g_free (self->ldflags); self->ldflags = g_value_dup_string(value); break ; + + case PROP_RUSTFLAGS: + g_free (self->rustflags); + self->rustflags = g_value_dup_string(value); + break ; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -181,6 +193,13 @@ builder_sdk_config_class_init (BuilderSdkConfigClass *klass) "", NULL, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_RUSTFLAGS, + g_param_spec_string ("rustflags", + "", + "", + NULL, + G_PARAM_READWRITE)); } static void @@ -219,6 +238,12 @@ builder_sdk_config_get_ldflags (BuilderSdkConfig *self) return self->ldflags; } +const char * +builder_sdk_config_get_rustflags (BuilderSdkConfig *self) +{ + return self->rustflags; +} + BuilderSdkConfig * builder_sdk_config_from_file (GFile *file, GError **error) diff --git a/src/builder-sdk-config.h b/src/builder-sdk-config.h index 1b4d67ba..c22505dc 100644 --- a/src/builder-sdk-config.h +++ b/src/builder-sdk-config.h @@ -38,6 +38,7 @@ const char * builder_sdk_config_get_cppflags (BuilderSdkConfig *self); const char * builder_sdk_config_get_cflags (BuilderSdkConfig *self); const char * builder_sdk_config_get_cxxflags (BuilderSdkConfig *self); const char * builder_sdk_config_get_ldflags (BuilderSdkConfig *self); +const char * builder_sdk_config_get_rustflags (BuilderSdkConfig *self); BuilderSdkConfig *builder_sdk_config_from_file (GFile *file, GError **error); diff --git a/tests/test-builder-flags.sh b/tests/test-builder-flags.sh index c8f09bdb..2ff475ef 100755 --- a/tests/test-builder-flags.sh +++ b/tests/test-builder-flags.sh @@ -23,7 +23,7 @@ set -euo pipefail skip_without_fuse -echo "1..4" +echo "1..7" setup_repo install_repo @@ -145,3 +145,88 @@ run_build test-cgo-only-override.json assert_file_has_content appdir/files/cgo_cflags_out '^unset$' echo "ok only cgo-cflags-override clears CGO_CFLAGS" + +# Default: RUSTFLAGS should be passed. The test SDK does not ship with +# defaults so it is set here via rustflags explicitly. +cat > test-rustflags-set.json <<'EOF' +{ + "app-id": "org.test.RustflagsSet", + "runtime": "org.test.Platform", + "sdk": "org.test.Sdk", + "build-options": { + "rustflags": "-C opt-level=2" + }, + "modules": [{ + "name": "test", + "buildsystem": "simple", + "build-commands": [ + "echo ${RUSTFLAGS} > /app/rustflags_out" + ] + }] +} +EOF + +run_build test-rustflags-set.json + +assert_file_has_content appdir/files/rustflags_out '\-C opt\-level=2' + +echo "ok rustflags is passed by default" + +# rustflags-override at module level clears manifest-level rustflags +# or equivalently clears SDK rustflags +cat > test-rustflags-override.json <<'EOF' +{ + "app-id": "org.test.RustflagsOverride", + "runtime": "org.test.Platform", + "sdk": "org.test.Sdk", + "build-options": { + "rustflags": "-C debuginfo=0" + }, + "modules": [{ + "name": "test", + "buildsystem": "simple", + "build-options": { + "rustflags": "-C opt-level=3", + "rustflags-override": true + }, + "build-commands": [ + "echo ${RUSTFLAGS} > /app/rustflags_out" + ] + }] +} +EOF + +run_build test-rustflags-override.json + +assert_file_has_content appdir/files/rustflags_out '\-C opt\-level=3' +assert_not_file_has_content appdir/files/rustflags_out 'debuginfo' + +echo "ok rustflags-override at module level clears manifest-level rustflags" + +# Only rustflags-override is set, rustflags should be cleared +cat > test-rustflags-only-override.json <<'EOF' +{ + "app-id": "org.test.RustflagsOnlyOverride", + "runtime": "org.test.Platform", + "sdk": "org.test.Sdk", + "build-options": { + "rustflags": "-C debuginfo=0" + }, + "modules": [{ + "name": "test", + "buildsystem": "simple", + "build-options": { + "rustflags-override": true + }, + "build-commands": [ + "echo ${RUSTFLAGS:-unset} > /app/rustflags_out" + ] + }] +} +EOF + +run_build test-rustflags-only-override.json + +assert_file_has_content appdir/files/rustflags_out '^unset$' + +echo "ok only rustflags-override clears rustflags"