Skip to content

Conversation

@vonosmas
Copy link
Contributor

Create a POSIX <nl_types.h> header with catopen, catclose, and catgets function declarations.
Provide the stub/placeholder implementations which always return error. This is consistent with the way
locales are currently (un-)implemented in llvm-libc.

Notably, providing <nl_types.h> fixes the last remaining issue with building libc++ against llvm-libc
(on certain configuration of x86_64 Linux) after disabling threads and wide-characters in libc++.

@vonosmas vonosmas requested a review from petrhosek October 21, 2025 05:52
@llvmbot llvmbot added the libc label Oct 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 21, 2025

@llvm/pr-subscribers-libc

Author: Alexey Samsonov (vonosmas)

Changes

Create a POSIX &lt;nl_types.h&gt; header with catopen, catclose, and catgets function declarations.
Provide the stub/placeholder implementations which always return error. This is consistent with the way
locales are currently (un-)implemented in llvm-libc.

Notably, providing &lt;nl_types.h&gt; fixes the last remaining issue with building libc++ against llvm-libc
(on certain configuration of x86_64 Linux) after disabling threads and wide-characters in libc++.


Full diff: https://github.com/llvm/llvm-project/pull/164360.diff

17 Files Affected:

  • (modified) libc/config/linux/x86_64/entrypoints.txt (+5)
  • (modified) libc/config/linux/x86_64/headers.txt (+1)
  • (modified) libc/include/CMakeLists.txt (+8)
  • (modified) libc/include/llvm-libc-types/CMakeLists.txt (+1)
  • (added) libc/include/llvm-libc-types/nl_catd.h (+15)
  • (added) libc/include/nl_types.yaml (+31)
  • (modified) libc/src/CMakeLists.txt (+1)
  • (added) libc/src/nl_types/CMakeLists.txt (+31)
  • (added) libc/src/nl_types/catclose.cpp (+23)
  • (added) libc/src/nl_types/catclose.h (+22)
  • (added) libc/src/nl_types/catgets.cpp (+26)
  • (added) libc/src/nl_types/catgets.h (+24)
  • (added) libc/src/nl_types/catopen.cpp (+25)
  • (added) libc/src/nl_types/catopen.h (+21)
  • (modified) libc/test/src/CMakeLists.txt (+1)
  • (added) libc/test/src/nl_types/CMakeLists.txt (+15)
  • (added) libc/test/src/nl_types/nl_types_test.cpp (+33)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index b4ab073ec912f..c53fd60e54858 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1373,6 +1373,11 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.wchar.wcstombs
     libc.src.wchar.wcsrtombs
     libc.src.wchar.wcsnrtombs
+
+    # nl_types.h entrypoints
+    libc.src.nl_types.catopen 
+    libc.src.nl_types.catclose
+    libc.src.nl_types.catgets
   )
 endif()
 
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 0573851fbc20b..d0f62eb104dcc 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -19,6 +19,7 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.malloc
     libc.include.math
     libc.include.netinet_in
+    libc.include.nl_types
     libc.include.poll
     libc.include.pthread
     libc.include.sched
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 81360aac984e0..7eceb679133f1 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -768,6 +768,14 @@ add_header_macro(
     .llvm-libc-macros.poll-macros
   )
 
+add_header_macro(
+  nl_types
+  ../libc/include/nl_types.yaml
+  nl_types.h
+  DEPENDS
+    .llvm-libc-types.nl_catd
+  )
+
 # UEFI spec references "Uefi.h" so we use that name for compatibility
 add_header_macro(
   uefi
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 5f506c4d25c9b..a428a0e73aab2 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -46,6 +46,7 @@ add_header(mbstate_t HDR mbstate_t.h)
 add_header(mode_t HDR mode_t.h)
 add_header(mtx_t HDR mtx_t.h DEPENDS .__futex_word .__mutex_type)
 add_header(nfds_t HDR nfds_t.h)
+add_header(nl_catd HDR nl_catd.h)
 add_header(nlink_t HDR nlink_t.h)
 add_header(off_t HDR off_t.h)
 add_header(once_flag HDR once_flag.h DEPENDS .__futex_word)
diff --git a/libc/include/llvm-libc-types/nl_catd.h b/libc/include/llvm-libc-types/nl_catd.h
new file mode 100644
index 0000000000000..f80a2df8c8d2a
--- /dev/null
+++ b/libc/include/llvm-libc-types/nl_catd.h
@@ -0,0 +1,15 @@
+//===-- Definition of nl_catd type ----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_NL_CATD_H
+#define LLVM_LIBC_TYPES_NL_CATD_H
+
+typedef void* nl_catd;
+
+#endif // LLVM_LIBC_TYPES_NL_CATD_H
+
diff --git a/libc/include/nl_types.yaml b/libc/include/nl_types.yaml
new file mode 100644
index 0000000000000..aecbb44a02224
--- /dev/null
+++ b/libc/include/nl_types.yaml
@@ -0,0 +1,31 @@
+header: nl_types.h
+standards:
+  - posix
+macros: []
+types:
+  - type_name: nl_catd
+enums: []
+objects: []
+functions:
+  - name: catopen
+    standards:
+      - posix
+    return_type: nl_catd
+    arguments:
+      - type: const char *
+      - type: int
+  - name: catclose
+    standards:
+      - posix
+    return_type: int
+    arguments:
+      - type: nl_catd
+  - name: catgets
+    standards:
+      - posix
+    return_type: char *
+    arguments:
+      - type: nl_catd
+      - type: int
+      - type: int
+      - type: const char*
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index d7a1e1f49e6ff..b2afe0a33acee 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -37,6 +37,7 @@ add_subdirectory(arpa)
 add_subdirectory(assert)
 add_subdirectory(compiler)
 add_subdirectory(locale)
+add_subdirectory(nl_types)
 add_subdirectory(search)
 add_subdirectory(setjmp)
 add_subdirectory(signal)
diff --git a/libc/src/nl_types/CMakeLists.txt b/libc/src/nl_types/CMakeLists.txt
new file mode 100644
index 0000000000000..9783e0ecb9678
--- /dev/null
+++ b/libc/src/nl_types/CMakeLists.txt
@@ -0,0 +1,31 @@
+add_entrypoint_object(
+  catopen
+  SRCS
+    catopen.cpp
+  HDRS
+    catopen.h
+  DEPENDS
+    libc.include.llvm-libc-types.nl_catd
+    libc.src.errno.errno
+)
+
+add_entrypoint_object(
+  catclose
+  SRCS
+    catclose.cpp
+  HDRS
+    catclose.h
+  DEPENDS
+    libc.include.llvm-libc-types.nl_catd
+)
+
+add_entrypoint_object(
+  catgets
+  SRCS
+    catgets.cpp
+  HDRS
+    catgets.h
+  DEPENDS
+    libc.include.llvm-libc-types.nl_catd
+)
+
diff --git a/libc/src/nl_types/catclose.cpp b/libc/src/nl_types/catclose.cpp
new file mode 100644
index 0000000000000..2cfc3686f4c7e
--- /dev/null
+++ b/libc/src/nl_types/catclose.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of catclose ----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/nl_types/catclose.h"
+#include "include/llvm-libc-types/nl_catd.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, catclose, ([[maybe_unused]] nl_catd catalog)) {
+  // Message catalogs are not implemented. Return error regardless of input.
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
+
diff --git a/libc/src/nl_types/catclose.h b/libc/src/nl_types/catclose.h
new file mode 100644
index 0000000000000..5cbce4fcfafae
--- /dev/null
+++ b/libc/src/nl_types/catclose.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for catclose ----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_NL_TYPES_CATCLOSE_H
+#define LLVM_LIBC_SRC_NL_TYPES_CATCLOSE_H
+
+#include "include/llvm-libc-types/nl_catd.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int catclose(nl_catd catalog);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_NL_TYPES_CATCLOSE_H
+
diff --git a/libc/src/nl_types/catgets.cpp b/libc/src/nl_types/catgets.cpp
new file mode 100644
index 0000000000000..c2f289c9d7090
--- /dev/null
+++ b/libc/src/nl_types/catgets.cpp
@@ -0,0 +1,26 @@
+//===-- Implementation of catgets -----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/nl_types/catgets.h"
+#include "include/llvm-libc-types/nl_catd.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(char*, catgets, ([[maybe_unused]] nl_catd catalog,
+			            [[maybe_unused]] int set_number,
+			            [[maybe_unused]] int message_number,
+				    const char* message)) {
+  // Message catalogs are not implemented.
+  // Return backup message regardless of input.
+  return const_cast<char*>(message);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
diff --git a/libc/src/nl_types/catgets.h b/libc/src/nl_types/catgets.h
new file mode 100644
index 0000000000000..c8b53d7aacaff
--- /dev/null
+++ b/libc/src/nl_types/catgets.h
@@ -0,0 +1,24 @@
+//===-- Implementation header for catgets -----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_NL_TYPES_CATGETS_H
+#define LLVM_LIBC_SRC_NL_TYPES_CATGETS_H
+
+#include "include/llvm-libc-types/nl_catd.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+char *catgets(nl_catd catalog, int set_number, int message_number,
+              const char *message);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_NL_TYPES_CATGETS_H
+
+
diff --git a/libc/src/nl_types/catopen.cpp b/libc/src/nl_types/catopen.cpp
new file mode 100644
index 0000000000000..f2755cfd9cdeb
--- /dev/null
+++ b/libc/src/nl_types/catopen.cpp
@@ -0,0 +1,25 @@
+//===-- Implementation of catopen -----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/nl_types/catopen.h"
+#include "include/llvm-libc-types/nl_catd.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(nl_catd, catopen, ([[maybe_unused]] const char *name,
+			              [[maybe_unused]] int flag)) {
+  // Message catalogs are not implemented. Return error regardless of input.
+  libc_errno = EINVAL;
+  return reinterpret_cast<nl_catd>(-1);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
diff --git a/libc/src/nl_types/catopen.h b/libc/src/nl_types/catopen.h
new file mode 100644
index 0000000000000..08ff71ac3d32d
--- /dev/null
+++ b/libc/src/nl_types/catopen.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for catopen -----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_NL_TYPES_CATOPEN_H
+#define LLVM_LIBC_SRC_NL_TYPES_CATOPEN_H
+
+#include "include/llvm-libc-types/nl_catd.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+nl_catd catopen(const char *name, int flag);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_NL_TYPES_CATOPEN_H
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index c576e08e84bc1..0c6ec9f07a9b7 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -96,6 +96,7 @@ add_subdirectory(assert)
 add_subdirectory(compiler)
 add_subdirectory(dirent)
 add_subdirectory(locale)
+add_subdirectory(nl_types)
 add_subdirectory(signal)
 add_subdirectory(spawn)
 
diff --git a/libc/test/src/nl_types/CMakeLists.txt b/libc/test/src/nl_types/CMakeLists.txt
new file mode 100644
index 0000000000000..520066034aef7
--- /dev/null
+++ b/libc/test/src/nl_types/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_custom_target(libc-nl-types-tests)
+
+add_libc_test(
+  nl_types_test
+  SUITE
+    libc-nl-types-tests
+  SRCS
+    nl_types_test.cpp
+  DEPENDS
+    libc.include.llvm-libc-types.nl_catd
+    libc.src.nl_types.catopen
+    libc.src.nl_types.catclose
+    libc.src.nl_types.catgets
+)
+
diff --git a/libc/test/src/nl_types/nl_types_test.cpp b/libc/test/src/nl_types/nl_types_test.cpp
new file mode 100644
index 0000000000000..9c5389203197c
--- /dev/null
+++ b/libc/test/src/nl_types/nl_types_test.cpp
@@ -0,0 +1,33 @@
+//===-- Unittests for nl_types --------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/llvm-libc-types/nl_catd.h"
+#include "src/nl_types/catclose.h"
+#include "src/nl_types/catgets.h"
+#include "src/nl_types/catopen.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+
+using LlvmLibcNlTypesTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcNlTypesTest, CatopenFails) {
+  ASSERT_EQ(LIBC_NAMESPACE::catopen("/somepath", 0),
+            reinterpret_cast<nl_catd>(-1));
+  ASSERT_ERRNO_EQ(EINVAL);
+}
+
+TEST_F(LlvmLibcNlTypesTest, CatcloseFails) {
+  ASSERT_EQ(LIBC_NAMESPACE::catclose(nullptr), -1);
+}
+
+TEST_F(LlvmLibcNlTypesTest, CatgetsFails) {
+  const char* message = "message";
+  // Note that we test for pointer equality here, since catgets
+  // is expected to return the input argument as-is.
+  ASSERT_EQ(LIBC_NAMESPACE::catgets(nullptr, 0, 0, message),
+            const_cast<char*>(message));
+}

@github-actions
Copy link

github-actions bot commented Oct 21, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@vonosmas vonosmas requested a review from lntue October 21, 2025 16:35
@vonosmas vonosmas merged commit 12abe8a into llvm:main Oct 21, 2025
19 of 20 checks passed
@vonosmas vonosmas deleted the nl-types branch October 21, 2025 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants