Building a testdir on FreeBSD 5.2.1, I see link errors of many programs:

  test-access
  test-areadlink
  test-areadlink-with-size
  test-atexit
  test-cloexec
  test-creat
  test-md5-stream
  test-sha1-stream
  test-sha256-stream
  test-sha512-stream
  test-dup2
  test-dup3
  test-euidaccess
  test-fclose
  test-fcntl-safer
  test-fcntl
  test-fdatasync
  test-fflush
  test-fgetc
  test-flock
  test-fopen-gnu
  test-fopen-safer
  test-fopen
  test-fpurge
  test-fputc
  test-fread
  test-freading
  test-freopen
  test-fsync
  test-ftell3
  test-ftello3
  test-fwrite
  test-getdelim
  test-getline
  test-getndelim2
  test-immutable
  test-isatty
  test-link
  test-lstat
  test-mkdir
  test-mkfifo
  test-mknod
  test-nonblocking
  test-open
  test-perror2
  test-posix_spawn-open1
  test-posix_spawn-open2
  test-posix_spawn-inherit0
  test-posix_spawn-inherit1
  test-posix_spawn-script
  test-posix_spawnp-script
  test-read
  test-readlink
  test-remove
  test-rename
  test-rmdir
  test-sf-istream
  test-sfl-istream
  test-symlink
  test-tempname
  test-truncate
  test-dup-safer
  test-unlink
  test-write

For example:

gcc -std=gnu99 -Wno-error -Wno-error -g -O2  -L/home/bruno/lib -L/usr/local/lib 
-o test-unlink test-unlink.o libtests.a ../gllib/libgnu.a libtests.a 
../gllib/libgnu.a libtests.a  -lm   -lm   -lm    -lm  -lm  -lm
../gllib/libgnu.a(openat-die.o): In function `openat_save_fail':
/usr/home/bruno/testdir-all/build/gllib/../../gllib/openat-die.c:37: undefined 
reference to `libintl_dgettext'
../gllib/libgnu.a(openat-die.o): In function `openat_restore_fail':
/usr/home/bruno/testdir-all/build/gllib/../../gllib/openat-die.c:56: undefined 
reference to `libintl_dgettext'
../gllib/libgnu.a(error.o): In function `print_errno_message':
/usr/home/bruno/testdir-all/build/gllib/../../gllib/error.c:208: undefined 
reference to `libintl_dgettext'
gmake[4]: *** [test-unlink] Error 1

What's happening?
  - unlink.o references readlinkat.
  - readlinkat.o references openat_save_fail.
  - openat-die.o references libintl_dgettext.

I can see three possible fixes:
  (A) Add $(LIBINTL) as dependency of module 'issymlink'. Link all these
      programs with $(LIBINTL).
  (B) Move the issymlinkat definition to a .c file, out of the .h file.
  (C) Move the issymlinkat declaration to a different .h file.

I prefer solution (C), although it is not backward-compatible and requires a
code change in coreutils (patch attached).


2025-12-04  Bruno Haible  <[email protected]>

        issymlinkat: Remove accidental dependency from issymlink on $(LIBINTL).
        * lib/issymlinkat.h: New file, based on lib/issymlink.h.
        * lib/issymlink.h (_GL_ISSYMLINKAT_INLINE, issymlinkat): Remove
        definitions.
        * lib/issymlinkat.c: Include issymlinkat.h instead of issymlink.h.
        * lib/fchmodat.c: Likewise.
        * lib/renameatu.c: Likewise.
        * lib/unlinkat.c: Likewise.
        * lib/lchmod.c: Include issymlinkat.h.
        * modules/issymlinkat (Files): Add lib/issymlinkat.h. Remove
        lib/issymlink.h.
        (Include): Specify issymlinkat.h instead of issymlink.h.
        * NEWS: Mention the change.

diff --git a/NEWS b/NEWS
index d954840bfa..5fea672149 100644
--- a/NEWS
+++ b/NEWS
@@ -78,6 +78,9 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2025-12-04  issymlinkat     The include file is changed from "issymlink.h" to
+                            "issymlinkat.h".
+
 2025-11-01  nstrftime       The return type is now signed not size_t,
             c-nstrftime     the failure return value is now -1 not 0,
             fprintftime     and errno is no longer preserved on success.
diff --git a/lib/fchmodat.c b/lib/fchmodat.c
index 9151778b8e..4aa764f851 100644
--- a/lib/fchmodat.c
+++ b/lib/fchmodat.c
@@ -46,7 +46,7 @@ orig_fchmodat (int dir, char const *file, mode_t mode, int 
flags)
 
 #include <intprops.h>
 
-#include "issymlink.h"
+#include "issymlinkat.h"
 
 /* Invoke chmod or lchmod on FILE, using mode MODE, in the directory
    open on descriptor FD.  If possible, do it without changing the
diff --git a/lib/issymlink.h b/lib/issymlink.h
index af6dc96564..a3f97cb521 100644
--- a/lib/issymlink.h
+++ b/lib/issymlink.h
@@ -23,7 +23,7 @@
 #endif
 
 #include <errno.h>
-#include <unistd.h> /* for readlink, readlinkat */
+#include <unistd.h> /* for readlink */
 
 
 _GL_INLINE_HEADER_BEGIN
@@ -31,11 +31,7 @@ _GL_INLINE_HEADER_BEGIN
 #ifndef _GL_ISSYMLINK_INLINE
 # define _GL_ISSYMLINK_INLINE _GL_INLINE
 #endif
-#ifndef _GL_ISSYMLINKAT_INLINE
-# define _GL_ISSYMLINKAT_INLINE _GL_INLINE
-#endif
 
-#if GNULIB_ISSYMLINK
 /* Tests whether FILENAME represents a symbolic link.
    This function is more reliable than lstat() / fstatat() followed by S_ISLNK,
    because it avoids possible EOVERFLOW errors.
@@ -44,9 +40,9 @@ _GL_INLINE_HEADER_BEGIN
      0                      if FILENAME exists and is not a symbolic link,
     -1 with errno set       if determination failed, in particular
     -1 with errno = ENOENT or ENOTDIR  if FILENAME does not exist.  */
-# ifdef __cplusplus
+#ifdef __cplusplus
 extern "C" {
-# endif
+#endif
 _GL_ISSYMLINK_INLINE int issymlink (const char *filename)
      _GL_ARG_NONNULL ((1));
 _GL_ISSYMLINK_INLINE int
@@ -60,42 +56,8 @@ issymlink (const char *filename)
   else
     return -1;
 }
-# ifdef __cplusplus
-}
-# endif
-#endif
-
-#if GNULIB_ISSYMLINKAT
-/* Tests whether FILENAME represents a symbolic link.
-   This function is more reliable than lstat() / fstatat() followed by S_ISLNK,
-   because it avoids possible EOVERFLOW errors.
-   If FILENAME is a relative file name, it is interpreted as relative to the
-   directory referred to by FD (where FD = AT_FDCWD denotes the current
-   directory).
-   Returns
-     1                      if FILENAME is a symbolic link,
-     0                      if FILENAME exists and is not a symbolic link,
-    -1 with errno set       if determination failed, in particular
-    -1 with errno = ENOENT or ENOTDIR  if FILENAME does not exist.  */
-# ifdef __cplusplus
-extern "C" {
-# endif
-_GL_ISSYMLINKAT_INLINE int issymlinkat (int fd, const char *filename)
-     _GL_ARG_NONNULL ((2));
-_GL_ISSYMLINKAT_INLINE int
-issymlinkat (int fd, const char *filename)
-{
-  char linkbuf[1];
-  if (readlinkat (fd, filename, linkbuf, sizeof (linkbuf)) >= 0)
-    return 1;
-  if (errno == EINVAL)
-    return 0;
-  else
-    return -1;
-}
-# ifdef __cplusplus
+#ifdef __cplusplus
 }
-# endif
 #endif
 
 _GL_INLINE_HEADER_END
diff --git a/lib/issymlinkat.c b/lib/issymlinkat.c
index 8286356c8a..ebd937e91b 100644
--- a/lib/issymlinkat.c
+++ b/lib/issymlinkat.c
@@ -17,4 +17,4 @@
 #include <config.h>
 
 #define _GL_ISSYMLINKAT_INLINE _GL_EXTERN_INLINE
-#include "issymlink.h"
+#include "issymlinkat.h"
diff --git a/lib/issymlinkat.h b/lib/issymlinkat.h
new file mode 100644
index 0000000000..abbbbfff83
--- /dev/null
+++ b/lib/issymlinkat.h
@@ -0,0 +1,68 @@
+/* Test whether a file is a symbolic link.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+
+   This file 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.1 of the
+   License, or (at your option) any later version.
+
+   This file 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 program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ISSYMLINKAT_H
+#define _ISSYMLINKAT_H
+
+/* This file uses _GL_ARG_NONNULL, _GL_INLINE.  */
+#if !_GL_CONFIG_H_INCLUDED
+ #error "Please include config.h first."
+#endif
+
+#include <errno.h>
+#include <unistd.h> /* for readlinkat */
+
+
+_GL_INLINE_HEADER_BEGIN
+
+#ifndef _GL_ISSYMLINKAT_INLINE
+# define _GL_ISSYMLINKAT_INLINE _GL_INLINE
+#endif
+
+/* Tests whether FILENAME represents a symbolic link.
+   This function is more reliable than lstat() / fstatat() followed by S_ISLNK,
+   because it avoids possible EOVERFLOW errors.
+   If FILENAME is a relative file name, it is interpreted as relative to the
+   directory referred to by FD (where FD = AT_FDCWD denotes the current
+   directory).
+   Returns
+     1                      if FILENAME is a symbolic link,
+     0                      if FILENAME exists and is not a symbolic link,
+    -1 with errno set       if determination failed, in particular
+    -1 with errno = ENOENT or ENOTDIR  if FILENAME does not exist.  */
+#ifdef __cplusplus
+extern "C" {
+#endif
+_GL_ISSYMLINKAT_INLINE int issymlinkat (int fd, const char *filename)
+     _GL_ARG_NONNULL ((2));
+_GL_ISSYMLINKAT_INLINE int
+issymlinkat (int fd, const char *filename)
+{
+  char linkbuf[1];
+  if (readlinkat (fd, filename, linkbuf, sizeof (linkbuf)) >= 0)
+    return 1;
+  if (errno == EINVAL)
+    return 0;
+  else
+    return -1;
+}
+#ifdef __cplusplus
+}
+#endif
+
+_GL_INLINE_HEADER_END
+
+#endif /* _ISSYMLINKAT_H */
diff --git a/lib/lchmod.c b/lib/lchmod.c
index deba4c50f5..acccef629c 100644
--- a/lib/lchmod.c
+++ b/lib/lchmod.c
@@ -30,6 +30,7 @@
 
 #include <intprops.h>
 #include "issymlink.h"
+#include "issymlinkat.h"
 
 /* Work like chmod, except when FILE is a symbolic link.
    In that case, on systems where permissions on symbolic links are unsupported
diff --git a/lib/renameatu.c b/lib/renameatu.c
index 29c4839269..ef40ad3d17 100644
--- a/lib/renameatu.c
+++ b/lib/renameatu.c
@@ -30,7 +30,7 @@
 # include <sys/syscall.h>
 #endif
 
-#include "issymlink.h"
+#include "issymlinkat.h"
 
 static int
 errno_fail (int e)
diff --git a/lib/unlinkat.c b/lib/unlinkat.c
index 3cf5fc5ea5..be4a8c2b63 100644
--- a/lib/unlinkat.c
+++ b/lib/unlinkat.c
@@ -30,7 +30,7 @@
 #include <stdlib.h>
 
 #include "filename.h"
-#include "issymlink.h"
+#include "issymlinkat.h"
 #include "openat.h"
 
 #if HAVE_UNLINKAT
diff --git a/modules/issymlinkat b/modules/issymlinkat
index c02e4e9678..b4e03c22b7 100644
--- a/modules/issymlinkat
+++ b/modules/issymlinkat
@@ -2,7 +2,7 @@ Description:
 Test whether a file is a symbolic link.
 
 Files:
-lib/issymlink.h
+lib/issymlinkat.h
 lib/issymlinkat.c
 
 Depends-on:
@@ -18,7 +18,7 @@ Makefile.am:
 lib_SOURCES += issymlinkat.c
 
 Include:
-"issymlink.h"
+"issymlinkat.h"
 
 Link:
 $(LTLIBINTL) when linking with libtool, $(LIBINTL) otherwise
>From 0b7847604250782c346200a1e3ee06745c6c5cb3 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Thu, 4 Dec 2025 21:14:45 +0100
Subject: [PATCH] maint: Update after gnulib changed

* src/copy.c: Include issymlinkat.h.
---
 src/copy.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/copy.c b/src/copy.c
index 4c6f87c01..fde4a82c7 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -45,6 +45,7 @@
 #include "hashcode-file.h"
 #include "ignore-value.h"
 #include "issymlink.h"
+#include "issymlinkat.h"
 #include "quote.h"
 #include "renameatu.h"
 #include "root-uid.h"
-- 
2.52.0

Reply via email to