diff --git a/.gitignore b/.gitignore index ce7b5b3..a5891d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ -build/ +build*/ julia/ +.vscode +*.code-workspace +compile_commands.json \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e7991eb..5127aaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/FindJulia.cmake b/FindJulia.cmake new file mode 100644 index 0000000..3f85997 --- /dev/null +++ b/FindJulia.cmake @@ -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 +) diff --git a/demo/cfunction.cpp b/demo/cfunction.cpp new file mode 100644 index 0000000..83a57e6 --- /dev/null +++ b/demo/cfunction.cpp @@ -0,0 +1,98 @@ +#define JULIAPP_DEBUG +#include "Julia.hpp" + +#include +#include + +namespace jl +{ + +namespace impl +{ + +template +inline std::string typename_str() +{ + return std::string(jl_symbol_name(jl::impl::get_type()->name->name)); +} + +template +struct _typestuple; + +template +struct _typestuple +{ + static inline std::string str() + { + return typename_str() + "," + _typestuple::str(); + } +}; + +template<> +struct _typestuple<> +{ + static inline std::string str() { return std::string(); } +}; + +template +struct typestuple +{ + inline static std::string str() + { + return std::string("(") + _typestuple::str() + std::string(")"); + } +}; + +template +struct _cfunction; + +template +struct _cfunction +{ + using returntype = R; + using funcpointertype = R (*)(Args...); + using argtypestuple = std::tuple; + inline static std::string returntype_str() { return typename_str(); } + inline static std::string argtypestuple_str() + { + return typestuple::str(); + } +}; + +} // namespace impl + +template +std::function cfunction(const std::string& name) +{ + using funcpointertype = + typename impl::_cfunction::funcpointertype; + auto returntype_str = impl::_cfunction::returntype_str(); + auto argtypestuple_str = impl::_cfunction::argtypestuple_str(); + std::string jl_src = std::string("@cfunction(") + // + name + ", " + // + returntype_str + ", " + // + argtypestuple_str + ")"; + funcpointertype fp = funcpointertype(jl::eval(jl_src).get()); + return std::function(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("f"); + std::cout << ">>> " << cf_int(123) << std::endl; + + auto cf_double = jl::cfunction("f"); + std::cout << ">>> " << cf_double(123.4) << std::endl; +} diff --git a/demo/demo.cpp b/demo/demo.cpp index c83aca8..56b5e74 100644 --- a/demo/demo.cpp +++ b/demo/demo.cpp @@ -39,7 +39,7 @@ int main() // jl_vec->x = 7.12345f; // std::printf("%f\n", jl_vec.get().x); - auto integer = "Core"_jlm["Int64"]; + auto integer[[maybe_unused]] = "Core"_jlm["Int64"]; // struct S // { diff --git a/src/Boxing.hpp b/src/Boxing.hpp index 97dc2b5..a19fa4f 100644 --- a/src/Boxing.hpp +++ b/src/Boxing.hpp @@ -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) + { + 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>(jl_typeof(arg_))) diff --git a/src/GenericValue.inl b/src/GenericValue.inl index e19ccad..2b41cf0 100644 --- a/src/GenericValue.inl +++ b/src/GenericValue.inl @@ -64,7 +64,10 @@ template{}>*> TargT generic_value::get() noexcept { if constexpr (std::is_pointer_v) - return reinterpret_cast(_boxed_value); + if constexpr (std::is_same_v) + return impl::unbox(_boxed_value); + else + return reinterpret_cast(_boxed_value); else return *reinterpret_cast*>(_boxed_value); } diff --git a/tests/ValueTests.cpp b/tests/ValueTests.cpp index 5c393cb..75ab741 100644 --- a/tests/ValueTests.cpp +++ b/tests/ValueTests.cpp @@ -125,3 +125,10 @@ TEST_CASE("Getting julia type") REQUIRE(jl::get_type() == "Mut"_jlg.value()); REQUIRE(jl::get_type() != "Core"_jlm["Int"].value()); } + +TEST_CASE("Unboxing void pointer") +{ + auto x = jl::eval("Ptr{Cvoid}(Int(0x10ff))"); + + REQUIRE(x.get() == (void*)(0x10ff)); +}