Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
build/
build*/
julia/
.vscode
*.code-workspace
compile_commands.json
34 changes: 24 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
cmake_minimum_required (VERSION 3.8)
project(julia-cpp LANGUAGES CXX)

find_library(
JULIA_LIB "julia-debug"
HINTS "julia/lib"
)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)

add_definitions(-Wall -Wextra -Wpedantic -Werror -Wfatal-errors)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}")

# set(Julia_EXECUTABLE "$ENV{HOME}/Desktop/julia/usr/bin/julia-debug")
# set(Julia_LIBRARY_NAME "julia-debug")
find_package(Julia)

add_definitions(${Julia_DEFINITIONS})
include_directories(${Julia_INCLUDE_DIRS})
link_directories(${Julia_LIBRARY_DIRS})

add_definitions(-DJULIA_ENABLE_THREADING=1)


add_executable(demo demo/demo.cpp)

add_executable(cfunction demo/cfunction.cpp)

add_executable(tests tests/Tests.cpp tests/ValueTests.cpp tests/FreeFunctionTests.cpp tests/FunctionTests.cpp tests/ModuleTests.cpp tests/GlobalTests.cpp)
target_compile_options(tests PUBLIC -DJULIA_ENABLE_THREADING=1 -fPIC -fprofile-arcs -ftest-coverage)
target_compile_options(demo PUBLIC -DJULIA_ENABLE_THREADING=1 -fPIC)
target_compile_options(tests PUBLIC -fprofile-arcs -ftest-coverage)

include_directories(src julia/include/julia)

target_link_libraries(demo ${JULIA_LIB})
target_link_libraries(tests ${JULIA_LIB} gcov --coverage)
target_link_libraries(demo ${Julia_LIBRARIES})
target_link_libraries(cfunction ${Julia_LIBRARIES})
target_link_libraries(tests ${Julia_LIBRARIES} gcov --coverage)

add_definitions(-Wall -Wextra -Wconversion -pedantic)
64 changes: 64 additions & 0 deletions FindJulia.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#.rst:
# FindJulia
# ---------
#
# Finds Julia library for embedding
#
# This will define the following variables::
#
# Julia_FOUND - True if the system has Julia
# Julia_VERSION - The version of Julia which was found
#


find_program(Julia_EXECUTABLE julia DOC "Julia executable")

if(NOT Julia_EXECUTABLE)
return()
endif()


execute_process(
COMMAND ${Julia_EXECUTABLE} --version
OUTPUT_VARIABLE Julia_VERSION
RESULT_VARIABLE RESULT
)
if(RESULT EQUAL 0)
string(REGEX REPLACE ".*([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1"
Julia_VERSION ${Julia_VERSION})
endif()


execute_process(
COMMAND ${Julia_EXECUTABLE} -e "print(Sys.BINDIR)"
OUTPUT_VARIABLE Julia_HOME
RESULT_VARIABLE RESULT
)

get_filename_component(Julia_DIR ${Julia_HOME} DIRECTORY)



set(Julia_DEFINITIONS -fPIC -DJULIA_INIT_DIR="${Julia_HOME}")
set(Julia_INCLUDE_DIRS ${Julia_DIR}/include/julia)
set(Julia_LIBRARY_DIRS ${Julia_DIR}/lib ${Julia_DIR}/lib/julia)

find_library( Julia_LIBRARIES
NAMES ${Julia_LIBRARY_NAME} julia
PATHS ${Julia_LIBRARY_DIRS}
)


include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Julia
FOUND_VAR Julia_FOUND
REQUIRED_VARS
Julia_DIR
Julia_HOME
Julia_EXECUTABLE
Julia_DEFINITIONS
Julia_INCLUDE_DIRS
Julia_LIBRARIES
Julia_LIBRARY_DIRS
VERSION_VAR Julia_VERSION
)
98 changes: 98 additions & 0 deletions demo/cfunction.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#define JULIAPP_DEBUG
#include "Julia.hpp"

#include <functional>
#include <iostream>

namespace jl
{

namespace impl
{

template<typename T>
inline std::string typename_str()
{
return std::string(jl_symbol_name(jl::impl::get_type<T>()->name->name));
}

template<typename... Ts>
struct _typestuple;

template<typename T, typename... Ts>
struct _typestuple<T, Ts...>
{
static inline std::string str()
{
return typename_str<T>() + "," + _typestuple<Ts...>::str();
}
};

template<>
struct _typestuple<>
{
static inline std::string str() { return std::string(); }
};

template<typename... Ts>
struct typestuple
{
inline static std::string str()
{
return std::string("(") + _typestuple<Ts...>::str() + std::string(")");
}
};

template<typename F>
struct _cfunction;

template<typename R, typename... Args>
struct _cfunction<R(Args...)>
{
using returntype = R;
using funcpointertype = R (*)(Args...);
using argtypestuple = std::tuple<Args...>;
inline static std::string returntype_str() { return typename_str<R>(); }
inline static std::string argtypestuple_str()
{
return typestuple<Args...>::str();
}
};

} // namespace impl

template<typename Signature>
std::function<Signature> cfunction(const std::string& name)
{
using funcpointertype =
typename impl::_cfunction<Signature>::funcpointertype;
auto returntype_str = impl::_cfunction<Signature>::returntype_str();
auto argtypestuple_str = impl::_cfunction<Signature>::argtypestuple_str();
std::string jl_src = std::string("@cfunction(") + //
name + ", " + //
returntype_str + ", " + //
argtypestuple_str + ")";
funcpointertype fp = funcpointertype(jl::eval(jl_src).get<void*>());
return std::function<Signature>(fp);
}

} // namespace jl

int main()
{
jl::eval(R"(
function f(x)
println("{",x,"}")
return x*x
end
)");

auto f = jl::function("f");
std::cout << ">>> " << double(f(123.4)) << std::endl;

auto cf_int = jl::cfunction<int(int)>("f");
std::cout << ">>> " << cf_int(123) << std::endl;

auto cf_double = jl::cfunction<double(double)>("f");
std::cout << ">>> " << cf_double(123.4) << std::endl;
}
2 changes: 1 addition & 1 deletion demo/demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ int main()
// jl_vec->x = 7.12345f;
// std::printf("%f\n", jl_vec.get<Vec2>().x);

auto integer = "Core"_jlm["Int64"];
auto integer[[maybe_unused]] = "Core"_jlm["Int64"];

// struct S
// {
Expand Down
8 changes: 8 additions & 0 deletions src/Boxing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ RetT unbox(jl_value_t* arg_)
throw result_type_error{
"Incorrect result type. Integral type requested"};
}
else if constexpr (std::is_same_v<RetT, void*>)
{
if (jl_typeis(arg_, jl_voidpointer_type))
return jl_unbox_voidpointer(arg_);

throw result_type_error{
"Incorrect result type. Void pointer type requested"};
}
else
{
if (!impl::types_match<std::decay_t<RetT>>(jl_typeof(arg_)))
Expand Down
5 changes: 4 additions & 1 deletion src/GenericValue.inl
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ template<typename TargT, std::enable_if_t<!std::is_fundamental<TargT>{}>*>
TargT generic_value::get() noexcept
{
if constexpr (std::is_pointer_v<TargT>)
return reinterpret_cast<TargT>(_boxed_value);
if constexpr (std::is_same_v<TargT, void*>)
return impl::unbox<TargT>(_boxed_value);
else
return reinterpret_cast<TargT>(_boxed_value);
else
return *reinterpret_cast<std::decay_t<TargT>*>(_boxed_value);
}
Expand Down
7 changes: 7 additions & 0 deletions tests/ValueTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,10 @@ TEST_CASE("Getting julia type")
REQUIRE(jl::get_type<Mut>() == "Mut"_jlg.value());
REQUIRE(jl::get_type<Mut>() != "Core"_jlm["Int"].value());
}

TEST_CASE("Unboxing void pointer")
{
auto x = jl::eval("Ptr{Cvoid}(Int(0x10ff))");

REQUIRE(x.get<void*>() == (void*)(0x10ff));
}