2

I cannot fix this error. build.sh is trying to create a shared library but it fails:

~/Desktop/deepseek$ ./build.sh
Building Haskell shared library...
Loaded package environment from /home/success/.ghc/x86_64-linux-9.6.7/environments/default
[2 of 2] Linking libminimal.so [Flags changed]
Build successful! Running Python test...
----------------------------------------
Traceback (most recent call last):
  File "/home/success/Desktop/deepseek/test_minimal.py", line 5, in <module>
    lib = ctypes.CDLL('./libminimal.so')
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/ctypes/__init__.py", line 379, in __init__
    self._handle = _dlopen(self._name, mode)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: /home/success/.ghcup/ghc/9.6.7/lib/ghc-9.6.7/lib/../lib/x86_64-linux-ghc-9.6.7/libHSghc-prim-0.10.0-ghc9.6.7.so: undefined symbol: stg_gc_unpt_r1

build.sh

#!/bin/bash

echo "Building Haskell shared library..."

# Compile Haskell to shared library
ghc -O2 -dynamic -shared -fPIC -o libminimal.so Minimal.hs

if [ $? -eq 0 ]; then
    echo "Build successful! Running Python test..."
    echo "----------------------------------------"
    python3 test_minimal.py
else
    echo "Build failed!"
    exit 1
fi

Minimal.hs

{-# LANGUAGE ForeignFunctionInterface #-}

module Minimal where

import Foreign.C.Types
import Foreign.Ptr

-- Simple function that receives a Python module and prints confirmation
foreign export ccall receivePythonModule :: Ptr () -> IO ()

receivePythonModule :: Ptr () -> IO ()
receivePythonModule modulePtr = do
    putStrLn "Haskell: Received Python module!"
    putStrLn "Haskell: This is where you'd process the module..."

test_minimal.py

#!/usr/bin/env python3
import ctypes, sys, types

# Load the shared library
lib = ctypes.CDLL('./libminimal.so')

# Define the function signature
lib.receivePythonModule.argtypes = [ctypes.c_void_p]
lib.receivePythonModule.restype = None

def pass_module_to_haskell():
    # Create a simple Python module
    test_module = types.ModuleType('test_module')
    test_module.some_value = 42
    test_module.some_function = lambda x: x * 2
    
    module_ptr = ctypes.c_void_p(id(test_module))    
    lib.receivePythonModule(module_ptr)

if __name__ == "__main__":
    pass_module_to_haskell()
1
  • You should also consider instead calling Python from Haskell. inline-python makes this much easier than the other way around. Commented 1 hour ago

1 Answer 1

5

I hade to make two changes to get this working. First you need to link the runtime system when building libminimal.so:

ghc -O2 -dynamic -shared -fPIC -o libminimal.so Minimal.hs -lHSrts-1.0.2-ghc9.8.1

You will have to pick the library name associated with your GHC version. I'm not sure the Right Way to discover this. The GHC documentation doesn't seem to be very clear about exactly what needs to be linked when doing foreign exports.

I also needed to invoke hs_init before calling your exported function:

if __name__ == "__main__":
    lib.hs_init(None, None)
    pass_module_to_haskell()

You should probably set this up to pass along sys.argv (or some suitably chosen chunk of it) instead of None so that users can set runtime options in the usual way.

Sign up to request clarification or add additional context in comments.

1 Comment

The -lHSrts-1.0.2-ghc9.8.1 part feels rather weird. I'd understand the need to pass that if we somehow used gcc or any other Haskell-agnostic linker, but when using ghc I'd somehow expect to add the relevant libs automatically. (I wonder if there's some hidden trick somewhere like the old --make.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.