From ed91ee0dc2d41f3ceb72abc375ad5c0fec62ed56 Mon Sep 17 00:00:00 2001
From: cxzhong <chenxin.zhong@outlook.com>
Date: Wed, 22 Oct 2025 20:28:23 +0800
Subject: [PATCH] Add libc++ support for macOS and Linux

---
 .github/workflows/ci.yml            | 147 ++++++++++++++++++++++++++++
 src/kernel/gmp++/gmp++_int_misc.C   |  11 +++
 src/kernel/recint/rrint.h           |  11 ---
 src/kernel/ring/modular-general.inl |  17 ++++
 4 files changed, 175 insertions(+), 11 deletions(-)
 create mode 100644 .github/workflows/ci.yml

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..ff4cc58e
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,147 @@
+name: CI Build and Test
+
+on:
+  push:
+    branches: 
+      - master
+  workflow_dispatch:
+
+jobs:
+  build-ubuntu-gcc:
+    name: Ubuntu with GCC
+    runs-on: ubuntu-latest
+    
+    steps:
+    - name: Checkout code
+      uses: actions/checkout@v4
+      
+    - name: Install dependencies
+      run: |
+        sudo apt-get update
+        sudo apt-get install -y build-essential autoconf automake libtool \
+                                pkg-config m4 libgmp-dev libgmpxx4ldbl
+    
+    - name: Configure
+      run: |
+        autoreconf -vif
+        mkdir -p build-gcc
+        cd build-gcc
+        ../configure CC=gcc CXX=g++
+    
+    - name: Build
+      run: |
+        cd build-gcc
+        make -j$(nproc)
+    
+    - name: Test
+      run: |
+        cd build-gcc
+        make check
+    
+    - name: Display test results
+      if: always()
+      run: |
+        cd build-gcc/tests
+        if [ -f test-suite.log ]; then
+          echo "=== Test Suite Summary ==="
+          tail -100 test-suite.log
+        fi
+
+  build-ubuntu-clang:
+    name: Ubuntu with Clang + libc++
+    runs-on: ubuntu-latest
+    
+    steps:
+    - name: Checkout code
+      uses: actions/checkout@v4
+      
+    - name: Install dependencies
+      run: |
+        sudo apt-get update
+        sudo apt-get install -y build-essential autoconf automake libtool \
+                                pkg-config m4 libgmp-dev libgmpxx4ldbl \
+                                clang libc++-dev libc++abi-dev
+    
+    - name: Configure
+      run: |
+        autoreconf -vif
+        mkdir -p build-clang
+        cd build-clang
+        ../configure CC=clang CXX=clang++ \
+                     CXXFLAGS="-stdlib=libc++ -D__GIVARO_GMP_NO_CXX" \
+                     LDFLAGS="-stdlib=libc++"
+    
+    - name: Build
+      run: |
+        cd build-clang
+        make -j$(nproc)
+    
+    - name: Test
+      run: |
+        cd build-clang
+        make check
+    
+    - name: Display test results
+      if: always()
+      run: |
+        cd build-clang/tests
+        if [ -f test-suite.log ]; then
+          echo "=== Test Suite Summary ==="
+          tail -100 test-suite.log
+        fi
+
+  build-macos-clang:
+    name: macOS with LLVM/Clang
+    runs-on: macos-latest
+    
+    steps:
+    - name: Checkout code
+      uses: actions/checkout@v4
+      
+    - name: Install dependencies
+      run: |
+        brew install autoconf automake libtool pkg-config gmp llvm
+    
+    - name: Configure
+      run: |
+        autoreconf -vif
+        mkdir -p build-macos
+        cd build-macos
+        # Set paths for Homebrew-installed GMP and LLVM
+        GMP_PREFIX=$(brew --prefix gmp)
+        LLVM_PREFIX=$(brew --prefix llvm)
+        export PATH="${LLVM_PREFIX}/bin:$PATH"
+        export CC="${LLVM_PREFIX}/bin/clang"
+        export CXX="${LLVM_PREFIX}/bin/clang++"
+        ../configure CC="${CC}" \
+                     CXX="${CXX}" \
+                     CPPFLAGS="-I${GMP_PREFIX}/include" \
+                     LDFLAGS="-L${GMP_PREFIX}/lib -L${LLVM_PREFIX}/lib/c++ -Wl,-rpath,${LLVM_PREFIX}/lib/c++ -stdlib=libc++" \
+                     CXXFLAGS="-stdlib=libc++"
+    
+    - name: Build
+      run: |
+        LLVM_PREFIX=$(brew --prefix llvm)
+        export PATH="${LLVM_PREFIX}/bin:$PATH"
+        export CC="${LLVM_PREFIX}/bin/clang"
+        export CXX="${LLVM_PREFIX}/bin/clang++"
+        cd build-macos
+        make -j$(sysctl -n hw.ncpu)
+    
+    - name: Test
+      run: |
+        LLVM_PREFIX=$(brew --prefix llvm)
+        export PATH="${LLVM_PREFIX}/bin:$PATH"
+        export CC="${LLVM_PREFIX}/bin/clang"
+        export CXX="${LLVM_PREFIX}/bin/clang++"
+        cd build-macos
+        make check
+    
+    - name: Display test results
+      if: always()
+      run: |
+        cd build-macos/tests
+        if [ -f test-suite.log ]; then
+          echo "=== Test Suite Summary ==="
+          tail -100 test-suite.log
+        fi
diff --git a/src/kernel/gmp++/gmp++_int_misc.C b/src/kernel/gmp++/gmp++_int_misc.C
index 28f41a44..01b96a24 100644
--- a/src/kernel/gmp++/gmp++_int_misc.C
+++ b/src/kernel/gmp++/gmp++_int_misc.C
@@ -430,9 +430,20 @@ namespace Givaro {
 
     Integer::operator std::string () const
     {
+#if defined(__GIVARO_GMP_NO_CXX) || defined(_LIBCPP_VERSION)
+        // Use C functions for libc++ to avoid GMP C++ iostream issues
+        char * str = NULL;
+        str = mpz_get_str(NULL, 10, (mpz_srcptr)&gmp_rep);
+        std::string result(str);
+        void (*freefunc)(void *, size_t);
+        mp_get_memory_functions(NULL, NULL, &freefunc);
+        freefunc(str, strlen(str) + 1);
+        return result;
+#else
         std::ostringstream o ;
         print(o);
         return o.str();
+#endif
     }
 
     Integer::operator Integer::vect_t () const
diff --git a/src/kernel/recint/rrint.h b/src/kernel/recint/rrint.h
index a99d58ea..4e37a7a9 100644
--- a/src/kernel/recint/rrint.h
+++ b/src/kernel/recint/rrint.h
@@ -117,17 +117,6 @@ namespace RecInt
 
 }
 
-namespace std
-{
-    template <size_t K> struct make_signed<RecInt::rint<K>> {
-        typedef RecInt::rint<K> type;
-    };
-    template <size_t K> struct make_signed<RecInt::ruint<K>> {
-        typedef RecInt::rint<K> type;
-    };
-
-}
-
 #endif
 
 /* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
diff --git a/src/kernel/ring/modular-general.inl b/src/kernel/ring/modular-general.inl
index 8b001cd1..a6c0863c 100644
--- a/src/kernel/ring/modular-general.inl
+++ b/src/kernel/ring/modular-general.inl
@@ -46,6 +46,23 @@ typename std::enable_if<std::is_floating_point<T>::value>::type> {
     typedef typename IntType<std::is_same<T,float>::value>::type type;
 };
 
+// Specializations for RecInt types
+// RecInt::ruint<K> -> RecInt::rint<K> (unsigned to signed)
+template<size_t K>
+struct make_signed_int<RecInt::ruint<K>, void> {
+    typedef RecInt::rint<K> type;
+};
+
+// RecInt::rint<K> -> RecInt::rint<K> (already signed)
+template<size_t K>
+struct make_signed_int<RecInt::rint<K>, void> {
+    typedef RecInt::rint<K> type;
+};
+
+// Convenience alias template (C++14 and later)
+template<typename T>
+using make_signed_int_t = typename make_signed_int<T>::type;
+
 template<typename> struct is_ruint : std::false_type {};
 template<size_t K> struct is_ruint<RecInt::ruint<K>> : std::true_type {};
 
