Link `PyInit` built object against other files

Greetings,

The example below calls on a lot of other Mojo code that all gets recompiled when any piece of the program changes. (This happens when this PythonObject is “imported” in Python code).

Also, the code that it relies on is required to exist in the current PATH, it would be nice to allow the code it calls upon to live elsewhere and just point the Mojo compiler to where to find it.

When creating a PythonObject with the interop (such as below), is there a way to link against other Mojo code files (or precompiled code)?

Also, I have gathered from error messages that building a PythonObject like this with the interop requires it to be Movable? Is there a way to remove this requirement?

Thanks!

T

def PyInit_GrainsBridge() -> PythonObject:
    try:
        var m = PythonModuleBuilder("GrainsBridge")

        # var person_type = mb.add_type[Person]("Person")
        _ = m.add_type[MMMAudioBridge]("MMMAudioBridge").def_py_init[MMMAudioBridge.py_init]()
            .def_method[MMMAudioBridge.next]("next")
            .def_method[MMMAudioBridge.set_screen_dims]("set_screen_dims")
            .def_method[MMMAudioBridge.update_mouse_pos]("update_mouse_pos")
            .def_method[MMMAudioBridge.update_bool_msg]("update_bool_msg")
            .def_method[MMMAudioBridge.update_bools_msg]("update_bools_msg")
            .def_method[MMMAudioBridge.update_float_msg]("update_float_msg")
            .def_method[MMMAudioBridge.update_floats_msg]("update_floats_msg")
            .def_method[MMMAudioBridge.update_int_msg]("update_int_msg")
            .def_method[MMMAudioBridge.update_ints_msg]("update_ints_msg")
            .def_method[MMMAudioBridge.update_trig_msg]("update_trig_msg")
            .def_method[MMMAudioBridge.update_trigs_msg]("update_trigs_msg")
            .def_method[MMMAudioBridge.update_string_msg]("update_string_msg")
            .def_method[MMMAudioBridge.update_strings_msg]("update_strings_msg")
            .def_method[MMMAudioBridge.set_channel_count]("set_channel_count")  

        return m.finalize()
    except e:
        _ = Error(String("error creating Python Mojo module: " + String(e)))
        abort()

I guess to follow up on Ted’s question. In 1.0.beta2 we choose the “c abi” for Python Interop. Does this mean that the emitted “c abi” can be linked from any language?

In general, this would be amazing. Create and test in python. Compile. Use in Rust/C/etc.

For our project, this would be magic. Create and test in MMMAudio. Compile. Embed MMMAudio instance (Mojo.so file) in a JUCE VST plugin. Use in any DAW.

Mojo’s compiler currently doesn’t have great incremental compilation support (Don’t worry, we are VERY aware of this as an issue since it actively increases CI costs) and it is also “LTO native” to paraphrase Chris. The Mojo compiler does parallelism internally, so a lot of the traditional advantages of split compilation don’t apply, aside from the caching advantages which can be gained in other ways.

Also, I have gathered from error messages that building a PythonObject like this with the interop requires it to be Movable? Is there a way to remove this requirement?

The struct needs to be moved into a python object, so I don’t think that there is. You can try adding some indirection and putting whatever can’t be moved into another allocation.

Non-abi("C") functions should still work with Python since the compiler can just generate a bit of glue code for you.

For any other language, abi("C") is strongly recommended unless you want to match how Mojo does name mangling and argument conventions.