On Tue, 2026-01-13 at 01:11:10 +0200, Adrian Bunk wrote:
> On Mon, Jan 12, 2026 at 11:36:26PM +0100, Guillem Jover wrote:
> > Sorry, I think -f should probably be omitted from there (as I think at
> > least GNU ld ignores those options anyway?),
> 
> On amd64 the FTBFS in question is with -fcf-protection.

Sorry, I meant that it appeared as if it validated the options but did
nothing with them afterwards. But I see now that this only applies to
-flto, -flto-partition= and -fuse-ld=. The problem is that «-f <arg>»
is «--auxiliary <SHLIB>», so any option prefixed as such is misparsed
(and that's why the requirements for -shared).

So, I initially removed the -f option from the man page change. And
was also thinking -l and -L were probably inappropriate as well.

> > otherwise it should be
> > made conditional to being passed only when -shared is passed, but that
> > starts to be too much detail for my taste.

(This looks wrong given the ld -f option semantics as mentioned above.)

> Sometimes changing documentation what each affected package has to do 
> manually sounds like the worst possible option to me.
>
> Either dpkg provides a LDFLAGS_FOR_LD that simply works for this case,
> or the best option might be to document not using dpkg LDFLAGS at all
> when ld gets called directly.

If a project is calling ld(1) directly, then this is going to be (in
theory) low level linker handling, so passing most options specified
for the compiler might be in general not appropriate.

I had initially in my first reply, as an alternative, to ban its usage
for direct ld(1) calls, but removed it as it seemed a bit too harsh.
But I think you are right that if anything should be passed, then
pre-cooking a variable for direct ld(1) use is probably going to be the
better solution, because dpkg-buildflags should know if those options
are (in general) safe to pass regardless of the intended use. Although
I'm still not entirely sure this is even a good idea, and/or whether
this should be qualified in the man page, because it could still mangle
the intended semantics.

So perhaps better the attached patch. I went for LD_LDFLAGS because
otherwise we get LDFLAGS_FOR_LD_FOR_BUILD (which seems meh, but open
to other suggestions). But I'm still considering whether to simply ban
its use with direct calls and not provide a direct ld(1) option,
although the current patch leaves this up to the maintainer to decide,
which is probably the best way forward.

Thanks,
Guillem
diff --git i/man/dpkg-buildflags.pod w/man/dpkg-buildflags.pod
index 7a759eb7a..cd24dcd70 100644
--- i/man/dpkg-buildflags.pod
+++ w/man/dpkg-buildflags.pod
@@ -322,13 +322,23 @@ Since dpkg 1.17.7.
 =item B<LDFLAGS>
 
 Options passed to the host compiler when linking executables or shared
-objects (if the linker is called directly, then
-B<-Wl>
-and
-B<,>
-have to be stripped from these options).
+objects.
+
+B<Note>: It is not safe to pass this option directly to L<ld(1)>,
+for that use B<LD_LDFLAGS> instead.
+
 Default value: empty.
 
+=item B<LD_LDFLAGS>
+
+Options passed directly to the host linker (without going via the compiler).
+Depending on the intended use of the L<ld(1)> call,
+it might still not be appropriate to pass this option.
+
+Default value: empty.
+
+Since dpkg 1.23.4.
+
 =item B<ASFLAGS_FOR_BUILD>
 
 Options for the build assembler.
@@ -387,11 +397,25 @@ Since dpkg 1.22.1.
 =item B<LDFLAGS_FOR_BUILD>
 
 Options passed to the build compiler when linking executables or shared
-objects (if the linker is called directly, then B<-Wl> and B<,> have to
-be stripped from these options).
+objects.
+
+B<Note>: It is not safe to pass this option directly to L<ld(1)>,
+for that use B<LD_LDFLAGS_FOR_BUILD> instead.
+
 Default value: empty.
+
 Since dpkg 1.22.1.
 
+=item B<LD_LDFLAGS_FOR_BUILD>
+
+Options passed directly to the build linker (without going via the compiler).
+Depending on the intended use of the L<ld(1)> call,
+it might still not be appropriate to pass this option.
+
+Default value: empty.
+
+Since dpkg 1.23.4.
+
 =back
 
 New flags might be added in the future if the need arises (for example
diff --git i/scripts/Dpkg/BuildFlags.pm w/scripts/Dpkg/BuildFlags.pm
index 49adb015b..1e27ad02e 100644
--- i/scripts/Dpkg/BuildFlags.pm
+++ w/scripts/Dpkg/BuildFlags.pm
@@ -101,6 +101,8 @@ sub _init_vendor_defaults {
         FCFLAGS_FOR_BUILD
         LDFLAGS
         LDFLAGS_FOR_BUILD
+        LD_LDFLAGS
+        LD_LDFLAGS_FOR_BUILD
     );
 
     $self->{features} = {};
diff --git i/scripts/Dpkg/Vendor/Debian.pm w/scripts/Dpkg/Vendor/Debian.pm
index 4e722cafa..aac28890d 100644
--- i/scripts/Dpkg/Vendor/Debian.pm
+++ w/scripts/Dpkg/Vendor/Debian.pm
@@ -514,6 +514,7 @@ sub add_build_flags {
             $flags->append($flag, "-D__DEB_CANARY_${flag}_${id}__");
         }
         $flags->append('LDFLAGS', "-Wl,-z,deb-canary-${id}");
+        $flags->append('LD_LDFLAGS', "-z deb-canary-${id}");
     }
 
     ## Area: reproducible
@@ -622,11 +623,13 @@ sub add_build_flags {
     # Read-only Relocations.
     if ($flags->use_feature('hardening', 'relro')) {
         $flags->append('LDFLAGS', '-Wl,-z,relro');
+        $flags->append('LD_LDFLAGS', '-z relro');
     }
 
     # Bindnow.
     if ($flags->use_feature('hardening', 'bindnow')) {
         $flags->append('LDFLAGS', '-Wl,-z,now');
+        $flags->append('LD_LDFLAGS', '-z now');
     }
 
     # Branch protection.
diff --git i/scripts/Dpkg/Vendor/Ubuntu.pm w/scripts/Dpkg/Vendor/Ubuntu.pm
index 1d62e05bf..63fa21c25 100644
--- i/scripts/Dpkg/Vendor/Ubuntu.pm
+++ w/scripts/Dpkg/Vendor/Ubuntu.pm
@@ -154,6 +154,7 @@ sub add_build_flags {
 
     # Per <https://wiki.ubuntu.com/DistCompilerFlags>.
     $flags->prepend('LDFLAGS', '-Wl,-Bsymbolic-functions');
+    $flags->prepend('LD_LDFLAGS', '-Bsymbolic-functions');
 
     # In Ubuntu these flags are set by the compiler, so when disabling the
     # features we need to pass appropriate flags to disable them.
diff --git i/scripts/mk/buildflags.mk w/scripts/mk/buildflags.mk
index 7998d99f5..f5a54d126 100644
--- i/scripts/mk/buildflags.mk
+++ w/scripts/mk/buildflags.mk
@@ -10,7 +10,8 @@
 #   DFLAGS: Flags for the host D compiler.
 #   FFLAGS: Flags for the host Fortran 77 compiler.
 #   FCFLAGS: Flags for the host Fortran 9x compiler.
-#   LDFLAGS: Flags for the host linker.
+#   LDFLAGS: Flags for the host linker called by the compiler.
+#   LD_LDFLAGS: Flags for the host linker called directly.
 #
 # And the following variables for the build tools (since dpkg 1.22.1):
 #
@@ -23,7 +24,8 @@
 #   DFLAGS_FOR_BUILD: Flags for the build D compiler.
 #   FFLAGS_FOR_BUILD: Flags for the build Fortran 77 compiler.
 #   FCFLAGS_FOR_BUILD: Flags for the build Fortran 9x compiler.
-#   LDFLAGS_FOR_BUILD: Flags for the build linker.
+#   LDFLAGS_FOR_BUILD: Flags for the build linker called by the compiler.
+#   LD_LDFLAGS_FOR_BUILD: Flags for the build linker called directly.
 #
 # You can also export them in the environment by setting
 # DPKG_EXPORT_BUILDFLAGS to a non-empty value.
@@ -51,6 +53,7 @@ DPKG_BUILDFLAGS_LIST := $(foreach var,\
   FFLAGS \
   FCFLAGS \
   LDFLAGS \
+  LD_LDFLAGS \
   ,$(var) $(var)_FOR_BUILD)
 
 define dpkg_buildflags_export_envvar
diff --git i/scripts/t/mk/buildflags.mk w/scripts/t/mk/buildflags.mk
index bc7e6a849..788cd2f45 100644
--- i/scripts/t/mk/buildflags.mk
+++ w/scripts/t/mk/buildflags.mk
@@ -27,6 +27,7 @@ vars := \
   FCFLAGS \
   FFLAGS \
   LDFLAGS \
+  LD_LDFLAGS \
   OBJCFLAGS \
   OBJCXXFLAGS \
   # EOL

Reply via email to