Skip to content

Clemapfel/jluna_deprecated

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

THIS PROJECT IS DEPRECATED, USE: https://github.com/Clemapfel/jluna.git INSTEAD

Julia is a beautiful language, it is well-designed and well-documented. julia C-API is also well-designed, less beautiful and much less... documented.

Heavily inspired in design and syntax by (but in no way affiliated with) the excellent Lua⭤C++ wrapper sol2, jluna aims to fully wrap the official Julia C-API and replace it in usage in C++ projects by making accessing julia unique strengths through C++ safe, hassle-free and just as beautiful.


Table of Contents

  1. Introduction
  2. Showcase
  3. Features
  4. Planned Features
  5. Documentation
    4.1 Manual
    4.2 Quick & Dirty Overview
  6. Dependencies
    5.1 Julia 1.7.0+
    5.2 g++10
    5.3 cmake 3.19+
    5.4 Linux / Mac OS
  7. License
  8. Installation
    7.1 Step-by-Step Guide
    7.2 Troubleshooting

Showcase

using namespace jluna;

// one-line initialization and setup
State::initialize();

// run arbitrary code with exception forwarding
State::safe_script(R"(
    mutable struct Holder
        _array_field::Array{Int64, 3}
        _vector_field::Vector{String}
    
        Holder() = new(reshape(collect(1:(3*3*3)), 3, 3, 3), Vector{String}())
    end
    
    instance = Holder();
)");

// access and mutate variables
Array<Int64, 3> array = Main["instance"]["_array_field"];
array.at(0, 1, 2) = 9999;

// std:: objects are supported out-of-the-box
Main["instance"]["_vector_field"] = std::vector<std::string>{"string", "string", "string"};

// call julia-side functions with C++-side arguments
auto println = State::script("return Base.println");
println(Main["instance"]);

// call c++-side functions julia-side arguments
State::register_function("cpp_print", [](jl_value_t* in) -> jl_value_t* {
   
    std::cout << "cpp called" << std::endl;
    
    auto as_vector = unbox<jluna::Vector<size_t>>(in);
    for (auto e : as_vector)
        e = ((size_t)) e + 1
                
    return as_vector;
});
State::safe_script("println(cppcall(:cpp_print, [1, 2, 3, 4]))");
Holder([1 4 7; 2 5 8; 3 6 9;;; 10 13 16; 11 14 17; 12 15 18;;; 19 9999 25; 20 23 26; 21 24 27], ["string", "string", "string"])

cpp called
[2, 3, 4, 5]

Features

Some of the many advantages jluna has over the C-API include:

  • expressive generic syntax
  • call C++ functions from julia using any julia-type
  • assigning C++-side proxies also mutates the corresponding variable with the same name Julia-side
  • Julia-side values, including temporaries, are kept safe from the garbage collector while they are in use C++-side
  • verbose exception forwarding from Julia, compile-time assertions
  • wraps most of the relevant C++ std objects and types
  • multidimensional, iterable array interface with Julia-style indexing
  • fully documented, including inline documentation for IDEs for both C++ and Julia code
  • mixing the C-API and jluna works no problem
  • And more!

Planned (but not yet implemented):

In order of priority, highest first:

  • v0.6: expression proxy, access to meta features via C++
  • v0.7: creating new modules and datatypes with member-access completely C++-Side
  • v0.8: thread-safe cppcall and proxy-data read/write
  • v0.9: No-Overhead performance version of proxies and cppcall
  • v1.0: multiple julia states, save-states: restoring a previous julia state

Documentation

A step-by-step introduction and reference guide intended for users is available here. Furthermore, all user-facing code has in-line documentation available through most IDEs (or the julia help? command).

Advanced users are encouraged to check the headers (available in jluna/include) for implementation details. They are formatted specifically to be easily understood by 3rd parties.


Dependencies

jluna aims to be as modern as is practical. It uses C++20 features extensively and aims to support the newest Julia version, rather than focusing on backwards compatibility. If you are looking for a C++ library that supports Julia 1.5 or lower, consider checking out CxxWrap instead.

For jluna you'll need:

Currently, only g++10 is supported, clang support is planned in the future.


License

jluna is freely available for non-commercial and educational use. For use in for-profit commercial applications, please contact the developer.


Installation

The following is a step-by-step guide to creating your own application using jluna.

First, we create our workspace directory. For the remainder of this section, this will be assumed to be ~/my_project. We now execute:

cd ~/my_project
git clone https://github.com/Clemapfel/jluna.git

This adds the folder jluna/ to our directory. We now need to recompile jluna:

# still in ~/my_project
cd jluna
mkdir build
cd build
cmake -D CMAKE_CXX_COMPILER=g++-10 ..
make

If some dependencies are not met, this may throw errors. Make sure g++-10, julia 1.7.0 (or higher) and cmake 3.16 (or higher) are installed on a system level.

Some warnings will appear. This is due to julia official C header julia.h being slightly outdated and is nothing to worry about. jluna itself should show no warnings.

We verify everything works by running the test executable we just compiled:

# in ~/my_project/jluna/build
./JLUNA_TEST

A lot of output will appear, at the very end it should show:

Number of tests unsuccessful: 0

If errors appear here, head to troubleshooting.

Moving on to creating our own application and linking it, we first create our own main.cpp:

cd ~/my_project
gedit main.cpp

This opens a GUI text editor. Any other editor (vim, nano, emacs, etc.) can be substituted for gedit.

We paste the following into our empty my_project/main.cpp:

#include <jluna.hpp>

using namespace jluna;

int main()
{
    State::initialize();
    Base["println"]("hello julia");
    State::shutdown();
}

and save.

Of course we need a good way to compile it. To do this, we create our very own CMakeLists.txt:

# in ~/my_project
gedit CMakeLists.txt

As a starting point, we paste the following into our my_project/CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)

# name of our project
project(MyProject)

# cmake and cpp settings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lstdc++fs -fconcepts -pthread -lpthread -lGL -Wl,--export-dynamic")
set(CMAKE_CXX_STANDARD 20)

# build type
set(CMAKE_BUILD_TYPE Debug)

# include directories needed by jluna
include_directories("./jluna/")
include_directories("./jluna/include")

# find julia
set(JULIA_EXECUTABLE julia) # may need to be modified, c.f. Troubleshooting
include(${CMAKE_SOURCE_DIR}/jluna/find_julia.cmake)

# find jluna and jluna_c_adapter
find_library(jluna REQUIRED NAMES libjluna.so PATHS ${CMAKE_SOURCE_DIR}/jluna/)
find_library(jluna_c_adapter REQUIRED NAMES libjluna_c_adapter.so PATHS ${CMAKE_SOURCE_DIR}/jluna/)

# add our executable
add_executable(MY_EXECUTABLE ./main.cpp)

# link executable with jluna, jluna_c_adapter and julia
target_link_libraries(MY_EXECUTABLE ${jluna} ${jluna_c_adapter} ${JULIA_DIR}/lib/libjulia.so)

Having created CMakeLists.txt, we now create our own build folder:

# in ~/my_project
mkdir build 

We can now compile our project:

# in ~/my_project
cd build
cmake -D CMAKE_CXX_COMPILER=g++-10 ..
make

Warnings will again appear (due to the official julia header).

Our directory should now look like this:

my_project/
    main.cpp
    CMakeLists.txt
    jluna/
        jluna.hpp
        libjluna.so
        libjluna_c_adapter.so
        build/
            JLUNA_TEST
            (...)
        (...)
    build/
        MY_EXECUTABLE
        (...)

Where any name with the postfix / is a folder.

We execute our freshly compiled executable using:

./MY_EXECUTABLE
[JULIA][LOG] initialization successfull.
hello julia

Troubleshooting

CMake cannot find Julia

jluna detects the julia version and build parameters using the julia command in bash. If this command is not available on a system level, we will need to manually supply the path for the julia executable to jluna and our own program. To do this:

We open jluna/CMakeLists.txt in an editor and modify the following statement in line 10

set(JULIA_EXECUTABLE julia)

to

set(JULIA_EXECUTABLE /path/to/our/.../julia/bin/julia) # replace with the path to julia/bin/julia here

Furthermore, in our own my_project/CMakeLists.txt we modify:

# find julia
set(JULIA_EXECUTABLE julia)

to

set(JULIA_EXECUTABLE /path/to/our/.../julia/bin/julia)

We then redo all steps except folder creation outlined in installation. During make, jluna should now be able to determine all the information to build and link jluna itself and our own executable properly.

jl_init() fails

jluna assumes that julia is installed on a system level. If this is not the case, we will need to manually specify the path to the julia image during the initialization step in C++.

When calling jluna::State::initialize() at the start of our C++ main my_project/main.cpp we replace

State::initialize();

with

State::initialize("/path/to/our/.../Julia/bin");

Make sure that the image is uncompressed, as .zip or .tar files cannot be used for initialization.

Other Issues

Please make sure that:

  • you are on a linux-based, 64-bit operating system
  • julia 1.7.0 (or higher) is installed
  • cmake 3.16 (or higher) is installed
  • g++-10 (exactly) and gcc-9 (or higher) are installed
  • my_project/CMakeLists.txt and my_project/main.cpp are identical to the code in installation
  • State::initialize and set(JULIA_EXECUTABLE (...)) are modified as outlined above
  • jluna was freshly pulled from the git repo
  • my_project/jluna/ contains libjluna.so and libjluna_c_adapter.so
  • my_project/jluna/build/JLUNA_TEST was ran

If all of the above apply, please create an issue stating your operating system, the output of JLUNA_TEST, and your problem in the issues tab.


About

General Purpose Julia <- C++ binding, aims to modernize the Julia C-API

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published