From 4089d97f6426f63daa8d2c80a9005f106140f6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crist=C3=B3v=C3=A3o=20D=2E=20Sousa?= Date: Thu, 13 Jun 2019 15:01:36 +0100 Subject: [PATCH 1/4] Improve CMake Julia as a dependency --- .gitignore | 5 +++- CMakeLists.txt | 30 +++++++++++++++-------- FindJulia.cmake | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ demo/demo.cpp | 2 +- 4 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 FindJulia.cmake 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..b0cc114 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,20 +1,30 @@ 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}") + +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(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(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/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 // { From 8361cb89dc6a0da87707dd91624490bc5525aac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crist=C3=B3v=C3=A3o=20D=2E=20Sousa?= Date: Thu, 13 Jun 2019 23:42:01 +0100 Subject: [PATCH 2/4] Add unboxing of void pointers --- src/Boxing.hpp | 8 ++++++++ src/GenericValue.inl | 5 ++++- tests/ValueTests.cpp | 7 +++++++ 3 files changed, 19 insertions(+), 1 deletion(-) 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)); +} From 3c82f10bd60fe2e7f3893216c7b1c960788a2378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crist=C3=B3v=C3=A3o=20D=2E=20Sousa?= Date: Thu, 13 Jun 2019 23:45:30 +0100 Subject: [PATCH 3/4] Some experiments with cfunction --- CMakeLists.txt | 6 +++++- demo/cfunction.cpp | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 demo/cfunction.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b0cc114..f2f3763 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,9 +6,10 @@ 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}) @@ -20,11 +21,14 @@ 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 -fprofile-arcs -ftest-coverage) include_directories(src julia/include/julia) target_link_libraries(demo ${Julia_LIBRARIES}) +target_link_libraries(cfunction ${Julia_LIBRARIES}) target_link_libraries(tests ${Julia_LIBRARIES} gcov --coverage) diff --git a/demo/cfunction.cpp b/demo/cfunction.cpp new file mode 100644 index 0000000..aacad23 --- /dev/null +++ b/demo/cfunction.cpp @@ -0,0 +1,20 @@ +#define JULIAPP_DEBUG +#include "Julia.hpp" + +#include + +int main() +{ + + jl::eval(R"( + f(x) = (println("{",x,"}"); 2x) + )"); + + jl::function f("f"); + std::cout << ">>> " << int(f(1337)) << std::endl; + + auto fp = reinterpret_cast( + jl::eval("fp = @cfunction(f, Int, (Int,))").get()); + + std::cout << ">>> " << fp(1234) << std::endl; +} From c1578a8b33a043cb185b98203b46766f77790734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crist=C3=B3v=C3=A3o=20D=2E=20Sousa?= Date: Sun, 16 Jun 2019 03:37:03 +0100 Subject: [PATCH 4/4] Add helper for cfunction creation --- CMakeLists.txt | 4 +- demo/cfunction.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2f3763..5127aaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ 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") +# set(Julia_EXECUTABLE "$ENV{HOME}/Desktop/julia/usr/bin/julia-debug") +# set(Julia_LIBRARY_NAME "julia-debug") find_package(Julia) add_definitions(${Julia_DEFINITIONS}) diff --git a/demo/cfunction.cpp b/demo/cfunction.cpp index aacad23..83a57e6 100644 --- a/demo/cfunction.cpp +++ b/demo/cfunction.cpp @@ -1,20 +1,98 @@ #define JULIAPP_DEBUG #include "Julia.hpp" +#include #include -int main() +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"( - f(x) = (println("{",x,"}"); 2x) - )"); + function f(x) + println("{",x,"}") + return x*x + end + )"); - jl::function f("f"); - std::cout << ">>> " << int(f(1337)) << std::endl; + auto f = jl::function("f"); + std::cout << ">>> " << double(f(123.4)) << std::endl; - auto fp = reinterpret_cast( - jl::eval("fp = @cfunction(f, Int, (Int,))").get()); + auto cf_int = jl::cfunction("f"); + std::cout << ">>> " << cf_int(123) << std::endl; - std::cout << ">>> " << fp(1234) << std::endl; + auto cf_double = jl::cfunction("f"); + std::cout << ">>> " << cf_double(123.4) << std::endl; }