[libc-commits] [libc] 636c61e - [libc] Add <libintl.h> and textdomain stub (#232351)

via libc-commits libc-commits at lists.llvm.org
Thu Oct 15 23:13:16 PDT 2026


Author: Jeff Bailey
Date: 2026-10-16T07:13:08+01:00
New Revision: 636c61e9565b7d83368874dacc8c538481dbe9e1

URL: https://github.com/llvm/llvm-project/commit/636c61e9565b7d83368874dacc8c538481dbe9e1
DIFF: https://github.com/llvm/llvm-project/commit/636c61e9565b7d83368874dacc8c538481dbe9e1.diff

LOG: [libc] Add <libintl.h> and textdomain stub (#232351)

POSIX.1-2024 standardises the <libintl.h> message translation
interfaces. Because LLVM-libc currently supports only the "C" locale,
message catalog functions can be satisfied with stateless stubs that do
not access the filesystem.

Added the <libintl.h> header generation specification and the textdomain
entrypoint behind LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS, returning
"messages" when querying or resetting the domain and returning the input
domain name otherwise.

Assisted-by: Automated tooling, human reviewed.

Added: 
    libc/include/libintl.yaml
    libc/src/libintl/CMakeLists.txt
    libc/src/libintl/textdomain.cpp
    libc/src/libintl/textdomain.h
    libc/test/src/libintl/CMakeLists.txt
    libc/test/src/libintl/libintl_test.cpp

Modified: 
    libc/config/baremetal/aarch64/entrypoints.txt
    libc/config/baremetal/aarch64/headers.txt
    libc/config/baremetal/arm/entrypoints.txt
    libc/config/baremetal/arm/headers.txt
    libc/config/baremetal/hexagon/entrypoints.txt
    libc/config/baremetal/hexagon/headers.txt
    libc/config/baremetal/riscv/entrypoints.txt
    libc/config/baremetal/riscv/headers.txt
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/aarch64/headers.txt
    libc/config/linux/arm/entrypoints.txt
    libc/config/linux/arm/headers.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/riscv/headers.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/config/linux/x86_64/headers.txt
    libc/include/CMakeLists.txt
    libc/src/CMakeLists.txt
    libc/test/src/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index cb341c2d8b0e30..a85fa19a92fccf 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -968,6 +968,9 @@ endif()
 
 if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
   list(APPEND TARGET_LIBC_ENTRYPOINTS
+    # libintl.h entrypoints
+    libc.src.libintl.textdomain
+
     # regex.h entrypoints
     libc.src.regex.regcomp
     libc.src.regex.regexec

diff  --git a/libc/config/baremetal/aarch64/headers.txt b/libc/config/baremetal/aarch64/headers.txt
index 42dcd87b680d65..b5ccf3c437a37c 100644
--- a/libc/config/baremetal/aarch64/headers.txt
+++ b/libc/config/baremetal/aarch64/headers.txt
@@ -27,5 +27,8 @@ set(TARGET_PUBLIC_HEADERS
 )
 
 if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
-  list(APPEND TARGET_PUBLIC_HEADERS libc.include.regex)
+  list(APPEND TARGET_PUBLIC_HEADERS
+    libc.include.libintl
+    libc.include.regex
+  )
 endif()

diff  --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 65e36c110d696f..87fdcd04652303 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -1003,6 +1003,9 @@ endif()
 
 if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
   list(APPEND TARGET_LIBC_ENTRYPOINTS
+    # libintl.h entrypoints
+    libc.src.libintl.textdomain
+
     # regex.h entrypoints
     libc.src.regex.regcomp
     libc.src.regex.regexec

diff  --git a/libc/config/baremetal/arm/headers.txt b/libc/config/baremetal/arm/headers.txt
index a69660a97fdae1..9740d65762e64d 100644
--- a/libc/config/baremetal/arm/headers.txt
+++ b/libc/config/baremetal/arm/headers.txt
@@ -28,5 +28,8 @@ set(TARGET_PUBLIC_HEADERS
 )
 
 if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
-  list(APPEND TARGET_PUBLIC_HEADERS libc.include.regex)
+  list(APPEND TARGET_PUBLIC_HEADERS
+    libc.include.libintl
+    libc.include.regex
+  )
 endif()

diff  --git a/libc/config/baremetal/hexagon/entrypoints.txt b/libc/config/baremetal/hexagon/entrypoints.txt
index c6244a2f4d728c..cfee5f8240e60c 100644
--- a/libc/config/baremetal/hexagon/entrypoints.txt
+++ b/libc/config/baremetal/hexagon/entrypoints.txt
@@ -984,6 +984,9 @@ endif()
 
 if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
   list(APPEND TARGET_LIBC_ENTRYPOINTS
+    # libintl.h entrypoints
+    libc.src.libintl.textdomain
+
     # regex.h entrypoints
     libc.src.regex.regcomp
     libc.src.regex.regexec

diff  --git a/libc/config/baremetal/hexagon/headers.txt b/libc/config/baremetal/hexagon/headers.txt
index a69660a97fdae1..9740d65762e64d 100644
--- a/libc/config/baremetal/hexagon/headers.txt
+++ b/libc/config/baremetal/hexagon/headers.txt
@@ -28,5 +28,8 @@ set(TARGET_PUBLIC_HEADERS
 )
 
 if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
-  list(APPEND TARGET_PUBLIC_HEADERS libc.include.regex)
+  list(APPEND TARGET_PUBLIC_HEADERS
+    libc.include.libintl
+    libc.include.regex
+  )
 endif()

diff  --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index caa5f3c559cc6c..19397087f3e92c 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -995,6 +995,9 @@ endif()
 
 if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
   list(APPEND TARGET_LIBC_ENTRYPOINTS
+    # libintl.h entrypoints
+    libc.src.libintl.textdomain
+
     # regex.h entrypoints
     libc.src.regex.regcomp
     libc.src.regex.regexec

diff  --git a/libc/config/baremetal/riscv/headers.txt b/libc/config/baremetal/riscv/headers.txt
index a69660a97fdae1..9740d65762e64d 100644
--- a/libc/config/baremetal/riscv/headers.txt
+++ b/libc/config/baremetal/riscv/headers.txt
@@ -28,5 +28,8 @@ set(TARGET_PUBLIC_HEADERS
 )
 
 if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
-  list(APPEND TARGET_PUBLIC_HEADERS libc.include.regex)
+  list(APPEND TARGET_PUBLIC_HEADERS
+    libc.include.libintl
+    libc.include.regex
+  )
 endif()

diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 42ce377d7dca9a..b2c8d62a65f4e1 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1496,6 +1496,9 @@ if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
       libc.src.glob.glob
       libc.src.glob.globfree
 
+      # libintl.h entrypoints
+      libc.src.libintl.textdomain
+
       # net/if.h entrypoints
       libc.src.net.if_freenameindex
       libc.src.net.if_nameindex

diff  --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index 5a2083c8f39d39..3e96e6637da940 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -98,6 +98,7 @@ set(TARGET_PUBLIC_HEADERS
 if(LLVM_LIBC_FULL_BUILD AND LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
   list(APPEND TARGET_PUBLIC_HEADERS
     libc.include.glob
+    libc.include.libintl
     libc.include.netdb
     libc.include.regex
     libc.include.sys_ptrace

diff  --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 85af57dc2c8d23..023d298170c245 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -724,6 +724,9 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
 if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
   if(LLVM_LIBC_FULL_BUILD)
     list(APPEND TARGET_LIBC_ENTRYPOINTS
+      # libintl.h entrypoints
+      libc.src.libintl.textdomain
+
       # regex.h entrypoints
       libc.src.regex.regcomp
       libc.src.regex.regexec

diff  --git a/libc/config/linux/arm/headers.txt b/libc/config/linux/arm/headers.txt
index a46840383142ae..6ccc9c476199d3 100644
--- a/libc/config/linux/arm/headers.txt
+++ b/libc/config/linux/arm/headers.txt
@@ -38,6 +38,7 @@ set(TARGET_PUBLIC_HEADERS
 
 if(LLVM_LIBC_FULL_BUILD AND LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
   list(APPEND TARGET_PUBLIC_HEADERS
+    libc.include.libintl
     libc.include.regex
     libc.include.sys_ptrace
   )

diff  --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 7e0511487c2cf5..3bdc686c0e4ce4 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1708,6 +1708,9 @@ if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
       libc.src.glob.glob
       libc.src.glob.globfree
 
+      # libintl.h entrypoints
+      libc.src.libintl.textdomain
+
       # net/if.h entrypoints
       libc.src.net.if_freenameindex
       libc.src.net.if_nameindex

diff  --git a/libc/config/linux/riscv/headers.txt b/libc/config/linux/riscv/headers.txt
index 19d13a8574bc41..a3c65e50e4e605 100644
--- a/libc/config/linux/riscv/headers.txt
+++ b/libc/config/linux/riscv/headers.txt
@@ -96,6 +96,7 @@ set(TARGET_PUBLIC_HEADERS
 if(LLVM_LIBC_FULL_BUILD AND LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
   list(APPEND TARGET_PUBLIC_HEADERS
     libc.include.glob
+    libc.include.libintl
     libc.include.regex
     libc.include.sys_ptrace
   )

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 155ae28d753bec..23a588f65d7435 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1734,6 +1734,9 @@ if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
       libc.src.glob.glob
       libc.src.glob.globfree
 
+      # libintl.h entrypoints
+      libc.src.libintl.textdomain
+
       # net/if.h entrypoints
       libc.src.net.if_freenameindex
       libc.src.net.if_nameindex

diff  --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 426972553b93b2..fa37b19e50987f 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -104,6 +104,7 @@ set(TARGET_PUBLIC_HEADERS
 if(LLVM_LIBC_FULL_BUILD AND LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
   list(APPEND TARGET_PUBLIC_HEADERS
     libc.include.glob
+    libc.include.libintl
     libc.include.netdb
     libc.include.regex
     libc.include.sys_ptrace

diff  --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 1c4d7f09c65a6c..73c65cbcb90594 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -194,6 +194,15 @@ add_header_macro(
     .llvm_libc_common_h
 )
 
+add_header_macro(
+  libintl
+  ../libc/include/libintl.yaml
+  libintl.h
+  DEPENDS
+    .llvm_libc_common_h
+    .llvm-libc-types.locale_t
+)
+
 add_header_macro(
   limits
   ../libc/include/limits.yaml

diff  --git a/libc/include/libintl.yaml b/libc/include/libintl.yaml
new file mode 100644
index 00000000000000..7e429f3a6b7b20
--- /dev/null
+++ b/libc/include/libintl.yaml
@@ -0,0 +1,15 @@
+header: libintl.h
+standards:
+  - posix
+macros: []
+types:
+  - type_name: locale_t
+enums: []
+objects: []
+functions:
+  - name: textdomain
+    standards:
+      - posix
+    return_type: char *
+    arguments:
+      - type: const char *

diff  --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 0c2d776e5faaea..485259980f7643 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -51,6 +51,7 @@ endif()
 
 add_subdirectory(assert)
 add_subdirectory(compiler)
+add_subdirectory(libintl)
 add_subdirectory(locale)
 add_subdirectory(netdb)
 add_subdirectory(nl_types)

diff  --git a/libc/src/libintl/CMakeLists.txt b/libc/src/libintl/CMakeLists.txt
new file mode 100644
index 00000000000000..063f12227a4b72
--- /dev/null
+++ b/libc/src/libintl/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_entrypoint_object(
+  textdomain
+  SRCS
+    textdomain.cpp
+  HDRS
+    textdomain.h
+)

diff  --git a/libc/src/libintl/textdomain.cpp b/libc/src/libintl/textdomain.cpp
new file mode 100644
index 00000000000000..ef5d2f4b20105d
--- /dev/null
+++ b/libc/src/libintl/textdomain.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of textdomain (stub).
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/libintl/textdomain.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(char *, textdomain, (const char *domainname)) {
+  // TODO: Implement message catalogs. For now, return the default "messages"
+  // domain when querying or resetting, and domainname otherwise.
+  if (domainname == nullptr || domainname[0] == '\0')
+    return const_cast<char *>("messages");
+  return const_cast<char *>(domainname);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/libintl/textdomain.h b/libc/src/libintl/textdomain.h
new file mode 100644
index 00000000000000..bb8df3190c09ef
--- /dev/null
+++ b/libc/src/libintl/textdomain.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for textdomain.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LIBINTL_TEXTDOMAIN_H
+#define LLVM_LIBC_SRC_LIBINTL_TEXTDOMAIN_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+char *textdomain(const char *domainname);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LIBINTL_TEXTDOMAIN_H

diff  --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 5018f7e15b66da..b4120fa5fe268b 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -126,6 +126,7 @@ endif()
 add_subdirectory(assert)
 add_subdirectory(compiler)
 add_subdirectory(dirent)
+add_subdirectory(libintl)
 add_subdirectory(locale)
 add_subdirectory(netdb)
 add_subdirectory(nl_types)

diff  --git a/libc/test/src/libintl/CMakeLists.txt b/libc/test/src/libintl/CMakeLists.txt
new file mode 100644
index 00000000000000..955c5214b53eba
--- /dev/null
+++ b/libc/test/src/libintl/CMakeLists.txt
@@ -0,0 +1,15 @@
+if(LLVM_LIBC_FULL_BUILD AND LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
+  add_custom_target(libc-libintl-tests)
+
+  add_libc_test(
+    libintl_test
+    SUITE
+      libc-libintl-tests
+    SRCS
+      libintl_test.cpp
+    DEPENDS
+      libc.src.libintl.textdomain
+      libc.test.UnitTest.ErrnoCheckingTest
+      libc.test.UnitTest.ErrnoSetterMatcher
+  )
+endif()

diff  --git a/libc/test/src/libintl/libintl_test.cpp b/libc/test/src/libintl/libintl_test.cpp
new file mode 100644
index 00000000000000..9f31d16b87bcb0
--- /dev/null
+++ b/libc/test/src/libintl/libintl_test.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittests for libintl stub functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/libintl/textdomain.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+using LlvmLibcLibintlTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcLibintlTest, Textdomain) {
+  EXPECT_STREQ(LIBC_NAMESPACE::textdomain(nullptr), "messages");
+  EXPECT_STREQ(LIBC_NAMESPACE::textdomain(""), "messages");
+
+  constexpr const char *DOMAIN_NAME = "my_app";
+  EXPECT_THAT(LIBC_NAMESPACE::textdomain(DOMAIN_NAME),
+              Succeeds(const_cast<char *>(DOMAIN_NAME)));
+}


        


More information about the libc-commits mailing list