python-3.xpass-by-referencecppyy

How to pass args by reference in python scripts using cppyy?


I am working on a Python front-end for some existing C++ libraries. As you can imagine, some of the C++ functions use the pass-by-reference method for some arguments. I do not know how to implement this kind of functions into python scripts, namely I should use a pointer to a struct as an argument, but I don't know how.

Note Even though python does not use pointers nor addresses explicitly, cppyy provides a way to access compiled libraries from python scripts. I guess that cppyy also covers this simple case and I am simply missing something like the correct syntax. I am using python 3.10 and cppyy 2.4.2.

Example pconf.h file:

struct Parser_Conf {
  std::string filename      = "";
  uint32_t    dump_addr_st  = 0;
  uint32_t    dump_addr_end = 255;
  bool        debug_session = false;
  bool        use_xterm     = true;
};

void print_conf(Parser_Conf ) ;
void print_conf_fromPtr(Parser_Conf * ) ;

Example pconf.cpp file:

#include <sstream>

struct Parser_Conf {
  std::string filename      = "";
  uint32_t    dump_addr_st  = 0;
  uint32_t    dump_addr_end = 255;
  bool        debug_session = false;
  bool        use_xterm     = true;
};

void print_conf(Parser_Conf ) ;
void print_conf_fromPtr(Parser_Conf * ) ;

Compiled library is in simplebuild/simple/libMINI.so. Example simple.py:

import os
import pysysc
#from cppyy import gbl as cpp
# more readable 
import cppyy
#looks as it is not loaded by default
import cppyy.ll

cppyy.include('boost/any.hpp') 
from cppyy.gbl import std, boost

build_dir= "simplebuild"
name = "PCONF Components"
myDir = os.path.dirname(os.path.realpath(__file__))
buildDir = os.path.join(myDir, build_dir)
program_file_name = "CSRAM_32Bits_macro.ihex"

if (not pysysc.load_systemc(17)):
    print('Error : failed to load systemc dynamic library')
    exit()

print("Loading " + name + " library")
#for HW-2-SW
pysysc.add_include_path(os.path.join(myDir, "simple"))
output = pysysc.add_library("pconf.h", "libMINI.so", buildDir)

parserConfCapsule = boost.any()
print("Preparing a Parser_Conf data")
parserConfCapsule.__assign__(cppyy.gbl.Parser_Conf())

print("Setting up the Parser_Conf data")
parserConfCapsule.type() == cppyy.typeid(cppyy.gbl.Parser_Conf)
print("=> Type of the 'parserConfCapsule' global:", type(parserConfCapsule).__name__)

extract = boost.any_cast[cppyy.gbl.Parser_Conf](parserConfCapsule)
print("=> Type of the 'extract' global:", type(extract).__name__)


print("Setting Parser_Conf fields")
extract.debug_session = False
extract.filename = program_file_name

print("Calling Library function with Parser_Conf struct")
cppyy.gbl.print_conf(extract)

print("Struct instance address is")
print(cppyy.ll.addressof(extract))

addr_of_extract = cppyy.ll.addressof(extract)
print("=> Type of the 'extract' global address:", type(addr_of_extract).__name__)

print("Q:Has the 'extract' global a deref? A:",
      hasattr(extract, '__deref__') or hasattr(extract, 'dereference'))
print("Q:Has the 'extract' global address a deref? A:",
      hasattr(addr_of_extract, '__deref__') or hasattr(addr_of_extract, 'dereference'))

print("Calling Library function with Parser_Conf address")
cppyy.gbl.print_conf_fromPtr(addr_of_extract)

Current output :

gre057823/PySysC-SC 236 >>python3 simple_example.py

        SystemC 2.3.4-Accellera --- Jul  2 2025 14:37:58
        Copyright (c) 1996-2022 by all Contributors,
        ALL RIGHTS RESERVED
Loading PCONF Components library
Preparing a Parser_Conf data
Setting up the Parser_Conf data
=> Type of the 'parserConfCapsule' global: any
=> Type of the 'extract' global: Parser_Conf
Setting Parser_Conf fields
Calling Library function with Parser_Conf struct
Dump range : 0 - FF
Struct instance address is
93974867696144
=> Type of the 'extract' global address: int
Q:Has the 'extract' global a deref? A: False
Q:Has the 'extract' global address a deref? A: False
Calling Library function with Parser_Conf address
Traceback (most recent call last):
  File "/home/360.1.417-StorAIge/USERS/lc177705/PySysC_TREE/PySysC-SC/simple_example.py", line 59, in <module>
    cppyy.gbl.print_conf_fromPtr(addr_of_extract)
TypeError: void ::print_conf_fromPtr(Parser_Conf*) =>
    TypeError: could not convert argument 1

I tried RTFM (https://cppyy.readthedocs.io/en/latest/lowlevel.html) but could not find a solution, any hints welcome.


Solution

  • Thanks to @Learn N Spread, that was the point, just it needs a bit of further work (see comment), this is the correct way to solve the issue:

    ptrLikeStuff = cppyy.ll.reinterpret_cast['Parser_Conf *'](cppyy.addressof(extract))
    print("=> Type of the 'ptrLikeStuff' global:", type(ptrLikeStuff).__name__)
    cppyy.gbl.print_conf_fromPtr(ptrLikeStuff)
    

    I tried to edit your answer but moderators say it does not make sense, so I am posting a new answer.

    Best regards,

    Lorenzo