From d4e9831fa28e6d1f68b71f572fb2ef8c3b58b430 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 17:29:28 +0100 Subject: [PATCH 01/71] Use a find module to find Julia --- CMakeLists.txt | 76 ++------------------------- cmake/find/FindJulia.cmake | 102 +++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 72 deletions(-) create mode 100644 cmake/find/FindJulia.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a5621d..9b0140b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,79 +1,11 @@ cmake_minimum_required(VERSION 3.16) -project(jluna) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_BUILD_TYPE Debug) +project(jluna LANGUAGES CXX) -if (WIN32) - message(WARNING "Windows support is experimental, some features my not work correctly. It maybe be necessary to fork jluna and modify jluna/CMakeLists.txt") -endif() - -### COMPILER SUPPORT ### - -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL "12.0.0") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-volatile") -elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL "10.0.0") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fconcepts -Wno-volatile") -elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL "19.20") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") -else() - message(FATAL_ERROR "Currently, the only supported compilers are G++10 (or higher), Clang-12 (or higher) and MSVC 19.30 (experimental)") -endif() - -### JULIA ### - -if (WIN32) - if (NOT DEFINED ENV{JULIA_PATH}) - message(FATAL_ERROR "Cannot determine location of julia image. Before running cmake, please manually set the environment variable JULIA_PATH using:\n\tset JULIA_PATH=\"C:/path/to/your/.../julia-1.7.2\"\nIf you are unsure of the location of your julia image, you can access the path from within the julia REPL using\n println(joinpath(Sys.BINDIR, \"..\"))") - endif() -else() - # access julia through julia environment variable - if (NOT DEFINED ENV{JULIA_PATH}) - execute_process( - COMMAND julia -e "println(joinpath(Sys.BINDIR, \"..\"))" - OUTPUT_VARIABLE JULIA_PATH_LOCAL) - - if ("${JULIA_PATH}" STREQUAL "") - message(FATAL_ERROR "Cannot determine location of julia image. Before running cmake, please manually set the environment variable JULIA_PATH using\n export JULIA_PATH=/path/to/your/.../julia\nIf you are unsure of the location of your julia image, you can access the path from within the julia REPL using\n println(joinpath(Sys.BINDIR, \"..\")) - For more information, visit https://github.com/Clemapfel/jluna/blob/master/README.md#troubleshooting") - endif() - - set(ENV{JULIA_PATH} ${JULIA_PATH_LOCAL}) - endif() -endif() - -if (WIN32) - set(JULIA_LIB "$ENV{JULIA_PATH}/lib/libjulia.dll.a") -else() - set(JULIA_LIB "$ENV{JULIA_PATH}/lib/libjulia.so") -endif() - -set(JULIA_INCLUDE "$ENV{JULIA_PATH}/include/julia") -set(JULIA_FOUND TRUE) - -# verify shared library -if (NOT EXISTS ${JULIA_LIB}) - if (WIN32) - message(WARNING "Cannot find shared library libjulia.dll.a in $ENV{JULIA_PATH}/lib/") - else() - message(WARNING "Cannot find shared library libjulia.so in $ENV{JULIA_PATH}/lib/") - endif() - set(JULIA_FOUND FALSE) -endif() - -# verify header -if (NOT EXISTS ${JULIA_INCLUDE}/julia.h) - message(WARNING "Cannot find library header julia.h in $ENV{JULIA_PATH}/include/julia/") - set(JULIA_FOUND FALSE) -endif() - -if (${JULIA_FOUND}) - message("[LOG] Successfully detected julia image at $ENV{JULIA_PATH}") -else() - message(FATAL_ERROR "Failed to detect julia image. Make sure JULIA_PATH is set correctly and that the julia image is uncompressed and not corrupted.\nFor more information, visit https://github.com/Clemapfel/jluna/blob/master/README.md#troubleshooting") -endif() +# ---- Find Julia ---- -include_directories(${JULIA_INCLUDE}) +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/find") +find_package(Julia REQUIRED) ### JLUNA ### diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake new file mode 100644 index 0000000..c855a82 --- /dev/null +++ b/cmake/find/FindJulia.cmake @@ -0,0 +1,102 @@ +macro(julia_bail_if_false message var) + if(NOT ${var}) + set(Julia_FOUND 0) + set(Julia_NOT_FOUND_MESSAGE "${message}") + return() + endif() +endmacro() + +# https://docs.julialang.org/en/v1/manual/environment-variables/#JULIA_BINDIR +find_program(JULIA_EXECUTABLE julia PATHS ENV JULIA_BINDIR) +julia_bail_if_false("The Julia executable could not be found" JULIA_EXECUTABLE) + +# The executable could be a chocolatey shim, so run some Julia code to report +# the path of the BINDIR +execute_process( + COMMAND "${JULIA_EXECUTABLE}" -e "print(Sys.BINDIR)" + OUTPUT_VARIABLE julia_bindir +) +file(TO_CMAKE_PATH "${julia_bindir}" julia_bindir) +set(JULIA_BINDIR "${julia_bindir}" CACHE PATH "") +julia_bail_if_false("The Julia executable could not report its location" JULIA_BINDIR) + +get_filename_component(julia_prefix "${JULIA_BINDIR}" DIRECTORY) + +if(WIN32) + if(CMAKE_FIND_LIBRARY_SUFFIXES) + set(julia_old_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") + list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .dll.a) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a") + endif() + if(CMAKE_FIND_LIBRARY_PREFIXES) + set(julia_old_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") + list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib) + else() + set(CMAKE_FIND_LIBRARY_PREFIXES ";lib") + endif() +endif() + +find_library(JULIA_LIBRARY julia HINTS "${julia_prefix}/lib") + +if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES "${julia_old_CMAKE_FIND_LIBRARY_SUFFIXES}") + set(CMAKE_FIND_LIBRARY_PREFIXES "${julia_old_CMAKE_FIND_LIBRARY_PREFIXES}") +endif() + +julia_bail_if_false("The Julia library could not be found" JULIA_LIBRARY) + +find_path( + JULIA_INCLUDE_DIR julia.h + HINTS "${julia_prefix}/include" "${julia_prefix}/include/julia" +) +julia_bail_if_false("The Julia header could not be found" JULIA_INCLUDE_DIR) + +file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" julia_version LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) +string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" julia_version "${julia_version}") +set(JULIA_VERSION "${julia_version}" CACHE STRING "Version of Julia") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + Julia + REQUIRED_VARS JULIA_EXECUTABLE JULIA_BINDIR JULIA_LIBRARY JULIA_INCLUDE_DIR + VERSION_VAR JULIA_VERSION +) + +if(NOT TARGET Julia::Julia) + set(julia_has_implib NO) + set(julia_library_type STATIC) + if(JULIA_LIBRARY MATCHES "\\.(so|dylib)$") + set(julia_library_type SHARED) + elseif(JULIA_LIBRARY MATCHES "\\.(lib|dll\\.a)$") + set(julia_library_type UNKNOWN) + find_file( + JULIA_LIBRARY_DLL + NAMES libjulia.dll julia.dll + HINTS "${JULIA_BINDIR}" + ) + if(JULIA_LIBRARY_DLL) + set(julia_has_implib YES) + set(julia_library_type SHARED) + endif() + endif() + + add_library(Julia::Julia "${julia_library_type}" IMPORTED) + set_target_properties( + Julia::Julia PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${JULIA_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES C + ) + if(julia_has_implib) + if(JULIA_LIBRARY AND EXISTS "${JULIA_LIBRARY}") + set_property(TARGET Julia::Julia PROPERTY IMPORTED_IMPLIB "${JULIA_LIBRARY}") + endif() + if(JULIA_LIBRARY_DLL AND EXISTS "${JULIA_LIBRARY_DLL}") + set_property(TARGET Julia::Julia PROPERTY IMPORTED_LOCATION "${JULIA_LIBRARY_DLL}") + endif() + elseif(JULIA_LIBRARY AND EXISTS "${JULIA_LIBRARY}") + set_property(TARGET Julia::Julia PROPERTY IMPORTED_LOCATION "${JULIA_LIBRARY}") + endif() +endif() + +mark_as_advanced(JULIA_EXECUTABLE JULIA_BINDIR JULIA_LIBRARY JULIA_INCLUDE_DIR JULIA_VERSION JULIA_LIBRARY_DLL) From 887744ecdf1b4b75b09b1452a5b297f825d9a016 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 17:49:50 +0100 Subject: [PATCH 02/71] Setup library targets using properties --- CMakeLists.txt | 46 +++++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b0140b..0b53c84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,14 +7,26 @@ project(jluna LANGUAGES CXX) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/find") find_package(Julia REQUIRED) -### JLUNA ### +# ---- Declare C adapter ---- -include_directories(${CMAKE_SOURCE_DIR}) +add_library( + jluna_c_adapter SHARED + .src/c_adapter.hpp + .src/c_adapter.cpp +) + +target_compile_features(jluna_c_adapter PUBLIC cxx_std_20) +target_include_directories(jluna_c_adapter PUBLIC "$") + +# NOTE: Julia::Julia is not present in the install interface. Consumers will +# have to link to julia manually. Julia doesn't have a CMake package. +target_link_libraries(jluna_c_adapter PUBLIC "$") -set(RESOURCE_PATH ${CMAKE_SOURCE_DIR}) -configure_file(${CMAKE_SOURCE_DIR}/.src/include_julia.inl.in ${CMAKE_SOURCE_DIR}/.src/include_julia.inl @ONLY) +# ---- Declare library ---- + +add_library( + jluna SHARED -add_library(jluna SHARED jluna.hpp include/exceptions.hpp @@ -75,31 +87,7 @@ add_library(jluna SHARED include/gc_sentinel.hpp ) -set_target_properties(jluna PROPERTIES - LINKER_LANGUAGE C - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR} -) target_compile_features(jluna PUBLIC cxx_std_20) - -### C ADAPTER ## - -add_library(jluna_c_adapter SHARED - .src/c_adapter.hpp - .src/c_adapter.cpp -) - -target_include_directories(jluna_c_adapter - PUBLIC $ - PUBLIC $ -) - -target_link_libraries(jluna_c_adapter PUBLIC $) - -set_target_properties(jluna_c_adapter PROPERTIES - LINKER_LANGUAGE C - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR} -) - target_link_libraries(jluna PUBLIC jluna_c_adapter) ### EXECUTABLES ### From 6df6448a91acfb81f03afa6c4be44b14fe912690 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 18:02:05 +0100 Subject: [PATCH 03/71] Add a `PROJECT_IS_TOP_LEVEL` polyfill This variable exists in CMake 3.21+ and it's useful for conditionally including code for packaging, testing and other related processes. --- CMakeLists.txt | 2 ++ cmake/project-is-top-level.cmake | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 cmake/project-is-top-level.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b53c84..e2a66a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16) project(jluna LANGUAGES CXX) +include(cmake/project-is-top-level.cmake) + # ---- Find Julia ---- list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/find") diff --git a/cmake/project-is-top-level.cmake b/cmake/project-is-top-level.cmake new file mode 100644 index 0000000..3435fc0 --- /dev/null +++ b/cmake/project-is-top-level.cmake @@ -0,0 +1,6 @@ +# This variable is set by project() in CMake 3.21+ +string( + COMPARE EQUAL + "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}" + PROJECT_IS_TOP_LEVEL +) From 0b8e0bfa8db984ac4b68984a67a83a20e1fbe068 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 18:09:14 +0100 Subject: [PATCH 04/71] Componentize the install rules This commit also adds a version config script. CMake packages are effectively broken without this version script. --- CMakeLists.txt | 36 ++++--------------- cmake/install-config.cmake | 1 + cmake/install-rules.cmake | 74 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 29 deletions(-) create mode 100644 cmake/install-config.cmake create mode 100644 cmake/install-rules.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e2a66a9..0e394ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(jluna LANGUAGES CXX) +project(jluna VERSION 0.0.0 LANGUAGES CXX) include(cmake/project-is-top-level.cmake) @@ -89,9 +89,14 @@ add_library( include/gc_sentinel.hpp ) -target_compile_features(jluna PUBLIC cxx_std_20) target_link_libraries(jluna PUBLIC jluna_c_adapter) +# ---- Install rules ---- + +if(NOT CMAKE_SKIP_INSTALL_RULES) + include(cmake/install-rules.cmake) +endif() + ### EXECUTABLES ### add_executable(JLUNA_TEST @@ -106,30 +111,3 @@ add_executable(JLUNA_BENCHMARK .benchmark/benchmark_aux.hpp ) target_link_libraries(JLUNA_BENCHMARK jluna ${JULIA_LIB}) - -### INSTALL ### - -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/jluna-config.cmake [[ -if (NOT ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL "12.0.0") OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL "10.0.0"))) - message(FATAL_ERROR "Currently, the only supported compilers are G++10, G++11 (recommended) and Clang-12") -endif() -include("${CMAKE_CURRENT_LIST_DIR}/jluna-targets.cmake") -]]) - -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/jluna-config.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jluna -) - -install(TARGETS jluna jluna_c_adapter EXPORT jluna_targets) - -install(EXPORT jluna_targets - FILE jluna-targets.cmake - NAMESPACE jluna:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jluna -) - -install(FILES jluna.hpp ${headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/jluna) -install(DIRECTORY include .src DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/jluna) - -target_include_directories(jluna INTERFACE $) \ No newline at end of file diff --git a/cmake/install-config.cmake b/cmake/install-config.cmake new file mode 100644 index 0000000..4a2dee1 --- /dev/null +++ b/cmake/install-config.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/jluna-targets.cmake") diff --git a/cmake/install-rules.cmake b/cmake/install-rules.cmake new file mode 100644 index 0000000..e3ffa6d --- /dev/null +++ b/cmake/install-rules.cmake @@ -0,0 +1,74 @@ +# find_package() call for consumers to find this project +set(package jluna) + +if(PROJECT_IS_TOP_LEVEL) + set(CMAKE_INSTALL_INCLUDEDIR "include/${package}" CACHE PATH "") +endif() + +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) + +install( + FILES jluna.hpp + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + COMPONENT jluna_Development +) + +install( + DIRECTORY include .src + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + COMPONENT jluna_Development +) + +install( + TARGETS jluna jluna_c_adapter + EXPORT jluna-targets + RUNTIME # + DESTINATION "${CMAKE_INSTALL_BINDIR}" + COMPONENT jluna_Runtime + LIBRARY # + DESTINATION "${CMAKE_INSTALL_LIBDIR}" + COMPONENT jluna_Runtime + NAMELINK_COMPONENT jluna_Development + ARCHIVE # + DESTINATION "${CMAKE_INSTALL_LIBDIR}" + COMPONENT jluna_Development + INCLUDES # + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) + +write_basic_package_version_file( + "${package}-config-version.cmake" + COMPATIBILITY SameMajorVersion +) + +# Allow package maintainers to freely override the path for the configs +set( + jluna_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${package}" + CACHE PATH "CMake package config location relative to the install prefix" +) +mark_as_advanced(jluna_INSTALL_CMAKEDIR) + +install( + FILES cmake/install-config.cmake + DESTINATION "${jluna_INSTALL_CMAKEDIR}" + RENAME "${package}-config.cmake" + COMPONENT jluna_Development +) + +install( + FILES "${PROJECT_BINARY_DIR}/${package}-config-version.cmake" + DESTINATION "${jluna_INSTALL_CMAKEDIR}" + COMPONENT jluna_Development +) + +install( + EXPORT jluna-targets + NAMESPACE jluna:: + DESTINATION "${jluna_INSTALL_CMAKEDIR}" + COMPONENT jluna_Development +) + +if(PROJECT_IS_TOP_LEVEL) + include(CPack) +endif() From 0aaf62e93ef1d494da938761f51ea6bf4cbcc68a Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 18:16:16 +0100 Subject: [PATCH 05/71] Put developer mode code behind an opt-in variable Opt-in developer mode allows consumers to only build the library targets they are *actually* interested in. Consumers couldn't care less about test and benchmark targets, those are only useful for the developer(s) while developing or in CI. --- CMakeLists.txt | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e394ca..15bb1b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.16) project(jluna VERSION 0.0.0 LANGUAGES CXX) include(cmake/project-is-top-level.cmake) +if(PROJECT_IS_TOP_LEVEL) + option(jluna_DEVELOPER_MODE "Enable developer mode" OFF) +endif() # ---- Find Julia ---- @@ -97,17 +100,35 @@ if(NOT CMAKE_SKIP_INSTALL_RULES) include(cmake/install-rules.cmake) endif() -### EXECUTABLES ### +# ---- Developer mode ---- -add_executable(JLUNA_TEST - .test/main.cpp - .test/test.hpp -) -target_link_libraries(JLUNA_TEST jluna ${JULIA_LIB}) +if(NOT jluna_DEVELOPER_MODE) + return() +elseif(NOT PROJECT_IS_TOP_LEVEL) + message( + AUTHOR_WARNING + "Developer mode is intended for developers of jluna" + ) +endif() -add_executable(JLUNA_BENCHMARK - .benchmark/main.cpp - .benchmark/benchmark.hpp - .benchmark/benchmark_aux.hpp -) -target_link_libraries(JLUNA_BENCHMARK jluna ${JULIA_LIB}) +include(CTest) +if(BUILD_TESTING) + add_executable( + jluna_test + .test/main.cpp + .test/test.hpp + ) + target_link_libraries(jluna_test PRIVATE jluna) + add_test(NAME jluna_test COMMAND jluna_test) +endif() + +option(BUILD_BENCHMARK "" ON) +if(BUILD_BENCHMARK) + add_executable( + jluna_benchmark + .benchmark/main.cpp + .benchmark/benchmark.hpp + .benchmark/benchmark_aux.hpp + ) + target_link_libraries(jluna_benchmark PRIVATE jluna) +endif() From e62997896d3563514a7fac190040cc956ccd66a8 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 18:18:05 +0100 Subject: [PATCH 06/71] Set minimum CMake to 3.12 based on features used C++20 support was added in CMake 3.12. No other feature used requires a newer CMake version. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15bb1b6..53c5f75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.12) project(jluna VERSION 0.0.0 LANGUAGES CXX) From e9f4b6414c14bbb30c937776891286e3008f5353 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 20:08:12 +0100 Subject: [PATCH 07/71] Configure `include_julia.inl` This file contains an absolute path to the project directory, which makes it not relocatable. This should be fixed later. --- CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53c5f75..c2c2e65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,14 @@ endif() list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/find") find_package(Julia REQUIRED) +# ---- Resource path include ---- + +# FIXME: This is pointing at the project directory, this obviously will not +# work after install. Figure out how to make this work as a relocatable +# CMake package with paths being relative to the prefix. +set(RESOURCE_PATH "${PROJECT_SOURCE_DIR}") +configure_file(.src/include_julia.inl.in .src/include_julia.inl @ONLY) + # ---- Declare C adapter ---- add_library( @@ -93,6 +101,7 @@ add_library( ) target_link_libraries(jluna PUBLIC jluna_c_adapter) +target_include_directories(jluna PRIVATE "$") # ---- Install rules ---- From c69c6672b8d1dffa4581242b614baf4f77e23322 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 20:11:17 +0100 Subject: [PATCH 08/71] Fix Windows compatibility The julia.h header includes headers that aren't standalone and work only through Windows.h, so the julia_wrapper.hpp header wraps the julia.h include. There was a reinterpret_cast from size_t to size_t. (???) Changed that to static_cast. --- .src/c_adapter.cpp | 2 +- .src/c_adapter.hpp | 2 +- .src/state.cpp | 6 +++--- .test/main.cpp | 2 +- CMakeLists.txt | 10 ++++++++-- include/box.hpp | 2 +- include/concepts.hpp | 2 +- include/cppcall.hpp | 2 +- include/exceptions.hpp | 2 +- include/gc_sentinel.hpp | 2 +- include/julia_extension.hpp | 2 +- include/julia_wrapper.hpp | 12 ++++++++++++ include/module.hpp | 2 +- include/proxy.hpp | 2 +- include/symbol.hpp | 2 +- include/type.hpp | 2 +- include/typedefs.hpp | 2 +- include/unbox.hpp | 2 +- include/usertype.hpp | 2 +- 19 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 include/julia_wrapper.hpp diff --git a/.src/c_adapter.cpp b/.src/c_adapter.cpp index 6861f6a..cad0106 100644 --- a/.src/c_adapter.cpp +++ b/.src/c_adapter.cpp @@ -1,6 +1,6 @@ #ifdef __cplusplus -#include +#include #include diff --git a/.src/c_adapter.hpp b/.src/c_adapter.hpp index 65b1138..261f933 100644 --- a/.src/c_adapter.hpp +++ b/.src/c_adapter.hpp @@ -10,7 +10,7 @@ #ifdef __cplusplus #include -#include +#include #include #include diff --git a/.src/state.cpp b/.src/state.cpp index 080e804..2e0c54f 100644 --- a/.src/state.cpp +++ b/.src/state.cpp @@ -3,7 +3,7 @@ // Created on 31.01.22 by clem (mail@clemens-cords.com) // -#include +#include #include #include @@ -214,7 +214,7 @@ namespace jluna::State::detail Any * get_reference(size_t key) { static Function* get_reference = jl_find_function("jluna.memory_handler", "get_reference"); - return jluna::safe_call(get_reference, jl_box_uint64(reinterpret_cast(key))); + return jluna::safe_call(get_reference, jl_box_uint64(static_cast(key))); } void free_reference(size_t key) @@ -226,7 +226,7 @@ namespace jluna::State::detail static Function* free_reference = jl_find_function("jluna.memory_handler", "free_reference"); jl_gc_pause; - jluna::safe_call(free_reference, jl_box_uint64(reinterpret_cast(key))); + jluna::safe_call(free_reference, jl_box_uint64(static_cast(key))); jl_gc_unpause; } diff --git a/.test/main.cpp b/.test/main.cpp index 754e5c3..2d28c99 100644 --- a/.test/main.cpp +++ b/.test/main.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include <.test/test.hpp> diff --git a/CMakeLists.txt b/CMakeLists.txt index c2c2e65..e560e83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,12 @@ add_library( target_link_libraries(jluna PUBLIC jluna_c_adapter) target_include_directories(jluna PRIVATE "$") +# ---- HACK: export all symbols on Windows ---- + +# FIXME: Exporting all symbols is bad practice. Fix this using the +# GenerateExportHeader CMake module and visibility proprties. +set_target_properties(jluna jluna_c_adapter PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS YES) + # ---- Install rules ---- if(NOT CMAKE_SKIP_INSTALL_RULES) @@ -121,7 +127,7 @@ elseif(NOT PROJECT_IS_TOP_LEVEL) endif() include(CTest) -if(BUILD_TESTING) +if(BUILD_TESTING AND NOT WIN32) add_executable( jluna_test .test/main.cpp @@ -132,7 +138,7 @@ if(BUILD_TESTING) endif() option(BUILD_BENCHMARK "" ON) -if(BUILD_BENCHMARK) +if(BUILD_BENCHMARK AND NOT WIN32) add_executable( jluna_benchmark .benchmark/main.cpp diff --git a/include/box.hpp b/include/box.hpp index be4ee3d..9d600e4 100644 --- a/include/box.hpp +++ b/include/box.hpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include diff --git a/include/concepts.hpp b/include/concepts.hpp index 78f3514..7244593 100644 --- a/include/concepts.hpp +++ b/include/concepts.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include #include diff --git a/include/cppcall.hpp b/include/cppcall.hpp index b34a5ae..1a9a549 100644 --- a/include/cppcall.hpp +++ b/include/cppcall.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include diff --git a/include/exceptions.hpp b/include/exceptions.hpp index 610197a..b20ac85 100644 --- a/include/exceptions.hpp +++ b/include/exceptions.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include diff --git a/include/gc_sentinel.hpp b/include/gc_sentinel.hpp index a040c18..e1aba71 100644 --- a/include/gc_sentinel.hpp +++ b/include/gc_sentinel.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include namespace jluna { diff --git a/include/julia_extension.hpp b/include/julia_extension.hpp index 67acfcd..d1720c9 100644 --- a/include/julia_extension.hpp +++ b/include/julia_extension.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include diff --git a/include/julia_wrapper.hpp b/include/julia_wrapper.hpp new file mode 100644 index 0000000..0202515 --- /dev/null +++ b/include/julia_wrapper.hpp @@ -0,0 +1,12 @@ +#pragma once + +#ifdef _WIN32 +/* julia.h includes Windows headers that are not self contained, so this + * wrapper header includes Windows.h before includeing julia.h, so everything + * is setup for the other headers to actually work */ +# define NOMINMAX +# define WIN32_LEAN_AND_MEAN +# include +#endif + +#include diff --git a/include/module.hpp b/include/module.hpp index d686560..438c4b2 100644 --- a/include/module.hpp +++ b/include/module.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include diff --git a/include/proxy.hpp b/include/proxy.hpp index d37e938..97e9f20 100644 --- a/include/proxy.hpp +++ b/include/proxy.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include diff --git a/include/symbol.hpp b/include/symbol.hpp index a394ef1..4b71f98 100644 --- a/include/symbol.hpp +++ b/include/symbol.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include namespace jluna diff --git a/include/type.hpp b/include/type.hpp index 628209b..00081fa 100644 --- a/include/type.hpp +++ b/include/type.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include #include diff --git a/include/typedefs.hpp b/include/typedefs.hpp index 2b1382c..514e7d2 100644 --- a/include/typedefs.hpp +++ b/include/typedefs.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include ".src/typedefs.inl" namespace jluna diff --git a/include/unbox.hpp b/include/unbox.hpp index beccc84..0217b5f 100644 --- a/include/unbox.hpp +++ b/include/unbox.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include diff --git a/include/usertype.hpp b/include/usertype.hpp index 9d34edd..35d0b5e 100644 --- a/include/usertype.hpp +++ b/include/usertype.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include From ee4892b8b538df236440f5d2a98361ccc22ee84a Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 23:17:57 +0100 Subject: [PATCH 09/71] Remove use of undeclared backup variables Make sure the julia_old_* variables are always present, so undeclared variable use errors are avoided. --- cmake/find/FindJulia.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index c855a82..cbd880d 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -23,6 +23,8 @@ julia_bail_if_false("The Julia executable could not report its location" JULIA_B get_filename_component(julia_prefix "${JULIA_BINDIR}" DIRECTORY) if(WIN32) + set(julia_old_CMAKE_FIND_LIBRARY_SUFFIXES "") + set(julia_old_CMAKE_FIND_LIBRARY_PREFIXES "") if(CMAKE_FIND_LIBRARY_SUFFIXES) set(julia_old_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .dll.a) From 4a41f5a259e92bfa2bd4589fdd6cbdeb9f5f7658 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Mon, 14 Mar 2022 23:28:27 +0100 Subject: [PATCH 10/71] Make FPHSA print the library when Julia is found FPHSA prints the first required variable's content when configuring. Printing the executable's path prints the Chocolatey shim's path on Windows if Julia is installed using Chocolatey, which I find to be less useful than printing the library, something that's part of the actual Julia installation. --- cmake/find/FindJulia.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index cbd880d..ae45bb8 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -61,7 +61,7 @@ set(JULIA_VERSION "${julia_version}" CACHE STRING "Version of Julia") include(FindPackageHandleStandardArgs) find_package_handle_standard_args( Julia - REQUIRED_VARS JULIA_EXECUTABLE JULIA_BINDIR JULIA_LIBRARY JULIA_INCLUDE_DIR + REQUIRED_VARS JULIA_LIBRARY JULIA_EXECUTABLE JULIA_BINDIR JULIA_INCLUDE_DIR VERSION_VAR JULIA_VERSION ) From 75035572bd4985f5b887574c40562cf6977c6ea0 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Tue, 15 Mar 2022 01:16:02 +0100 Subject: [PATCH 11/71] Run the julia executable only when necessary The julia executable does not need to be executed when the JULIA_BINDIR variable is defined. This commit avoids running the bindir extraction code on every configure. --- cmake/find/FindJulia.cmake | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index ae45bb8..67e080a 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -10,14 +10,16 @@ endmacro() find_program(JULIA_EXECUTABLE julia PATHS ENV JULIA_BINDIR) julia_bail_if_false("The Julia executable could not be found" JULIA_EXECUTABLE) -# The executable could be a chocolatey shim, so run some Julia code to report -# the path of the BINDIR -execute_process( - COMMAND "${JULIA_EXECUTABLE}" -e "print(Sys.BINDIR)" - OUTPUT_VARIABLE julia_bindir -) -file(TO_CMAKE_PATH "${julia_bindir}" julia_bindir) -set(JULIA_BINDIR "${julia_bindir}" CACHE PATH "") +if(NOT DEFINED JULIA_BINDIR) + # The executable could be a chocolatey shim, so run some Julia code to report + # the path of the BINDIR + execute_process( + COMMAND "${JULIA_EXECUTABLE}" -e "print(Sys.BINDIR)" + OUTPUT_VARIABLE julia_bindir + ) + file(TO_CMAKE_PATH "${julia_bindir}" julia_bindir) + set(JULIA_BINDIR "${julia_bindir}" CACHE PATH "") +endif() julia_bail_if_false("The Julia executable could not report its location" JULIA_BINDIR) get_filename_component(julia_prefix "${JULIA_BINDIR}" DIRECTORY) From 173eec9ed5873dd0369b84cf803d156bb1fc807e Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Tue, 15 Mar 2022 14:40:11 +0100 Subject: [PATCH 12/71] Prevent reading the version on every ceonfigure This commit is similar to 75035572bd4985f5b887574c40562cf6977c6ea0 in that it prevents unnecessary work, but this commit prevents reading the version header when the version is already set in the cache. --- cmake/find/FindJulia.cmake | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index 67e080a..e7ff427 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -56,9 +56,11 @@ find_path( ) julia_bail_if_false("The Julia header could not be found" JULIA_INCLUDE_DIR) -file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" julia_version LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) -string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" julia_version "${julia_version}") -set(JULIA_VERSION "${julia_version}" CACHE STRING "Version of Julia") +if(NOT DEFINED JULIA_VERSION) + file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" julia_version LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) + string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" julia_version "${julia_version}") + set(JULIA_VERSION "${julia_version}" CACHE STRING "Version of Julia") +endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( From 10e63e10478582449ce115277c07a23e05087489 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Wed, 16 Mar 2022 13:46:06 +0100 Subject: [PATCH 13/71] Specify the version requirement for Julia in CMake According to the README, this project requires at least 1.7, so pass that to the find_package() call for early diagnostics. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e560e83..d5a520f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ endif() # ---- Find Julia ---- list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/find") -find_package(Julia REQUIRED) +find_package(Julia 1.7 REQUIRED) # ---- Resource path include ---- From 65fd3e892f2a309fee23b83501e80afcf7c07952 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Wed, 16 Mar 2022 20:47:09 +0100 Subject: [PATCH 14/71] Use 4 space indentation in CMake code --- CMakeLists.txt | 42 ++++++------- cmake/find/FindJulia.cmake | 124 ++++++++++++++++++------------------- cmake/install-rules.cmake | 4 +- 3 files changed, 85 insertions(+), 85 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5a520f..ce17f32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(jluna VERSION 0.0.0 LANGUAGES CXX) include(cmake/project-is-top-level.cmake) if(PROJECT_IS_TOP_LEVEL) - option(jluna_DEVELOPER_MODE "Enable developer mode" OFF) + option(jluna_DEVELOPER_MODE "Enable developer mode" OFF) endif() # ---- Find Julia ---- @@ -112,38 +112,38 @@ set_target_properties(jluna jluna_c_adapter PROPERTIES WINDOWS_EXPORT_ALL_SYMBOL # ---- Install rules ---- if(NOT CMAKE_SKIP_INSTALL_RULES) - include(cmake/install-rules.cmake) + include(cmake/install-rules.cmake) endif() # ---- Developer mode ---- if(NOT jluna_DEVELOPER_MODE) - return() + return() elseif(NOT PROJECT_IS_TOP_LEVEL) - message( - AUTHOR_WARNING - "Developer mode is intended for developers of jluna" - ) + message( + AUTHOR_WARNING + "Developer mode is intended for developers of jluna" + ) endif() include(CTest) if(BUILD_TESTING AND NOT WIN32) - add_executable( - jluna_test - .test/main.cpp - .test/test.hpp - ) - target_link_libraries(jluna_test PRIVATE jluna) - add_test(NAME jluna_test COMMAND jluna_test) + add_executable( + jluna_test + .test/main.cpp + .test/test.hpp + ) + target_link_libraries(jluna_test PRIVATE jluna) + add_test(NAME jluna_test COMMAND jluna_test) endif() option(BUILD_BENCHMARK "" ON) if(BUILD_BENCHMARK AND NOT WIN32) - add_executable( - jluna_benchmark - .benchmark/main.cpp - .benchmark/benchmark.hpp - .benchmark/benchmark_aux.hpp - ) - target_link_libraries(jluna_benchmark PRIVATE jluna) + add_executable( + jluna_benchmark + .benchmark/main.cpp + .benchmark/benchmark.hpp + .benchmark/benchmark_aux.hpp + ) + target_link_libraries(jluna_benchmark PRIVATE jluna) endif() diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index e7ff427..09cd3c2 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -1,9 +1,9 @@ macro(julia_bail_if_false message var) - if(NOT ${var}) - set(Julia_FOUND 0) - set(Julia_NOT_FOUND_MESSAGE "${message}") - return() - endif() + if(NOT ${var}) + set(Julia_FOUND 0) + set(Julia_NOT_FOUND_MESSAGE "${message}") + return() + endif() endmacro() # https://docs.julialang.org/en/v1/manual/environment-variables/#JULIA_BINDIR @@ -11,41 +11,41 @@ find_program(JULIA_EXECUTABLE julia PATHS ENV JULIA_BINDIR) julia_bail_if_false("The Julia executable could not be found" JULIA_EXECUTABLE) if(NOT DEFINED JULIA_BINDIR) - # The executable could be a chocolatey shim, so run some Julia code to report - # the path of the BINDIR - execute_process( - COMMAND "${JULIA_EXECUTABLE}" -e "print(Sys.BINDIR)" - OUTPUT_VARIABLE julia_bindir - ) - file(TO_CMAKE_PATH "${julia_bindir}" julia_bindir) - set(JULIA_BINDIR "${julia_bindir}" CACHE PATH "") + # The executable could be a chocolatey shim, so run some Julia code to report + # the path of the BINDIR + execute_process( + COMMAND "${JULIA_EXECUTABLE}" -e "print(Sys.BINDIR)" + OUTPUT_VARIABLE julia_bindir + ) + file(TO_CMAKE_PATH "${julia_bindir}" julia_bindir) + set(JULIA_BINDIR "${julia_bindir}" CACHE PATH "") endif() julia_bail_if_false("The Julia executable could not report its location" JULIA_BINDIR) get_filename_component(julia_prefix "${JULIA_BINDIR}" DIRECTORY) if(WIN32) - set(julia_old_CMAKE_FIND_LIBRARY_SUFFIXES "") - set(julia_old_CMAKE_FIND_LIBRARY_PREFIXES "") - if(CMAKE_FIND_LIBRARY_SUFFIXES) - set(julia_old_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") - list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .dll.a) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a") - endif() - if(CMAKE_FIND_LIBRARY_PREFIXES) - set(julia_old_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") - list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib) - else() - set(CMAKE_FIND_LIBRARY_PREFIXES ";lib") - endif() + set(julia_old_CMAKE_FIND_LIBRARY_SUFFIXES "") + set(julia_old_CMAKE_FIND_LIBRARY_PREFIXES "") + if(CMAKE_FIND_LIBRARY_SUFFIXES) + set(julia_old_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") + list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .dll.a) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a") + endif() + if(CMAKE_FIND_LIBRARY_PREFIXES) + set(julia_old_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") + list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib) + else() + set(CMAKE_FIND_LIBRARY_PREFIXES ";lib") + endif() endif() find_library(JULIA_LIBRARY julia HINTS "${julia_prefix}/lib") if(WIN32) - set(CMAKE_FIND_LIBRARY_SUFFIXES "${julia_old_CMAKE_FIND_LIBRARY_SUFFIXES}") - set(CMAKE_FIND_LIBRARY_PREFIXES "${julia_old_CMAKE_FIND_LIBRARY_PREFIXES}") + set(CMAKE_FIND_LIBRARY_SUFFIXES "${julia_old_CMAKE_FIND_LIBRARY_SUFFIXES}") + set(CMAKE_FIND_LIBRARY_PREFIXES "${julia_old_CMAKE_FIND_LIBRARY_PREFIXES}") endif() julia_bail_if_false("The Julia library could not be found" JULIA_LIBRARY) @@ -57,9 +57,9 @@ find_path( julia_bail_if_false("The Julia header could not be found" JULIA_INCLUDE_DIR) if(NOT DEFINED JULIA_VERSION) - file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" julia_version LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) - string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" julia_version "${julia_version}") - set(JULIA_VERSION "${julia_version}" CACHE STRING "Version of Julia") + file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" julia_version LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) + string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" julia_version "${julia_version}") + set(JULIA_VERSION "${julia_version}" CACHE STRING "Version of Julia") endif() include(FindPackageHandleStandardArgs) @@ -70,39 +70,39 @@ find_package_handle_standard_args( ) if(NOT TARGET Julia::Julia) - set(julia_has_implib NO) - set(julia_library_type STATIC) - if(JULIA_LIBRARY MATCHES "\\.(so|dylib)$") - set(julia_library_type SHARED) - elseif(JULIA_LIBRARY MATCHES "\\.(lib|dll\\.a)$") - set(julia_library_type UNKNOWN) - find_file( - JULIA_LIBRARY_DLL - NAMES libjulia.dll julia.dll - HINTS "${JULIA_BINDIR}" - ) - if(JULIA_LIBRARY_DLL) - set(julia_has_implib YES) - set(julia_library_type SHARED) + set(julia_has_implib NO) + set(julia_library_type STATIC) + if(JULIA_LIBRARY MATCHES "\\.(so|dylib)$") + set(julia_library_type SHARED) + elseif(JULIA_LIBRARY MATCHES "\\.(lib|dll\\.a)$") + set(julia_library_type UNKNOWN) + find_file( + JULIA_LIBRARY_DLL + NAMES libjulia.dll julia.dll + HINTS "${JULIA_BINDIR}" + ) + if(JULIA_LIBRARY_DLL) + set(julia_has_implib YES) + set(julia_library_type SHARED) + endif() endif() - endif() - add_library(Julia::Julia "${julia_library_type}" IMPORTED) - set_target_properties( - Julia::Julia PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${JULIA_INCLUDE_DIR}" - IMPORTED_LINK_INTERFACE_LANGUAGES C - ) - if(julia_has_implib) - if(JULIA_LIBRARY AND EXISTS "${JULIA_LIBRARY}") - set_property(TARGET Julia::Julia PROPERTY IMPORTED_IMPLIB "${JULIA_LIBRARY}") - endif() - if(JULIA_LIBRARY_DLL AND EXISTS "${JULIA_LIBRARY_DLL}") - set_property(TARGET Julia::Julia PROPERTY IMPORTED_LOCATION "${JULIA_LIBRARY_DLL}") + add_library(Julia::Julia "${julia_library_type}" IMPORTED) + set_target_properties( + Julia::Julia PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${JULIA_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES C + ) + if(julia_has_implib) + if(JULIA_LIBRARY AND EXISTS "${JULIA_LIBRARY}") + set_property(TARGET Julia::Julia PROPERTY IMPORTED_IMPLIB "${JULIA_LIBRARY}") + endif() + if(JULIA_LIBRARY_DLL AND EXISTS "${JULIA_LIBRARY_DLL}") + set_property(TARGET Julia::Julia PROPERTY IMPORTED_LOCATION "${JULIA_LIBRARY_DLL}") + endif() + elseif(JULIA_LIBRARY AND EXISTS "${JULIA_LIBRARY}") + set_property(TARGET Julia::Julia PROPERTY IMPORTED_LOCATION "${JULIA_LIBRARY}") endif() - elseif(JULIA_LIBRARY AND EXISTS "${JULIA_LIBRARY}") - set_property(TARGET Julia::Julia PROPERTY IMPORTED_LOCATION "${JULIA_LIBRARY}") - endif() endif() mark_as_advanced(JULIA_EXECUTABLE JULIA_BINDIR JULIA_LIBRARY JULIA_INCLUDE_DIR JULIA_VERSION JULIA_LIBRARY_DLL) diff --git a/cmake/install-rules.cmake b/cmake/install-rules.cmake index e3ffa6d..7325226 100644 --- a/cmake/install-rules.cmake +++ b/cmake/install-rules.cmake @@ -2,7 +2,7 @@ set(package jluna) if(PROJECT_IS_TOP_LEVEL) - set(CMAKE_INSTALL_INCLUDEDIR "include/${package}" CACHE PATH "") + set(CMAKE_INSTALL_INCLUDEDIR "include/${package}" CACHE PATH "") endif() include(CMakePackageConfigHelpers) @@ -70,5 +70,5 @@ install( ) if(PROJECT_IS_TOP_LEVEL) - include(CPack) + include(CPack) endif() From aee8cc281390dbf96ec0f6b83111dd060e28b225 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Wed, 16 Mar 2022 20:50:05 +0100 Subject: [PATCH 15/71] Fix the comment style in `julia_wrapper.hpp` --- include/julia_wrapper.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/julia_wrapper.hpp b/include/julia_wrapper.hpp index 0202515..4f2acf1 100644 --- a/include/julia_wrapper.hpp +++ b/include/julia_wrapper.hpp @@ -1,9 +1,9 @@ #pragma once #ifdef _WIN32 -/* julia.h includes Windows headers that are not self contained, so this - * wrapper header includes Windows.h before includeing julia.h, so everything - * is setup for the other headers to actually work */ +// julia.h includes Windows headers that are not self contained. This wrapper +// header includes Windows.h before including julia.h, so everything is setup +// for the other headers to actually work. # define NOMINMAX # define WIN32_LEAN_AND_MEAN # include From 36dc53497695c092b8fda4df973b906c64c88cdc Mon Sep 17 00:00:00 2001 From: Clem Cords Date: Wed, 16 Mar 2022 22:02:46 +0100 Subject: [PATCH 16/71] update error message --- cmake/find/FindJulia.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index 09cd3c2..ee08dfc 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -54,7 +54,7 @@ find_path( JULIA_INCLUDE_DIR julia.h HINTS "${julia_prefix}/include" "${julia_prefix}/include/julia" ) -julia_bail_if_false("The Julia header could not be found" JULIA_INCLUDE_DIR) +julia_bail_if_false("Cannot find julia.h. Make sure JULIA_BINDIR is set correctly and that your image is uncompressed.\nFor more information, visit https://github.com/Clemapfel/jluna/blob/master/docs/installation.md" JULIA_INCLUDE_DIR) if(NOT DEFINED JULIA_VERSION) file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" julia_version LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) From 6dc19192fede5dbe0f92ecad69444bb338d3160a Mon Sep 17 00:00:00 2001 From: Clem Cords Date: Wed, 16 Mar 2022 22:03:41 +0100 Subject: [PATCH 17/71] update version --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce17f32..55bc4f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.12) -project(jluna VERSION 0.0.0 LANGUAGES CXX) +project(jluna VERSION 0.8.4 LANGUAGES CXX) include(cmake/project-is-top-level.cmake) if(PROJECT_IS_TOP_LEVEL) From 7341c0153c9db55d6901ba6c29ffeb817ee32ff9 Mon Sep 17 00:00:00 2001 From: clem Date: Wed, 16 Mar 2022 22:41:01 +0100 Subject: [PATCH 18/71] working --- CMakeLists.txt | 22 +++++++++------------- cmake/find/FindJulia.cmake | 31 +++++++++++++++---------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 55bc4f9..1b661a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,13 +4,13 @@ project(jluna VERSION 0.8.4 LANGUAGES CXX) include(cmake/project-is-top-level.cmake) if(PROJECT_IS_TOP_LEVEL) - option(jluna_DEVELOPER_MODE "Enable developer mode" OFF) + option(DEVELOPER_MODE "Enable developer mode" OFF) endif() # ---- Find Julia ---- list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/find") -find_package(Julia 1.7 REQUIRED) +find_package(Julia 1.7.0 REQUIRED) # ---- Resource path include ---- @@ -30,15 +30,11 @@ add_library( target_compile_features(jluna_c_adapter PUBLIC cxx_std_20) target_include_directories(jluna_c_adapter PUBLIC "$") - -# NOTE: Julia::Julia is not present in the install interface. Consumers will -# have to link to julia manually. Julia doesn't have a CMake package. target_link_libraries(jluna_c_adapter PUBLIC "$") # ---- Declare library ---- -add_library( - jluna SHARED +add_library(jluna SHARED jluna.hpp @@ -107,7 +103,10 @@ target_include_directories(jluna PRIVATE "$ Date: Wed, 16 Mar 2022 23:07:19 +0100 Subject: [PATCH 19/71] reworking c adapter location --- .src/include_julia.inl.in | 4 ++-- .src/state.cpp | 1 - CMakeLists.txt | 8 ++++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.src/include_julia.inl.in b/.src/include_julia.inl.in index 65d5fa2..b133b52 100644 --- a/.src/include_julia.inl.in +++ b/.src/include_julia.inl.in @@ -5,12 +5,12 @@ #pragma once -#cmakedefine RESOURCE_PATH "@RESOURCE_PATH@" +#cmakedefine C_ADAPTER_PATH "@C_ADAPTER_PATH@" namespace jluna::detail { ///@brief allow julia to load jluna by using C++ #import statement static inline const char* include = R"( - include("@RESOURCE_PATH@/include/jluna.jl") + @JULIA_SOURCE@ )"; } \ No newline at end of file diff --git a/.src/state.cpp b/.src/state.cpp index 2e0c54f..df31940 100644 --- a/.src/state.cpp +++ b/.src/state.cpp @@ -17,7 +17,6 @@ #include #include - namespace jluna::detail { static void on_exit() diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b661a0..2c72d3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,8 +17,9 @@ find_package(Julia 1.7.0 REQUIRED) # FIXME: This is pointing at the project directory, this obviously will not # work after install. Figure out how to make this work as a relocatable # CMake package with paths being relative to the prefix. -set(RESOURCE_PATH "${PROJECT_SOURCE_DIR}") -configure_file(.src/include_julia.inl.in .src/include_julia.inl @ONLY) +set(C_ADAPTER_PATH "${CMAKE_INSTALL_PREFIX}") +file(READ include/jluna.jl JULIA_SOURCE) +configure_file("${CMAKE_SOURCE_DIR}/.src/include_julia.inl.in" "${CMAKE_SOURCE_DIR}/.src/include_julia.inl" @ONLY) # ---- Declare C adapter ---- @@ -31,6 +32,9 @@ add_library( target_compile_features(jluna_c_adapter PUBLIC cxx_std_20) target_include_directories(jluna_c_adapter PUBLIC "$") target_link_libraries(jluna_c_adapter PUBLIC "$") +set_target_properties(jluna_c_adapter PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${C_ADAPTER_PATH} +) # ---- Declare library ---- From e9589fb865a2be9426728726f5fb6296620aad4b Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 00:43:36 +0100 Subject: [PATCH 20/71] working --- .src/include_julia.inl.in | 6 +++--- .src/state.cpp | 8 +++++--- CMakeLists.txt | 11 +++++++---- include/jluna.jl | 4 ++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.src/include_julia.inl.in b/.src/include_julia.inl.in index b133b52..e2ffacc 100644 --- a/.src/include_julia.inl.in +++ b/.src/include_julia.inl.in @@ -5,12 +5,12 @@ #pragma once -#cmakedefine C_ADAPTER_PATH "@C_ADAPTER_PATH@" - namespace jluna::detail { - ///@brief allow julia to load jluna by using C++ #import statement + static inline const char* c_adapter_path = "@C_ADAPTER_PATH@"; + static inline const char* include = R"( @JULIA_SOURCE@ )"; + } \ No newline at end of file diff --git a/.src/state.cpp b/.src/state.cpp index df31940..7fbe8a6 100644 --- a/.src/state.cpp +++ b/.src/state.cpp @@ -13,9 +13,9 @@ #include #include #include -#include <.src/include_julia.inl> #include #include +#include "include_julia.inl" namespace jluna::detail { @@ -44,7 +44,6 @@ namespace jluna::State jl_eval_string(jluna::detail::include); forward_last_exception(); - jl_eval_string(R"( begin local version = tryparse(Float32, SubString(string(VERSION), 1, 3)) @@ -56,7 +55,10 @@ namespace jluna::State )"); forward_last_exception(); - jl_eval_string(("jluna._cppcall.eval(:(_library_name = \"" + std::string(RESOURCE_PATH) + "/libjluna_c_adapter.so\"))").c_str()); + std::stringstream str; + str << "jluna._cppcall.eval(:(_library_name = \"" << jluna::detail::c_adapter_path << "/libjluna_c_adapter.so\"))"; + + jl_eval_string(str.str().c_str()); forward_last_exception(); jl_eval_string(R"( diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c72d3a..35a2e53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,8 +17,8 @@ find_package(Julia 1.7.0 REQUIRED) # FIXME: This is pointing at the project directory, this obviously will not # work after install. Figure out how to make this work as a relocatable # CMake package with paths being relative to the prefix. -set(C_ADAPTER_PATH "${CMAKE_INSTALL_PREFIX}") file(READ include/jluna.jl JULIA_SOURCE) +set(C_ADAPTER_PATH ${CMAKE_INSTALL_PREFIX}) configure_file("${CMAKE_SOURCE_DIR}/.src/include_julia.inl.in" "${CMAKE_SOURCE_DIR}/.src/include_julia.inl" @ONLY) # ---- Declare C adapter ---- @@ -30,12 +30,15 @@ add_library( ) target_compile_features(jluna_c_adapter PUBLIC cxx_std_20) -target_include_directories(jluna_c_adapter PUBLIC "$") +target_include_directories(jluna_c_adapter PUBLIC "$") target_link_libraries(jluna_c_adapter PUBLIC "$") + set_target_properties(jluna_c_adapter PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${C_ADAPTER_PATH} ) +message("[LOG] writing libjluna_c_adapter to globally available directory \"${C_ADAPTER_PATH}\"") + # ---- Declare library ---- add_library(jluna SHARED @@ -101,13 +104,13 @@ add_library(jluna SHARED ) target_link_libraries(jluna PUBLIC jluna_c_adapter) -target_include_directories(jluna PRIVATE "$") +target_include_directories(jluna PRIVATE "$") # ---- HACK: export all symbols on Windows ---- # FIXME: Exporting all symbols is bad practice. Fix this using the # GenerateExportHeader CMake module and visibility proprties. -set_target_properties(jluna jluna_c_adapter PROPERTIES +set_target_properties(jluna PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS YES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR} ) diff --git a/include/jluna.jl b/include/jluna.jl index 6fa101f..15565f4 100644 --- a/include/jluna.jl +++ b/include/jluna.jl @@ -707,7 +707,7 @@ module jluna println("jluna.memory_handler._refs: "); for e in _refs[] - println("\t", Int64(e.first), " => ", e.second[], " (", typeof(e.second[]), ")") + println("\t", Int64(e.first), " => ", e.second[], " (", typeof(e.second[]), ") ") end end @@ -809,7 +809,7 @@ module jluna State() = new((), nothing) end - _library_name = "" + _library_name = "" _state = Base.Ref{_cppcall.State}(State()) """ From 27d924a0dc2bab1b6f2e51f76354bef6710caaa9 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 16:36:44 +0100 Subject: [PATCH 21/71] changed installation directory --- CMakeLists.txt | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 35a2e53..78e9334 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,26 +2,30 @@ cmake_minimum_required(VERSION 3.12) project(jluna VERSION 0.8.4 LANGUAGES CXX) +# ### +# +# +# +# + + include(cmake/project-is-top-level.cmake) if(PROJECT_IS_TOP_LEVEL) option(DEVELOPER_MODE "Enable developer mode" OFF) endif() -# ---- Find Julia ---- +### Find Julia ### list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/find") find_package(Julia 1.7.0 REQUIRED) -# ---- Resource path include ---- +### Configure Files ### -# FIXME: This is pointing at the project directory, this obviously will not -# work after install. Figure out how to make this work as a relocatable -# CMake package with paths being relative to the prefix. file(READ include/jluna.jl JULIA_SOURCE) set(C_ADAPTER_PATH ${CMAKE_INSTALL_PREFIX}) configure_file("${CMAKE_SOURCE_DIR}/.src/include_julia.inl.in" "${CMAKE_SOURCE_DIR}/.src/include_julia.inl" @ONLY) -# ---- Declare C adapter ---- +### Declare C adapter ### add_library( jluna_c_adapter SHARED @@ -33,13 +37,9 @@ target_compile_features(jluna_c_adapter PUBLIC cxx_std_20) target_include_directories(jluna_c_adapter PUBLIC "$") target_link_libraries(jluna_c_adapter PUBLIC "$") -set_target_properties(jluna_c_adapter PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${C_ADAPTER_PATH} -) - message("[LOG] writing libjluna_c_adapter to globally available directory \"${C_ADAPTER_PATH}\"") -# ---- Declare library ---- +### Declare Library ### add_library(jluna SHARED @@ -106,22 +106,20 @@ add_library(jluna SHARED target_link_libraries(jluna PUBLIC jluna_c_adapter) target_include_directories(jluna PRIVATE "$") -# ---- HACK: export all symbols on Windows ---- +### HACK: export all symbols on Windows ### -# FIXME: Exporting all symbols is bad practice. Fix this using the -# GenerateExportHeader CMake module and visibility proprties. -set_target_properties(jluna PROPERTIES +set_target_properties(jluna jluna_c_adapter PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${C_ADAPTER_PATH} WINDOWS_EXPORT_ALL_SYMBOLS YES - LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR} ) -# ---- Install rules ---- +### Install rules ### if(NOT CMAKE_SKIP_INSTALL_RULES) include(cmake/install-rules.cmake) endif() -# ---- Developer mode ---- +### Developer mode ### if(NOT DEVELOPER_MODE) return() From 79fc77f3f9acb52b7e286ed6ae0871583289fa14 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 16:36:50 +0100 Subject: [PATCH 22/71] new installation tutorial --- docs/installation.md | 386 ++--------------------------------------- docs/~installation.md | 394 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 412 insertions(+), 368 deletions(-) create mode 100644 docs/~installation.md diff --git a/docs/installation.md b/docs/installation.md index 760d7f7..1361ac5 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,394 +1,44 @@ # Creating a Project with jluna -The following is a step-by-step guide to creating an application using `jluna` from scratch. +The following is a step-by-step guide to creating an application using `jluna` from scratch. -### Table of Contents -1. [Creating the Project](#creating-the-project) -2. [Setting JULIA_PATH](#setting-julia_path) -3. [Recompiling `jluna`](#building-jluna) -4. [Linking `jluna`](#linking-jluna)
- 4.1 [main.cpp](#linking-jluna)
- 4.2 [CMakeLists.txt](#linking-jluna)
-5. [Troubleshooting](#troubleshooting)
- 5.1 [CMake: Cannot determine location of julia image](#cannot-determine-location-of-julia-image)
- 5.2 [CMake: Cannot find julia.h / libjulia.so](#cannot-find-juliah--libjuliaso)
- 5.3 [C++: Cannot find / ](#cannot-find-juliah--jlunahpp)
- 5.4 [C++: State::initialize fails](#stateinitialize-fails)
-6. [Creating an Issue](#) -### Creating the Project - -First, we create our workspace directory. For the remainder of this section, this will be assumed to be `~/my_project`. We now execute: - -```bash -cd ~/my_project -git clone https://github.com/Clemapfel/jluna.git -``` - -This adds the folder `jluna/` to our directory. We now need to compile `jluna`. - -### Setting JULIA_PATH - -To tell `jluna` where to find julia, we need to set the environment variable `JULIA_PATH`, which contains the path to the local julia image. We set it in bash using: - -```bash -export JULIA_PATH=$(julia -e "println(joinpath(Sys.BINDIR, \"..\"))") -``` - -Here, we're calling the julia REPL inline to output the global variable `Sys.BINDIR`, which contains the path to the currently used julia binary. We verify `JULIA_PATH` was set correctly by using: - -```bash -echo $JULIA_PATH -``` -``` -/home/user/Applications/julia/bin/.. -``` -Of course, this path will be different for each user.
Note the prefix `/` which designates an absolute path starting at root and that there is no post-fix `/`. If `JULIA_PATH` reports an empty string, it may be because the `julia` command is not available on a system level. If this is the case, we can simply call the above command from within the julia REPL manually - -```julia -println(joinpath(Sys.BINDIR, "..")) -``` -``` -/path/to/your/julia/bin/.. -``` - -And copy-paste the resulting output to assign `JULIA_PATH` in bash like so: - -```bash -export JULIA_PATH=/path/to/your/julia/bin/.. -``` - -We can now continue to compiling `jluna` using cmake, being sure to stay in the same bash session where we set `JULIA_PATH`. To set `JULIA_PATH` globally, consider consulting [this guide](https://unix.stackexchange.com/questions/117467/how-to-permanently-set-environmental-variables). This way, it does not have to re-set anytime a bash session ends. - -### Building `jluna` - -With `JULIA_PATH` set correctly, we navigate into `~/my_project/jluna/` and create a new build directory, then call cmake from within that directory: +To install jluna globally, go into any public folder (henceforth assumed to be `Desktop`) and execute: ```bash -cd ~/my_project/jluna +git clone https://github.com/clemapfel/jluna.git +cd jluna mkdir build cd build -cmake -D CMAKE_CXX_COMPILER=g++-11 .. # or clang++-12 -make ``` -You may need to specify the absolute path to `g++-11` / `clang-12` if their respective executables are not available in the default search paths. - -When compiling, warnings of the following type may appear: - -``` -(...) -/home/user/Applications/julia/bin/../include/julia/julia_locks.h:72:32: warning: ‘++’ expression of ‘volatile’-qualified type is deprecated [-Wvolatile] - 72 | jl_current_task->ptls->defer_signal++; \ -(...) -``` - -This is because the official julia header `julia.h` is slightly out of date. The warning is unrelated to `jluna`s codebase, `jluna` itself should report no warnings or errors. If this is not the case, head to [troubleshooting](#troubleshooting). - -We verify everything works by running `JLUNA_TEST` which we just compiled: +This will have cloned the `jluna` git repository into a folder called `Desktop/jluna`. We know execute: ```bash -# in ~/my_project/jluna/build/ -./JLUNA_TEST +# in Desktop/jluna/build +cmake .. -DCMAKE_CXX_COMPILER=g++-10 ``` +At this point, some errors may appear. If this is the case, head to [troubleshooting](#troubleshooting). We manually specify the C++ compiler here. It can be any of: ++ `g++-10` ++ `g++-11` ++ `clang++-12` -A lot of output will appear. At the very end it should show: - -``` -Number of tests unsuccessful: 0 -``` +If the command does not recognize the compiler, even though you are are sure it is installed, it may be necessary to specify the full path to the compiler executable, e.g: `-DCMAKE_CXX_COMPILER=/usr/bin/g++-10`. -This means everything works! - -We then clean up the build files using: - -```bash -# in ~/my_project/jluna/build -cd .. -rm -r build -``` - -We have now compiled and verified `jluna` and are left with a shiny new `libjluna.so` and `libjluna_c_adapter.so` in `~/my_project/jluna/`. These are the shared libraries that contain `jluna`s functionality. - -Advanced users can stop this tutorial now and simply link their library against `libjluna.so`, `libjluna_c_adapter.so` (both in '`~/my_project/jluna/`) and against `libjulia.so`, which is in the directory `$ENV{JULIA_PATH}/lib/`. - - -For people who aren't yet as familiar with cmake and linking, let's continue: - -### Linking `jluna` - -We now need to create our own application. First we create a `main.cpp`: +After having configured cmake, we can now run: ```bash -cd ~/my_project -gedit main.cpp +# in Desktop/jluna/build +make install ``` -This will open a GUI editor, if `gedit` is unavailable, any other editor (`vim`, `nano`, `emacs`, etc.) can be used. - -We replace the contents of `main.cpp` with the following: - -```cpp -#include - -using namespace jluna; - -int main() -{ - State::initialize(); - Base["println"]("hello julia"); -} -``` - -then safe and close the file. - -To compile our project, we again use cmake. We first create `CMakeLists.txt`: +This will install jluna into the default shared library folder (usually `/usr/local` (on unix)). If we do not want jluna to be install there, we can manually specify `-DCMAKE_INSTALL_PREFIX`: ```bash -# in ~/my_project/ -gedit CMakeLists.txt -``` - -And replace its contents with the following: - -```cmake -cmake_minimum_required(VERSION 3.16) - -# name of our project -project(MyProject) - -# julia -if (NOT DEFINED ENV{JULIA_PATH}) - message(WARNING "JULIA_PATH was not set correctly. Consider re-reading the jluna installation tutorial at https://github.com/Clemapfel/jluna/blob/master/docs/installation.md#setting-julia_path to fix this issue") -endif() - -set(JULIA_INCLUDE "$ENV{JULIA_PATH}/include/julia") - -set(JULIA_LIB "$ENV{JULIA_PATH}/lib/libjulia.so") - -find_package(jluna REQUIRED) - -# add our executable -add_executable(MY_EXECUTABLE ${CMAKE_SOURCE_DIR}/main.cpp) - -target_include_directories(MY_EXECUTABLE PRIVATE ${JULIA_INCLUDE}) - -# link executable with jluna, jluna_c_adapter and julia -target_link_libraries(MY_EXECUTABLE jluna::jluna ${JULIA_LIB}) -``` - -We again save and close the file, then create our own build folder and run cmake, just like we did with `jluna` before - -```bash -# in ~/my_project -mkdir build -cd build -cmake -D CMAKE_CXX_COMPILER=g++-11 .. -make -``` - -If errors appear, be sure `JULIA_PATH` is still set correctly, as it is needed to find `julia.h`. Otherwise, head to [troubleshooting](#troubleshooting). - -After compilation succeeded, the directory should now have the following layout: - -``` -my_project/ - CMakeLists.txt - main.cpp - jluna/ - libjluna.so - libjluna_c_adapter.so - jluna.hpp - (...) - build/ - MY_EXECUTABLE - (...) -``` -Where names with a `/` suffix are folders. - -We can now run our application using: - -```bash -# in ~/my_project/build -./MY_EXECUTABLE -``` -``` -[JULIA][LOG] initialization successfull. -hello julia -``` - -`State::initialize()` may fail. If this is the case, head to [troubleshooting](#troubleshooting). Otherwise, congratulations! We are done and can now start developing our own application with the aid of julia and `jluna`. - ---- - -## Troubleshooting - -### Cannot determine location of julia image - -When compiling `jluna`, the following error may occur: - -``` - Cannot determine location of julia image. Before running cmake, please - manually set the environment variable JULIA_PATH using - - export JULIA_PATH=/path/to/your/.../julia - - If you are unsure of the location of your julia image, you can access the - path from within the julia REPL using - - println(joinpath(Sys.BINDIR, "..")) - - For more information, visit - https://github.com/Clemapfel/jluna/blob/master/README.md#troubleshooting -``` - -This is because `JULIA_PATH` is not properly set. Repeat the section on [setting `JULIA_PATH`](#setting-julia_path) to resolve this issue. - -### Cannot find julia.h / libjulia.so - -When building `jluna`, the following warnings may appear: - -``` -CMake Warning at CMakeLists.txt:37 (message): - Cannot find library header julia.h in (...) -``` - -This means verification of the directory specified through `JULIA_PATH` failed. We can make sure the path is correct by verifying: - -+ the path is an absolute path starting at root -+ the path has a prefix `/` -+ the path has no suffix `/` -+ the path is the same as reported in the julia REPL - -If all of these are true, it may be that your julia image is corrupted or compressed. The julia folder should have the following layout: - -``` -julia/ - bin/ - julia - include/ - julia/ - julia.h - (...) - lib/ - libjulia.so - (...) - - (...) -``` -Where names with a suffix `/` are folders. If your julia folder looks different, redownload the latest official release [here](https://julialang.org/downloads/#current_stable_release) and reassign `JULIA_PATH` accordingly. - -### Cannot find / - -The following error may appear when compiling your library: - -``` -fatal error: julia.h: No such file or directory - 3 | #include - | ^~~~~~~~~ -compilation terminated. -``` - -or, similarly: - -``` -fatal error: jluna.hpp: No such file or directory - 3 | #include - | ^~~~~~~~~~~ -compilation terminated. -``` - -This means the `include_directories` in cmake where set improperly. Make sure the following lines are present in your `CMakeLists.txt`: - -``` -include_directories("${CMAKE_SOURCE_DIR}/jluna") -include_directories("$ENV{JULIA_PATH}/include/julia") -``` - -Furthermore, make sure your directory has the following structure: - -``` -my_project/ - main.cpp - CMakeLists.txt - jluna/ - libjluna.so - libjluna_c_adapter.so - jluna.hpp - include/ - (...) - (...) - build/ - (...) -``` - -And make sure `JULIA_PATH` is set correctly (see above). - -### State::initialize fails - -#### AssertionError("jluna requires julia v1.7.0 or higher") - -`jluna` asserts wether the correct version of julia is present on initialization. If the following exception occurs when calling `State::initialize`: - -``` -terminate called after throwing an instance of 'jluna::JuliaException' - what(): [JULIA][EXCEPTION] AssertionError("jluna requires julia v1.7.0 or higher, but v1.6.2 was detected. Please download the latest julia release at https://julialang.org/downloads/#current_stable_release, set JULIA_PATH accordingly, then recompile jluna using cmake. For more information, visit https://github.com/Clemapfel/jluna/blob/master/README.md#troubleshooting") - -signal (6): Aborted -in expression starting at none:0 -(...) -``` - -It means that your julia version is out of date. [Download the latest version](https://julialang.org/downloads/#current_stable_release), set `JULIA_PATH` to point to it, then recompile `jluna` as outlined [above](#building-jluna). - -### ERROR: could not load library - -When calling `State::initialize`, julias C-API may report an error of the following type: - -``` -ERROR: could not load library "(...)/lib/julia/sys.so" -(...)/lib/julia/sys.so: cannot open shared object file: No such file or directory -``` - -This can mean three things - -+ A) `JULIA_PATH` was set incorrectly (see above) -+ B) your executable `MY_EXECUTABLE` does not have read permission for the folders in `JULIA_PATH` -+ C) julia is not installed on a system level - -If C is true, replace `State::initialize()` with its overload: - -```cpp -State::initialize("/path/to/(...)/julia/bin") -``` -Where `/path/to/(...)` is replaced with the absolute path to your image of julia. This will tell the C-API to load julia from that image, rather than from the default system image. - -## Creating an Issue +# in Desktop/jluna/build +make install -DCMAKE_INSTALL_PREFIX -If your problem still persists, it may be appropriate to open a github issue. First, please verify that: -+ you are on a linux-based, 64-bit operating system -+ julia 1.7.0 (or higher) is installed and no older version exists on your machine -+ cmake 3.16 (or higher) is installed and no older version exists on your machine -+ g++-10 or g++-11 is installed -+ gcc-9 (or higher) is installed -+ when building with cmake, you specified `-D CMAKE_CXX_COMPILER=g++-11` correctly - - cmake is able to find the executable `g++-11` in the default search paths - - the same applies to `-D CMAKE_C_COMPILER=gcc-9` as well - - any given issue may be compiler specific, consider trying `clang-12` instead -+ `~/my_project/CMakeLists.txt` is identical to the code in [installation](#linking-jluna) -+ `State::initialize` and `JULIA_PATH` are modified as outlined [above](#stateinitialize-fails) -+ `jluna` was freshly pulled from the git repo and recompiled -+ `~/my_project/jluna/` contains `libjluna.so` and `libjluna_c_adapter.so` -+ `~/my_project/jluna/build/JLUNA_TEST` was ran -+ your issue is not otherwise covered in [troubleshooting](#troubleshooting), or any other already resolved issue -If and only if all of the above apply, head to the [issues tab](https://github.com/Clemapfel/jluna/issues). There, please create an issue and -+ describe your problem -+ state your operating system, distro and compiler version -+ copy-paste the output of `JLUNA_TEST` (even if all tests are `OK`) -+ provide a minimum working example of your project that recreates the bug -We will try to resolve your problem as soon as possible and are thankful for your input and collaboration. ---- \ No newline at end of file diff --git a/docs/~installation.md b/docs/~installation.md new file mode 100644 index 0000000..760d7f7 --- /dev/null +++ b/docs/~installation.md @@ -0,0 +1,394 @@ +# Creating a Project with jluna + +The following is a step-by-step guide to creating an application using `jluna` from scratch. + +### Table of Contents +1. [Creating the Project](#creating-the-project) +2. [Setting JULIA_PATH](#setting-julia_path) +3. [Recompiling `jluna`](#building-jluna) +4. [Linking `jluna`](#linking-jluna)
+ 4.1 [main.cpp](#linking-jluna)
+ 4.2 [CMakeLists.txt](#linking-jluna)
+5. [Troubleshooting](#troubleshooting)
+ 5.1 [CMake: Cannot determine location of julia image](#cannot-determine-location-of-julia-image)
+ 5.2 [CMake: Cannot find julia.h / libjulia.so](#cannot-find-juliah--libjuliaso)
+ 5.3 [C++: Cannot find / ](#cannot-find-juliah--jlunahpp)
+ 5.4 [C++: State::initialize fails](#stateinitialize-fails)
+6. [Creating an Issue](#) + +### Creating the Project + +First, we create our workspace directory. For the remainder of this section, this will be assumed to be `~/my_project`. We now execute: + +```bash +cd ~/my_project +git clone https://github.com/Clemapfel/jluna.git +``` + +This adds the folder `jluna/` to our directory. We now need to compile `jluna`. + +### Setting JULIA_PATH + +To tell `jluna` where to find julia, we need to set the environment variable `JULIA_PATH`, which contains the path to the local julia image. We set it in bash using: + +```bash +export JULIA_PATH=$(julia -e "println(joinpath(Sys.BINDIR, \"..\"))") +``` + +Here, we're calling the julia REPL inline to output the global variable `Sys.BINDIR`, which contains the path to the currently used julia binary. We verify `JULIA_PATH` was set correctly by using: + +```bash +echo $JULIA_PATH +``` +``` +/home/user/Applications/julia/bin/.. +``` +Of course, this path will be different for each user.
Note the prefix `/` which designates an absolute path starting at root and that there is no post-fix `/`. If `JULIA_PATH` reports an empty string, it may be because the `julia` command is not available on a system level. If this is the case, we can simply call the above command from within the julia REPL manually + +```julia +println(joinpath(Sys.BINDIR, "..")) +``` +``` +/path/to/your/julia/bin/.. +``` + +And copy-paste the resulting output to assign `JULIA_PATH` in bash like so: + +```bash +export JULIA_PATH=/path/to/your/julia/bin/.. +``` + +We can now continue to compiling `jluna` using cmake, being sure to stay in the same bash session where we set `JULIA_PATH`. To set `JULIA_PATH` globally, consider consulting [this guide](https://unix.stackexchange.com/questions/117467/how-to-permanently-set-environmental-variables). This way, it does not have to re-set anytime a bash session ends. + +### Building `jluna` + +With `JULIA_PATH` set correctly, we navigate into `~/my_project/jluna/` and create a new build directory, then call cmake from within that directory: + +```bash +cd ~/my_project/jluna +mkdir build +cd build +cmake -D CMAKE_CXX_COMPILER=g++-11 .. # or clang++-12 +make +``` + +You may need to specify the absolute path to `g++-11` / `clang-12` if their respective executables are not available in the default search paths. + +When compiling, warnings of the following type may appear: + +``` +(...) +/home/user/Applications/julia/bin/../include/julia/julia_locks.h:72:32: warning: ‘++’ expression of ‘volatile’-qualified type is deprecated [-Wvolatile] + 72 | jl_current_task->ptls->defer_signal++; \ +(...) +``` + +This is because the official julia header `julia.h` is slightly out of date. The warning is unrelated to `jluna`s codebase, `jluna` itself should report no warnings or errors. If this is not the case, head to [troubleshooting](#troubleshooting). + +We verify everything works by running `JLUNA_TEST` which we just compiled: + +```bash +# 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 +``` + +This means everything works! + +We then clean up the build files using: + +```bash +# in ~/my_project/jluna/build +cd .. +rm -r build +``` + +We have now compiled and verified `jluna` and are left with a shiny new `libjluna.so` and `libjluna_c_adapter.so` in `~/my_project/jluna/`. These are the shared libraries that contain `jluna`s functionality. + +Advanced users can stop this tutorial now and simply link their library against `libjluna.so`, `libjluna_c_adapter.so` (both in '`~/my_project/jluna/`) and against `libjulia.so`, which is in the directory `$ENV{JULIA_PATH}/lib/`. + + +For people who aren't yet as familiar with cmake and linking, let's continue: + +### Linking `jluna` + +We now need to create our own application. First we create a `main.cpp`: + +```bash +cd ~/my_project +gedit main.cpp +``` + +This will open a GUI editor, if `gedit` is unavailable, any other editor (`vim`, `nano`, `emacs`, etc.) can be used. + +We replace the contents of `main.cpp` with the following: + +```cpp +#include + +using namespace jluna; + +int main() +{ + State::initialize(); + Base["println"]("hello julia"); +} +``` + +then safe and close the file. + +To compile our project, we again use cmake. We first create `CMakeLists.txt`: + +```bash +# in ~/my_project/ +gedit CMakeLists.txt +``` + +And replace its contents with the following: + +```cmake +cmake_minimum_required(VERSION 3.16) + +# name of our project +project(MyProject) + +# julia +if (NOT DEFINED ENV{JULIA_PATH}) + message(WARNING "JULIA_PATH was not set correctly. Consider re-reading the jluna installation tutorial at https://github.com/Clemapfel/jluna/blob/master/docs/installation.md#setting-julia_path to fix this issue") +endif() + +set(JULIA_INCLUDE "$ENV{JULIA_PATH}/include/julia") + +set(JULIA_LIB "$ENV{JULIA_PATH}/lib/libjulia.so") + +find_package(jluna REQUIRED) + +# add our executable +add_executable(MY_EXECUTABLE ${CMAKE_SOURCE_DIR}/main.cpp) + +target_include_directories(MY_EXECUTABLE PRIVATE ${JULIA_INCLUDE}) + +# link executable with jluna, jluna_c_adapter and julia +target_link_libraries(MY_EXECUTABLE jluna::jluna ${JULIA_LIB}) +``` + +We again save and close the file, then create our own build folder and run cmake, just like we did with `jluna` before + +```bash +# in ~/my_project +mkdir build +cd build +cmake -D CMAKE_CXX_COMPILER=g++-11 .. +make +``` + +If errors appear, be sure `JULIA_PATH` is still set correctly, as it is needed to find `julia.h`. Otherwise, head to [troubleshooting](#troubleshooting). + +After compilation succeeded, the directory should now have the following layout: + +``` +my_project/ + CMakeLists.txt + main.cpp + jluna/ + libjluna.so + libjluna_c_adapter.so + jluna.hpp + (...) + build/ + MY_EXECUTABLE + (...) +``` +Where names with a `/` suffix are folders. + +We can now run our application using: + +```bash +# in ~/my_project/build +./MY_EXECUTABLE +``` +``` +[JULIA][LOG] initialization successfull. +hello julia +``` + +`State::initialize()` may fail. If this is the case, head to [troubleshooting](#troubleshooting). Otherwise, congratulations! We are done and can now start developing our own application with the aid of julia and `jluna`. + +--- + +## Troubleshooting + +### Cannot determine location of julia image + +When compiling `jluna`, the following error may occur: + +``` + Cannot determine location of julia image. Before running cmake, please + manually set the environment variable JULIA_PATH using + + export JULIA_PATH=/path/to/your/.../julia + + If you are unsure of the location of your julia image, you can access the + path from within the julia REPL using + + println(joinpath(Sys.BINDIR, "..")) + + For more information, visit + https://github.com/Clemapfel/jluna/blob/master/README.md#troubleshooting +``` + +This is because `JULIA_PATH` is not properly set. Repeat the section on [setting `JULIA_PATH`](#setting-julia_path) to resolve this issue. + +### Cannot find julia.h / libjulia.so + +When building `jluna`, the following warnings may appear: + +``` +CMake Warning at CMakeLists.txt:37 (message): + Cannot find library header julia.h in (...) +``` + +This means verification of the directory specified through `JULIA_PATH` failed. We can make sure the path is correct by verifying: + ++ the path is an absolute path starting at root ++ the path has a prefix `/` ++ the path has no suffix `/` ++ the path is the same as reported in the julia REPL + +If all of these are true, it may be that your julia image is corrupted or compressed. The julia folder should have the following layout: + +``` +julia/ + bin/ + julia + include/ + julia/ + julia.h + (...) + lib/ + libjulia.so + (...) + + (...) +``` +Where names with a suffix `/` are folders. If your julia folder looks different, redownload the latest official release [here](https://julialang.org/downloads/#current_stable_release) and reassign `JULIA_PATH` accordingly. + +### Cannot find / + +The following error may appear when compiling your library: + +``` +fatal error: julia.h: No such file or directory + 3 | #include + | ^~~~~~~~~ +compilation terminated. +``` + +or, similarly: + +``` +fatal error: jluna.hpp: No such file or directory + 3 | #include + | ^~~~~~~~~~~ +compilation terminated. +``` + +This means the `include_directories` in cmake where set improperly. Make sure the following lines are present in your `CMakeLists.txt`: + +``` +include_directories("${CMAKE_SOURCE_DIR}/jluna") +include_directories("$ENV{JULIA_PATH}/include/julia") +``` + +Furthermore, make sure your directory has the following structure: + +``` +my_project/ + main.cpp + CMakeLists.txt + jluna/ + libjluna.so + libjluna_c_adapter.so + jluna.hpp + include/ + (...) + (...) + build/ + (...) +``` + +And make sure `JULIA_PATH` is set correctly (see above). + +### State::initialize fails + +#### AssertionError("jluna requires julia v1.7.0 or higher") + +`jluna` asserts wether the correct version of julia is present on initialization. If the following exception occurs when calling `State::initialize`: + +``` +terminate called after throwing an instance of 'jluna::JuliaException' + what(): [JULIA][EXCEPTION] AssertionError("jluna requires julia v1.7.0 or higher, but v1.6.2 was detected. Please download the latest julia release at https://julialang.org/downloads/#current_stable_release, set JULIA_PATH accordingly, then recompile jluna using cmake. For more information, visit https://github.com/Clemapfel/jluna/blob/master/README.md#troubleshooting") + +signal (6): Aborted +in expression starting at none:0 +(...) +``` + +It means that your julia version is out of date. [Download the latest version](https://julialang.org/downloads/#current_stable_release), set `JULIA_PATH` to point to it, then recompile `jluna` as outlined [above](#building-jluna). + +### ERROR: could not load library + +When calling `State::initialize`, julias C-API may report an error of the following type: + +``` +ERROR: could not load library "(...)/lib/julia/sys.so" +(...)/lib/julia/sys.so: cannot open shared object file: No such file or directory +``` + +This can mean three things + ++ A) `JULIA_PATH` was set incorrectly (see above) ++ B) your executable `MY_EXECUTABLE` does not have read permission for the folders in `JULIA_PATH` ++ C) julia is not installed on a system level + +If C is true, replace `State::initialize()` with its overload: + +```cpp +State::initialize("/path/to/(...)/julia/bin") +``` +Where `/path/to/(...)` is replaced with the absolute path to your image of julia. This will tell the C-API to load julia from that image, rather than from the default system image. + +## Creating an Issue + +If your problem still persists, it may be appropriate to open a github issue. First, please verify that: + ++ you are on a linux-based, 64-bit operating system ++ julia 1.7.0 (or higher) is installed and no older version exists on your machine ++ cmake 3.16 (or higher) is installed and no older version exists on your machine ++ g++-10 or g++-11 is installed ++ gcc-9 (or higher) is installed ++ when building with cmake, you specified `-D CMAKE_CXX_COMPILER=g++-11` correctly + - cmake is able to find the executable `g++-11` in the default search paths + - the same applies to `-D CMAKE_C_COMPILER=gcc-9` as well + - any given issue may be compiler specific, consider trying `clang-12` instead ++ `~/my_project/CMakeLists.txt` is identical to the code in [installation](#linking-jluna) ++ `State::initialize` and `JULIA_PATH` are modified as outlined [above](#stateinitialize-fails) ++ `jluna` was freshly pulled from the git repo and recompiled ++ `~/my_project/jluna/` contains `libjluna.so` and `libjluna_c_adapter.so` ++ `~/my_project/jluna/build/JLUNA_TEST` was ran ++ your issue is not otherwise covered in [troubleshooting](#troubleshooting), or any other already resolved issue + +If and only if all of the above apply, head to the [issues tab](https://github.com/Clemapfel/jluna/issues). There, please create an issue and ++ describe your problem ++ state your operating system, distro and compiler version ++ copy-paste the output of `JLUNA_TEST` (even if all tests are `OK`) ++ provide a minimum working example of your project that recreates the bug + +We will try to resolve your problem as soon as possible and are thankful for your input and collaboration. + +--- \ No newline at end of file From 414afd03c711806d73ad665dfb17736bc2bb9cc6 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 18:50:50 +0100 Subject: [PATCH 23/71] working on install script --- CMakeLists.txt | 9 +- CMakePresets.json | 64 +++++++ cmake/find/FindJulia.cmake | 1 - docs/installation.md | 158 +++++++++++++++++- examples/MyProject/CMakeLists.txt | 23 +++ examples/MyProject/cmake/find/FindJulia.cmake | 106 ++++++++++++ examples/MyProject/main.cpp | 13 ++ 7 files changed, 359 insertions(+), 15 deletions(-) create mode 100644 CMakePresets.json create mode 100644 examples/MyProject/CMakeLists.txt create mode 100644 examples/MyProject/cmake/find/FindJulia.cmake create mode 100644 examples/MyProject/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 78e9334..0b2e7ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,13 +2,6 @@ cmake_minimum_required(VERSION 3.12) project(jluna VERSION 0.8.4 LANGUAGES CXX) -# ### -# -# -# -# - - include(cmake/project-is-top-level.cmake) if(PROJECT_IS_TOP_LEVEL) option(DEVELOPER_MODE "Enable developer mode" OFF) @@ -103,7 +96,7 @@ add_library(jluna SHARED include/gc_sentinel.hpp ) -target_link_libraries(jluna PUBLIC jluna_c_adapter) +target_link_libraries(jluna PUBLIC jluna_c_adapter "$") target_include_directories(jluna PRIVATE "$") ### HACK: export all symbols on Windows ### diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..bc2821e --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,64 @@ +{ + "version": 2, + "cmakeMinimumRequired": { + "major": 3, + "minor": 20, + "patch": 0 + }, + "configurePresets": [ + { + "name": "cmake-pedantic", + "hidden": true, + "warnings": { + "dev": true, + "deprecated": true, + "uninitialized": true, + "unusedCli": true, + "systemVars": false + }, + "errors": { + "dev": true, + "deprecated": true + } + }, + { + "name": "dev-mode", + "hidden": true, + "inherits": "cmake-pedantic", + "cacheVariables": { + "shared_DEVELOPER_MODE": "ON" + } + }, + { + "name": "clang-tidy", + "hidden": true, + "cacheVariables": { + "CMAKE_CXX_CLANG_TIDY": "clang-tidy;--header-filter=${sourceDir}/*" + } + }, + { + "name": "ci-std", + "description": "This preset makes sure the project actually builds with at least the specified standard", + "hidden": true, + "cacheVariables": { + "CMAKE_CXX_EXTENSIONS": "OFF", + "CMAKE_CXX_STANDARD": "20", + "CMAKE_CXX_STANDARD_REQUIRED": "ON" + } + }, + { + "name": "flags-unix", + "hidden": true, + "cacheVariables": { + "CMAKE_CXX_FLAGS": "-Wno-deprecated-volatile -Wno-dev" + } + }, + { + "name": "flags-windows", + "hidden": true, + "cacheVariables": { + "CMAKE_CXX_FLAGS": "/W4 /permissive- /utf-8 /volatile:iso /EHsc /Zc:__cplusplus /Zc:throwingNew" + } + } + ] +} diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index 549c88b..5c1e445 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -54,7 +54,6 @@ find_path( ) julia_bail_if_false("Cannot find julia.h. Make sure JULIA_BINDIR is set correctly and that your image is uncompressed.\nFor more information, visit https://github.com/Clemapfel/jluna/blob/master/docs/installation.md" JULIA_INCLUDE_DIR) - #if(NOT DEFINED JULIA_VERSION) file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" JULIA_VERSION_LOCAL LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" JULIA_VERSION_LOCAL "${JULIA_VERSION_LOCAL}") diff --git a/docs/installation.md b/docs/installation.md index 1361ac5..e6a675f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,8 +2,11 @@ The following is a step-by-step guide to creating an application using `jluna` from scratch. +### Table of Contents -To install jluna globally, go into any public folder (henceforth assumed to be `Desktop`) and execute: +## Installing jluna + +To install jluna globally, we navigate into any public folder (henceforth assumed to be `Desktop`) and execute: ```bash git clone https://github.com/clemapfel/jluna.git @@ -12,33 +15,176 @@ mkdir build cd build ``` -This will have cloned the `jluna` git repository into a folder called `Desktop/jluna`. We know execute: +This will have cloned the `jluna` git repository into a folder called `Desktop/jluna`. We know call: ```bash # in Desktop/jluna/build cmake .. -DCMAKE_CXX_COMPILER=g++-10 +make install ``` -At this point, some errors may appear. If this is the case, head to [troubleshooting](#troubleshooting). We manually specify the C++ compiler here. It can be any of: +At this point, some errors may appear. If this is the case, head to [troubleshooting](#troubleshooting). + +We manually specify the C++ compiler here. It can be any of: + `g++-10` + `g++-11` + `clang++-12` +> Note that window supports is experimental. This means specifying `MSVC` may work, however this is untested. The [cpp compiler support]() list seems to imply that MSVC 19.30 or newer is required to compile `jluna`. + If the command does not recognize the compiler, even though you are are sure it is installed, it may be necessary to specify the full path to the compiler executable, e.g: `-DCMAKE_CXX_COMPILER=/usr/bin/g++-10`. -After having configured cmake, we can now run: +These commands will install jluna into the default shared library folder (usually `/usr/local` (on unix)). If we want the shared libraries to appear somewhere else, we can instead specify the directory like so: ```bash # in Desktop/jluna/build +cmake .. -DCMAKE_CXX_COMPILER=g++-10 -DCMAKE_INSTALL_PREFIX=~/our/custom/path make install ``` -This will install jluna into the default shared library folder (usually `/usr/local` (on unix)). If we do not want jluna to be install there, we can manually specify `-DCMAKE_INSTALL_PREFIX`: +Having installed `jluna`, two shared libraries `libjluna.so` and `libjluna_c_adapter.so` have now appeared in the install directories. Advanced users can now make jluna available from withing their `CMakeLists.txt` by using: + +```cmake +find_package(jluna REQUIRES NAMES libjluna.so HINTS /path/to/jluna) +``` + +Where `/path/to/jluna` is the directory jluna was installed in the previous step specified through `CMAKE_INSTALL_PREFIX`. + +Note that on windows, instead of `libjluna.so`, one of `libjluna.lib`, `libjluna.dll` or `libjluna.dll.a` should be used. + +## Troubleshooting + +### Unable to detect the Julia executable + +When calling: ```bash # in Desktop/jluna/build -make install -DCMAKE_INSTALL_PREFIX +cmake .. -DCMAKE_COMPILER=g++-10 # or other compiler +``` + +You may encounter the following error: + +``` +CMake Error at cmake/find/FindJulia.cmake:5 (message): + Unable to detect the julia executable. Make sure JULIA_BINDIR is set + correctly. + + For more information, visit + https://github.com/Clemapfel/jluna/blob/master/docs/installation.md +Call Stack (most recent call first): + cmake/find/FindJulia.cmake:11 (julia_bail_if_false) + CMakeLists.txt:20 (find_package) + + +-- Configuring incomplete, errors occurred! +``` + +This error appears because jluna was unable to locate the julia package on your system. To make jluna aware of the location manually, we can pass the following variable to the cmake command: + +```bash +cmake .. -DJULIA_BINDIR=path/to/your/julia/bin -DCMAKE_COMPILER=g++-10 +``` +This is the path to he binary directory of your julia image. If you are unsure of it's location, you can execute + +```julia +println(Sys.BINDIR) +``` + +From inside the julia REPL. + +### Could NOT find Julia: Found unsuitable version + +During the cmake configuration step, the following error may appear: + +``` +CMake Error at /home/(...)/FindPackageHandleStandardArgs.cmake:218 (message): + Could NOT find Julia: Found unsuitable version "1.5.1", but required is at + least "1.7.0" (found /home/clem/Applications/julia/lib/libjulia.so) +``` + +Where `1.5.1` could instead be any version before `1.7.0`. This means your julia version is out of date, either update it through your packet manager or download the latest version [here](https://julialang.org/downloads/), install it, then make sure `JULIA_BINDIR` is pointing to the newer version. + +### Could NOT find Julia (missing: X) +Where X can be any of : ++ `JULIA_LIBRARY` ++ `JULIA_EXECUTABLE` ++ `JULIA_BINDIR` ++ `JULIA_INCLUDE_DIR` + +This means that either `JULIA_BINDIR` was not set correctly or the directory it is pointing to is not the julia binary dir (a path always ending in `/bin`), or your julia image is compressed. Make sure the folder `JULIA_BINDIR` points to has the following layout: + +``` +julia*/ + bin/ + julia + include/ + julia/ + julia.h + (...) + lib/ + libjulia.so + (...) + + (...) +``` +Then set `JULIA_BINDIR` to `/path/to/.../julia/bin`. +### Cannot find / +The following error may appear when compiling your library: + +``` +fatal error: julia.h: No such file or directory + 3 | #include + | ^~~~~~~~~ +compilation terminated. +``` + +or, similarly: + +``` +fatal error: jluna.hpp: No such file or directory + 3 | #include + | ^~~~~~~~~~~ +compilation terminated. +``` +This means the `include_directories` in cmake were set improperly. Make sure the following lines are present in your `CMakeLists.txt`: + +``` +find_package(Julia) +find_package(jluna) +``` + +### When trying to initialize jluna.cppcall: cannot find libjluna_c_adapter + +When calling + +```cpp +State::initialize() +``` + +The following error may appear: + +``` +AssertionError: when trying to initialize jluna.cppcall: cannot find /home/Desktop/jluna/libjluna_c_adapter.so +Stacktrace: + [1] verify_library() + @ Main.jluna._cppcall ./none:951 + [2] top-level scope + @ none:2 +[JULIA][ERROR] initialization failed. +terminate called after throwing an instance of 'jluna::JuliaException' + what(): [JULIA][EXCEPTION] AssertionError("[JULIA][ERROR] initialization failed.") + +signal (6): Aborted +``` + +To allow the local julia state to interface with jluna, it needs the shared c-adapter-library to be available. During `make install`, the following line should have appeared: + +``` +[LOG] writing libjluna_c_adapter to globally available directory "/home/Desktop/jluna/libjluna_c_adapter.so" +``` +Make sure the c_adapter shared library is still in that directory, if it is not, recompile jluna. The C-adapter library is installed into the directory specified by `CMAKE_INSTALL_PREFIX` and needs to remain there in order for `jluna` to work. diff --git a/examples/MyProject/CMakeLists.txt b/examples/MyProject/CMakeLists.txt new file mode 100644 index 0000000..bcaead3 --- /dev/null +++ b/examples/MyProject/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.12) + +project(MyProject VERSION 0.0.0 LANGUAGES CXX) + +### Find julia / jluna + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/find") +find_package(Julia 1.7.0 REQUIRED) +find_library(jluna REQUIRED NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib HINTS ${CMAKE_SOURCE_DIR}/jluna/build) + +### Declare Executable + +add_executable(my_executable ${CMAKE_SOURCE_DIR}/main.cpp) +target_link_libraries(my_executable PRIVATE + ${jluna} + "$" +) +target_compile_features(my_executable PUBLIC cxx_std_20) +target_include_directories(my_executable PRIVATE + "$" + ${CMAKE_SOURCE_DIR}/../.. #TODO + ${JULIA_INCLUDE_DIR} +) \ No newline at end of file diff --git a/examples/MyProject/cmake/find/FindJulia.cmake b/examples/MyProject/cmake/find/FindJulia.cmake new file mode 100644 index 0000000..ef7627d --- /dev/null +++ b/examples/MyProject/cmake/find/FindJulia.cmake @@ -0,0 +1,106 @@ +macro(julia_bail_if_false message var) + if(NOT ${var}) + set(Julia_FOUND 0) + set(Julia_NOT_FOUND_MESSAGE "${message}") + message(FATAL_ERROR "${message}") + return() + endif() +endmacro() + +find_program(JULIA_EXECUTABLE julia PATHS ENV JULIA_BINDIR) +julia_bail_if_false("Unable to detect the julia executable. Make sure JULIA_BINDIR is set correctly." JULIA_EXECUTABLE) + +if(NOT DEFINED JULIA_BINDIR) + # The executable could be a chocolatey shim, so run some Julia code to report + # the path of the BINDIR + execute_process( + COMMAND "${JULIA_EXECUTABLE}" -e "print(Sys.BINDIR)" + OUTPUT_VARIABLE JULIA_BINDIR_LOCAL + ) + file(TO_CMAKE_PATH "${JULIA_BINDIR_LOCAL}" JULIA_BINDIR_LOCAL) + set(JULIA_BINDIR "${JULIA_BINDIR_LOCAL}" CACHE PATH "") +endif() +get_filename_component(JULIA_PATH_PREFIX "${JULIA_BINDIR}" DIRECTORY) + +if(WIN32) + set(julia_old_CMAKE_FIND_LIBRARY_SUFFIXES "") + set(julia_old_CMAKE_FIND_LIBRARY_PREFIXES "") + if(CMAKE_FIND_LIBRARY_SUFFIXES) + set(julia_old_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") + list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .dll.a) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a") + endif() + if(CMAKE_FIND_LIBRARY_PREFIXES) + set(julia_old_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") + list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib) + else() + set(CMAKE_FIND_LIBRARY_PREFIXES ";lib") + endif() +endif() + +find_library(JULIA_LIBRARY julia HINTS "${JULIA_PATH_PREFIX}/lib") + +if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES "${julia_old_CMAKE_FIND_LIBRARY_SUFFIXES}") + set(CMAKE_FIND_LIBRARY_PREFIXES "${julia_old_CMAKE_FIND_LIBRARY_PREFIXES}") +endif() + +julia_bail_if_false("Unable to find the julia shared library. Make sure JULIA_BINDIR is set correctly and that the julia image is uncompressed" JULIA_LIBRARY) + +find_path( + JULIA_INCLUDE_DIR julia.h + HINTS "${JULIA_PATH_PREFIX}/include" "${JULIA_PATH_PREFIX}/include/julia" +) +julia_bail_if_false("Unable to find julia.h. Make sure JULIA_BINDIR is set correctly and that your image is uncompressed." JULIA_INCLUDE_DIR) + +#if(NOT DEFINED JULIA_VERSION) + file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" JULIA_VERSION_LOCAL LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) + string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" JULIA_VERSION_LOCAL "${JULIA_VERSION_LOCAL}") + set(JULIA_VERSION "${JULIA_VERSION_LOCAL}") +#endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + Julia + REQUIRED_VARS JULIA_LIBRARY JULIA_EXECUTABLE JULIA_BINDIR JULIA_INCLUDE_DIR + VERSION_VAR JULIA_VERSION +) + +if(NOT TARGET Julia::Julia) + set(julia_has_implib NO) + set(julia_library_type STATIC) + if(JULIA_LIBRARY MATCHES "\\.(so|dylib)$") + set(julia_library_type SHARED) + elseif(JULIA_LIBRARY MATCHES "\\.(lib|dll\\.a)$") + set(julia_library_type UNKNOWN) + find_file( + JULIA_LIBRARY_DLL + NAMES libjulia.dll julia.dll + HINTS "${JULIA_BINDIR}" + ) + if(JULIA_LIBRARY_DLL) + set(julia_has_implib YES) + set(julia_library_type SHARED) + endif() + endif() + + add_library(Julia::Julia "${julia_library_type}" IMPORTED) + set_target_properties( + Julia::Julia PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${JULIA_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES C + ) + if(julia_has_implib) + if(JULIA_LIBRARY AND EXISTS "${JULIA_LIBRARY}") + set_property(TARGET Julia::Julia PROPERTY IMPORTED_IMPLIB "${JULIA_LIBRARY}") + endif() + if(JULIA_LIBRARY_DLL AND EXISTS "${JULIA_LIBRARY_DLL}") + set_property(TARGET Julia::Julia PROPERTY IMPORTED_LOCATION "${JULIA_LIBRARY_DLL}") + endif() + elseif(JULIA_LIBRARY AND EXISTS "${JULIA_LIBRARY}") + set_property(TARGET Julia::Julia PROPERTY IMPORTED_LOCATION "${JULIA_LIBRARY}") + endif() +endif() + +mark_as_advanced(JULIA_EXECUTABLE JULIA_BINDIR JULIA_LIBRARY JULIA_INCLUDE_DIR JULIA_VERSION JULIA_LIBRARY_DLL) diff --git a/examples/MyProject/main.cpp b/examples/MyProject/main.cpp new file mode 100644 index 0000000..3fb71dd --- /dev/null +++ b/examples/MyProject/main.cpp @@ -0,0 +1,13 @@ +// +// this main.cpp was created by jluna/install.sh +// + +#include + +using namespace jluna; + +int main() +{ + State::initialize(); + Base["println"]("hello julia"); +} From 816dd5b82c9f01bc11fbe2bb2ffe98d0ff2255e8 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 19:44:12 +0100 Subject: [PATCH 24/71] working on install script --- install/init.sh | 54 +++++++++++++++++++ .../resources}/CMakeLists.txt | 2 +- .../resources}/FindJulia.cmake | 0 .../MyProject => install/resources}/main.cpp | 0 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 install/init.sh rename {examples/MyProject => install/resources}/CMakeLists.txt (95%) rename {examples/MyProject/cmake/find => install/resources}/FindJulia.cmake (100%) rename {examples/MyProject => install/resources}/main.cpp (100%) diff --git a/install/init.sh b/install/init.sh new file mode 100644 index 0000000..0e832f6 --- /dev/null +++ b/install/init.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# +# init.sh +# +# this bash script creates a new C++ project using jluna. +# It is intended to be used for novice users, advanced users are encouraged to +# `make install` jluna and link to it and julia in their own project +# +# for more information, visit https://github.com/Clemapfel/jluna/blob/master/docs/installation.md +# + +if [ -z "$1" ] | [ -z "$2" ]; then + echo "Usage: /bin/bash init.sh " + exit 1 +fi + +project_name="$1" +project_root="$2" + +echo "creating $project_root/$project_name..." + +cd $project_root +mkdir -p $project_name +cd $project_name + +git clone -b cmake_rework https://github.com/Clemapfel/jluna.git + +cd jluna +mkdir -p build +cd build + +cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DCMAKE_INSTALL_PREFIX="$project_root/$project_name/jluna" + +cd ../.. +cp ./jluna/install/resources/CMakeLists.txt ./CMakeLists.txt +cp ./jluna/install/resources/main.cpp ./main.cpp + +mkdir -p $project_root/$project_name/cmake/find +cp ./jluna/install/resources/FindJulia.cmake ./cmake/find/FindJulia.cmake + +cd $project_root/$project_name +mkdir - build +cd build +cmake .. +make + +#rm -r $project_root/$project_name + +exit 0 + + + + diff --git a/examples/MyProject/CMakeLists.txt b/install/resources/CMakeLists.txt similarity index 95% rename from examples/MyProject/CMakeLists.txt rename to install/resources/CMakeLists.txt index bcaead3..bb9e7c7 100644 --- a/examples/MyProject/CMakeLists.txt +++ b/install/resources/CMakeLists.txt @@ -18,6 +18,6 @@ target_link_libraries(my_executable PRIVATE target_compile_features(my_executable PUBLIC cxx_std_20) target_include_directories(my_executable PRIVATE "$" - ${CMAKE_SOURCE_DIR}/../.. #TODO + ${CMAKE_SOURCE_DIR}/../.. ${JULIA_INCLUDE_DIR} ) \ No newline at end of file diff --git a/examples/MyProject/cmake/find/FindJulia.cmake b/install/resources/FindJulia.cmake similarity index 100% rename from examples/MyProject/cmake/find/FindJulia.cmake rename to install/resources/FindJulia.cmake diff --git a/examples/MyProject/main.cpp b/install/resources/main.cpp similarity index 100% rename from examples/MyProject/main.cpp rename to install/resources/main.cpp From 1ce625dea4e2908499a44ae3c40aa9dd291f70ac Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 19:50:15 +0100 Subject: [PATCH 25/71] modified --- install/init.sh | 3 +-- install/resources/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/install/init.sh b/install/init.sh index 0e832f6..23663e7 100644 --- a/install/init.sh +++ b/install/init.sh @@ -31,6 +31,7 @@ mkdir -p build cd build cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DCMAKE_INSTALL_PREFIX="$project_root/$project_name/jluna" +make install cd ../.. cp ./jluna/install/resources/CMakeLists.txt ./CMakeLists.txt @@ -45,8 +46,6 @@ cd build cmake .. make -#rm -r $project_root/$project_name - exit 0 diff --git a/install/resources/CMakeLists.txt b/install/resources/CMakeLists.txt index bb9e7c7..58ea369 100644 --- a/install/resources/CMakeLists.txt +++ b/install/resources/CMakeLists.txt @@ -6,7 +6,7 @@ project(MyProject VERSION 0.0.0 LANGUAGES CXX) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/find") find_package(Julia 1.7.0 REQUIRED) -find_library(jluna REQUIRED NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib HINTS ${CMAKE_SOURCE_DIR}/jluna/build) +find_library(jluna REQUIRED NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib HINTS ${CMAKE_SOURCE_DIR}/jluna) ### Declare Executable From 8d6dc3ab80160f1f23f48f5b39b88e2ebdd20464 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 19:56:16 +0100 Subject: [PATCH 26/71] stashing --- install/init.sh | 2 +- install/resources/CMakeLists.txt | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/install/init.sh b/install/init.sh index 23663e7..4783845 100644 --- a/install/init.sh +++ b/install/init.sh @@ -31,7 +31,7 @@ mkdir -p build cd build cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DCMAKE_INSTALL_PREFIX="$project_root/$project_name/jluna" -make install +make cd ../.. cp ./jluna/install/resources/CMakeLists.txt ./CMakeLists.txt diff --git a/install/resources/CMakeLists.txt b/install/resources/CMakeLists.txt index 58ea369..c738b09 100644 --- a/install/resources/CMakeLists.txt +++ b/install/resources/CMakeLists.txt @@ -2,11 +2,14 @@ cmake_minimum_required(VERSION 3.12) project(MyProject VERSION 0.0.0 LANGUAGES CXX) -### Find julia / jluna - +# find julia list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/find") find_package(Julia 1.7.0 REQUIRED) -find_library(jluna REQUIRED NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib HINTS ${CMAKE_SOURCE_DIR}/jluna) + +# find jluna +find_library(jluna REQUIRED + NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib + PATHS ${CMAKE_SOURCE_DIR}/jluna ${CMAKE_SOURCE_DIR}/jluna/build) ### Declare Executable From 7b7e7df25f1ab154415e874f037fb250b96779f7 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 19:56:52 +0100 Subject: [PATCH 27/71] stashing --- install/resources/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/resources/CMakeLists.txt b/install/resources/CMakeLists.txt index c738b09..43a7bb9 100644 --- a/install/resources/CMakeLists.txt +++ b/install/resources/CMakeLists.txt @@ -21,6 +21,6 @@ target_link_libraries(my_executable PRIVATE target_compile_features(my_executable PUBLIC cxx_std_20) target_include_directories(my_executable PRIVATE "$" - ${CMAKE_SOURCE_DIR}/../.. + ${CMAKE_SOURCE_DIR}/jluna ${JULIA_INCLUDE_DIR} ) \ No newline at end of file From c8ad423b5a6fd8049a840ae5407d4d01084e4f2a Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 19:58:54 +0100 Subject: [PATCH 28/71] stashing --- install/init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/init.sh b/install/init.sh index 4783845..85b5434 100644 --- a/install/init.sh +++ b/install/init.sh @@ -30,7 +30,7 @@ cd jluna mkdir -p build cd build -cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DCMAKE_INSTALL_PREFIX="$project_root/$project_name/jluna" +cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DCMAKE_INSTALL_PREFIX="$project_root/$project_name/jluna/build" make cd ../.. From 1632679def777eb15cc72aa386acc607c357f06f Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 21:57:49 +0100 Subject: [PATCH 29/71] first draft new installation guide --- README.md | 74 +++--- docs/installation.md | 296 +++++++++++++++++++++-- docs/~installation.md | 394 ------------------------------- install/init.sh | 48 +++- install/resources/CMakeLists.txt | 6 +- install/resources/main.cpp | 6 +- 6 files changed, 369 insertions(+), 455 deletions(-) delete mode 100644 docs/~installation.md diff --git a/README.md b/README.md index 333ad45..b8b222c 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ Heavily inspired in design and syntax by (but in no way affiliated with) the exc 5. [Dependencies](#dependencies)
5.1 [julia 1.7.0+](#dependencies)
5.2 [Supported Compilers: gcc10, gcc11, clang12](#dependencies)
- 5.3 [cmake 3.16+](#dependencies)
- 5.4 [unix-based OS](#dependencies)
+ 5.3 [cmake 3.12+](#dependencies)
6. [License](#license) +7. [Authors](#credits) --- @@ -146,6 +146,7 @@ NonJuliaType(["new"]) Some of the many advantages `jluna` has over the C-API include: + expressive, generic syntax ++ automatically detects and links julia + call C++ functions from julia using any julia-type + assigning C++-side proxies also mutates the corresponding variable julia-side + any C++ type can be moved between Julia and C++. Any julia-type can be wrapped @@ -183,9 +184,8 @@ Advanced users are encouraged to check the headers (available in `jluna/include/ For `jluna` you'll need: + [**Julia 1.7.0**](https://julialang.org/downloads/#current_stable_release) (or higher) -+ [**cmake 3.16**](https://cmake.org/download/) (or higher) ++ [**cmake 3.12**](https://cmake.org/download/) (or higher) + C++ Compiler (see below) -+ unix-based* 64-bit operating system Currently [**g++10**](https://askubuntu.com/questions/1192955/how-to-install-g-10-on-ubuntu-18-04), [**g++11**](https://lindevs.com/install-g-on-ubuntu/) and [**clang++-12**](https://linux-packages.com/ubuntu-focal-fossa/package/clang-12) are fully supported. g++-11 is the primary compiler used for development of `jluna` and is thus recommended. MSVC is untested but may work. @@ -197,50 +197,62 @@ Currently [**g++10**](https://askubuntu.com/questions/1192955/how-to-install-g-1 A step-by-step tutorial on how to create, compile, and link a new C++ Project with `jluna` can be found [here](./docs/installation.md). It is recommended that you follow this guide closely, instead of trying to resolve issues on your own. -### For Advanced Users Only +### Creating a new Project from Scratch -Users familiar with C++ and cmake can go through the following steps (on unix-based operating systems): +> this feature is only available on unix systems -Install: +Download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). -+ `g++-11` (or `clang++-12`) -+ `julia 1.7+` -+ `cmake 3.16+` +Then execute (in the same folder you downloaded `init.sh` to): -Then execute (in the same directory as your `CMakeLists.txt`): +```cpp +/bin/bash init.sh [ = clang++-12] +``` +Where ++ `` is the name of your desired project folder, for example `MyProject` ++ `` is the root path to your new project folder, for exmaple `/home/user/Desktop` ++ `` is one of `g++-10`, `g++-11`, `clang++-12` -```bash -git clone https://github.com/Clemapfel/jluna.git +The bash script will create a folder in `/` (i.e. `/home/user/Desktop/MyProject`), clone jluna, build it, then create for you a full project with a working `hello world` for you. `init.sh` even compiles the new project for you once to make sure everything works. -export JULIA_PATH=$(julia -e "println(joinpath(Sys.BINDIR, \"..\"))") +If errors appear at any point, head to [troubleshooting](./docs/installation.md#troubleshooting). -mkdir build -cd build -cmake -D CMAKE_CXX_COMPILER=g++-11 .. # or clang++-12 -make -./JLUNA_TEST +### Installing `jluna` Globally -cd .. -rm -r build -``` +Execute, in any public directory -Where `JULIA_PATH` needs to be set at the time of compilation. +```bash +git clone https://github.com/Clemapfel/jluna +cd jluna +mkdir build +cd build +cmake .. -DCMAKE_CXX_COMPILER= -DCMAKE_INSTALL_PREFIX= +make install +``` -Link against `jluna/libjluna.so`, `jluna/libjluna_c_adapter.so` and `$ENV{JULIA_PATH}/lib/libjulia.so`. +Where ++ `` is one of `g++-10`, `g++-11`, `clang++-12` ++ `` is the install directory, for example `usr/local` -Add `"${CMAKE_SOURCE_DIR}/jluna"` and `"$ENV{JULIA_PATH}/include/julia"` to your include directories. +Afterwards, you can make `jluna` available to your library using -Then you can make `jluna` available to your library using: +```cmake +find_library(jluna REQUIRED + NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib + PATHS ) -```cpp -#include -#include +target_link_libraries( ${jluna} ${}) ``` -If errors appear at any point, head to the [step-by-step guide](./docs/installation.md). +Where ++ `` is the same path specified during `cmake ..`, before ++ `` is the Julia Package + ---- +It may be instructive to check out [this basic template cmake](./install/resources/CMakeLists.txt). A `FindJulia.cmake` can be found [here](./install/resources/FindJulia.cmake).Download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). + +If errors appear at any point, head to [troubleshooting](./docs/installation.md#troubleshooting). ## License diff --git a/docs/installation.md b/docs/installation.md index e6a675f..6d7de5c 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,11 +1,33 @@ # Creating a Project with jluna -The following is a step-by-step guide to creating an application using `jluna` from scratch. +The following is a step-by-step guide on how to install jluna and how to create our application using `jluna`, from scratch. ### Table of Contents - +1. [Installing jluna](#installing-jluna)
+ 1.1 [Cloning from Git](#cloning-from-git)
+ 1.2 [Configuring CMake](#configure-cmake)
+ 1.3 [make install](#make-install)
+2. [Creating a new Project](#creating-a-project-with-jluna)
+ 2.1 [Project Folder](#project-folder)
+ 2.2 [Cloning jluna](#cloning-jluna)
+ 2.3 [Building jluna](#building-jluna)
+ 2.4 [main.cpp](#our-maincpp)
+ 2.5 [CMakelists.txt](#our-cmakeliststxt)
+ 2.6 [FindJulia.cmake](#findjuliacmake)
+ 2.7 [Building our Application](#building-our-application)
+3. [Troubleshooting](#troubleshooting)
+ 3.1 [Permission Denied](#permission-denied)
+ 3.2 [Unable to Detect Julia Executable](#unable-to-detect-the-julia-executable)
+ 3.3 [Found Unsuitable Version](#could-not-find-julia-found-unsuitable-version)
+ 3.4 [Could NOT find Julia: Missing X](#could-not-find-julia-missing-x)
+ 3.5 [Could not find `julia.h` / `jluna.hpp`](#cannot-find-juliah--jlunahpp)
+ 3.6 [Could not find libjluna_c_adapter](#when-trying-to-initialize-jlunacppcall-cannot-find-libjluna_c_adapter)
+ + ## Installing jluna +### Cloning from Git + To install jluna globally, we navigate into any public folder (henceforth assumed to be `Desktop`) and execute: ```bash @@ -15,44 +37,288 @@ mkdir build cd build ``` -This will have cloned the `jluna` git repository into a folder called `Desktop/jluna`. We know call: +This will have cloned the `jluna` git repository into a folder called `Desktop/jluna`. + +### Configure CMake + +We now call: ```bash # in Desktop/jluna/build -cmake .. -DCMAKE_CXX_COMPILER=g++-10 -make install +cmake .. -DCMAKE_CXX_COMPILER= -DCMAKE_INSTALL_PREFIX= ``` -At this point, some errors may appear. If this is the case, head to [troubleshooting](#troubleshooting). -We manually specify the C++ compiler here. It can be any of: +Where `` is one of: + `g++-10` + `g++-11` + `clang++-12` -> Note that window supports is experimental. This means specifying `MSVC` may work, however this is untested. The [cpp compiler support]() list seems to imply that MSVC 19.30 or newer is required to compile `jluna`. +> Window supports is experimental. This means specifying `MSVC` may work, however this is untested. The [cpp compiler support]() list seems to imply that MSVC 19.30 or newer is required to compile `jluna`. + +And `` is the desired install path (for example `/usr/local`). Keep note of this path, as we may need it later. -If the command does not recognize the compiler, even though you are are sure it is installed, it may be necessary to specify the full path to the compiler executable, e.g: `-DCMAKE_CXX_COMPILER=/usr/bin/g++-10`. +If the command does not recognize the compiler, even though you are are sure it is installed, it may be necessary to specify the full path to the compiler executable, instead of just the name. For example: +``` +-DCMAKE_CXX_COMPILER=/usr/bin/g++-10 +``` -These commands will install jluna into the default shared library folder (usually `/usr/local` (on unix)). If we want the shared libraries to appear somewhere else, we can instead specify the directory like so: +Some errors may appear here, if this is the case, head to [troubleshooting](#troubleshooting). + +### Make Install + +Having succesfully configured cmake, we now call: ```bash # in Desktop/jluna/build -cmake .. -DCMAKE_CXX_COMPILER=g++-10 -DCMAKE_INSTALL_PREFIX=~/our/custom/path make install ``` -Having installed `jluna`, two shared libraries `libjluna.so` and `libjluna_c_adapter.so` have now appeared in the install directories. Advanced users can now make jluna available from withing their `CMakeLists.txt` by using: +Which will create two shared libraries `libjluna.so`, and `libjluna_c_adapter.so` in the install directories. We can now link our own library or executable in our own `CMakeLists.txt`, using + +```cmake +# in users own CMakeLists.txt +set(JLUNA_DIR "") +find_library(jluna REQUIRED + NAMES libjluna.so libjluna.dll libjluna.dll.a libjluna.lib + HINTS ${JLUNA_DIR} +) +``` + +Where `` is the path specified as `-DCMAKE_INSTALL_PREFIX` during configuration. + +After `find_library`, we link our own library `my_library` using: + +```cmake +# in users own CMakeLists.txt +target_link_libraries(my_library ${jluna} ${}) +target_include_directories(${JLUNA_DIR}) +``` + +Where `` is the package containing the julia C-API. + +## Creating a New Project + +This section will guide users unfamiliar with cmake or C++ through the process of creating a working hello-world executable using julia and `jluna`. + +> Note that, on unix-like systems, this process can be automated using `jluna/install/init.sh`. See the here](../README.md#creating-a-new-project-from-scratch) + +### Project Folder + +First, we need to create our project folder. This will be assumed to be `~/Desktop/MyProject`: + +```bash +cd ~/Desktop/ +mkdir MyProject +``` + +### Cloning jluna + +We now need to clone jluna and install it locally: + +```bash +# in ~/Desktop/MyProject +git clone https://github.com/clemapfel/jluna.git +``` + +### Building jluna + +For `jluna` to know where to look for our julia executable, we need to set `JULIA_BINDIR`. On some system, this environment variable is set automatically during the install of julia. If this is not the case, we need to manually set it. + +First we access the julia binary directory using: + +```bash +# in ~/Desktop/MyProject +julia -e "println(Sys.BINDIR)" +``` +``` +~/path/to/our/julia-1.7.2/bin +``` + +Where the output of this call different for each user. + +Taking note of the julia binary path, we now build jluna + +```bash +# in ~/Desktop/MyProject +cd jluna +mkdir build +cd build +cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DCMAKE_INSTALL_PREFIX=~/Desktop/MyProject/jluna/build -DJULIA_BINDIR=~/path/to/our/julia-1.7.2/bin +make +``` + +Where `-DJULIA_BINDIR` is set to the output of `julia -e "println(Sys.BINDIR)"`, and `-DCMAKE_INSTALL_PREFIX` is set to MyProject/jluna/build. + +This will compile jluna, leaving `libjluna_c_adapter` nad `libjluna` in `MyProject/jluna/build`. + +If errors appear at any point during configuration or make, head to [troubleshooting](#troubleshooting). + +### Our main.cpp + +We need C++ code for our own application to call, because of this we create `main.cpp` in the folder `~Desktop/MyProject/`: + +```bash +cd ~/Desktop/MyProject +gedit main.cpp +``` + +Where `gedit` can be replaced with any common text editor, such as `vim`, `emacs`, `Notepad++`, etc.. + +We replace the contents of `main.cpp` with: + +```cpp +#include + +using namespace jluna; + +int main() +{ + State::initialize(); + Base["println"]("Your project is setup and working!"); +} +``` + +Then safe and close the file. + +### Our CMakeLists.txt + +We will be building our own project with cmake again, so we first create a `CMakeLists.txt` in `~/Desktop/MyProject`: + +```bash +# in ~/Deskopt/MyProject +gedit CMakeLists.txt +``` +And replace it's content with the following: + +```cmake +cmake_minimum_required(VERSION 3.12) + +# project name and version +project(MyProject VERSION 0.0.0 LANGUAGES CXX) + +# make FindJulia available to our cmake +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/find") + +# locate the julia package +find_package(Julia 1.7.0 REQUIRED) + +# locate the jluna library +find_library(jluna REQUIRED + NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib + HINTS ${CMAKE_SOURCE_DIR}/jluna ${CMAKE_SOURCE_DIR}/jluna/build) + +# declare our executable +add_executable(my_executable ${CMAKE_SOURCE_DIR}/main.cpp) + +# link jluna and julia +target_link_libraries(my_executable PRIVATE + ${jluna} + "$" +) + +# set it to C++20 +target_compile_features(my_executable PUBLIC cxx_std_20) + +# add the jluna and julia directory as include directories +target_include_directories(my_executable PRIVATE + "$" + ${CMAKE_SOURCE_DIR}/jluna + ${JULIA_INCLUDE_DIR} +) +``` + +This `CMakeLists.txt` finds both Julia and `jluna` for us, then links them with our executable, and adds the include directory for `julia.h` and `jluna.hpp` to our paths. + +### FindJulia.cmake + +To find julia, we need a `FindJulia.cmake`, which is provided by `jluna`. First, we create the the corresponding file in `MyProject/cmake/find`: + +```bash +# in ~/Desktop/MyProject +mkdir cmake +cd cmake +mkdir find +cd find +gedit FindJulia.cmake +``` + +And replace its content with [this](../install/resources/FindJulia.cmake). + +It is not necessary to understand what this file does, just know that by calling ```cmake -find_package(jluna REQUIRES NAMES libjluna.so HINTS /path/to/jluna) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/find") ``` -Where `/path/to/jluna` is the directory jluna was installed in the previous step specified through `CMAKE_INSTALL_PREFIX`. +It allows us to `find_package` julia, which we need to link our executable with. + +## Building our Application -Note that on windows, instead of `libjluna.so`, one of `libjluna.lib`, `libjluna.dll` or `libjluna.dll.a` should be used. +We're almost done! We lastly add the `build` folder to our own project: + +```bash +# in ~Desktop/MyProject/ +mkdir build +``` + +Our project directory should now look like this: + +``` +MyProject/ + main.cpp + CMakeLists.txt + build/ + cmake/ + find/ + FindJulia.cmake + jluna + jluna.hpp + (...) + include/ + (...) + build/ + libjluna.* + libjluna_c_adapter.* +``` + +Where `*` is one of `.so`, `.dll`, `.dll.a`, `.lib`. + +We are now ready to build our application: + +```bash +# in ~/Desktop/MyProject +cd Build +cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DJULIA_BINDIR=~/path/to/our/julia-1.7.2/bin +``` + +Where `DJULIA_BINDIR` was set to the same path, that we used [when building jluna](#building-jluna). + +We can now call + +```bash +# in ~/Desktop/MyProject +make +``` + +Which will compile our application and leave us with `my_executable` which we can now execute: + +```bash +# in ~/Desktop/MyProject +./my_executable +``` +``` +[JULIA][LOG] initialization successfull. +hello julia +``` + +--- ## Troubleshooting +### Permission Denied + +During `make install` or execution the bash script, your OS may notify you that it was unable to write to a folder due to missing permissions. Either run `make install` as `sudo` (or as administrator on windows), or specify a different folder for which basic processes have write permission. + ### Unable to detect the Julia executable When calling: diff --git a/docs/~installation.md b/docs/~installation.md deleted file mode 100644 index 760d7f7..0000000 --- a/docs/~installation.md +++ /dev/null @@ -1,394 +0,0 @@ -# Creating a Project with jluna - -The following is a step-by-step guide to creating an application using `jluna` from scratch. - -### Table of Contents -1. [Creating the Project](#creating-the-project) -2. [Setting JULIA_PATH](#setting-julia_path) -3. [Recompiling `jluna`](#building-jluna) -4. [Linking `jluna`](#linking-jluna)
- 4.1 [main.cpp](#linking-jluna)
- 4.2 [CMakeLists.txt](#linking-jluna)
-5. [Troubleshooting](#troubleshooting)
- 5.1 [CMake: Cannot determine location of julia image](#cannot-determine-location-of-julia-image)
- 5.2 [CMake: Cannot find julia.h / libjulia.so](#cannot-find-juliah--libjuliaso)
- 5.3 [C++: Cannot find / ](#cannot-find-juliah--jlunahpp)
- 5.4 [C++: State::initialize fails](#stateinitialize-fails)
-6. [Creating an Issue](#) - -### Creating the Project - -First, we create our workspace directory. For the remainder of this section, this will be assumed to be `~/my_project`. We now execute: - -```bash -cd ~/my_project -git clone https://github.com/Clemapfel/jluna.git -``` - -This adds the folder `jluna/` to our directory. We now need to compile `jluna`. - -### Setting JULIA_PATH - -To tell `jluna` where to find julia, we need to set the environment variable `JULIA_PATH`, which contains the path to the local julia image. We set it in bash using: - -```bash -export JULIA_PATH=$(julia -e "println(joinpath(Sys.BINDIR, \"..\"))") -``` - -Here, we're calling the julia REPL inline to output the global variable `Sys.BINDIR`, which contains the path to the currently used julia binary. We verify `JULIA_PATH` was set correctly by using: - -```bash -echo $JULIA_PATH -``` -``` -/home/user/Applications/julia/bin/.. -``` -Of course, this path will be different for each user.
Note the prefix `/` which designates an absolute path starting at root and that there is no post-fix `/`. If `JULIA_PATH` reports an empty string, it may be because the `julia` command is not available on a system level. If this is the case, we can simply call the above command from within the julia REPL manually - -```julia -println(joinpath(Sys.BINDIR, "..")) -``` -``` -/path/to/your/julia/bin/.. -``` - -And copy-paste the resulting output to assign `JULIA_PATH` in bash like so: - -```bash -export JULIA_PATH=/path/to/your/julia/bin/.. -``` - -We can now continue to compiling `jluna` using cmake, being sure to stay in the same bash session where we set `JULIA_PATH`. To set `JULIA_PATH` globally, consider consulting [this guide](https://unix.stackexchange.com/questions/117467/how-to-permanently-set-environmental-variables). This way, it does not have to re-set anytime a bash session ends. - -### Building `jluna` - -With `JULIA_PATH` set correctly, we navigate into `~/my_project/jluna/` and create a new build directory, then call cmake from within that directory: - -```bash -cd ~/my_project/jluna -mkdir build -cd build -cmake -D CMAKE_CXX_COMPILER=g++-11 .. # or clang++-12 -make -``` - -You may need to specify the absolute path to `g++-11` / `clang-12` if their respective executables are not available in the default search paths. - -When compiling, warnings of the following type may appear: - -``` -(...) -/home/user/Applications/julia/bin/../include/julia/julia_locks.h:72:32: warning: ‘++’ expression of ‘volatile’-qualified type is deprecated [-Wvolatile] - 72 | jl_current_task->ptls->defer_signal++; \ -(...) -``` - -This is because the official julia header `julia.h` is slightly out of date. The warning is unrelated to `jluna`s codebase, `jluna` itself should report no warnings or errors. If this is not the case, head to [troubleshooting](#troubleshooting). - -We verify everything works by running `JLUNA_TEST` which we just compiled: - -```bash -# 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 -``` - -This means everything works! - -We then clean up the build files using: - -```bash -# in ~/my_project/jluna/build -cd .. -rm -r build -``` - -We have now compiled and verified `jluna` and are left with a shiny new `libjluna.so` and `libjluna_c_adapter.so` in `~/my_project/jluna/`. These are the shared libraries that contain `jluna`s functionality. - -Advanced users can stop this tutorial now and simply link their library against `libjluna.so`, `libjluna_c_adapter.so` (both in '`~/my_project/jluna/`) and against `libjulia.so`, which is in the directory `$ENV{JULIA_PATH}/lib/`. - - -For people who aren't yet as familiar with cmake and linking, let's continue: - -### Linking `jluna` - -We now need to create our own application. First we create a `main.cpp`: - -```bash -cd ~/my_project -gedit main.cpp -``` - -This will open a GUI editor, if `gedit` is unavailable, any other editor (`vim`, `nano`, `emacs`, etc.) can be used. - -We replace the contents of `main.cpp` with the following: - -```cpp -#include - -using namespace jluna; - -int main() -{ - State::initialize(); - Base["println"]("hello julia"); -} -``` - -then safe and close the file. - -To compile our project, we again use cmake. We first create `CMakeLists.txt`: - -```bash -# in ~/my_project/ -gedit CMakeLists.txt -``` - -And replace its contents with the following: - -```cmake -cmake_minimum_required(VERSION 3.16) - -# name of our project -project(MyProject) - -# julia -if (NOT DEFINED ENV{JULIA_PATH}) - message(WARNING "JULIA_PATH was not set correctly. Consider re-reading the jluna installation tutorial at https://github.com/Clemapfel/jluna/blob/master/docs/installation.md#setting-julia_path to fix this issue") -endif() - -set(JULIA_INCLUDE "$ENV{JULIA_PATH}/include/julia") - -set(JULIA_LIB "$ENV{JULIA_PATH}/lib/libjulia.so") - -find_package(jluna REQUIRED) - -# add our executable -add_executable(MY_EXECUTABLE ${CMAKE_SOURCE_DIR}/main.cpp) - -target_include_directories(MY_EXECUTABLE PRIVATE ${JULIA_INCLUDE}) - -# link executable with jluna, jluna_c_adapter and julia -target_link_libraries(MY_EXECUTABLE jluna::jluna ${JULIA_LIB}) -``` - -We again save and close the file, then create our own build folder and run cmake, just like we did with `jluna` before - -```bash -# in ~/my_project -mkdir build -cd build -cmake -D CMAKE_CXX_COMPILER=g++-11 .. -make -``` - -If errors appear, be sure `JULIA_PATH` is still set correctly, as it is needed to find `julia.h`. Otherwise, head to [troubleshooting](#troubleshooting). - -After compilation succeeded, the directory should now have the following layout: - -``` -my_project/ - CMakeLists.txt - main.cpp - jluna/ - libjluna.so - libjluna_c_adapter.so - jluna.hpp - (...) - build/ - MY_EXECUTABLE - (...) -``` -Where names with a `/` suffix are folders. - -We can now run our application using: - -```bash -# in ~/my_project/build -./MY_EXECUTABLE -``` -``` -[JULIA][LOG] initialization successfull. -hello julia -``` - -`State::initialize()` may fail. If this is the case, head to [troubleshooting](#troubleshooting). Otherwise, congratulations! We are done and can now start developing our own application with the aid of julia and `jluna`. - ---- - -## Troubleshooting - -### Cannot determine location of julia image - -When compiling `jluna`, the following error may occur: - -``` - Cannot determine location of julia image. Before running cmake, please - manually set the environment variable JULIA_PATH using - - export JULIA_PATH=/path/to/your/.../julia - - If you are unsure of the location of your julia image, you can access the - path from within the julia REPL using - - println(joinpath(Sys.BINDIR, "..")) - - For more information, visit - https://github.com/Clemapfel/jluna/blob/master/README.md#troubleshooting -``` - -This is because `JULIA_PATH` is not properly set. Repeat the section on [setting `JULIA_PATH`](#setting-julia_path) to resolve this issue. - -### Cannot find julia.h / libjulia.so - -When building `jluna`, the following warnings may appear: - -``` -CMake Warning at CMakeLists.txt:37 (message): - Cannot find library header julia.h in (...) -``` - -This means verification of the directory specified through `JULIA_PATH` failed. We can make sure the path is correct by verifying: - -+ the path is an absolute path starting at root -+ the path has a prefix `/` -+ the path has no suffix `/` -+ the path is the same as reported in the julia REPL - -If all of these are true, it may be that your julia image is corrupted or compressed. The julia folder should have the following layout: - -``` -julia/ - bin/ - julia - include/ - julia/ - julia.h - (...) - lib/ - libjulia.so - (...) - - (...) -``` -Where names with a suffix `/` are folders. If your julia folder looks different, redownload the latest official release [here](https://julialang.org/downloads/#current_stable_release) and reassign `JULIA_PATH` accordingly. - -### Cannot find / - -The following error may appear when compiling your library: - -``` -fatal error: julia.h: No such file or directory - 3 | #include - | ^~~~~~~~~ -compilation terminated. -``` - -or, similarly: - -``` -fatal error: jluna.hpp: No such file or directory - 3 | #include - | ^~~~~~~~~~~ -compilation terminated. -``` - -This means the `include_directories` in cmake where set improperly. Make sure the following lines are present in your `CMakeLists.txt`: - -``` -include_directories("${CMAKE_SOURCE_DIR}/jluna") -include_directories("$ENV{JULIA_PATH}/include/julia") -``` - -Furthermore, make sure your directory has the following structure: - -``` -my_project/ - main.cpp - CMakeLists.txt - jluna/ - libjluna.so - libjluna_c_adapter.so - jluna.hpp - include/ - (...) - (...) - build/ - (...) -``` - -And make sure `JULIA_PATH` is set correctly (see above). - -### State::initialize fails - -#### AssertionError("jluna requires julia v1.7.0 or higher") - -`jluna` asserts wether the correct version of julia is present on initialization. If the following exception occurs when calling `State::initialize`: - -``` -terminate called after throwing an instance of 'jluna::JuliaException' - what(): [JULIA][EXCEPTION] AssertionError("jluna requires julia v1.7.0 or higher, but v1.6.2 was detected. Please download the latest julia release at https://julialang.org/downloads/#current_stable_release, set JULIA_PATH accordingly, then recompile jluna using cmake. For more information, visit https://github.com/Clemapfel/jluna/blob/master/README.md#troubleshooting") - -signal (6): Aborted -in expression starting at none:0 -(...) -``` - -It means that your julia version is out of date. [Download the latest version](https://julialang.org/downloads/#current_stable_release), set `JULIA_PATH` to point to it, then recompile `jluna` as outlined [above](#building-jluna). - -### ERROR: could not load library - -When calling `State::initialize`, julias C-API may report an error of the following type: - -``` -ERROR: could not load library "(...)/lib/julia/sys.so" -(...)/lib/julia/sys.so: cannot open shared object file: No such file or directory -``` - -This can mean three things - -+ A) `JULIA_PATH` was set incorrectly (see above) -+ B) your executable `MY_EXECUTABLE` does not have read permission for the folders in `JULIA_PATH` -+ C) julia is not installed on a system level - -If C is true, replace `State::initialize()` with its overload: - -```cpp -State::initialize("/path/to/(...)/julia/bin") -``` -Where `/path/to/(...)` is replaced with the absolute path to your image of julia. This will tell the C-API to load julia from that image, rather than from the default system image. - -## Creating an Issue - -If your problem still persists, it may be appropriate to open a github issue. First, please verify that: - -+ you are on a linux-based, 64-bit operating system -+ julia 1.7.0 (or higher) is installed and no older version exists on your machine -+ cmake 3.16 (or higher) is installed and no older version exists on your machine -+ g++-10 or g++-11 is installed -+ gcc-9 (or higher) is installed -+ when building with cmake, you specified `-D CMAKE_CXX_COMPILER=g++-11` correctly - - cmake is able to find the executable `g++-11` in the default search paths - - the same applies to `-D CMAKE_C_COMPILER=gcc-9` as well - - any given issue may be compiler specific, consider trying `clang-12` instead -+ `~/my_project/CMakeLists.txt` is identical to the code in [installation](#linking-jluna) -+ `State::initialize` and `JULIA_PATH` are modified as outlined [above](#stateinitialize-fails) -+ `jluna` was freshly pulled from the git repo and recompiled -+ `~/my_project/jluna/` contains `libjluna.so` and `libjluna_c_adapter.so` -+ `~/my_project/jluna/build/JLUNA_TEST` was ran -+ your issue is not otherwise covered in [troubleshooting](#troubleshooting), or any other already resolved issue - -If and only if all of the above apply, head to the [issues tab](https://github.com/Clemapfel/jluna/issues). There, please create an issue and -+ describe your problem -+ state your operating system, distro and compiler version -+ copy-paste the output of `JLUNA_TEST` (even if all tests are `OK`) -+ provide a minimum working example of your project that recreates the bug - -We will try to resolve your problem as soon as possible and are thankful for your input and collaboration. - ---- \ No newline at end of file diff --git a/install/init.sh b/install/init.sh index 85b5434..9539ad8 100644 --- a/install/init.sh +++ b/install/init.sh @@ -1,38 +1,64 @@ #!/bin/bash - -# # init.sh # # this bash script creates a new C++ project using jluna. -# It is intended to be used for novice users, advanced users are encouraged to -# `make install` jluna and link to it and julia in their own project +# It is intended for novice users, advanced users are encouraged to +# `make install` jluna and link it and julia to their own project manually # # for more information, visit https://github.com/Clemapfel/jluna/blob/master/docs/installation.md # +# @param $1: project name (i.e. "MyProject") +# @param $2: project root path (i.e "/home/user/Desktop") +# @param $3: (optional) compiler. One of: "g++-10", "g++-11", "clang++-12" +# +# catch input if [ -z "$1" ] | [ -z "$2" ]; then - echo "Usage: /bin/bash init.sh " + echo "Usage: /bin/bash init.sh [ = clang++-12]" exit 1 fi +if [ -n "$3" ]; then + compiler="clang++-12" +else + compiler="$3" +fi + +# catch unset JULIA_BINDIR +if [ -z "$JULIA_BINDIR" ]; then + printf "JULIA_BINDIR was not set. Please do so manually, using \`export JULIA_BINDIR=\$(julia -e \"println(Sys.BINDIR)\")\`\n" + exit 0 +fi + +# project directory project_name="$1" project_root="$2" +# prevent accidental deletion +if [ -d "$project_root/$project_name" ]; then + printf "Folder $project_root/$project_name already exists. Please first delete it manually or specify a different directory\n" + exit 0 +fi + +# setup project folder echo "creating $project_root/$project_name..." cd $project_root mkdir -p $project_name cd $project_name +# clone jluna git clone -b cmake_rework https://github.com/Clemapfel/jluna.git +# build jluna cd jluna mkdir -p build cd build -cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DCMAKE_INSTALL_PREFIX="$project_root/$project_name/jluna/build" +cmake .. -DCMAKE_CXX_COMPILER=$compiler -DCMAKE_INSTALL_PREFIX="$project_root/$project_name/jluna/build" make +# copy main.cpp, CMakeLists.txt and FindJulia into project folder cd ../.. cp ./jluna/install/resources/CMakeLists.txt ./CMakeLists.txt cp ./jluna/install/resources/main.cpp ./main.cpp @@ -40,12 +66,18 @@ cp ./jluna/install/resources/main.cpp ./main.cpp mkdir -p $project_root/$project_name/cmake/find cp ./jluna/install/resources/FindJulia.cmake ./cmake/find/FindJulia.cmake +# build project cd $project_root/$project_name -mkdir - build +mkdir build cd build -cmake .. +cmake .. -DCMAKE_CXX_COMPILER=$compiler make +# execute hello world +printf "\n" +./my_executable + +# exit exit 0 diff --git a/install/resources/CMakeLists.txt b/install/resources/CMakeLists.txt index 43a7bb9..880d4bc 100644 --- a/install/resources/CMakeLists.txt +++ b/install/resources/CMakeLists.txt @@ -1,5 +1,6 @@ -cmake_minimum_required(VERSION 3.12) +# this file was generate by jluna/install/init.sh +cmake_minimum_required(VERSION 3.12) project(MyProject VERSION 0.0.0 LANGUAGES CXX) # find julia @@ -11,8 +12,7 @@ find_library(jluna REQUIRED NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib PATHS ${CMAKE_SOURCE_DIR}/jluna ${CMAKE_SOURCE_DIR}/jluna/build) -### Declare Executable - +# executable add_executable(my_executable ${CMAKE_SOURCE_DIR}/main.cpp) target_link_libraries(my_executable PRIVATE ${jluna} diff --git a/install/resources/main.cpp b/install/resources/main.cpp index 3fb71dd..bdc2762 100644 --- a/install/resources/main.cpp +++ b/install/resources/main.cpp @@ -1,6 +1,4 @@ -// -// this main.cpp was created by jluna/install.sh -// +// this file was generated by jluna/install.sh #include @@ -9,5 +7,5 @@ using namespace jluna; int main() { State::initialize(); - Base["println"]("hello julia"); + Base["println"]("Your project is setup and working!"); } From c06242b5cbd41d0dc10a1b07729ca79f1ebb77c4 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 22:03:44 +0100 Subject: [PATCH 30/71] polish --- README.md | 14 ++++++++------ docs/installation.md | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b8b222c..0f435ff 100644 --- a/README.md +++ b/README.md @@ -199,9 +199,11 @@ A step-by-step tutorial on how to create, compile, and link a new C++ Project wi ### Creating a new Project from Scratch +`jluna` offers a one-line wizard for installing it and creating a new project, along with its own, finished `CMakeLists.txt` and a hello world. + > this feature is only available on unix systems -Download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). +To do so, download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). Then execute (in the same folder you downloaded `init.sh` to): @@ -210,14 +212,13 @@ Then execute (in the same folder you downloaded `init.sh` to): ``` Where + `` is the name of your desired project folder, for example `MyProject` -+ `` is the root path to your new project folder, for exmaple `/home/user/Desktop` ++ `` is the root path to your new project folder, for example `/home/user/Desktop` + `` is one of `g++-10`, `g++-11`, `clang++-12` -The bash script will create a folder in `/` (i.e. `/home/user/Desktop/MyProject`), clone jluna, build it, then create for you a full project with a working `hello world` for you. `init.sh` even compiles the new project for you once to make sure everything works. +The bash script will create a folder in `/` (i.e. `/home/user/Desktop/MyProject`), clone jluna, build it, then, create for you a full project with a working `hello world`. `init.sh` even compiles the new project once. to make sure everything works. If errors appear at any point, head to [troubleshooting](./docs/installation.md#troubleshooting). - ### Installing `jluna` Globally Execute, in any public directory @@ -246,11 +247,12 @@ target_link_libraries( ${jluna} ${}) ``` Where -+ `` is the same path specified during `cmake ..`, before ++ `` is the same path specified during configuration before + `` is the Julia Package ++ `` is the name of your library or executable -It may be instructive to check out [this basic template cmake](./install/resources/CMakeLists.txt). A `FindJulia.cmake` can be found [here](./install/resources/FindJulia.cmake).Download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). +It may be instructive to check out [this basic template cmake](./install/resources/CMakeLists.txt). A `FindJulia.cmake` can be found [here](./install/resources/FindJulia.cmake). Download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). If errors appear at any point, head to [troubleshooting](./docs/installation.md#troubleshooting). diff --git a/docs/installation.md b/docs/installation.md index 6d7de5c..7233a6d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -80,7 +80,7 @@ Which will create two shared libraries `libjluna.so`, and `libjluna_c_adapter.s set(JLUNA_DIR "") find_library(jluna REQUIRED NAMES libjluna.so libjluna.dll libjluna.dll.a libjluna.lib - HINTS ${JLUNA_DIR} + PATHS ${JLUNA_DIR} ) ``` From 02a828f7d962a14773e947b3e2571dfe0b3a5a27 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 22:06:50 +0100 Subject: [PATCH 31/71] renamed developer mode --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b2e7ea..9231549 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(jluna VERSION 0.8.4 LANGUAGES CXX) include(cmake/project-is-top-level.cmake) if(PROJECT_IS_TOP_LEVEL) - option(DEVELOPER_MODE "Enable developer mode" OFF) + option(jluna_DEVELOPER_MODE "Enable developer mode" OFF) endif() ### Find Julia ### @@ -114,7 +114,7 @@ endif() ### Developer mode ### -if(NOT DEVELOPER_MODE) +if(NOT jluna_DEVELOPER_MODE) return() elseif(NOT PROJECT_IS_TOP_LEVEL) message( @@ -124,7 +124,7 @@ elseif(NOT PROJECT_IS_TOP_LEVEL) endif() include(CTest) -if(DEVELOPER_MODE) +if(jluna_DEVELOPER_MODE) add_executable( jluna_test .test/main.cpp From fbaadd400e707518b8fa419ec92d84d88cfdea1c Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 22:09:47 +0100 Subject: [PATCH 32/71] fixed include_julia.inl brackets --- .src/state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.src/state.cpp b/.src/state.cpp index 7fbe8a6..9a7ba6d 100644 --- a/.src/state.cpp +++ b/.src/state.cpp @@ -15,7 +15,7 @@ #include #include #include -#include "include_julia.inl" +#include <.src/include_julia.inl> namespace jluna::detail { From 612f89fe6f09f9f6b68b8cb027b3ad6ef7121156 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 23:32:02 +0100 Subject: [PATCH 33/71] polish --- cmake/find/FindJulia.cmake | 5 ++--- install/init.sh | 2 ++ install/resources/CMakeLists.txt | 18 ++++++++++++------ install/resources/FindJulia.cmake | 1 - 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index 5c1e445..886886f 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -2,7 +2,6 @@ macro(julia_bail_if_false message var) if(NOT ${var}) set(Julia_FOUND 0) set(Julia_NOT_FOUND_MESSAGE "${message}") - message(FATAL_ERROR "${message}") return() endif() endmacro() @@ -54,11 +53,11 @@ find_path( ) julia_bail_if_false("Cannot find julia.h. Make sure JULIA_BINDIR is set correctly and that your image is uncompressed.\nFor more information, visit https://github.com/Clemapfel/jluna/blob/master/docs/installation.md" JULIA_INCLUDE_DIR) -#if(NOT DEFINED JULIA_VERSION) +if(NOT DEFINED JULIA_VERSION) file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" JULIA_VERSION_LOCAL LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" JULIA_VERSION_LOCAL "${JULIA_VERSION_LOCAL}") set(JULIA_VERSION "${JULIA_VERSION_LOCAL}") -#endif() +endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( diff --git a/install/init.sh b/install/init.sh index 9539ad8..ae05e6f 100644 --- a/install/init.sh +++ b/install/init.sh @@ -61,6 +61,8 @@ make # copy main.cpp, CMakeLists.txt and FindJulia into project folder cd ../.. cp ./jluna/install/resources/CMakeLists.txt ./CMakeLists.txt +sed -i "s/@PROJECT_NAME@/$project_name/" ./CMakeLists.txt + cp ./jluna/install/resources/main.cpp ./main.cpp mkdir -p $project_root/$project_name/cmake/find diff --git a/install/resources/CMakeLists.txt b/install/resources/CMakeLists.txt index 880d4bc..70ce7b6 100644 --- a/install/resources/CMakeLists.txt +++ b/install/resources/CMakeLists.txt @@ -1,16 +1,18 @@ # this file was generate by jluna/install/init.sh - cmake_minimum_required(VERSION 3.12) -project(MyProject VERSION 0.0.0 LANGUAGES CXX) +project(@PROJECT_NAME@ VERSION 0.0.0 LANGUAGES CXX) # find julia list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/find") find_package(Julia 1.7.0 REQUIRED) # find jluna +set(CMAKE_FIND_LIBRARY_SUFFIXES_WIN32 ".lib;.dll;.dll.a;") +set(CMAKE_FIND_LIBRARY_SUFFIXES_UNIX ".so") + find_library(jluna REQUIRED - NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib - PATHS ${CMAKE_SOURCE_DIR}/jluna ${CMAKE_SOURCE_DIR}/jluna/build) + NAMES jluna + PATHS ${CMAKE_SOURCE_DIR}/jluna/build) # executable add_executable(my_executable ${CMAKE_SOURCE_DIR}/main.cpp) @@ -18,9 +20,13 @@ target_link_libraries(my_executable PRIVATE ${jluna} "$" ) -target_compile_features(my_executable PUBLIC cxx_std_20) + +# set C++ standard +target_compile_features(my_executable PRIVATE cxx_std_20) + +# include directories target_include_directories(my_executable PRIVATE - "$" + ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/jluna ${JULIA_INCLUDE_DIR} ) \ No newline at end of file diff --git a/install/resources/FindJulia.cmake b/install/resources/FindJulia.cmake index ef7627d..d583964 100644 --- a/install/resources/FindJulia.cmake +++ b/install/resources/FindJulia.cmake @@ -2,7 +2,6 @@ macro(julia_bail_if_false message var) if(NOT ${var}) set(Julia_FOUND 0) set(Julia_NOT_FOUND_MESSAGE "${message}") - message(FATAL_ERROR "${message}") return() endif() endmacro() From b4eb1a4600d9984e489a6f4099b49f55356600c3 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 23:32:11 +0100 Subject: [PATCH 34/71] removed presets --- CMakePresets.json | 64 ----------------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 CMakePresets.json diff --git a/CMakePresets.json b/CMakePresets.json deleted file mode 100644 index bc2821e..0000000 --- a/CMakePresets.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "version": 2, - "cmakeMinimumRequired": { - "major": 3, - "minor": 20, - "patch": 0 - }, - "configurePresets": [ - { - "name": "cmake-pedantic", - "hidden": true, - "warnings": { - "dev": true, - "deprecated": true, - "uninitialized": true, - "unusedCli": true, - "systemVars": false - }, - "errors": { - "dev": true, - "deprecated": true - } - }, - { - "name": "dev-mode", - "hidden": true, - "inherits": "cmake-pedantic", - "cacheVariables": { - "shared_DEVELOPER_MODE": "ON" - } - }, - { - "name": "clang-tidy", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_CLANG_TIDY": "clang-tidy;--header-filter=${sourceDir}/*" - } - }, - { - "name": "ci-std", - "description": "This preset makes sure the project actually builds with at least the specified standard", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_EXTENSIONS": "OFF", - "CMAKE_CXX_STANDARD": "20", - "CMAKE_CXX_STANDARD_REQUIRED": "ON" - } - }, - { - "name": "flags-unix", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_FLAGS": "-Wno-deprecated-volatile -Wno-dev" - } - }, - { - "name": "flags-windows", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_FLAGS": "/W4 /permissive- /utf-8 /volatile:iso /EHsc /Zc:__cplusplus /Zc:throwingNew" - } - } - ] -} From 6e1403b57b9d917886b802d3b1de535d186d533e Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 23:32:25 +0100 Subject: [PATCH 35/71] removed manual logging --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9231549..7caa575 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,6 @@ target_compile_features(jluna_c_adapter PUBLIC cxx_std_20) target_include_directories(jluna_c_adapter PUBLIC "$") target_link_libraries(jluna_c_adapter PUBLIC "$") -message("[LOG] writing libjluna_c_adapter to globally available directory \"${C_ADAPTER_PATH}\"") - ### Declare Library ### add_library(jluna SHARED @@ -96,7 +94,7 @@ add_library(jluna SHARED include/gc_sentinel.hpp ) -target_link_libraries(jluna PUBLIC jluna_c_adapter "$") +target_link_libraries(jluna PUBLIC jluna_c_adapter) target_include_directories(jluna PRIVATE "$") ### HACK: export all symbols on Windows ### @@ -125,6 +123,8 @@ endif() include(CTest) if(jluna_DEVELOPER_MODE) + + #TODO: add proper CTest for TESTING_BUILD add_executable( jluna_test .test/main.cpp From 171ea88b84bb1aaadfafde09b8a8714bd984782d Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 23:35:59 +0100 Subject: [PATCH 36/71] removed "" includes --- CMakeLists.txt | 1 - include/array.hpp | 4 ++-- include/box.hpp | 2 +- include/cppcall.hpp | 2 +- include/exceptions.hpp | 2 +- include/module.hpp | 2 +- include/proxy.hpp | 2 +- include/state.hpp | 2 +- include/symbol.hpp | 2 +- include/type.hpp | 2 +- include/typedefs.hpp | 2 +- include/unbox.hpp | 2 +- include/usertype.hpp | 2 +- 13 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7caa575..71b3787 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,6 @@ endif() include(CTest) if(jluna_DEVELOPER_MODE) - #TODO: add proper CTest for TESTING_BUILD add_executable( jluna_test .test/main.cpp diff --git a/include/array.hpp b/include/array.hpp index ea16890..cdb2e7f 100644 --- a/include/array.hpp +++ b/include/array.hpp @@ -318,5 +318,5 @@ namespace jluna } } -#include ".src/array.inl" -#include ".src/array_iterator.inl" \ No newline at end of file +#include <.src/array.inl" +#include <.src/array_iterator.inl" \ No newline at end of file diff --git a/include/box.hpp b/include/box.hpp index 9d600e4..f722df0 100644 --- a/include/box.hpp +++ b/include/box.hpp @@ -197,4 +197,4 @@ namespace jluna }; } -#include ".src/box.inl" \ No newline at end of file +#include <.src/box.inl" \ No newline at end of file diff --git a/include/cppcall.hpp b/include/cppcall.hpp index 1a9a549..b5e09e3 100644 --- a/include/cppcall.hpp +++ b/include/cppcall.hpp @@ -87,4 +87,4 @@ namespace jluna Function* register_unnamed_function(const Lambda_t& lambda); } -#include ".src/cppcall.inl" \ No newline at end of file +#include <.src/cppcall.inl" \ No newline at end of file diff --git a/include/exceptions.hpp b/include/exceptions.hpp index b20ac85..871a6fa 100644 --- a/include/exceptions.hpp +++ b/include/exceptions.hpp @@ -82,4 +82,4 @@ namespace jluna Any* operator""_eval(const char*, size_t); } -#include ".src/exceptions.inl" \ No newline at end of file +#include <.src/exceptions.inl" \ No newline at end of file diff --git a/include/module.hpp b/include/module.hpp index 438c4b2..c7c59bf 100644 --- a/include/module.hpp +++ b/include/module.hpp @@ -121,4 +121,4 @@ namespace jluna }; } -#include ".src/module.inl" \ No newline at end of file +#include <.src/module.inl" \ No newline at end of file diff --git a/include/proxy.hpp b/include/proxy.hpp index 97e9f20..d8740dc 100644 --- a/include/proxy.hpp +++ b/include/proxy.hpp @@ -207,4 +207,4 @@ namespace jluna }; } -#include ".src/proxy.inl" \ No newline at end of file +#include <.src/proxy.inl" \ No newline at end of file diff --git a/include/state.hpp b/include/state.hpp index 6281e1e..42770d4 100644 --- a/include/state.hpp +++ b/include/state.hpp @@ -406,4 +406,4 @@ namespace jluna::State [[deprecated("use State::safe_eval instead")]] Proxy safe_script(const std::string&); } -#include ".src/state.inl" \ No newline at end of file +#include <.src/state.inl" \ No newline at end of file diff --git a/include/symbol.hpp b/include/symbol.hpp index 4b71f98..ab57313 100644 --- a/include/symbol.hpp +++ b/include/symbol.hpp @@ -68,4 +68,4 @@ namespace jluna }; } -#include ".src/symbol.inl" \ No newline at end of file +#include <.src/symbol.inl" \ No newline at end of file diff --git a/include/type.hpp b/include/type.hpp index 00081fa..8573983 100644 --- a/include/type.hpp +++ b/include/type.hpp @@ -206,4 +206,4 @@ namespace jluna inline Type WeakRef_t; } -#include ".src/type.inl" \ No newline at end of file +#include <.src/type.inl" \ No newline at end of file diff --git a/include/typedefs.hpp b/include/typedefs.hpp index 514e7d2..7f73aa2 100644 --- a/include/typedefs.hpp +++ b/include/typedefs.hpp @@ -6,7 +6,7 @@ #pragma once #include -#include ".src/typedefs.inl" +#include <.src/typedefs.inl> namespace jluna { diff --git a/include/unbox.hpp b/include/unbox.hpp index 0217b5f..d3aa2bf 100644 --- a/include/unbox.hpp +++ b/include/unbox.hpp @@ -154,4 +154,4 @@ namespace jluna }; } -#include ".src/unbox.inl" \ No newline at end of file +#include <.src/unbox.inl" \ No newline at end of file diff --git a/include/usertype.hpp b/include/usertype.hpp index 35d0b5e..9a79363 100644 --- a/include/usertype.hpp +++ b/include/usertype.hpp @@ -86,4 +86,4 @@ namespace jluna }; } -#include ".src/usertype.inl" \ No newline at end of file +#include <.src/usertype.inl" \ No newline at end of file From 537c01e86cd5645c0b6c393f79ac6299adb9152b Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 23:36:08 +0100 Subject: [PATCH 37/71] stashing --- docs/installation.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 7233a6d..48c2e37 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -45,7 +45,7 @@ We now call: ```bash # in Desktop/jluna/build -cmake .. -DCMAKE_CXX_COMPILER= -DCMAKE_INSTALL_PREFIX= +cmake .. -DCMAKE_CXX_COMPILER= [-DCMAKE_INSTALL_PREFIX=] ``` Where `` is one of: @@ -55,9 +55,9 @@ Where `` is one of: > Window supports is experimental. This means specifying `MSVC` may work, however this is untested. The [cpp compiler support]() list seems to imply that MSVC 19.30 or newer is required to compile `jluna`. -And `` is the desired install path (for example `/usr/local`). Keep note of this path, as we may need it later. +And `` is the desired install path. `-DCMAKE_INSTALL_PREFIX=` is optional, if it is specified manually, keep note of this path as we will need it later. -If the command does not recognize the compiler, even though you are are sure it is installed, it may be necessary to specify the full path to the compiler executable, instead of just the name. For example: +If the command does not recognize the compiler, even though you are sure it is installed, it may be necessary to specify the full path to the compiler executable instead of just the name. For example: ``` -DCMAKE_CXX_COMPILER=/usr/bin/g++-10 ``` @@ -66,25 +66,30 @@ Some errors may appear here, if this is the case, head to [troubleshooting](#tro ### Make Install -Having succesfully configured cmake, we now call: +Having successfully configured cmake, we now call: ```bash # in Desktop/jluna/build make install ``` -Which will create two shared libraries `libjluna.so`, and `libjluna_c_adapter.so` in the install directories. We can now link our own library or executable in our own `CMakeLists.txt`, using +Which will create two shared libraries `libjluna.*`, and `libjluna_c_adapter.*` in the install directories, where `*` is platform dependent, usually `.so` on unix and `.lib` or `.dll` on windows. We can now link our own library to our own `CMakeLists.txt`, using ```cmake -# in users own CMakeLists.txt -set(JLUNA_DIR "") +# in users own CMakeLists.txt +find_library(jluna REQUIRED) +``` + +If a custom install directory was specified, we need to make cmake aware of that using: + +```cmake +# in users own CMakeLists.txt find_library(jluna REQUIRED - NAMES libjluna.so libjluna.dll libjluna.dll.a libjluna.lib - PATHS ${JLUNA_DIR} + PATHS ) ``` -Where `` is the path specified as `-DCMAKE_INSTALL_PREFIX` during configuration. +Where `` is the path specified as `-DCMAKE_INSTALL_PREFIX` during configuration before. After `find_library`, we link our own library `my_library` using: From d2cb55ab2ac1a0b9a9518bde644a5bed54b70229 Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 23:40:13 +0100 Subject: [PATCH 38/71] polish --- install/init.sh | 3 ++- install/resources/CMakeLists.txt | 8 ++++---- install/resources/main.cpp | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/install/init.sh b/install/init.sh index ae05e6f..2f9b55a 100644 --- a/install/init.sh +++ b/install/init.sh @@ -18,6 +18,7 @@ if [ -z "$1" ] | [ -z "$2" ]; then exit 1 fi +# default compiler if [ -n "$3" ]; then compiler="clang++-12" else @@ -77,7 +78,7 @@ make # execute hello world printf "\n" -./my_executable +./hello_world # exit exit 0 diff --git a/install/resources/CMakeLists.txt b/install/resources/CMakeLists.txt index 70ce7b6..8e0b429 100644 --- a/install/resources/CMakeLists.txt +++ b/install/resources/CMakeLists.txt @@ -15,17 +15,17 @@ find_library(jluna REQUIRED PATHS ${CMAKE_SOURCE_DIR}/jluna/build) # executable -add_executable(my_executable ${CMAKE_SOURCE_DIR}/main.cpp) -target_link_libraries(my_executable PRIVATE +add_executable(hello_world ${CMAKE_SOURCE_DIR}/main.cpp) +target_link_libraries(hello_world PRIVATE ${jluna} "$" ) # set C++ standard -target_compile_features(my_executable PRIVATE cxx_std_20) +target_compile_features(hello_world PRIVATE cxx_std_20) # include directories -target_include_directories(my_executable PRIVATE +target_include_directories(hello_world PRIVATE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/jluna ${JULIA_INCLUDE_DIR} diff --git a/install/resources/main.cpp b/install/resources/main.cpp index bdc2762..4b7c0e0 100644 --- a/install/resources/main.cpp +++ b/install/resources/main.cpp @@ -1,4 +1,4 @@ -// this file was generated by jluna/install.sh +// this file was generated by jluna/init.sh #include From fcaad5b75225de1d38e20ba5f67ecd616da5b87d Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 23:52:25 +0100 Subject: [PATCH 39/71] removed non <> includes --- include/array.hpp | 4 ++-- include/box.hpp | 2 +- include/cppcall.hpp | 2 +- include/exceptions.hpp | 2 +- include/module.hpp | 2 +- include/proxy.hpp | 2 +- include/state.hpp | 2 +- include/symbol.hpp | 2 +- include/type.hpp | 2 +- include/unbox.hpp | 2 +- include/usertype.hpp | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/array.hpp b/include/array.hpp index cdb2e7f..22e5cb7 100644 --- a/include/array.hpp +++ b/include/array.hpp @@ -318,5 +318,5 @@ namespace jluna } } -#include <.src/array.inl" -#include <.src/array_iterator.inl" \ No newline at end of file +#include <.src/array.inl> +#include <.src/array_iterator.inl> \ No newline at end of file diff --git a/include/box.hpp b/include/box.hpp index f722df0..694ff25 100644 --- a/include/box.hpp +++ b/include/box.hpp @@ -197,4 +197,4 @@ namespace jluna }; } -#include <.src/box.inl" \ No newline at end of file +#include <.src/box.inl> \ No newline at end of file diff --git a/include/cppcall.hpp b/include/cppcall.hpp index b5e09e3..f768d5d 100644 --- a/include/cppcall.hpp +++ b/include/cppcall.hpp @@ -87,4 +87,4 @@ namespace jluna Function* register_unnamed_function(const Lambda_t& lambda); } -#include <.src/cppcall.inl" \ No newline at end of file +#include <.src/cppcall.inl> \ No newline at end of file diff --git a/include/exceptions.hpp b/include/exceptions.hpp index 871a6fa..81fa036 100644 --- a/include/exceptions.hpp +++ b/include/exceptions.hpp @@ -82,4 +82,4 @@ namespace jluna Any* operator""_eval(const char*, size_t); } -#include <.src/exceptions.inl" \ No newline at end of file +#include <.src/exceptions.inl> \ No newline at end of file diff --git a/include/module.hpp b/include/module.hpp index c7c59bf..cad9020 100644 --- a/include/module.hpp +++ b/include/module.hpp @@ -121,4 +121,4 @@ namespace jluna }; } -#include <.src/module.inl" \ No newline at end of file +#include <.src/module.inl> \ No newline at end of file diff --git a/include/proxy.hpp b/include/proxy.hpp index d8740dc..ee281fb 100644 --- a/include/proxy.hpp +++ b/include/proxy.hpp @@ -207,4 +207,4 @@ namespace jluna }; } -#include <.src/proxy.inl" \ No newline at end of file +#include <.src/proxy.inl> \ No newline at end of file diff --git a/include/state.hpp b/include/state.hpp index 42770d4..821e369 100644 --- a/include/state.hpp +++ b/include/state.hpp @@ -406,4 +406,4 @@ namespace jluna::State [[deprecated("use State::safe_eval instead")]] Proxy safe_script(const std::string&); } -#include <.src/state.inl" \ No newline at end of file +#include <.src/state.inl> \ No newline at end of file diff --git a/include/symbol.hpp b/include/symbol.hpp index ab57313..d7800b7 100644 --- a/include/symbol.hpp +++ b/include/symbol.hpp @@ -68,4 +68,4 @@ namespace jluna }; } -#include <.src/symbol.inl" \ No newline at end of file +#include <.src/symbol.inl> \ No newline at end of file diff --git a/include/type.hpp b/include/type.hpp index 8573983..91e39bc 100644 --- a/include/type.hpp +++ b/include/type.hpp @@ -206,4 +206,4 @@ namespace jluna inline Type WeakRef_t; } -#include <.src/type.inl" \ No newline at end of file +#include <.src/type.inl> \ No newline at end of file diff --git a/include/unbox.hpp b/include/unbox.hpp index d3aa2bf..605f238 100644 --- a/include/unbox.hpp +++ b/include/unbox.hpp @@ -154,4 +154,4 @@ namespace jluna }; } -#include <.src/unbox.inl" \ No newline at end of file +#include <.src/unbox.inl> \ No newline at end of file diff --git a/include/usertype.hpp b/include/usertype.hpp index 9a79363..f0f68a0 100644 --- a/include/usertype.hpp +++ b/include/usertype.hpp @@ -86,4 +86,4 @@ namespace jluna }; } -#include <.src/usertype.inl" \ No newline at end of file +#include <.src/usertype.inl> \ No newline at end of file From c02159c5b7348e5155b520a7948f995dfba65bcf Mon Sep 17 00:00:00 2001 From: clem Date: Thu, 17 Mar 2022 23:52:30 +0100 Subject: [PATCH 40/71] polish --- .src/include_julia.inl.in | 1 - 1 file changed, 1 deletion(-) diff --git a/.src/include_julia.inl.in b/.src/include_julia.inl.in index e2ffacc..5917c39 100644 --- a/.src/include_julia.inl.in +++ b/.src/include_julia.inl.in @@ -12,5 +12,4 @@ namespace jluna::detail static inline const char* include = R"( @JULIA_SOURCE@ )"; - } \ No newline at end of file From 6bb36f23bff992a90f4ad5618388a49428264714 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 00:00:50 +0100 Subject: [PATCH 41/71] stashing --- docs/installation.md | 46 ++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 48c2e37..afc9770 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,6 +1,6 @@ # Creating a Project with jluna -The following is a step-by-step guide on how to install jluna and how to create our application using `jluna`, from scratch. +The following is a step-by-step guide on how to install jluna, and how to create our own C++ application using jluna from scratch. ### Table of Contents 1. [Installing jluna](#installing-jluna)
@@ -23,12 +23,13 @@ The following is a step-by-step guide on how to install jluna and how to create 3.5 [Could not find `julia.h` / `jluna.hpp`](#cannot-find-juliah--jlunahpp)
3.6 [Could not find libjluna_c_adapter](#when-trying-to-initialize-jlunacppcall-cannot-find-libjluna_c_adapter)
- ## Installing jluna +This section will guide users on how to install jluna, either so it is globally available to all applications, or so it is localized to only a specific folder. + ### Cloning from Git -To install jluna globally, we navigate into any public folder (henceforth assumed to be `Desktop`) and execute: +We navigate into any public folder (henceforth assumed to be `Desktop`) and execute: ```bash git clone https://github.com/clemapfel/jluna.git @@ -45,7 +46,7 @@ We now call: ```bash # in Desktop/jluna/build -cmake .. -DCMAKE_CXX_COMPILER= [-DCMAKE_INSTALL_PREFIX=] +cmake .. -DCMAKE_CXX_COMPILER= -DCMAKE_INSTALL_PREFIX= ``` Where `` is one of: @@ -57,13 +58,14 @@ Where `` is one of: And `` is the desired install path. `-DCMAKE_INSTALL_PREFIX=` is optional, if it is specified manually, keep note of this path as we will need it later. -If the command does not recognize the compiler, even though you are sure it is installed, it may be necessary to specify the full path to the compiler executable instead of just the name. For example: +Some errors may appear here, if this is the case, head to [troubleshooting](#troubleshooting). + +If the command does not recognize the compiler, even though you are sure it is installed, it may be necessary to specify the full path to the compiler executable, instead. For example: + ``` -DCMAKE_CXX_COMPILER=/usr/bin/g++-10 ``` -Some errors may appear here, if this is the case, head to [troubleshooting](#troubleshooting). - ### Make Install Having successfully configured cmake, we now call: @@ -73,33 +75,49 @@ Having successfully configured cmake, we now call: make install ``` -Which will create two shared libraries `libjluna.*`, and `libjluna_c_adapter.*` in the install directories, where `*` is platform dependent, usually `.so` on unix and `.lib` or `.dll` on windows. We can now link our own library to our own `CMakeLists.txt`, using +Which will create two shared libraries `libjluna.*`, and `libjluna_c_adapter.*` in the install directories, where `*` is platform dependent, usually `.so` on unix and `.lib` or `.dll` on windows. + +We can now link our own executables or libraries using: ```cmake # in users own CMakeLists.txt -find_library(jluna REQUIRED) +find_library(jluna REQUIRED + NAMES jluna +) ``` -If a custom install directory was specified, we need to make cmake aware of that using: +If a custom install directory was specified, we need to make cmake aware of this: ```cmake # in users own CMakeLists.txt find_library(jluna REQUIRED + NAMES jluna PATHS ) ``` -Where `` is the path specified as `-DCMAKE_INSTALL_PREFIX` during configuration before. +Where `` is the path specified as `-DCMAKE_INSTALL_PREFIX` during configuration before. + +If `jluna` is still not found using `find_library`, we may need to manually specify the shared library suffixes like so: + +```cpp +set(CMAKE_FIND_LIBRARY_SUFFIXES_WIN32 ".lib;.dll;.dll.a;") +set(CMAKE_FIND_LIBRARY_SUFFIXES_UNIX ".so") +``` -After `find_library`, we link our own library `my_library` using: +After `find_library`, we link our own library (here assumed to be named `my_library`), using: ```cmake # in users own CMakeLists.txt target_link_libraries(my_library ${jluna} ${}) -target_include_directories(${JLUNA_DIR}) +target_include_directories(${JLUNA_DIR} ${}) ``` -Where `` is the package containing the julia C-API. +Where `` is the package containing the julia C-API and `` is the folder containing `julia.h`, usually `${JULIA_BINDIR}/../include` or `${JULIA_BINDIR}/../include/julia`. + +A simple, template 'CMakeLists.txt' is available [here](../install/resources/CMakeLists.txt) + +--- ## Creating a New Project From b87883180ca09ad0388671333f444fe12adf63de Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 00:55:54 +0100 Subject: [PATCH 42/71] second draft --- docs/installation.md | 145 +++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 81 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index afc9770..f282fe8 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -14,7 +14,7 @@ The following is a step-by-step guide on how to install jluna, and how to create 2.4 [main.cpp](#our-maincpp)
2.5 [CMakelists.txt](#our-cmakeliststxt)
2.6 [FindJulia.cmake](#findjuliacmake)
- 2.7 [Building our Application](#building-our-application)
+ 2.7 [make](#building-our-application)
3. [Troubleshooting](#troubleshooting)
3.1 [Permission Denied](#permission-denied)
3.2 [Unable to Detect Julia Executable](#unable-to-detect-the-julia-executable)
@@ -25,11 +25,11 @@ The following is a step-by-step guide on how to install jluna, and how to create ## Installing jluna -This section will guide users on how to install jluna, either so it is globally available to all applications, or so it is localized to only a specific folder. +This section will guide users on how to install `jluna`, either globally or in a folder-contained manner. ### Cloning from Git -We navigate into any public folder (henceforth assumed to be `Desktop`) and execute: +We first need to download `jluna`, to do this we navigate into any public folder (henceforth assumed to be `Desktop`) and execute: ```bash git clone https://github.com/clemapfel/jluna.git @@ -38,7 +38,7 @@ mkdir build cd build ``` -This will have cloned the `jluna` git repository into a folder called `Desktop/jluna`. +This will have cloned the `jluna` git repository into the folder `Desktop/jluna`. ### Configure CMake @@ -54,13 +54,14 @@ Where `` is one of: + `g++-11` + `clang++-12` -> Window supports is experimental. This means specifying `MSVC` may work, however this is untested. The [cpp compiler support]() list seems to imply that MSVC 19.30 or newer is required to compile `jluna`. - And `` is the desired install path. `-DCMAKE_INSTALL_PREFIX=` is optional, if it is specified manually, keep note of this path as we will need it later. + +> Window supports is experimental. This means using MSVC may work, however this is currently untested. The [cpp compiler support]() page seems to imply that MSVC 19.30 or newer is required to compile `jluna`. + Some errors may appear here, if this is the case, head to [troubleshooting](#troubleshooting). -If the command does not recognize the compiler, even though you are sure it is installed, it may be necessary to specify the full path to the compiler executable, instead. For example: +If the command does not recognize the compiler, even though you are sure it is installed, it may be necessary to specify the full path to the compiler executable instead, like so: ``` -DCMAKE_CXX_COMPILER=/usr/bin/g++-10 @@ -75,9 +76,9 @@ Having successfully configured cmake, we now call: make install ``` -Which will create two shared libraries `libjluna.*`, and `libjluna_c_adapter.*` in the install directories, where `*` is platform dependent, usually `.so` on unix and `.lib` or `.dll` on windows. +Which will create two shared libraries `libjluna.*`, and `libjluna_c_adapter.*` in the specified install directories, or the default install directory if unspecified. `*`, here, is platform dependent, usually `.so` on unix and `.lib` or `.dll` on windows. -We can now link our own executables or libraries using: +Now that `jluna` is installed on our system, we can link any executable or library inside any non-`jluna` `CMakeLists.txt` using: ```cmake # in users own CMakeLists.txt @@ -98,7 +99,7 @@ find_library(jluna REQUIRED Where `` is the path specified as `-DCMAKE_INSTALL_PREFIX` during configuration before. -If `jluna` is still not found using `find_library`, we may need to manually specify the shared library suffixes like so: +If `find_library` is still not able to find `jluna`, we may need to manually specify the shared library suffixes like so: ```cpp set(CMAKE_FIND_LIBRARY_SUFFIXES_WIN32 ".lib;.dll;.dll.a;") @@ -113,9 +114,16 @@ target_link_libraries(my_library ${jluna} ${}) target_include_directories(${JLUNA_DIR} ${}) ``` -Where `` is the package containing the julia C-API and `` is the folder containing `julia.h`, usually `${JULIA_BINDIR}/../include` or `${JULIA_BINDIR}/../include/julia`. +Where `` is the package containing the julia C-API and `` is the folder containing `julia.h`. + +The shared library location is usually ++ `${JULIA_BINDIR}/../lib` + +while the julia include directory is usually ++ `${JULIA_BINDIR}/../include/` or ++ `${JULIA_BINDIR}/../include/julia/` -A simple, template 'CMakeLists.txt' is available [here](../install/resources/CMakeLists.txt) +A simple template `CMakeLists.txt`, that may be a good point to start out with, is available [here](../install/resources/CMakeLists.txt). --- @@ -123,7 +131,7 @@ A simple, template 'CMakeLists.txt' is available [here](../install/resources/CMa This section will guide users unfamiliar with cmake or C++ through the process of creating a working hello-world executable using julia and `jluna`. -> Note that, on unix-like systems, this process can be automated using `jluna/install/init.sh`. See the here](../README.md#creating-a-new-project-from-scratch) +> Note that, on unix-like systems, this process can be automated using `jluna/install/init.sh`, as detailed [here](../README.md#creating-a-new-project-from-scratch). ### Project Folder @@ -157,35 +165,36 @@ julia -e "println(Sys.BINDIR)" ~/path/to/our/julia-1.7.2/bin ``` -Where the output of this call different for each user. - -Taking note of the julia binary path, we now build jluna +Where the output of this call different for each user. Using the julia binary path, we now build `jluna`: ```bash # in ~/Desktop/MyProject cd jluna mkdir build cd build -cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DCMAKE_INSTALL_PREFIX=~/Desktop/MyProject/jluna/build -DJULIA_BINDIR=~/path/to/our/julia-1.7.2/bin +cmake .. \ +-DCMAKE_CXX_COMPILER=clang++-12 \ +-DCMAKE_INSTALL_PREFIX=~/Desktop/MyProject/jluna/build \ +-DJULIA_BINDIR=~/path/to/our/julia-1.7.2/bin make ``` -Where `-DJULIA_BINDIR` is set to the output of `julia -e "println(Sys.BINDIR)"`, and `-DCMAKE_INSTALL_PREFIX` is set to MyProject/jluna/build. +Where `-DJULIA_BINDIR` is set to the output of `julia -e "println(Sys.BINDIR)"`, and `-DCMAKE_INSTALL_PREFIX` is set to `MyProject/jluna/build`. -This will compile jluna, leaving `libjluna_c_adapter` nad `libjluna` in `MyProject/jluna/build`. +This will compile jluna, leaving the shared libraries in `MyProject/jluna/build`. If errors appear at any point during configuration or make, head to [troubleshooting](#troubleshooting). -### Our main.cpp +### main.cpp -We need C++ code for our own application to call, because of this we create `main.cpp` in the folder `~Desktop/MyProject/`: +We need C++ code for our own application to call, so we need to create a `main.cpp`. We'll open a new documented named as such in the folder `~Desktop/MyProject/`: ```bash cd ~/Desktop/MyProject gedit main.cpp ``` -Where `gedit` can be replaced with any common text editor, such as `vim`, `emacs`, `Notepad++`, etc.. +Where `gedit` can be replaced with any common text editor, such as `vim`, `emacs`, `Notepad++`, etc. We replace the contents of `main.cpp` with: @@ -205,56 +214,19 @@ Then safe and close the file. ### Our CMakeLists.txt -We will be building our own project with cmake again, so we first create a `CMakeLists.txt` in `~/Desktop/MyProject`: +Just like `jluna`, we will be building our own applicatoin using cmake. We create a `CMakeLists.txt` in `~/Desktop/MyProject`: ```bash # in ~/Deskopt/MyProject gedit CMakeLists.txt ``` -And replace it's content with the following: - -```cmake -cmake_minimum_required(VERSION 3.12) - -# project name and version -project(MyProject VERSION 0.0.0 LANGUAGES CXX) - -# make FindJulia available to our cmake -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/find") - -# locate the julia package -find_package(Julia 1.7.0 REQUIRED) - -# locate the jluna library -find_library(jluna REQUIRED - NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib - HINTS ${CMAKE_SOURCE_DIR}/jluna ${CMAKE_SOURCE_DIR}/jluna/build) - -# declare our executable -add_executable(my_executable ${CMAKE_SOURCE_DIR}/main.cpp) - -# link jluna and julia -target_link_libraries(my_executable PRIVATE - ${jluna} - "$" -) - -# set it to C++20 -target_compile_features(my_executable PUBLIC cxx_std_20) - -# add the jluna and julia directory as include directories -target_include_directories(my_executable PRIVATE - "$" - ${CMAKE_SOURCE_DIR}/jluna - ${JULIA_INCLUDE_DIR} -) -``` +And replace it's content with [this template `CMakeLists.txt`](../install/resources/CMakeLists.txt). -This `CMakeLists.txt` finds both Julia and `jluna` for us, then links them with our executable, and adds the include directory for `julia.h` and `jluna.hpp` to our paths. +This `CMakeLists.txt` finds both Julia and `jluna` for us, then links them with our executable, and adds the include directory for `julia.h` and `jluna.hpp` to our paths. Note that this `CMakeLists.txt` depends on our project layout being exactly as detailed here, if we move `MyProject`, we may need to recompile `jluna` to updated any location-dependent code. ### FindJulia.cmake -To find julia, we need a `FindJulia.cmake`, which is provided by `jluna`. First, we create the the corresponding file in `MyProject/cmake/find`: +To find julia, we need a `FindJulia.cmake`, which is provided by `jluna`. First, we create the corresponding file in `MyProject/cmake/find`: ```bash # in ~/Desktop/MyProject @@ -273,11 +245,11 @@ It is not necessary to understand what this file does, just know that by calling list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/find") ``` -It allows us to `find_package` julia, which we need to link our executable with. +It allows us to `find_package` julia, which we need to link our executable with soon. ## Building our Application -We're almost done! We lastly add the `build` folder to our own project: +We're almost done! We only need to add the `build` folder for our own executable ```bash # in ~Desktop/MyProject/ @@ -306,6 +278,8 @@ MyProject/ Where `*` is one of `.so`, `.dll`, `.dll.a`, `.lib`. +Please verify the folder structure if you're coding along with this. + We are now ready to build our application: ```bash @@ -314,7 +288,7 @@ cd Build cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DJULIA_BINDIR=~/path/to/our/julia-1.7.2/bin ``` -Where `DJULIA_BINDIR` was set to the same path, that we used [when building jluna](#building-jluna). +Where `DJULIA_BINDIR` was set to the same path, that we used, [when building jluna](#building-jluna). We can now call @@ -323,7 +297,7 @@ We can now call make ``` -Which will compile our application and leave us with `my_executable` which we can now execute: +Which will compile our application and leave us with `my_executable` in `~/Desktop/MyProject/build`. We execute it like so: ```bash # in ~/Desktop/MyProject @@ -334,13 +308,15 @@ Which will compile our application and leave us with `my_executable` which we ca hello julia ``` +Again, this process can be completely automated using `jluna/install/init.sh`, available [here]([here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh)). + --- ## Troubleshooting ### Permission Denied -During `make install` or execution the bash script, your OS may notify you that it was unable to write to a folder due to missing permissions. Either run `make install` as `sudo` (or as administrator on windows), or specify a different folder for which basic processes have write permission. +During `make install`, or during execution of the bash script, your OS may notify you that it was unable to write to a folder due to missing permissions. To fix this, either run `make install` as `sudo` (or as administrator on windows), or specify a different folder using `-DCMAKE_INSTALL_PREFIX` for which `jluna` or cmake does have permission. ### Unable to detect the Julia executable @@ -368,12 +344,12 @@ Call Stack (most recent call first): -- Configuring incomplete, errors occurred! ``` -This error appears because jluna was unable to locate the julia package on your system. To make jluna aware of the location manually, we can pass the following variable to the cmake command: +This error appears, because `jluna` was unable to locate the julia package on your system. To make jluna aware of the location manually, we can pass the following variable to the cmake command: ```bash cmake .. -DJULIA_BINDIR=path/to/your/julia/bin -DCMAKE_COMPILER=g++-10 ``` -This is the path to he binary directory of your julia image. If you are unsure of it's location, you can execute +This is the path of the binary directory of your julia image. If you are unsure of its location, you can execute ```julia println(Sys.BINDIR) @@ -381,7 +357,7 @@ println(Sys.BINDIR) From inside the julia REPL. -### Could NOT find Julia: Found unsuitable version +### Found unsuitable version During the cmake configuration step, the following error may appear: @@ -401,7 +377,9 @@ Where X can be any of : + `JULIA_BINDIR` + `JULIA_INCLUDE_DIR` -This means that either `JULIA_BINDIR` was not set correctly or the directory it is pointing to is not the julia binary dir (a path always ending in `/bin`), or your julia image is compressed. Make sure the folder `JULIA_BINDIR` points to has the following layout: +This means that either `JULIA_BINDIR` was not set correctly or the directory it is pointing to is not the julia binary dir. Verify that the value of `JULIA_BINDIR` starts at root (`/` on unix and `C:/` on windows), ends in `/bin`, and that your julia image folder is uncompressed. + +Make sure the folder `JULIA_BINDIR` points to has the following layout: ``` julia*/ @@ -418,7 +396,7 @@ julia*/ (...) ``` -Then set `JULIA_BINDIR` to `/path/to/.../julia/bin`. +Where `*` may be a version suffix, such as `julia-1.7.2`. ### Cannot find / @@ -443,11 +421,15 @@ compilation terminated. This means the `include_directories` in cmake were set improperly. Make sure the following lines are present in your `CMakeLists.txt`: ``` -find_package(Julia) -find_package(jluna) +target_include_directories() +target_include_directories() ``` +Where + ++ `` is the install path of the `jluna` shared libary, specified during cmake configuration using `-DCMAKE_INSTALL_PREFIX` ++ `` is the location of `julia.h`, usually `${JULIA_BINDIR}/../include` or `${JULIA_BINDIR}/../include/julia` -### When trying to initialize jluna.cppcall: cannot find libjluna_c_adapter +### Cannot find libjluna_c_adapter When calling @@ -471,9 +453,10 @@ terminate called after throwing an instance of 'jluna::JuliaException' signal (6): Aborted ``` -To allow the local julia state to interface with jluna, it needs the shared c-adapter-library to be available. During `make install`, the following line should have appeared: +To allow the local julia state to interface with `jluna`, it needs the shared C-adapter-library to be available. During `make install`, `jluna` modifies its own code to keep track of the location of the C-adapter. If it was moved, `jluna` may no longer be able to find it. +To fix this, recompile jluna, as detailed [above](#make-install). +The C-adapter library is installed into the directory specified by `CMAKE_INSTALL_PREFIX` and needs to remain there in order for `jluna` to work. -``` -[LOG] writing libjluna_c_adapter to globally available directory "/home/Desktop/jluna/libjluna_c_adapter.so" -``` -Make sure the c_adapter shared library is still in that directory, if it is not, recompile jluna. The C-adapter library is installed into the directory specified by `CMAKE_INSTALL_PREFIX` and needs to remain there in order for `jluna` to work. +--- + +If your particular problem was not addressed in this section, feel free to [open an issue on GitHub](https://github.com/Clemapfel/jluna/issues). From 0c931578fe9a5a0470976dab31682abcad781b43 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 01:18:21 +0100 Subject: [PATCH 43/71] polish --- CMakeLists.txt | 59 +++++++++++++++++++++++-------- cmake/find/FindJulia.cmake | 32 +++++++++++++++-- cmake/install-rules.cmake | 4 +++ cmake/project-is-top-level.cmake | 3 ++ docs/installation.md | 14 +++++--- install/resources/FindJulia.cmake | 30 ++++++++++++++-- 6 files changed, 118 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71b3787..34c32ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,24 @@ cmake_minimum_required(VERSION 3.12) +# +# Build jluna. This cmake attempts to automatically detect the julia image +# If this is not possible, manually specify the path to the julia binary +# using: +# +# `-DJULIA_BINDIR=/path/to/.../julia/bin` +# +# If you are unsure of the location of this folder, you can access +# it from within the REPL using: +# +# `println(Sys.BINDIR)` +# +# ### Options ## +# +# jluna_DEVELOPER_MODE : enable building test and benchmark executables. Off by default +# BUILD_TESTING : build jluna_test, as CTest. On by default +# BUILD_BENCHMARK : build jluna_benchmark. On by default +# + project(jluna VERSION 0.8.4 LANGUAGES CXX) include(cmake/project-is-top-level.cmake) @@ -124,19 +143,29 @@ endif() include(CTest) if(jluna_DEVELOPER_MODE) - add_executable( - jluna_test - .test/main.cpp - .test/test.hpp - ) - target_link_libraries(jluna_test PRIVATE jluna) - add_test(NAME jluna_test COMMAND jluna_test) - - add_executable( - jluna_benchmark - .benchmark/main.cpp - .benchmark/benchmark.hpp - .benchmark/benchmark_aux.hpp - ) - target_link_libraries(jluna_benchmark PRIVATE jluna) + ### Declare Test ### + + option(BUILD_TESTING "Enable jluna_test" ON) + if (BUILD_TESTING) + add_executable( + jluna_test + .test/main.cpp + .test/test.hpp + ) + target_link_libraries(jluna_test PRIVATE jluna) + add_test(NAME jluna_test COMMAND jluna_test) + endif() + + ### Declare Benchmark ### + + option(BUILD_BENCHMARK "Enable jluna_benchmark" ON) + if (BUILD_BENCHMARK) + add_executable( + jluna_benchmark + .benchmark/main.cpp + .benchmark/benchmark.hpp + .benchmark/benchmark_aux.hpp + ) + target_link_libraries(jluna_benchmark PRIVATE jluna) + endif() endif() diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index 886886f..3c7352a 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -1,3 +1,22 @@ +# +# This FindJulia.cmake is intended to detect julia as a package. +# +# Use +# `list(APPEND CMAKE_MODULE_PATH "path/to/this/file")` +# `find_package(Julia 1.7.0 REQUIRED)` +# +# to make the julia target available through: +# `"$"` +# +# Furthermore the following variables will be set on +# successful detection: +# +# JULIA_LIBRARY : julia shared library +# JULIA_EXECUTABLE : julia REPL executable +# JULIA_BINDIR : directory to julia binary +# JULIA_INCLUDE_DIR : directory that contains julia.h +# + macro(julia_bail_if_false message var) if(NOT ${var}) set(Julia_FOUND 0) @@ -6,9 +25,11 @@ macro(julia_bail_if_false message var) endif() endmacro() +# detect julia executable find_program(JULIA_EXECUTABLE julia PATHS ENV JULIA_BINDIR) -julia_bail_if_false("Unable to detect the julia executable. Make sure JULIA_BINDIR is set correctly.\nFor more information, visit https://github.com/Clemapfel/jluna/blob/master/docs/installation.md" JULIA_EXECUTABLE) +julia_bail_if_false("Unable to detect the julia executable. Make sure JULIA_BINDIR is set correctly." JULIA_EXECUTABLE) +# detect julia binary dir if(NOT DEFINED JULIA_BINDIR) # The executable could be a chocolatey shim, so run some Julia code to report # the path of the BINDIR @@ -38,6 +59,7 @@ if(WIN32) endif() endif() +# detect julia library find_library(JULIA_LIBRARY julia HINTS "${JULIA_PATH_PREFIX}/lib") if(WIN32) @@ -45,14 +67,16 @@ if(WIN32) set(CMAKE_FIND_LIBRARY_PREFIXES "${julia_old_CMAKE_FIND_LIBRARY_PREFIXES}") endif() -julia_bail_if_false("Unable to find the julia shared library.\nFor more information, visit https://github.com/Clemapfel/jluna/blob/master/docs/installation.md" JULIA_LIBRARY) +julia_bail_if_false("Unable to find the julia shared library. Make sure JULIA_BINDIR is set correctly and that the julia image is uncompressed" JULIA_LIBRARY) +# detect julia include dir find_path( JULIA_INCLUDE_DIR julia.h HINTS "${JULIA_PATH_PREFIX}/include" "${JULIA_PATH_PREFIX}/include/julia" ) -julia_bail_if_false("Cannot find julia.h. Make sure JULIA_BINDIR is set correctly and that your image is uncompressed.\nFor more information, visit https://github.com/Clemapfel/jluna/blob/master/docs/installation.md" JULIA_INCLUDE_DIR) +julia_bail_if_false("Unable to find julia.h. Make sure JULIA_BINDIR is set correctly and that your image is uncompressed." JULIA_INCLUDE_DIR) +# detect julia version if(NOT DEFINED JULIA_VERSION) file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" JULIA_VERSION_LOCAL LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" JULIA_VERSION_LOCAL "${JULIA_VERSION_LOCAL}") @@ -66,6 +90,7 @@ find_package_handle_standard_args( VERSION_VAR JULIA_VERSION ) +# detect target properties if(NOT TARGET Julia::Julia) set(julia_has_implib NO) set(julia_library_type STATIC) @@ -102,4 +127,5 @@ if(NOT TARGET Julia::Julia) endif() endif() +# finish mark_as_advanced(JULIA_EXECUTABLE JULIA_BINDIR JULIA_LIBRARY JULIA_INCLUDE_DIR JULIA_VERSION JULIA_LIBRARY_DLL) diff --git a/cmake/install-rules.cmake b/cmake/install-rules.cmake index 7325226..4e647a7 100644 --- a/cmake/install-rules.cmake +++ b/cmake/install-rules.cmake @@ -1,3 +1,7 @@ +# +# Install rules for jluna/CMakeLists.txt +# + # find_package() call for consumers to find this project set(package jluna) diff --git a/cmake/project-is-top-level.cmake b/cmake/project-is-top-level.cmake index 3435fc0..f5bef7a 100644 --- a/cmake/project-is-top-level.cmake +++ b/cmake/project-is-top-level.cmake @@ -1,4 +1,7 @@ +# +# Indicate, whether project() was above was in the top level CMakeLists.txt file # This variable is set by project() in CMake 3.21+ +# string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}" diff --git a/docs/installation.md b/docs/installation.md index f282fe8..0d17510 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -54,7 +54,7 @@ Where `` is one of: + `g++-11` + `clang++-12` -And `` is the desired install path. `-DCMAKE_INSTALL_PREFIX=` is optional, if it is specified manually, keep note of this path as we will need it later. +And `` is the desired install path. `-DCMAKE_INSTALL_PREFIX=` is optional, if it is specified manually (not recommended), keep note of this path as we will need it later. > Window supports is experimental. This means using MSVC may work, however this is currently untested. The [cpp compiler support]() page seems to imply that MSVC 19.30 or newer is required to compile `jluna`. @@ -106,7 +106,13 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES_WIN32 ".lib;.dll;.dll.a;") set(CMAKE_FIND_LIBRARY_SUFFIXES_UNIX ".so") ``` -After `find_library`, we link our own library (here assumed to be named `my_library`), using: +Note that `jlunas` install rules also export is as a package, so it will be available through `find_package` on systems where it was installed globally like so: + +```cmake +find_package(jluna REQUIRED) +``` + +After `find_library` or `find_package`, we link our own library (here assumed to be named `my_library`), using: ```cmake # in users own CMakeLists.txt @@ -114,9 +120,9 @@ target_link_libraries(my_library ${jluna} ${}) target_include_directories(${JLUNA_DIR} ${}) ``` -Where `` is the package containing the julia C-API and `` is the folder containing `julia.h`. +Where `` is the library/package containing the julia C-API and `` is the folder containing `julia.h`. -The shared library location is usually +The shared julia library location is usually + `${JULIA_BINDIR}/../lib` while the julia include directory is usually diff --git a/install/resources/FindJulia.cmake b/install/resources/FindJulia.cmake index d583964..3c7352a 100644 --- a/install/resources/FindJulia.cmake +++ b/install/resources/FindJulia.cmake @@ -1,3 +1,22 @@ +# +# This FindJulia.cmake is intended to detect julia as a package. +# +# Use +# `list(APPEND CMAKE_MODULE_PATH "path/to/this/file")` +# `find_package(Julia 1.7.0 REQUIRED)` +# +# to make the julia target available through: +# `"$"` +# +# Furthermore the following variables will be set on +# successful detection: +# +# JULIA_LIBRARY : julia shared library +# JULIA_EXECUTABLE : julia REPL executable +# JULIA_BINDIR : directory to julia binary +# JULIA_INCLUDE_DIR : directory that contains julia.h +# + macro(julia_bail_if_false message var) if(NOT ${var}) set(Julia_FOUND 0) @@ -6,9 +25,11 @@ macro(julia_bail_if_false message var) endif() endmacro() +# detect julia executable find_program(JULIA_EXECUTABLE julia PATHS ENV JULIA_BINDIR) julia_bail_if_false("Unable to detect the julia executable. Make sure JULIA_BINDIR is set correctly." JULIA_EXECUTABLE) +# detect julia binary dir if(NOT DEFINED JULIA_BINDIR) # The executable could be a chocolatey shim, so run some Julia code to report # the path of the BINDIR @@ -38,6 +59,7 @@ if(WIN32) endif() endif() +# detect julia library find_library(JULIA_LIBRARY julia HINTS "${JULIA_PATH_PREFIX}/lib") if(WIN32) @@ -47,17 +69,19 @@ endif() julia_bail_if_false("Unable to find the julia shared library. Make sure JULIA_BINDIR is set correctly and that the julia image is uncompressed" JULIA_LIBRARY) +# detect julia include dir find_path( JULIA_INCLUDE_DIR julia.h HINTS "${JULIA_PATH_PREFIX}/include" "${JULIA_PATH_PREFIX}/include/julia" ) julia_bail_if_false("Unable to find julia.h. Make sure JULIA_BINDIR is set correctly and that your image is uncompressed." JULIA_INCLUDE_DIR) -#if(NOT DEFINED JULIA_VERSION) +# detect julia version +if(NOT DEFINED JULIA_VERSION) file(STRINGS "${JULIA_INCLUDE_DIR}/julia_version.h" JULIA_VERSION_LOCAL LIMIT_COUNT 1 REGEX JULIA_VERSION_STRING) string(REGEX REPLACE ".*\"([^\"]+)\".*" "\\1" JULIA_VERSION_LOCAL "${JULIA_VERSION_LOCAL}") set(JULIA_VERSION "${JULIA_VERSION_LOCAL}") -#endif() +endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( @@ -66,6 +90,7 @@ find_package_handle_standard_args( VERSION_VAR JULIA_VERSION ) +# detect target properties if(NOT TARGET Julia::Julia) set(julia_has_implib NO) set(julia_library_type STATIC) @@ -102,4 +127,5 @@ if(NOT TARGET Julia::Julia) endif() endif() +# finish mark_as_advanced(JULIA_EXECUTABLE JULIA_BINDIR JULIA_LIBRARY JULIA_INCLUDE_DIR JULIA_VERSION JULIA_LIBRARY_DLL) From d3d7cdb831b628c3adfcc2a644c9221d80a95e32 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 01:18:34 +0100 Subject: [PATCH 44/71] polish --- cmake/project-is-top-level.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/project-is-top-level.cmake b/cmake/project-is-top-level.cmake index f5bef7a..8bb3807 100644 --- a/cmake/project-is-top-level.cmake +++ b/cmake/project-is-top-level.cmake @@ -2,6 +2,7 @@ # Indicate, whether project() was above was in the top level CMakeLists.txt file # This variable is set by project() in CMake 3.21+ # + string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}" From f8963e001bc9b821021b03eebed9e374df49e877 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 01:23:51 +0100 Subject: [PATCH 45/71] added override --- install/init.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/install/init.sh b/install/init.sh index 2f9b55a..24890ac 100644 --- a/install/init.sh +++ b/install/init.sh @@ -10,6 +10,7 @@ # @param $1: project name (i.e. "MyProject") # @param $2: project root path (i.e "/home/user/Desktop") # @param $3: (optional) compiler. One of: "g++-10", "g++-11", "clang++-12" +# @param $4: (optional) If `TRUE`, overwrites folder if it already exists. # # catch input @@ -37,8 +38,13 @@ project_root="$2" # prevent accidental deletion if [ -d "$project_root/$project_name" ]; then - printf "Folder $project_root/$project_name already exists. Please first delete it manually or specify a different directory\n" - exit 0 + + if [ "$4" == "TRUE" ]; then + rm -r "$project_root/$project_name" + else + printf "Folder $project_root/$project_name already exists. Please first delete it manually or specify a different directory\n" + exit 0 + fi fi # setup project folder From e1c08ee61632e4f5d12a325d232d019e947ee2c5 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 01:30:13 +0100 Subject: [PATCH 46/71] removed output directory --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34c32ed..0f894a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,8 +118,7 @@ target_include_directories(jluna PRIVATE "$ ### HACK: export all symbols on Windows ### -set_target_properties(jluna jluna_c_adapter PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${C_ADAPTER_PATH} +set_target_properties(jluna PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS YES ) From 6bcf74d2debe29086d254d630ad6d9032c5a16b6 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 01:35:18 +0100 Subject: [PATCH 47/71] added library output directory --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f894a2..0a87e2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,8 +118,9 @@ target_include_directories(jluna PRIVATE "$ ### HACK: export all symbols on Windows ### -set_target_properties(jluna PROPERTIES +set_target_properties(jluna jluna_c_adapter PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS YES + LIBRARY_OUTPUT_DIRECTORY ${C_ADAPTER_PATH} ) ### Install rules ### From b2208259ffc5e929bbc07d97d16810f14163fc86 Mon Sep 17 00:00:00 2001 From: Clem Cords Date: Fri, 18 Mar 2022 16:34:38 +0100 Subject: [PATCH 48/71] remove source directory prefix Co-authored-by: friendlyanon <1736896+friendlyanon@users.noreply.github.com> --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a87e2c..d396fe2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ find_package(Julia 1.7.0 REQUIRED) file(READ include/jluna.jl JULIA_SOURCE) set(C_ADAPTER_PATH ${CMAKE_INSTALL_PREFIX}) -configure_file("${CMAKE_SOURCE_DIR}/.src/include_julia.inl.in" "${CMAKE_SOURCE_DIR}/.src/include_julia.inl" @ONLY) +configure_file(.src/include_julia.inl.in .src/include_julia.inl @ONLY) ### Declare C adapter ### From 041c1e76dbdf15aa43461ba9354f343589c95bbc Mon Sep 17 00:00:00 2001 From: Clem Cords Date: Fri, 18 Mar 2022 16:38:04 +0100 Subject: [PATCH 49/71] use project source dir Co-authored-by: friendlyanon <1736896+friendlyanon@users.noreply.github.com> --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d396fe2..c025ec9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ add_library( ) target_compile_features(jluna_c_adapter PUBLIC cxx_std_20) -target_include_directories(jluna_c_adapter PUBLIC "$") +target_include_directories(jluna_c_adapter PUBLIC "$") target_link_libraries(jluna_c_adapter PUBLIC "$") ### Declare Library ### From 6765c837e98519fb61233b618dcb9751411564df Mon Sep 17 00:00:00 2001 From: Clem Cords Date: Fri, 18 Mar 2022 16:38:28 +0100 Subject: [PATCH 50/71] user project source dir instead of cmake source Co-authored-by: friendlyanon <1736896+friendlyanon@users.noreply.github.com> --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c025ec9..7608330 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,7 @@ add_library(jluna SHARED ) target_link_libraries(jluna PUBLIC jluna_c_adapter) -target_include_directories(jluna PRIVATE "$") +target_include_directories(jluna PRIVATE "$") ### HACK: export all symbols on Windows ### From cab885caff644dc6aeb5331ab75de4cd955a706d Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 16:39:42 +0100 Subject: [PATCH 51/71] removed redundant conditional branch --- CMakeLists.txt | 51 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a87e2c..349a3d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,31 +141,28 @@ elseif(NOT PROJECT_IS_TOP_LEVEL) endif() include(CTest) -if(jluna_DEVELOPER_MODE) - - ### Declare Test ### - - option(BUILD_TESTING "Enable jluna_test" ON) - if (BUILD_TESTING) - add_executable( - jluna_test - .test/main.cpp - .test/test.hpp - ) - target_link_libraries(jluna_test PRIVATE jluna) - add_test(NAME jluna_test COMMAND jluna_test) - endif() - - ### Declare Benchmark ### - - option(BUILD_BENCHMARK "Enable jluna_benchmark" ON) - if (BUILD_BENCHMARK) - add_executable( - jluna_benchmark - .benchmark/main.cpp - .benchmark/benchmark.hpp - .benchmark/benchmark_aux.hpp - ) - target_link_libraries(jluna_benchmark PRIVATE jluna) - endif() +### Declare Test ### + +option(BUILD_TESTING "Enable jluna_test" ON) +if (BUILD_TESTING) + add_executable( + jluna_test + .test/main.cpp + .test/test.hpp + ) + target_link_libraries(jluna_test PRIVATE jluna) + add_test(NAME jluna_test COMMAND jluna_test) +endif() + +### Declare Benchmark ### + +option(BUILD_BENCHMARK "Enable jluna_benchmark" ON) +if (BUILD_BENCHMARK) + add_executable( + jluna_benchmark + .benchmark/main.cpp + .benchmark/benchmark.hpp + .benchmark/benchmark_aux.hpp + ) + target_link_libraries(jluna_benchmark PRIVATE jluna) endif() From acb10bf84d95fa43da62d0899ac71004040ad89b Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 16:51:39 +0100 Subject: [PATCH 52/71] update comments --- CMakeLists.txt | 43 ++++++++++++++++++------------- cmake/find/FindJulia.cmake | 53 +++++++++++++++++++++++++------------- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f60030e..5fc9a8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,30 @@ cmake_minimum_required(VERSION 3.12) -# -# Build jluna. This cmake attempts to automatically detect the julia image -# If this is not possible, manually specify the path to the julia binary -# using: -# -# `-DJULIA_BINDIR=/path/to/.../julia/bin` -# -# If you are unsure of the location of this folder, you can access -# it from within the REPL using: -# -# `println(Sys.BINDIR)` -# -# ### Options ## -# -# jluna_DEVELOPER_MODE : enable building test and benchmark executables. Off by default -# BUILD_TESTING : build jluna_test, as CTest. On by default -# BUILD_BENCHMARK : build jluna_benchmark. On by default -# +#[=======================================================================[.rst: + +Build jluna +----------- + +This cmake attempts to automatically detect the julia image. +If this is not possible, manually specify the path to the julia binary using: + + ``-DJULIA_BINDIR=/path/to/.../julia/bin`` + +If you are unsure of the location of this folder, you can access +it from within the REPL using: + + ``println(Sys.BINDIR)`` + +Options +^^^^^^^ +``jluna_DEVELOPER_MODE`` + enable building test and benchmark executables. Off by default +``BUILD_TESTING`` + build jluna_test, as CTest. On by default +``BUILD_BENCHMARK`` + build jluna_benchmark. On by default + +#]=======================================================================] project(jluna VERSION 0.8.4 LANGUAGES CXX) diff --git a/cmake/find/FindJulia.cmake b/cmake/find/FindJulia.cmake index 3c7352a..daa11c1 100644 --- a/cmake/find/FindJulia.cmake +++ b/cmake/find/FindJulia.cmake @@ -1,21 +1,38 @@ -# -# This FindJulia.cmake is intended to detect julia as a package. -# -# Use -# `list(APPEND CMAKE_MODULE_PATH "path/to/this/file")` -# `find_package(Julia 1.7.0 REQUIRED)` -# -# to make the julia target available through: -# `"$"` -# -# Furthermore the following variables will be set on -# successful detection: -# -# JULIA_LIBRARY : julia shared library -# JULIA_EXECUTABLE : julia REPL executable -# JULIA_BINDIR : directory to julia binary -# JULIA_INCLUDE_DIR : directory that contains julia.h -# +#[=======================================================================[.rst: + +FindJulia +----------- + +This module is intended to detect julia as a package. + +Imported Targets +^^^^^^^^^^^^^^^^ + +``Julia::Julia`` + Julia Package, if found + +Result Variables +^^^^^^^^^^^^^^^^ + +``JULIA_LIBRARY`` + julia shared library +``JULIA_EXECUTABLE`` + julia REPL executable +``JULIA_BINDIR`` + directory to julia binary +``JULIA_INCLUDE_DIR`` + directory that contains julia.h + +Usage +^^^^^ +Use: + ``list(APPEND CMAKE_MODULE_PATH "path/to/this/file")`` + ``find_package(Julia 1.7.0 REQUIRED)`` + +to make the julia target available to your target through + ``"$"`` + +#]=======================================================================] macro(julia_bail_if_false message var) if(NOT ${var}) From cb79868311ee439ba6024eee4790cf94c1732dd6 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 16:54:05 +0100 Subject: [PATCH 53/71] added fixme windows comment back in --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fc9a8e..10ebf95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,10 @@ target_include_directories(jluna PRIVATE "$ Date: Fri, 18 Mar 2022 16:54:47 +0100 Subject: [PATCH 54/71] fix unquoted variable use Co-authored-by: friendlyanon <1736896+friendlyanon@users.noreply.github.com> --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 10ebf95..0b89f5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ find_package(Julia 1.7.0 REQUIRED) ### Configure Files ### file(READ include/jluna.jl JULIA_SOURCE) -set(C_ADAPTER_PATH ${CMAKE_INSTALL_PREFIX}) +set(C_ADAPTER_PATH "${CMAKE_INSTALL_PREFIX}") configure_file(.src/include_julia.inl.in .src/include_julia.inl @ONLY) ### Declare C adapter ### From 387126af39138b307c841236daf6642fa17da98b Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 17:04:49 +0100 Subject: [PATCH 55/71] added versioning --- CMakeLists.txt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b89f5d..2c8ef63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,6 @@ target_link_libraries(jluna_c_adapter PUBLIC "$") ### Declare Library ### add_library(jluna SHARED - jluna.hpp include/exceptions.hpp @@ -125,14 +124,13 @@ target_include_directories(jluna PRIVATE "$ Date: Fri, 18 Mar 2022 17:09:34 +0100 Subject: [PATCH 56/71] fixed unquoted variable use --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c8ef63..8ce4c56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,7 +128,7 @@ set_target_properties(jluna jluna_c_adapter PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS YES # TODO VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION}" - LIBRARY_OUTPUT_DIRECTORY ${C_ADAPTER_PATH} + LIBRARY_OUTPUT_DIRECTORY "${C_ADAPTER_PATH}" ) # Fix this using the GenerateExportHeader CMake module and visibility properties. From 22cc937cd7d101429fe991d3a09d3b62e8045565 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 17:34:50 +0100 Subject: [PATCH 57/71] polish --- README.md | 67 +++++++++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 0f435ff..522985b 100644 --- a/README.md +++ b/README.md @@ -195,31 +195,8 @@ Currently [**g++10**](https://askubuntu.com/questions/1192955/how-to-install-g-1 ## [Installation & Troubleshooting](./docs/installation.md) -A step-by-step tutorial on how to create, compile, and link a new C++ Project with `jluna` can be found [here](./docs/installation.md). It is recommended that you follow this guide closely, instead of trying to resolve issues on your own. -### Creating a new Project from Scratch - -`jluna` offers a one-line wizard for installing it and creating a new project, along with its own, finished `CMakeLists.txt` and a hello world. - -> this feature is only available on unix systems - -To do so, download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). - -Then execute (in the same folder you downloaded `init.sh` to): - -```cpp -/bin/bash init.sh [ = clang++-12] -``` -Where -+ `` is the name of your desired project folder, for example `MyProject` -+ `` is the root path to your new project folder, for example `/home/user/Desktop` -+ `` is one of `g++-10`, `g++-11`, `clang++-12` - -The bash script will create a folder in `/` (i.e. `/home/user/Desktop/MyProject`), clone jluna, build it, then, create for you a full project with a working `hello world`. `init.sh` even compiles the new project once. to make sure everything works. - -If errors appear at any point, head to [troubleshooting](./docs/installation.md#troubleshooting). - -### Installing `jluna` Globally +> A step-by-step guide intended for users unfamiliar with cmake is available [here](./docs/installation.md) Execute, in any public directory @@ -228,31 +205,49 @@ git clone https://github.com/Clemapfel/jluna cd jluna mkdir build cd build -cmake .. -DCMAKE_CXX_COMPILER= -DCMAKE_INSTALL_PREFIX= +cmake .. -DCMAKE_CXX_COMPILER= make install ``` Where + `` is one of `g++-10`, `g++-11`, `clang++-12` -+ `` is the install directory, for example `usr/local` Afterwards, you can make `jluna` available to your library using ```cmake -find_library(jluna REQUIRED - NAMES libjluna.so libjluna.dll.a libjluna.dll libjluna.lib - PATHS ) - -target_link_libraries( ${jluna} ${}) +# inside your own CMakeLists.txt +find_library(jluna REQUIRED) +target_link_libraries( PRIVATE + "${jluna}" + "${}") ``` - Where -+ `` is the same path specified during configuration before -+ `` is the Julia Package ++ `` is the Julia Library (usually available in `"${JULIA_BINDIR}/../lib"`) + `` is the name of your library or executable - -It may be instructive to check out [this basic template cmake](./install/resources/CMakeLists.txt). A `FindJulia.cmake` can be found [here](./install/resources/FindJulia.cmake). Download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). +If errors appear at any point, head to [troubleshooting](./docs/installation.md#troubleshooting). + +--- + +### Creating a Project from Scratch + +`jluna` offers a one-line wizard for installing it and creating a new project using it. + +> this feature is only available on unix systems + +To do so, download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). + +Then execute (in the same folder you downloaded `init.sh` to): + +```cpp +/bin/bash init.sh +``` +Where ++ `` is the name of your desired project folder, for example `MyProject` ++ `` is the root path to your new project folder, for example `/home/user/Desktop` ++ `` is one of `g++-10`, `g++-11`, `clang++-12` + +The bash script will create a folder in `/`, install jluna in that folder and setup a working hello_world executable for you. If errors appear at any point, head to [troubleshooting](./docs/installation.md#troubleshooting). From a39704bc5a2bce210aff9835365ba76399f65cd2 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 17:39:23 +0100 Subject: [PATCH 58/71] polish --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 522985b..a46ce75 100644 --- a/README.md +++ b/README.md @@ -231,13 +231,11 @@ If errors appear at any point, head to [troubleshooting](./docs/installation.md# ### Creating a Project from Scratch -`jluna` offers a one-line wizard for installing it and creating a new project using it. +`jluna` offers a one-line wizard for installing it and creating a new project. This option is only recommended for novice users, more experienced users should create the project themself and link it as detailed above. > this feature is only available on unix systems -To do so, download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). - -Then execute (in the same folder you downloaded `init.sh` to): +Download `init.sh` [here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh). Then, execute (in the same folder you downloaded `init.sh` to): ```cpp /bin/bash init.sh From 39dd56788fbb97ca1fb7e4d3f1dbaadebd54db92 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 17:43:53 +0100 Subject: [PATCH 59/71] fixed unquoted variable use --- install/resources/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/install/resources/CMakeLists.txt b/install/resources/CMakeLists.txt index 8e0b429..f68b163 100644 --- a/install/resources/CMakeLists.txt +++ b/install/resources/CMakeLists.txt @@ -12,12 +12,12 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES_UNIX ".so") find_library(jluna REQUIRED NAMES jluna - PATHS ${CMAKE_SOURCE_DIR}/jluna/build) + PATHS "${CMAKE_SOURCE_DIR}/jluna/build") # executable -add_executable(hello_world ${CMAKE_SOURCE_DIR}/main.cpp) +add_executable(hello_world "${CMAKE_SOURCE_DIR}/main.cpp") target_link_libraries(hello_world PRIVATE - ${jluna} + "${jluna}" "$" ) @@ -26,7 +26,7 @@ target_compile_features(hello_world PRIVATE cxx_std_20) # include directories target_include_directories(hello_world PRIVATE - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/jluna - ${JULIA_INCLUDE_DIR} + "${CMAKE_SOURCE_DIR}" + "${CMAKE_SOURCE_DIR}/jluna" + "${JULIA_INCLUDE_DIR}" ) \ No newline at end of file From b1bfe3c8e468d831bace8b5a941c5d8b0167b419 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 17:55:32 +0100 Subject: [PATCH 60/71] third draft --- docs/installation.md | 254 ++++--------------------------------------- 1 file changed, 24 insertions(+), 230 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 0d17510..7ab87e3 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -7,21 +7,13 @@ The following is a step-by-step guide on how to install jluna, and how to create 1.1 [Cloning from Git](#cloning-from-git)
1.2 [Configuring CMake](#configure-cmake)
1.3 [make install](#make-install)
-2. [Creating a new Project](#creating-a-project-with-jluna)
- 2.1 [Project Folder](#project-folder)
- 2.2 [Cloning jluna](#cloning-jluna)
- 2.3 [Building jluna](#building-jluna)
- 2.4 [main.cpp](#our-maincpp)
- 2.5 [CMakelists.txt](#our-cmakeliststxt)
- 2.6 [FindJulia.cmake](#findjuliacmake)
- 2.7 [make](#building-our-application)
-3. [Troubleshooting](#troubleshooting)
- 3.1 [Permission Denied](#permission-denied)
- 3.2 [Unable to Detect Julia Executable](#unable-to-detect-the-julia-executable)
- 3.3 [Found Unsuitable Version](#could-not-find-julia-found-unsuitable-version)
- 3.4 [Could NOT find Julia: Missing X](#could-not-find-julia-missing-x)
- 3.5 [Could not find `julia.h` / `jluna.hpp`](#cannot-find-juliah--jlunahpp)
- 3.6 [Could not find libjluna_c_adapter](#when-trying-to-initialize-jlunacppcall-cannot-find-libjluna_c_adapter)
+2. [Troubleshooting](#troubleshooting)
+ 2.1 [Permission Denied](#permission-denied)
+ 2.2 [Unable to Detect Julia Executable](#unable-to-detect-the-julia-executable)
+ 2.3 [Found Unsuitable Version](#could-not-find-julia-found-unsuitable-version)
+ 2.4 [Could NOT find Julia: Missing X](#could-not-find-julia-missing-x)
+ 2.5 [Could not find `julia.h` / `jluna.hpp`](#cannot-find-juliah--jlunahpp)
+ 2.6 [Could not find libjluna_c_adapter](#when-trying-to-initialize-jlunacppcall-cannot-find-libjluna_c_adapter)
## Installing jluna @@ -76,7 +68,7 @@ Having successfully configured cmake, we now call: make install ``` -Which will create two shared libraries `libjluna.*`, and `libjluna_c_adapter.*` in the specified install directories, or the default install directory if unspecified. `*`, here, is platform dependent, usually `.so` on unix and `.lib` or `.dll` on windows. +Which will create two shared libraries `libjluna.*`, and `libjluna_c_adapter.*`, where `*` is the platform-dependent library suffix. Now that `jluna` is installed on our system, we can link any executable or library inside any non-`jluna` `CMakeLists.txt` using: @@ -97,14 +89,7 @@ find_library(jluna REQUIRED ) ``` -Where `` is the path specified as `-DCMAKE_INSTALL_PREFIX` during configuration before. - -If `find_library` is still not able to find `jluna`, we may need to manually specify the shared library suffixes like so: - -```cpp -set(CMAKE_FIND_LIBRARY_SUFFIXES_WIN32 ".lib;.dll;.dll.a;") -set(CMAKE_FIND_LIBRARY_SUFFIXES_UNIX ".so") -``` +Where `` is the path specified as `-DCMAKE_INSTALL_PREFIX` during configuration before. Note that `jlunas` install rules also export is as a package, so it will be available through `find_package` on systems where it was installed globally like so: @@ -112,12 +97,12 @@ Note that `jlunas` install rules also export is as a package, so it will be avai find_package(jluna REQUIRED) ``` -After `find_library` or `find_package`, we link our own library (here assumed to be named `my_library`), using: +After `find_library` or `find_package`, we link our own library like so: ```cmake # in users own CMakeLists.txt -target_link_libraries(my_library ${jluna} ${}) -target_include_directories(${JLUNA_DIR} ${}) +target_link_libraries(my_library "${jluna}" "${}") +target_include_directories("${JLUNA_DIR}" "${}") ``` Where `` is the library/package containing the julia C-API and `` is the folder containing `julia.h`. @@ -129,192 +114,7 @@ while the julia include directory is usually + `${JULIA_BINDIR}/../include/` or + `${JULIA_BINDIR}/../include/julia/` -A simple template `CMakeLists.txt`, that may be a good point to start out with, is available [here](../install/resources/CMakeLists.txt). - ---- - -## Creating a New Project - -This section will guide users unfamiliar with cmake or C++ through the process of creating a working hello-world executable using julia and `jluna`. - -> Note that, on unix-like systems, this process can be automated using `jluna/install/init.sh`, as detailed [here](../README.md#creating-a-new-project-from-scratch). - -### Project Folder - -First, we need to create our project folder. This will be assumed to be `~/Desktop/MyProject`: - -```bash -cd ~/Desktop/ -mkdir MyProject -``` - -### Cloning jluna - -We now need to clone jluna and install it locally: - -```bash -# in ~/Desktop/MyProject -git clone https://github.com/clemapfel/jluna.git -``` - -### Building jluna - -For `jluna` to know where to look for our julia executable, we need to set `JULIA_BINDIR`. On some system, this environment variable is set automatically during the install of julia. If this is not the case, we need to manually set it. - -First we access the julia binary directory using: - -```bash -# in ~/Desktop/MyProject -julia -e "println(Sys.BINDIR)" -``` -``` -~/path/to/our/julia-1.7.2/bin -``` - -Where the output of this call different for each user. Using the julia binary path, we now build `jluna`: - -```bash -# in ~/Desktop/MyProject -cd jluna -mkdir build -cd build -cmake .. \ --DCMAKE_CXX_COMPILER=clang++-12 \ --DCMAKE_INSTALL_PREFIX=~/Desktop/MyProject/jluna/build \ --DJULIA_BINDIR=~/path/to/our/julia-1.7.2/bin -make -``` - -Where `-DJULIA_BINDIR` is set to the output of `julia -e "println(Sys.BINDIR)"`, and `-DCMAKE_INSTALL_PREFIX` is set to `MyProject/jluna/build`. - -This will compile jluna, leaving the shared libraries in `MyProject/jluna/build`. - -If errors appear at any point during configuration or make, head to [troubleshooting](#troubleshooting). - -### main.cpp - -We need C++ code for our own application to call, so we need to create a `main.cpp`. We'll open a new documented named as such in the folder `~Desktop/MyProject/`: - -```bash -cd ~/Desktop/MyProject -gedit main.cpp -``` - -Where `gedit` can be replaced with any common text editor, such as `vim`, `emacs`, `Notepad++`, etc. - -We replace the contents of `main.cpp` with: - -```cpp -#include - -using namespace jluna; - -int main() -{ - State::initialize(); - Base["println"]("Your project is setup and working!"); -} -``` - -Then safe and close the file. - -### Our CMakeLists.txt - -Just like `jluna`, we will be building our own applicatoin using cmake. We create a `CMakeLists.txt` in `~/Desktop/MyProject`: - -```bash -# in ~/Deskopt/MyProject -gedit CMakeLists.txt -``` -And replace it's content with [this template `CMakeLists.txt`](../install/resources/CMakeLists.txt). - -This `CMakeLists.txt` finds both Julia and `jluna` for us, then links them with our executable, and adds the include directory for `julia.h` and `jluna.hpp` to our paths. Note that this `CMakeLists.txt` depends on our project layout being exactly as detailed here, if we move `MyProject`, we may need to recompile `jluna` to updated any location-dependent code. - -### FindJulia.cmake - -To find julia, we need a `FindJulia.cmake`, which is provided by `jluna`. First, we create the corresponding file in `MyProject/cmake/find`: - -```bash -# in ~/Desktop/MyProject -mkdir cmake -cd cmake -mkdir find -cd find -gedit FindJulia.cmake -``` - -And replace its content with [this](../install/resources/FindJulia.cmake). - -It is not necessary to understand what this file does, just know that by calling - -```cmake -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/find") -``` - -It allows us to `find_package` julia, which we need to link our executable with soon. - -## Building our Application - -We're almost done! We only need to add the `build` folder for our own executable - -```bash -# in ~Desktop/MyProject/ -mkdir build -``` - -Our project directory should now look like this: - -``` -MyProject/ - main.cpp - CMakeLists.txt - build/ - cmake/ - find/ - FindJulia.cmake - jluna - jluna.hpp - (...) - include/ - (...) - build/ - libjluna.* - libjluna_c_adapter.* -``` - -Where `*` is one of `.so`, `.dll`, `.dll.a`, `.lib`. - -Please verify the folder structure if you're coding along with this. - -We are now ready to build our application: - -```bash -# in ~/Desktop/MyProject -cd Build -cmake .. -DCMAKE_CXX_COMPILER=clang++-12 -DJULIA_BINDIR=~/path/to/our/julia-1.7.2/bin -``` - -Where `DJULIA_BINDIR` was set to the same path, that we used, [when building jluna](#building-jluna). - -We can now call - -```bash -# in ~/Desktop/MyProject -make -``` - -Which will compile our application and leave us with `my_executable` in `~/Desktop/MyProject/build`. We execute it like so: - -```bash -# in ~/Desktop/MyProject -./my_executable -``` -``` -[JULIA][LOG] initialization successfull. -hello julia -``` - -Again, this process can be completely automated using `jluna/install/init.sh`, available [here]([here](https://raw.githubusercontent.com/Clemapfel/jluna/cmake_rework/install/init.sh)). +If building your library triggers linker or compiler errors, head to [troubleshoot](#troubleshooting). --- @@ -322,7 +122,7 @@ Again, this process can be completely automated using `jluna/install/init.sh`, a ### Permission Denied -During `make install`, or during execution of the bash script, your OS may notify you that it was unable to write to a folder due to missing permissions. To fix this, either run `make install` as `sudo` (or as administrator on windows), or specify a different folder using `-DCMAKE_INSTALL_PREFIX` for which `jluna` or cmake does have permission. +During `make install`, or during execution of the bash script, your OS may notify you that it was unable to write to a folder due to missing permissions. To fix this, either run `make install` as `sudo` (or as administrator on windows), or specify a different folder using `-DCMAKE_INSTALL_PREFIX` for which `jluna` or cmake does have write/read permission. ### Unable to detect the Julia executable @@ -339,23 +139,15 @@ You may encounter the following error: CMake Error at cmake/find/FindJulia.cmake:5 (message): Unable to detect the julia executable. Make sure JULIA_BINDIR is set correctly. - - For more information, visit - https://github.com/Clemapfel/jluna/blob/master/docs/installation.md -Call Stack (most recent call first): - cmake/find/FindJulia.cmake:11 (julia_bail_if_false) - CMakeLists.txt:20 (find_package) - - --- Configuring incomplete, errors occurred! ``` -This error appears, because `jluna` was unable to locate the julia package on your system. To make jluna aware of the location manually, we can pass the following variable to the cmake command: +This error appears, because `jluna` was unable to locate the julia package on your system. To make `jluna` aware of the location manually, we can pass the following variable to the cmake command: ```bash cmake .. -DJULIA_BINDIR=path/to/your/julia/bin -DCMAKE_COMPILER=g++-10 ``` -This is the path of the binary directory of your julia image. If you are unsure of its location, you can execute + +Where `path/to/your/julia/bin` is the path of the binary directory of your julia image. If you are unsure of its location, you can execute ```julia println(Sys.BINDIR) @@ -383,9 +175,9 @@ Where X can be any of : + `JULIA_BINDIR` + `JULIA_INCLUDE_DIR` -This means that either `JULIA_BINDIR` was not set correctly or the directory it is pointing to is not the julia binary dir. Verify that the value of `JULIA_BINDIR` starts at root (`/` on unix and `C:/` on windows), ends in `/bin`, and that your julia image folder is uncompressed. +This means that either `JULIA_BINDIR` was not set correctly or the directory it is pointing to is not the julia binary directory. Verify that the value of `JULIA_BINDIR` starts at root (`/` on unix and `C:/` on windows), ends in `/bin`, and that your julia image folder is uncompressed. -Make sure the folder `JULIA_BINDIR` points to has the following layout: +Make sure the folder `JULIA_BINDIR` points to, has the following layout: ``` julia*/ @@ -424,7 +216,7 @@ fatal error: jluna.hpp: No such file or directory compilation terminated. ``` -This means the `include_directories` in cmake were set improperly. Make sure the following lines are present in your `CMakeLists.txt`: +This means the `include_directories` in your `CMakeLists.txt` were set improperly. Make sure the following lines are present in your `CMakeLists.txt`: ``` target_include_directories() @@ -432,7 +224,7 @@ target_include_directories() ``` Where -+ `` is the install path of the `jluna` shared libary, specified during cmake configuration using `-DCMAKE_INSTALL_PREFIX` ++ `` is the install path of the `jluna` shared libary, possibly specified during cmake configuration using `-DCMAKE_INSTALL_PREFIX` + `` is the location of `julia.h`, usually `${JULIA_BINDIR}/../include` or `${JULIA_BINDIR}/../include/julia` ### Cannot find libjluna_c_adapter @@ -461,7 +253,9 @@ signal (6): Aborted To allow the local julia state to interface with `jluna`, it needs the shared C-adapter-library to be available. During `make install`, `jluna` modifies its own code to keep track of the location of the C-adapter. If it was moved, `jluna` may no longer be able to find it. To fix this, recompile jluna, as detailed [above](#make-install). -The C-adapter library is installed into the directory specified by `CMAKE_INSTALL_PREFIX` and needs to remain there in order for `jluna` to work. + + +The C-adapter library is always installed into the directory specified by `CMAKE_INSTALL_PREFIX`, regardless of cmake presets used. Be aware of this. --- From c844dcd6dc96e0aba5adc5d38b28f2708dd091a4 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 18:00:57 +0100 Subject: [PATCH 61/71] polish --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 7ab87e3..616ebfc 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -129,7 +129,7 @@ During `make install`, or during execution of the bash script, your OS may notif When calling: ```bash -# in Desktop/jluna/build +# in ~/Desktop/jluna/build cmake .. -DCMAKE_COMPILER=g++-10 # or other compiler ``` From 650d958eb51cb567939bb1e6b8b1ea7f6fdcef54 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 18:01:40 +0100 Subject: [PATCH 62/71] clone now points to master --- install/init.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/install/init.sh b/install/init.sh index 24890ac..4c75d4d 100644 --- a/install/init.sh +++ b/install/init.sh @@ -55,7 +55,7 @@ mkdir -p $project_name cd $project_name # clone jluna -git clone -b cmake_rework https://github.com/Clemapfel/jluna.git +git clone https://github.com/Clemapfel/jluna.git # build jluna cd jluna @@ -88,7 +88,3 @@ printf "\n" # exit exit 0 - - - - From 38166d4f0d463a673c7f584ce896f9722dbf5a62 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 18:14:11 +0100 Subject: [PATCH 63/71] fixed cmake target include directory declaration --- docs/installation.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 616ebfc..46a7577 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -101,8 +101,14 @@ After `find_library` or `find_package`, we link our own library like so: ```cmake # in users own CMakeLists.txt -target_link_libraries(my_library "${jluna}" "${}") -target_include_directories("${JLUNA_DIR}" "${}") +target_link_libraries(my_library PRIVATE + "${jluna}" + "${}" +) +target_include_directories(my_library PRIVATE + "${JLUNA_DIR}" + "${}" +) ``` Where `` is the library/package containing the julia C-API and `` is the folder containing `julia.h`. @@ -219,11 +225,14 @@ compilation terminated. This means the `include_directories` in your `CMakeLists.txt` were set improperly. Make sure the following lines are present in your `CMakeLists.txt`: ``` -target_include_directories() -target_include_directories() +target_include_directories( PRIVATE + "" + "" +) ``` Where ++ is the build target, a library or executable + `` is the install path of the `jluna` shared libary, possibly specified during cmake configuration using `-DCMAKE_INSTALL_PREFIX` + `` is the location of `julia.h`, usually `${JULIA_BINDIR}/../include` or `${JULIA_BINDIR}/../include/julia` From c398d75e3abf026426dae66cd571e4823c10aea1 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 18:17:27 +0100 Subject: [PATCH 64/71] polish --- docs/installation.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 46a7577..f3da3ca 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -70,13 +70,11 @@ make install Which will create two shared libraries `libjluna.*`, and `libjluna_c_adapter.*`, where `*` is the platform-dependent library suffix. -Now that `jluna` is installed on our system, we can link any executable or library inside any non-`jluna` `CMakeLists.txt` using: +Now that `jluna` is installed on our system, we can access it using: ```cmake # in users own CMakeLists.txt -find_library(jluna REQUIRED - NAMES jluna -) +find_library(jluna REQUIRED) ``` If a custom install directory was specified, we need to make cmake aware of this: @@ -106,12 +104,15 @@ target_link_libraries(my_library PRIVATE "${}" ) target_include_directories(my_library PRIVATE - "${JLUNA_DIR}" + "${}" "${}" ) ``` -Where `` is the library/package containing the julia C-API and `` is the folder containing `julia.h`. +Where ++ `` is the folder containing `jluna.hpp` ++ `` is the library/package containing the julia C-API ++ `` is the folder containing `julia.h`. The shared julia library location is usually + `${JULIA_BINDIR}/../lib` From 958bbf6d7000518fc76831a6a1f840848b9b7f44 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 18:39:50 +0100 Subject: [PATCH 65/71] [WINDOWS] raised iterator scope to public --- include/array.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/array.hpp b/include/array.hpp index 22e5cb7..c3da8f2 100644 --- a/include/array.hpp +++ b/include/array.hpp @@ -18,10 +18,10 @@ namespace jluna template class Array : public Proxy { - friend class ConstIterator; - class Iterator; - public: + friend class ConstIterator; + class Iterator; + /// @brief value type using value_type = Value_t; @@ -143,6 +143,7 @@ namespace jluna void throw_if_index_out_of_range(int index, size_t dimension) const; size_t get_dimension(int) const; + public: class ConstIterator { public: From 583732a59941beedd3ac259e6b598345ec02bf8c Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 19:23:16 +0100 Subject: [PATCH 66/71] prefixed configure file path with CMAKE_SOURCE_DIR. Not doing so caused errors on windows --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ce4c56..80ec773 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,7 @@ find_package(Julia 1.7.0 REQUIRED) file(READ include/jluna.jl JULIA_SOURCE) set(C_ADAPTER_PATH "${CMAKE_INSTALL_PREFIX}") -configure_file(.src/include_julia.inl.in .src/include_julia.inl @ONLY) +configure_file("${CMAKE_SOURCE_DIR}/.src/include_julia.inl.in" "${CMAKE_SOURCE_DIR}/.src/include_julia.inl" @ONLY) ### Declare C adapter ### From fcc038d1954acf9f8005d9fd3a85c9f3c53baf43 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 19:51:28 +0100 Subject: [PATCH 67/71] [WINDOWS] split julia script into parts --- .src/include_julia.inl.in | 30 +- .src/state.cpp | 17 +- CMakeLists.txt | 32 +- include/jluna.jl | 974 -------------------------- include/julia/01_common.jl | 276 ++++++++ include/julia/02_common.jl | 201 ++++++ include/julia/03_exception_handler.jl | 133 ++++ include/julia/04_memory_handler.jl | 177 +++++ include/julia/05_cppcall.jl | 191 +++++ include/julia/06_public.jl | 58 ++ 10 files changed, 1111 insertions(+), 978 deletions(-) create mode 100644 include/julia/01_common.jl create mode 100644 include/julia/02_common.jl create mode 100644 include/julia/03_exception_handler.jl create mode 100644 include/julia/04_memory_handler.jl create mode 100644 include/julia/05_cppcall.jl create mode 100644 include/julia/06_public.jl diff --git a/.src/include_julia.inl.in b/.src/include_julia.inl.in index 5917c39..821ff2e 100644 --- a/.src/include_julia.inl.in +++ b/.src/include_julia.inl.in @@ -9,7 +9,33 @@ namespace jluna::detail { static inline const char* c_adapter_path = "@C_ADAPTER_PATH@"; - static inline const char* include = R"( - @JULIA_SOURCE@ + // source split like this because of: https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2026?view=msvc-160 + + static inline const char* module_start = "module jluna"; + + static inline const char* include_01 = R"( + @01_COMMON@ + )"; + + static inline const char* include_02 = R"( + @02_COMMON@ + )"; + + static inline const char* include_03 = R"( + @03_EXCEPTION_HANDLER@ + )"; + + static inline const char* include_04 = R"( + @04_MEMORY_HANDLER@ + )"; + + static inline const char* include_05 = R"( + @05_CPPCALL@ + )"; + + static inline const char* module_end = "end"; + + static inline const char* include_06 = R"( + @06_PUBLIC@ )"; } \ No newline at end of file diff --git a/.src/state.cpp b/.src/state.cpp index 9a7ba6d..e65f5e7 100644 --- a/.src/state.cpp +++ b/.src/state.cpp @@ -41,7 +41,22 @@ namespace jluna::State else jl_init_with_image(path.c_str(), NULL); - jl_eval_string(jluna::detail::include); + { // execute jluna julia code in pieces + using namespace jluna::detail; + std::stringstream str; + str << module_start; + str << include_01; + str << include_02; + str << include_03; + str << include_04; + str << include_05; + str << module_end; + + str << include_06; + + jl_eval_string(str.str().c_str()); + } + forward_last_exception(); jl_eval_string(R"( diff --git a/CMakeLists.txt b/CMakeLists.txt index 80ec773..ffcd2cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,8 +40,38 @@ find_package(Julia 1.7.0 REQUIRED) ### Configure Files ### -file(READ include/jluna.jl JULIA_SOURCE) set(C_ADAPTER_PATH "${CMAKE_INSTALL_PREFIX}") + +file(READ + include/julia/01_common.jl + 01_COMMON +) + +file(READ + include/julia/02_common.jl + 02_COMMON +) + +file(READ + include/julia/03_exception_handler.jl + 03_EXCEPTION_HANDLER +) + +file(READ + include/julia/04_memory_handler.jl + 04_MEMORY_HANDLER +) + +file(READ + include/julia/05_cppcall.jl + 05_CPPCALL +) + +file(READ + include/julia/06_public.jl + 06_PUBLIC +) + configure_file("${CMAKE_SOURCE_DIR}/.src/include_julia.inl.in" "${CMAKE_SOURCE_DIR}/.src/include_julia.inl" @ONLY) ### Declare C adapter ### diff --git a/include/jluna.jl b/include/jluna.jl index 15565f4..4b9bb2e 100644 --- a/include/jluna.jl +++ b/include/jluna.jl @@ -9,989 +9,15 @@ Most end-user should not call any function in this module, with `cppcall` being """ module jluna - """ - `get_value_type_of_array(::Array{T}) -> Type` - forward value type of array - """ - function get_value_type_of_array(_::Array{T}) ::Type where T - return T - end - - """ - `get_reference_value(::Base.RefValue{T}) -> T` - - forward value of reference - """ - function get_reference_value(ref::Base.RefValue{T}) ::T where T - - return ref[]; - end - - setindex!(str::String, c::Char, i::Int64) = setindex!(collect(str), c, i) - - """ - `is_number_only(::String) -> Bool` - - check whether a string can be transformed into a base 10 number - """ - function is_number_only(x::String) ::Bool - - for s in x - if s != '0' || s != '1' || s != '2' || s != '3' || s != '4' || s != '5' || s != '6' || s != '7' || s != '8' || s != '9' - return false - end - end - - return true; - end - - """ - `is_method_available(::Function, ::Any) -> Bool` - - check if method of given function is available for a specific variable - """ - function is_method_available(f::Function, variable) ::Bool - - return hasmethod(f, Tuple{typeof(variable)}) - end - - """ - `get_function(::Symbol, ::Module) -> Function` - - exception-safe function access wrapper - """ - function get_function(function_name::Symbol, m::Module) ::Function - - return m.eval(function_name) - end - export get_function - - """ - `exists(<:AbstractArray, ::Any) -> Bool` - - check if element exists in array - """ - function exists(array::T, v::Any) ::Bool where T <: AbstractArray - - return !isempty(findall(x -> x == v, array)) - end - - """ - `tuple_at(::Tuple, ::Integer) -> Any` - - get nth element of tuple - """ - function tuple_at(x::Tuple, i::Integer) - return x[i] - end - - """ - `tuple_length(::Tuple) -> Integer` - - get length of tuple - """ - function tuple_length(x::Tuple{N}) where N - return N - end - - """ - `make_new(::String, xs...) -> Any` - - parse string to type, then call ctor with given args - """ - function make_new(name::String, xs...) ::Any - - return Main.eval(:($(Meta.parse(name))($(xs...)))) - end - - """ - `make_vector(::T...) -> Vector{T}` - - wrap vector ctor in varargs argument, used by box/unbox - """ - function make_vector(args::T...) ::Vector{T} where T - - return [args...] - end - - """ - `make_vector(t::Type) -> Vector{t}` - - create empty vector of given type - """ - function make_vector(t::Type) ::Vector{t} - - return Vector{t}() - end - - """ - `make_vector(::Type{T}, ::Any...) -> Vector{T}` - - create vector by converting all elements to target type - """ - function make_vector(type::Type{T}, xs...) where T - return convert.(T, [xs...]) - end - - """ - `new_vector(::Integer, ::T) -> Vector{T}` - - create vector by deducing argument type - """ - function new_vector(size::Integer, _::T) where T - return Vector{T}(undef, size) - end - - """ - `new_vector(::Integer, ::T) -> Vector{T}` - - create vector by deducing argument type - """ - function new_vector(size::Integer, type::Type) - return Vector{type}(undef, size) - end - - """ - `make_set(::T...) -> Set{T}` - - wrap set ctor in varargs argument, used by box/unbox - """ - function make_set(args::T...) ::Set{T} where T - - return Set([args...]); - end - - """ - `make_set(::Type{T}, ::Any...) -> Set{T}` - - - """ - function make_set(type::Type{T}, xs...) ::Set{T} where T - - return Set(make_vector(type, xs...)); - end - - """ - `make_pair(::T, ::U) -> Pair{T, U}` - - wrap pair ctor - """ - function make_pair(a::T, b::U) ::Pair{T, U} where {T, U} - - return a => b - end - - """ - `make_complex(:T, :T) -> Complex{T}` - - wrap complex ctor - """ - function make_complex(real::T, imag::T) ::Complex{T} where T - return Complex{T}(real, imag) - end - - """ - `assert_isa(::T, ::Symbol) -> Nothing` - - throw assertion if x is not of named type - """ - function assert_isa(x::Any, type::Type) ::Nothing - - if !(x isa type) - throw(AssertionError("expected " * string(type) * " but got an object of type " * string(typeof(x)))); - end - - return nothing - end - - """ - `convert(::T, symbol::Symbol) -> Any` - - convert value type, declared via symbol - """ - function convert(x::T, symbol::Symbol) ::Any where T - - type = Main.eval(symbol); - @assert type isa Type - - if T isa type - return T - end - - return Base.convert(type, x) - end - - """ - `string_to_type` -> Type - - evaluate string to type name if possible - """ - function string_to_type(str::String) ::Type - - res = Main.eval(Meta.parse(str)) - if !(res isa Type) - throw(UndefVarError(Symbol(str))) - end - return res - end - - """ - `invoke(function::Any, arguments::Any...) -> Any` - - wrap function call for non-function objects - """ - function invoke(x::Any, args...) ::Any - return x(args...) - end - - """ - `create_or_assign(::Symbol, ::T) -> T` - - assign variable in main, or if none exist, create it and assign - """ - function create_or_assign(symbol::Symbol, value::T) ::T where T - - return Main.eval(Expr(:(=), symbol, value)) - end - - """ - `serialize(<:AbstractDict{T, U}) -> Vector{Pair{T, U}}` - - transform dict into array - """ - function serialize(x::T) ::Vector{Pair{Key_t, Value_t}} where {Key_t, Value_t, T <: AbstractDict{Key_t, Value_t}} - - out = Vector{Pair{Key_t, Value_t}}() - for e in x - push!(out, e) - end - return out; - end - - """ - `serialize(::Set{T}) -> Vector{T}` - - transform dict into array - """ - function serialize(x::T) ::Vector{U} where {U, T <: AbstractSet{U}} - - out = Vector{U}() - - for e in x - push!(out, e) - end - - return out; - end - - """ - `dot(::Array, field::Symbol) -> Any` - - wrapped dot operator - """ - function dot(x::Array, field_name::Symbol) ::Any - - index_maybe = parse(Int, string(field_name)); - @assert index_maybe isa Integer - return x[index_maybe]; - end - export dot; - - """ - `dot(::Module, field::Symbol) -> Any` - - wrapped dot operator - """ - dot(x::Module, field_name::Symbol) = return x.eval(field_name); - - """ - `dot(x::Any, field::Symbol) -> Any` - - wrapped dot operator, x.field - """ - dot(x::Any, field_name::Symbol) = return eval(:($x.$field_name)) - - """ - `unroll_type(::Type) -> Type` - - unroll type declaration - """ - function unroll_type(type::Type) ::Type - - while hasproperty(type, :body) - type = type.body - end - - return type - end - - """ - `is_name_typename(::Type, ::Type) -> Bool` - - unroll type declaration, then check if name is typename - """ - function is_name_typename(type_in::Type, type_comparison::Type) ::Bool - return getproperty(type_in, :name) == Base.typename(type_comparison) - end - - """ - `get_n_fields(::Type) -> Int64` - """ - function get_n_fields(type::Type) ::Int64 - return length(fieldnames(type)) - end - - """ - `get_fields(::Type) -> Vector{Pair{Symbol, Type}}` - - get field symbols and types, used by jluna::Type::get_fields - """ - function get_fields(type::Type) ::Vector{Pair{Symbol, Type}} - - out = Vector{Pair{Symbol, Type}}(); - names = fieldnames(type) - types = fieldtypes(type) - - for i in 1:(length(names)) - push!(out, names[i] => types[i]) - end - - return out - end - - """ - `get_parameter(::Type) -> Vector{Pair{Symbol, Type}}` - - get parameter symbols and upper type limits, used by jluna::Type::get_parameters - """ - function get_parameters(type::Type) ::Vector{Pair{Symbol, Type}} - - type = unroll_type(type) - - out = Vector{Pair{Symbol, Type}}(); - parameters = getproperty(type, :parameters) - - for i in 1:(length(parameters)) - push!(out, parameters[i].name => parameters[i].ub) - end - - return out - end - - """ - `get_n_parameters(::Type) -> Int64` - """ - function get_n_parameters(type::Type) ::Int64 - - type = unroll_type(type) - - return length(getproperty(type, :parameters)) - end - - """ - `assign_in_module(::Module, ::Symbol, ::T) -> T` - - assign variable in other module, throws if variable does not exist - """ - function assign_in_module(m::Module, variable_name::Symbol, value::T) ::T where T - - if (!isdefined(m, variable_name)) - throw(UndefVarError(Symbol(string(m) * "." * string(variable_name)))) - end - - return Base.eval(m, :($variable_name = $value)) - end - - """ - `create_in_module(::Module, ::Symbol, ::T) -> T` - - assign variable in other module, if variable does not exist, create then assign - """ - function create_or_assign_in_module(m::Module, variable_name::Symbol, value::T) ::T where T - return Base.eval(m, :($variable_name = $value)) - end - - """ - `get_names(::Module) -> IdDict{Symbol, Any}` - - access all module members as dict - """ - function get_names(m::Module) ::IdDict{Symbol, Any} - - out = IdDict{Symbol, Any}() - - for n in names(m; all = true) - if string(n)[1] != '#' - out[n] = m.eval(n) - end - end - - return out - end - """ - `get_nth_method(::Function, ::Integer) -> Method` - wrap method access, used by jlune::Method - """ - function get_nth_method(f::Function, i::Integer) ::Method - return methods(f)[i] - end - - """ - `get_return_type_of_nth_method(::Function, ::Integer) -> Type` - - used by jluna::Function to deduce method signature - """ - function get_return_type_of_nth_method(f::Function, i::Integer) ::Type - - return Base.return_types(test)[i] - end - - """ - `get_argument_type_of_nths_methods(::Function, ::Integer) -> Vector{Type}` - - used by jluna::Function to deduce method signature - """ - function get_argument_types_of_nth_method(f::Function, i::Integer) ::Vector{Type} - - out = Vector{Type}() - types = methods(f)[i].sig.types - - for i in 2:length(types) - push!(out, types[i]) - end - - return out - end - - - """ - `get_length_of_generator(::Base.Generator) -> Int64` - - deduce length of Base.Generator object - """ - function get_length_of_generator(gen::Base.Generator) ::Int64 - - if (Base.haslength(gen)) - return length(gen) - else - # heuristically deduce length - for i in Iterators.reverse(gen.iter.itr) - if gen.iter.flt(i) - return i - end - end - end - end - - """ - offers verbose exception interface. Any call with safe_call will store - the last exception and full stack trace as string in _last_exception and - _last_message respectively - """ - module exception_handler - - """ - exception Placeholder that signals that no exception occurred - """ - struct NoException <: Exception end - export NoException - - """ - current state of the exception handler - - _last_exception <:Exception - _last_message ::String - """ - mutable struct State - _last_exception - _last_message::String - _exception_occurred::Bool - end - - const _state = Ref{State}(State(NoException(), "", false)); - - """ - `safe_call(::Function, ::Any...) -> Any` - - call any function, update the handler then forward the result, if any - """ - function safe_call(f::Any, args...) - - result = undef - try - result = f(args...) - update() - catch exc - result = nothing - update(exc) - end - - return result; - end - - """ - `safe_call(::Expr, ::Module = Main) -> Any` - - call any line of code, update the handler then forward the result, if any - """ - function safe_call(expr::Expr, m::Module = Main) ::Any - - if expr.head == :block - expr.head = :toplevel - end - - return safe_call(Base.eval, m, expr); - end - - """ - `unsafe_call(::Expr, ::Module = Main) -> Any` - - call any line of code without updating the handler - """ - function unsafe_call(expr::Expr, m::Module = Main) ::Any - - if expr.head == :block - expr.head = :toplevel - end - - return Base.eval(m, expr); - end - - """ - `update(<:Exception) -> Nothing` - - update the handler after an exception was thrown - """ - function update(exception::Exception) ::Nothing - - try - global _state[]._last_message = sprint(Base.showerror, exception, catch_backtrace()) - global _state[]._last_exception = exception - global _state[]._exception_occurred = true - catch e end - return nothing - end - - """ - `update() -> Nothing` - - update the handler after *no* exception was thrown - """ - function update() ::Nothing - - if !(_state[]._last_exception isa NoException) - - global _state[]._last_message = "" - global _state[]._last_exception = NoException() - global _state[]._exception_occurred = false - end - return nothing - end - - """ - `has_exception_occurred() -> Bool` - - is last exception type no "jluna.exception_handler.NoException" - """ - function has_exception_occurred() ::Bool - - return _state[]._exception_occurred - end - - """ - `get_last_message() -> String` - - wrapper for _state access - """ - function get_last_message() ::String - return _state[]._last_message - end - - """ - `get_last_exception() -> Exception` - - wrapper for _state access - """ - function get_last_exception() ::Exception - return _state[]._last_exception - end - end - - """ - offers julia-side memory management for C++ jluna - """ - module memory_handler - - const _current_id = Ref(UInt64(0)); - const _refs = Ref(Dict{UInt64, Base.RefValue{Any}}()) - const _ref_counter = Ref(Dict{UInt64, UInt64}()) - - const _ref_id_marker = '#' - const _refs_expression = Meta.parse("jluna.memory_handler._refs[]") - - # proxy id that is actually an expression, the ID of topmodule Main is - ProxyID = Union{Expr, Symbol, Nothing} - - # make as unnamed - make_unnamed_proxy_id(id::UInt64) = return Expr(:ref, Expr(:ref, _refs_expression, id)) - - # make as named with owner and symbol name - make_named_proxy_id(id::Symbol, owner_id::ProxyID) ::ProxyID = return Expr(:(.), owner_id, QuoteNode(id)) - - # make as named with main as owner and symbol name - make_named_proxy_id(id::Symbol, owner_id::Nothing) ::ProxyID = return id - - # make as named with owner and array index name - make_named_proxy_id(id::Number, owner_id::ProxyID) ::ProxyID = return Expr(:ref, owner_id, convert(Int64, id)) - - # assign to proxy id - function assign(new_value::T, name::ProxyID) where T - if new_value isa Symbol || new_value isa Expr - return Main.eval(Expr(:(=), name, QuoteNode(new_value))) - else - return Main.eval(Expr(:(=), name, new_value)); - end - end - - # eval proxy id - evaluate(name::ProxyID) ::Any = return Main.eval(name) - evaluate(name::Symbol) ::Any = return Main.eval(:($name)) - - """ - `get_name(::ProxyID) -> String` - - parse name from proxy id - """ - function get_name(id::ProxyID) ::String - - if length(id.args) == 0 - return "Main" - end - - current = id - while current.args[1] isa Expr && length(current.args) >= 2 - - if current.args[2] isa UInt64 - current.args[2] = convert(Int64, current.args[2]) - end - - current = current.args[1] - end - - out = string(id) - reg = r"\Q((jluna.memory_handler._refs[])[\E(.*)\Q])[]\E" - captures = match(reg, out) - - if captures != nothing - out = replace(out, reg => "") - end - - return out; - end - - get_name(::Nothing) ::String = return "Main" - get_name(s::Symbol) ::String = return string(s) - get_name(i::Integer) ::String = return "[" * string(i) * "]" - - """ - `print_refs() -> Nothing` - - pretty print _ref state, for debugging - """ - function print_refs() ::Nothing - - println("jluna.memory_handler._refs: "); - for e in _refs[] - println("\t", Int64(e.first), " => ", e.second[], " (", typeof(e.second[]), ") ") - end - end - - """ - `create_reference(::UInt64, ::Any) -> UInt64` - - add reference to _refs - """ - function create_reference(to_wrap::Any) ::UInt64 - - global _current_id[] += 1; - key::UInt64 = _current_id[]; - if (haskey(_refs[], key)) - _ref_counter[][key] += 1 - else - _refs[][key] = Base.RefValue{Any}(to_wrap) - _ref_counter[][key] = 1 - end - return key; - end - create_reference(_::Nothing) ::UInt64 = return 0 - """ - `set_reference(::UInt64, ::T) -> Nothing` - - update the value of a reference in _refs without adding a new entry or changing it's key, ref pointers C++ side stay valid - """ - function set_reference(key::UInt64, new_value::T) ::Base.RefValue{Any} where T - - _refs[][key] = Base.RefValue{Any}(new_value) - return _refs[][key] - end - - """ - `get_reference(::Int64) -> Any` - - access reference in _refs - """ - function get_reference(key::UInt64) ::Any - - if (key == 0) - return nothing - end - - return _refs[][key] - end - - """ - `free_reference(::UInt64) -> Nothing` - - free reference from _refs - """ - function free_reference(key::UInt64) ::Nothing - - if (key == 0) - return nothing; - end - - if _refs[][key][] isa Module - return - end - - global _ref_counter[][key] -= 1 - count::UInt64 = _ref_counter[][key] - - if (count == 0) - delete!(_ref_counter[], key) - delete!(_refs[], key) - end - - return nothing; - end - - """ - `force_free() -> Nothing` - - immediately deallocate all C++-managed values - """ - function force_free() ::Nothing - - for k in keys(_refs) - delete!(_refs[], k) - delete!(_ref_counter[], k) - end - - return nothing; - end - end - - module _cppcall - - mutable struct State - _arguments::Tuple - _result::Any - - State() = new((), nothing) - end - - _library_name = "" - _state = Base.Ref{_cppcall.State}(State()) - - """ - Wrapper object for unnamed functions, frees function once object is destroyed - """ - mutable struct UnnamedFunctionProxy{N, Return_t} - - _id::Symbol - _call::Function - _n_args::Int64 - - function UnnamedFunctionProxy{N, Return_t}(id::Symbol) where {N, Return_t} - - @assert(-1 <= N <= 4) - - _id = id - x = new{N, Return_t}(id, function (xs...) Main.cppcall(_id, xs...) end, N) - - finalizer(function (t::UnnamedFunctionProxy{N, Return_t}) - ccall((:free_function, _cppcall._library_name), Cvoid, (Csize_t,), hash(t._id)) - end, x) - - return x - end - end - - # call with signature (1x Any) -> [Any / Nothing] - function (instance::UnnamedFunctionProxy{0, T})() ::T where T - return instance._call(); - end - - # call with signature (1x Any) -> [Any / Nothing] - function (instance::UnnamedFunctionProxy{1, T})(arg1) ::T where T - return instance._call(arg1); - end - - # call with signature (2x Any) -> [Any / Nothing] - function (instance::UnnamedFunctionProxy{2, T})(arg1, arg2) ::T where T - return instance._call(arg1, arg2); - end - - # call with signature (3x Any) -> [Any / Nothing] - function (instance::UnnamedFunctionProxy{3, T})(arg1, arg2, arg3) ::T where T - return instance._call(arg1, arg2, arg3); - end - - # call with signature (4x Any) -> [Any / Nothing] - function (instance::UnnamedFunctionProxy{4, T})(arg1, arg2, arg3, arg4) ::T where T - return instance._call(arg1, arg2, arg3, arg4); - end - - # call with other signature - function (instance::UnnamedFunctionProxy{Int64(-1), T})(args::Vector) ::T where T - return instance._call(args...); - end - - # ctor wrapper for jluna - new_unnamed_function(s::Symbol, N::Integer, T::Type) = return UnnamedFunctionProxy{N, T}(s) - - """ - an exception thrown when trying to invoke cppcall with a function name that - has not yet been registered via jluna::register_function - """ - mutable struct UnregisteredFunctionNameException <: Exception - - _function_name::Symbol - end - Base.showerror(io::IO, e::UnregisteredFunctionNameException) = print(io, "cppcall.UnregisteredFunctionNameException: no C++ function with name :" * string(e._function_name) * " registered") - - """ - an exception thrown when the number of arguments does not match the number of arguments - expected by the registered lambda - """ - mutable struct TupleSizeMismatchException <: Exception - - _function_name::Symbol - _expected::Int64 - _got::Int64 - end - Base.showerror(io::IO, e::TupleSizeMismatchException) = print(io, "cppcall.TupleSizeMismatchException: C++ function with name :" * string(e._function_name) * " expects " * string(e._expected) * " arguments but was called with " * string(e._got)) - - """ - `set_result(::Any) -> Nothing` - - modify _cppcall state result - """ - function set_result(x::Any) ::Nothing - - global _cppcall._state[]._result = x - return nothing - end - - """ - `get_result() -> Any` - - access _cppcall result - """ - function get_result() ::Any - - return _cppcall._state[]._result - end - - """ - `set_arguments(xs...) -> Nothing` - - modify _cppcall state argument tuple - """ - function set_arguments(xs...) ::Nothing - - global _cppcall._state[]._arguments = xs - return nothing - end - - """ - `get_result() -> Tuple` - - access _cppcall state argument tuple - """ - function get_arguments() ::Tuple - - return _cppcall._state[]._arguments - end - - """ - `verify_library() -> Bool` - - check if c_adapter library is available - """ - function verify_library() ::Bool - - if isfile(_cppcall._library_name) - return true - end - - message = "when trying to initialize jluna.cppcall: " - message *= "cannot find " * _cppcall._library_name - - println(sprint(Base.showerror, AssertionError(message), backtrace())) - return false - end - end - - # obfuscate internal state to encourage using operator[] sytanx - struct ProxyInternal - - _fieldnames_in_order::Vector{Symbol} - _fields::Dict{Symbol, Union{Any, Missing}} - ProxyInternal() = new(Vector{Symbol}(), Dict{Symbol, Union{Any, Missing}}()) - end - - # proxy as deepcopy of cpp-side usertype object - struct Proxy - - _typename::Symbol - _value::ProxyInternal - - Proxy(name::Symbol) = new(name, ProxyInternal()) - end - export proxy - new_proxy(name::Symbol) = return Proxy(name) - - function implement(template::Proxy, m::Module = Main) ::Type - - out::Expr = :(mutable struct $(template._typename) end) - deleteat!(out.args[3].args, 1) - - for name in template._value._fieldnames_in_order - push!(out.args[3].args, Expr(:(::), name, :($(typeof(template._value._fields[name]))))) - end - - new_call::Expr = Expr(:(=), Expr(:call, template._typename), Expr(:call, :new)) - - for name in template._value._fieldnames_in_order - push!(new_call.args[2].args, template._value._fields[name]) - end - - push!(out.args[3].args, new_call) - Base.eval(m, out) - return m.eval(template._typename) - end - export implement -end using Main.jluna; diff --git a/include/julia/01_common.jl b/include/julia/01_common.jl new file mode 100644 index 0000000..71e28c4 --- /dev/null +++ b/include/julia/01_common.jl @@ -0,0 +1,276 @@ +""" +`get_value_type_of_array(::Array{T}) -> Type` + +forward value type of array +""" +function get_value_type_of_array(_::Array{T}) ::Type where T + + return T +end + +""" +`get_reference_value(::Base.RefValue{T}) -> T` + +forward value of reference +""" +function get_reference_value(ref::Base.RefValue{T}) ::T where T + + return ref[]; +end + +setindex!(str::String, c::Char, i::Int64) = setindex!(collect(str), c, i) + +""" +`is_number_only(::String) -> Bool` + +check whether a string can be transformed into a base 10 number +""" +function is_number_only(x::String) ::Bool + + for s in x + if s != '0' || s != '1' || s != '2' || s != '3' || s != '4' || s != '5' || s != '6' || s != '7' || s != '8' || s != '9' + return false + end + end + + return true; +end + +""" +`is_method_available(::Function, ::Any) -> Bool` + +check if method of given function is available for a specific variable +""" +function is_method_available(f::Function, variable) ::Bool + + return hasmethod(f, Tuple{typeof(variable)}) +end + +""" +`get_function(::Symbol, ::Module) -> Function` + +exception-safe function access wrapper +""" +function get_function(function_name::Symbol, m::Module) ::Function + + return m.eval(function_name) +end +export get_function + +""" +`exists(<:AbstractArray, ::Any) -> Bool` + +check if element exists in array +""" +function exists(array::T, v::Any) ::Bool where T <: AbstractArray + + return !isempty(findall(x -> x == v, array)) +end + +""" +`tuple_at(::Tuple, ::Integer) -> Any` + +get nth element of tuple +""" +function tuple_at(x::Tuple, i::Integer) + return x[i] +end + +""" +`tuple_length(::Tuple) -> Integer` + +get length of tuple +""" +function tuple_length(x::Tuple{N}) where N + return N +end + +""" +`make_new(::String, xs...) -> Any` + +parse string to type, then call ctor with given args +""" +function make_new(name::String, xs...) ::Any + + return Main.eval(:($(Meta.parse(name))($(xs...)))) +end + +""" +`make_vector(::T...) -> Vector{T}` + +wrap vector ctor in varargs argument, used by box/unbox +""" +function make_vector(args::T...) ::Vector{T} where T + + return [args...] +end + +""" +`make_vector(t::Type) -> Vector{t}` + +create empty vector of given type +""" +function make_vector(t::Type) ::Vector{t} + + return Vector{t}() +end + +""" +`make_vector(::Type{T}, ::Any...) -> Vector{T}` + +create vector by converting all elements to target type +""" +function make_vector(type::Type{T}, xs...) where T + return convert.(T, [xs...]) +end + +""" +`new_vector(::Integer, ::T) -> Vector{T}` + +create vector by deducing argument type +""" +function new_vector(size::Integer, _::T) where T + return Vector{T}(undef, size) +end + +""" +`new_vector(::Integer, ::T) -> Vector{T}` + +create vector by deducing argument type +""" +function new_vector(size::Integer, type::Type) + return Vector{type}(undef, size) +end + +""" +`make_set(::T...) -> Set{T}` + +wrap set ctor in varargs argument, used by box/unbox +""" +function make_set(args::T...) ::Set{T} where T + + return Set([args...]); +end + +""" +`make_set(::Type{T}, ::Any...) -> Set{T}` + + +""" +function make_set(type::Type{T}, xs...) ::Set{T} where T + + return Set(make_vector(type, xs...)); +end + +""" +`make_pair(::T, ::U) -> Pair{T, U}` + +wrap pair ctor +""" +function make_pair(a::T, b::U) ::Pair{T, U} where {T, U} + + return a => b +end + +""" +`make_complex(:T, :T) -> Complex{T}` + +wrap complex ctor +""" +function make_complex(real::T, imag::T) ::Complex{T} where T + return Complex{T}(real, imag) +end + +""" +`assert_isa(::T, ::Symbol) -> Nothing` + +throw assertion if x is not of named type +""" +function assert_isa(x::Any, type::Type) ::Nothing + + if !(x isa type) + throw(AssertionError("expected " * string(type) * " but got an object of type " * string(typeof(x)))); + end + + return nothing +end + +""" +`convert(::T, symbol::Symbol) -> Any` + +convert value type, declared via symbol +""" +function convert(x::T, symbol::Symbol) ::Any where T + + type = Main.eval(symbol); + @assert type isa Type + + if T isa type + return T + end + + return Base.convert(type, x) +end + +""" +`string_to_type` -> Type + +evaluate string to type name if possible +""" +function string_to_type(str::String) ::Type + + res = Main.eval(Meta.parse(str)) + if !(res isa Type) + throw(UndefVarError(Symbol(str))) + end + return res +end + +""" +`invoke(function::Any, arguments::Any...) -> Any` + +wrap function call for non-function objects +""" +function invoke(x::Any, args...) ::Any + return x(args...) +end + +""" +`create_or_assign(::Symbol, ::T) -> T` + +assign variable in main, or if none exist, create it and assign +""" +function create_or_assign(symbol::Symbol, value::T) ::T where T + + return Main.eval(Expr(:(=), symbol, value)) +end + +""" +`serialize(<:AbstractDict{T, U}) -> Vector{Pair{T, U}}` + +transform dict into array +""" +function serialize(x::T) ::Vector{Pair{Key_t, Value_t}} where {Key_t, Value_t, T <: AbstractDict{Key_t, Value_t}} + + out = Vector{Pair{Key_t, Value_t}}() + for e in x + push!(out, e) + end + return out; +end + +""" +`serialize(::Set{T}) -> Vector{T}` + +transform dict into array +""" +function serialize(x::T) ::Vector{U} where {U, T <: AbstractSet{U}} + + out = Vector{U}() + + for e in x + push!(out, e) + end + + return out; +end \ No newline at end of file diff --git a/include/julia/02_common.jl b/include/julia/02_common.jl new file mode 100644 index 0000000..4faebd8 --- /dev/null +++ b/include/julia/02_common.jl @@ -0,0 +1,201 @@ +""" +`dot(::Array, field::Symbol) -> Any` + +wrapped dot operator +""" +function dot(x::Array, field_name::Symbol) ::Any + + index_maybe = parse(Int, string(field_name)); + @assert index_maybe isa Integer + return x[index_maybe]; +end +export dot; + +""" +`dot(::Module, field::Symbol) -> Any` + +wrapped dot operator +""" +dot(x::Module, field_name::Symbol) = return x.eval(field_name); + +""" +`dot(x::Any, field::Symbol) -> Any` + +wrapped dot operator, x.field +""" +dot(x::Any, field_name::Symbol) = return eval(:($x.$field_name)) + +""" +`unroll_type(::Type) -> Type` + +unroll type declaration +""" +function unroll_type(type::Type) ::Type + + while hasproperty(type, :body) + type = type.body + end + + return type +end + +""" +`is_name_typename(::Type, ::Type) -> Bool` + +unroll type declaration, then check if name is typename +""" +function is_name_typename(type_in::Type, type_comparison::Type) ::Bool + return getproperty(type_in, :name) == Base.typename(type_comparison) +end + +""" +`get_n_fields(::Type) -> Int64` +""" +function get_n_fields(type::Type) ::Int64 + return length(fieldnames(type)) +end + +""" +`get_fields(::Type) -> Vector{Pair{Symbol, Type}}` + +get field symbols and types, used by jluna::Type::get_fields +""" +function get_fields(type::Type) ::Vector{Pair{Symbol, Type}} + + out = Vector{Pair{Symbol, Type}}(); + names = fieldnames(type) + types = fieldtypes(type) + + for i in 1:(length(names)) + push!(out, names[i] => types[i]) + end + + return out +end + +""" +`get_parameter(::Type) -> Vector{Pair{Symbol, Type}}` + +get parameter symbols and upper type limits, used by jluna::Type::get_parameters +""" +function get_parameters(type::Type) ::Vector{Pair{Symbol, Type}} + + type = unroll_type(type) + + out = Vector{Pair{Symbol, Type}}(); + parameters = getproperty(type, :parameters) + + for i in 1:(length(parameters)) + push!(out, parameters[i].name => parameters[i].ub) + end + + return out +end + +""" +`get_n_parameters(::Type) -> Int64` +""" +function get_n_parameters(type::Type) ::Int64 + + type = unroll_type(type) + + return length(getproperty(type, :parameters)) +end + +""" +`assign_in_module(::Module, ::Symbol, ::T) -> T` + +assign variable in other module, throws if variable does not exist +""" +function assign_in_module(m::Module, variable_name::Symbol, value::T) ::T where T + + if (!isdefined(m, variable_name)) + throw(UndefVarError(Symbol(string(m) * "." * string(variable_name)))) + end + + return Base.eval(m, :($variable_name = $value)) +end + +""" +`create_in_module(::Module, ::Symbol, ::T) -> T` + +assign variable in other module, if variable does not exist, create then assign +""" +function create_or_assign_in_module(m::Module, variable_name::Symbol, value::T) ::T where T + return Base.eval(m, :($variable_name = $value)) +end + +""" +`get_names(::Module) -> IdDict{Symbol, Any}` + +access all module members as dict +""" +function get_names(m::Module) ::IdDict{Symbol, Any} + + out = IdDict{Symbol, Any}() + + for n in names(m; all = true) + if string(n)[1] != '#' + out[n] = m.eval(n) + end + end + + return out +end + +""" +`get_nth_method(::Function, ::Integer) -> Method` + +wrap method access, used by jlune::Method +""" +function get_nth_method(f::Function, i::Integer) ::Method + + return methods(f)[i] +end + +""" +`get_return_type_of_nth_method(::Function, ::Integer) -> Type` + +used by jluna::Function to deduce method signature +""" +function get_return_type_of_nth_method(f::Function, i::Integer) ::Type + + return Base.return_types(test)[i] +end + +""" +`get_argument_type_of_nths_methods(::Function, ::Integer) -> Vector{Type}` + +used by jluna::Function to deduce method signature +""" +function get_argument_types_of_nth_method(f::Function, i::Integer) ::Vector{Type} + + out = Vector{Type}() + types = methods(f)[i].sig.types + + for i in 2:length(types) + push!(out, types[i]) + end + + return out +end + + +""" +`get_length_of_generator(::Base.Generator) -> Int64` + +deduce length of Base.Generator object +""" +function get_length_of_generator(gen::Base.Generator) ::Int64 + + if (Base.haslength(gen)) + return length(gen) + else + # heuristically deduce length + for i in Iterators.reverse(gen.iter.itr) + if gen.iter.flt(i) + return i + end + end + end +end \ No newline at end of file diff --git a/include/julia/03_exception_handler.jl b/include/julia/03_exception_handler.jl new file mode 100644 index 0000000..d08601b --- /dev/null +++ b/include/julia/03_exception_handler.jl @@ -0,0 +1,133 @@ +""" +offers verbose exception interface. Any call with safe_call will store +the last exception and full stack trace as string in _last_exception and +_last_message respectively +""" +module exception_handler + + """ + exception Placeholder that signals that no exception occurred + """ + struct NoException <: Exception end + export NoException + + """ + current state of the exception handler + + _last_exception <:Exception + _last_message ::String + """ + mutable struct State + _last_exception + _last_message::String + _exception_occurred::Bool + end + + const _state = Ref{State}(State(NoException(), "", false)); + + """ + `safe_call(::Function, ::Any...) -> Any` + + call any function, update the handler then forward the result, if any + """ + function safe_call(f::Any, args...) + + result = undef + try + result = f(args...) + update() + catch exc + result = nothing + update(exc) + end + + return result; + end + + """ + `safe_call(::Expr, ::Module = Main) -> Any` + + call any line of code, update the handler then forward the result, if any + """ + function safe_call(expr::Expr, m::Module = Main) ::Any + + if expr.head == :block + expr.head = :toplevel + end + + return safe_call(Base.eval, m, expr); + end + + """ + `unsafe_call(::Expr, ::Module = Main) -> Any` + + call any line of code without updating the handler + """ + function unsafe_call(expr::Expr, m::Module = Main) ::Any + + if expr.head == :block + expr.head = :toplevel + end + + return Base.eval(m, expr); + end + + """ + `update(<:Exception) -> Nothing` + + update the handler after an exception was thrown + """ + function update(exception::Exception) ::Nothing + + try + global _state[]._last_message = sprint(Base.showerror, exception, catch_backtrace()) + global _state[]._last_exception = exception + global _state[]._exception_occurred = true + catch e end + return nothing + end + + """ + `update() -> Nothing` + + update the handler after *no* exception was thrown + """ + function update() ::Nothing + + if !(_state[]._last_exception isa NoException) + + global _state[]._last_message = "" + global _state[]._last_exception = NoException() + global _state[]._exception_occurred = false + end + return nothing + end + + """ + `has_exception_occurred() -> Bool` + + is last exception type no "jluna.exception_handler.NoException" + """ + function has_exception_occurred() ::Bool + + return _state[]._exception_occurred + end + + """ + `get_last_message() -> String` + + wrapper for _state access + """ + function get_last_message() ::String + return _state[]._last_message + end + + """ + `get_last_exception() -> Exception` + + wrapper for _state access + """ + function get_last_exception() ::Exception + return _state[]._last_exception + end +end \ No newline at end of file diff --git a/include/julia/04_memory_handler.jl b/include/julia/04_memory_handler.jl new file mode 100644 index 0000000..98aef55 --- /dev/null +++ b/include/julia/04_memory_handler.jl @@ -0,0 +1,177 @@ +""" +offers julia-side memory management for C++ jluna +""" +module memory_handler + + const _current_id = Ref(UInt64(0)); + const _refs = Ref(Dict{UInt64, Base.RefValue{Any}}()) + const _ref_counter = Ref(Dict{UInt64, UInt64}()) + + const _ref_id_marker = '#' + const _refs_expression = Meta.parse("jluna.memory_handler._refs[]") + + # proxy id that is actually an expression, the ID of topmodule Main is + ProxyID = Union{Expr, Symbol, Nothing} + + # make as unnamed + make_unnamed_proxy_id(id::UInt64) = return Expr(:ref, Expr(:ref, _refs_expression, id)) + + # make as named with owner and symbol name + make_named_proxy_id(id::Symbol, owner_id::ProxyID) ::ProxyID = return Expr(:(.), owner_id, QuoteNode(id)) + + # make as named with main as owner and symbol name + make_named_proxy_id(id::Symbol, owner_id::Nothing) ::ProxyID = return id + + # make as named with owner and array index name + make_named_proxy_id(id::Number, owner_id::ProxyID) ::ProxyID = return Expr(:ref, owner_id, convert(Int64, id)) + + # assign to proxy id + function assign(new_value::T, name::ProxyID) where T + if new_value isa Symbol || new_value isa Expr + return Main.eval(Expr(:(=), name, QuoteNode(new_value))) + else + return Main.eval(Expr(:(=), name, new_value)); + end + end + + # eval proxy id + evaluate(name::ProxyID) ::Any = return Main.eval(name) + evaluate(name::Symbol) ::Any = return Main.eval(:($name)) + + """ + `get_name(::ProxyID) -> String` + + parse name from proxy id + """ + function get_name(id::ProxyID) ::String + + if length(id.args) == 0 + return "Main" + end + + current = id + while current.args[1] isa Expr && length(current.args) >= 2 + + if current.args[2] isa UInt64 + current.args[2] = convert(Int64, current.args[2]) + end + + current = current.args[1] + end + + out = string(id) + reg = r"\Q((jluna.memory_handler._refs[])[\E(.*)\Q])[]\E" + captures = match(reg, out) + + if captures != nothing + out = replace(out, reg => "") + end + + return out; + end + + get_name(::Nothing) ::String = return "Main" + get_name(s::Symbol) ::String = return string(s) + get_name(i::Integer) ::String = return "[" * string(i) * "]" + + """ + `print_refs() -> Nothing` + + pretty print _ref state, for debugging + """ + function print_refs() ::Nothing + + println("jluna.memory_handler._refs: "); + for e in _refs[] + println("\t", Int64(e.first), " => ", e.second[], " (", typeof(e.second[]), ") ") + end + end + + """ + `create_reference(::UInt64, ::Any) -> UInt64` + + add reference to _refs + """ + function create_reference(to_wrap::Any) ::UInt64 + + global _current_id[] += 1; + key::UInt64 = _current_id[]; + + if (haskey(_refs[], key)) + _ref_counter[][key] += 1 + else + _refs[][key] = Base.RefValue{Any}(to_wrap) + _ref_counter[][key] = 1 + end + + return key; + end + + create_reference(_::Nothing) ::UInt64 = return 0 + + """ + `set_reference(::UInt64, ::T) -> Nothing` + + update the value of a reference in _refs without adding a new entry or changing it's key, ref pointers C++ side stay valid + """ + function set_reference(key::UInt64, new_value::T) ::Base.RefValue{Any} where T + + _refs[][key] = Base.RefValue{Any}(new_value) + return _refs[][key] + end + + """ + `get_reference(::Int64) -> Any` + + access reference in _refs + """ + function get_reference(key::UInt64) ::Any + + if (key == 0) + return nothing + end + + return _refs[][key] + end + + """ + `free_reference(::UInt64) -> Nothing` + + free reference from _refs + """ + function free_reference(key::UInt64) ::Nothing + + if (key == 0) + return nothing; + end + + if _refs[][key][] isa Module + return + end + + global _ref_counter[][key] -= 1 + count::UInt64 = _ref_counter[][key] + + if (count == 0) + delete!(_ref_counter[], key) + delete!(_refs[], key) + end + + return nothing; + end + + """ + `force_free() -> Nothing` + + immediately deallocate all C++-managed values + """ + function force_free() ::Nothing + + for k in keys(_refs) + delete!(_refs[], k) + delete!(_ref_counter[], k) + end + + return nothing; + end +end \ No newline at end of file diff --git a/include/julia/05_cppcall.jl b/include/julia/05_cppcall.jl new file mode 100644 index 0000000..403efa1 --- /dev/null +++ b/include/julia/05_cppcall.jl @@ -0,0 +1,191 @@ +module _cppcall + + mutable struct State + _arguments::Tuple + _result::Any + + State() = new((), nothing) + end + + _library_name = "" + _state = Base.Ref{_cppcall.State}(State()) + + """ + Wrapper object for unnamed functions, frees function once object is destroyed + """ + mutable struct UnnamedFunctionProxy{N, Return_t} + + _id::Symbol + _call::Function + _n_args::Int64 + + function UnnamedFunctionProxy{N, Return_t}(id::Symbol) where {N, Return_t} + + @assert(-1 <= N <= 4) + + _id = id + x = new{N, Return_t}(id, function (xs...) Main.cppcall(_id, xs...) end, N) + + finalizer(function (t::UnnamedFunctionProxy{N, Return_t}) + ccall((:free_function, _cppcall._library_name), Cvoid, (Csize_t,), hash(t._id)) + end, x) + + return x + end + end + + # call with signature (1x Any) -> [Any / Nothing] + function (instance::UnnamedFunctionProxy{0, T})() ::T where T + return instance._call(); + end + + # call with signature (1x Any) -> [Any / Nothing] + function (instance::UnnamedFunctionProxy{1, T})(arg1) ::T where T + return instance._call(arg1); + end + + # call with signature (2x Any) -> [Any / Nothing] + function (instance::UnnamedFunctionProxy{2, T})(arg1, arg2) ::T where T + return instance._call(arg1, arg2); + end + + # call with signature (3x Any) -> [Any / Nothing] + function (instance::UnnamedFunctionProxy{3, T})(arg1, arg2, arg3) ::T where T + return instance._call(arg1, arg2, arg3); + end + + # call with signature (4x Any) -> [Any / Nothing] + function (instance::UnnamedFunctionProxy{4, T})(arg1, arg2, arg3, arg4) ::T where T + return instance._call(arg1, arg2, arg3, arg4); + end + + # call with other signature + function (instance::UnnamedFunctionProxy{Int64(-1), T})(args::Vector) ::T where T + return instance._call(args...); + end + + # ctor wrapper for jluna + new_unnamed_function(s::Symbol, N::Integer, T::Type) = return UnnamedFunctionProxy{N, T}(s) + + """ + an exception thrown when trying to invoke cppcall with a function name that + has not yet been registered via jluna::register_function + """ + mutable struct UnregisteredFunctionNameException <: Exception + + _function_name::Symbol + end + Base.showerror(io::IO, e::UnregisteredFunctionNameException) = print(io, "cppcall.UnregisteredFunctionNameException: no C++ function with name :" * string(e._function_name) * " registered") + + """ + an exception thrown when the number of arguments does not match the number of arguments + expected by the registered lambda + """ + mutable struct TupleSizeMismatchException <: Exception + + _function_name::Symbol + _expected::Int64 + _got::Int64 + end + Base.showerror(io::IO, e::TupleSizeMismatchException) = print(io, "cppcall.TupleSizeMismatchException: C++ function with name :" * string(e._function_name) * " expects " * string(e._expected) * " arguments but was called with " * string(e._got)) + + """ + `set_result(::Any) -> Nothing` + + modify _cppcall state result + """ + function set_result(x::Any) ::Nothing + + global _cppcall._state[]._result = x + return nothing + end + + """ + `get_result() -> Any` + + access _cppcall result + """ + function get_result() ::Any + + return _cppcall._state[]._result + end + + """ + `set_arguments(xs...) -> Nothing` + + modify _cppcall state argument tuple + """ + function set_arguments(xs...) ::Nothing + + global _cppcall._state[]._arguments = xs + return nothing + end + + """ + `get_result() -> Tuple` + + access _cppcall state argument tuple + """ + function get_arguments() ::Tuple + + return _cppcall._state[]._arguments + end + + """ + `verify_library() -> Bool` + + check if c_adapter library is available + """ + function verify_library() ::Bool + + if isfile(_cppcall._library_name) + return true + end + + message = "when trying to initialize jluna.cppcall: " + message *= "cannot find " * _cppcall._library_name + + println(sprint(Base.showerror, AssertionError(message), backtrace())) + return false + end +end + +# obfuscate internal state to encourage using operator[] sytanx +struct ProxyInternal + + _fieldnames_in_order::Vector{Symbol} + _fields::Dict{Symbol, Union{Any, Missing}} + ProxyInternal() = new(Vector{Symbol}(), Dict{Symbol, Union{Any, Missing}}()) +end + +# proxy as deepcopy of cpp-side usertype object +struct Proxy + + _typename::Symbol + _value::ProxyInternal + + Proxy(name::Symbol) = new(name, ProxyInternal()) +end +export proxy +new_proxy(name::Symbol) = return Proxy(name) + +function implement(template::Proxy, m::Module = Main) ::Type + + out::Expr = :(mutable struct $(template._typename) end) + deleteat!(out.args[3].args, 1) + + for name in template._value._fieldnames_in_order + push!(out.args[3].args, Expr(:(::), name, :($(typeof(template._value._fields[name]))))) + end + + new_call::Expr = Expr(:(=), Expr(:call, template._typename), Expr(:call, :new)) + + for name in template._value._fieldnames_in_order + push!(new_call.args[2].args, template._value._fields[name]) + end + + push!(out.args[3].args, new_call) + Base.eval(m, out) + return m.eval(template._typename) +end +export implement \ No newline at end of file diff --git a/include/julia/06_public.jl b/include/julia/06_public.jl new file mode 100644 index 0000000..7d03358 --- /dev/null +++ b/include/julia/06_public.jl @@ -0,0 +1,58 @@ +using Main.jluna; + +""" +`setindex!(::Proxy, <:Any, ::Symbol) -> Nothing` + +extend base.setindex! +""" +function Base.setindex!(proxy::Main.jluna.Proxy, value, key::Symbol) ::Nothing + + if (!haskey(proxy._value._fields, key)) + push!(proxy._value._fieldnames_in_order, key) + end + + proxy._value._fields[key] = value + return nothing +end +export setindex! + +""" +`getindex(::Proxy, ::Symbol) -> Any` + +extend base.getindex +""" +function Base.getindex(proxy::Main.jluna.Proxy, value, key::Symbol) #::Auto + return proxy._value._fields[key] +end +export getindex + +""" +`cppall(::Symbol, ::Any...) -> Any` + +Call a lambda registered via `jluna::State::register_function` using `xs...` as arguments. +After the C++-side function returns, return the resulting object +(or `nothing` if the C++ function returns `void`) + +This function is not thread-safe and should not be used in a parallel context +""" +function cppcall(function_name::Symbol, xs...) ::Any + + id = hash(function_name) + + if !ccall((:is_registered, jluna._cppcall._library_name), Bool, (Csize_t,), id) + throw(jluna._cppcall.UnregisteredFunctionNameException(function_name)) + end + + n_args_expected = ccall((:get_n_args, jluna._cppcall._library_name), Csize_t, (Csize_t,), id) + if length(xs) != n_args_expected + throw(jluna._cppcall.TupleSizeMismatchException(function_name, n_args_expected, length(xs))) + end + + jluna._cppcall.set_arguments(xs...) + jluna._cppcall.set_result(nothing) + + ccall((:call_function, jluna._cppcall._library_name), Cvoid, (Csize_t,), id) + + return jluna._cppcall.get_result() +end +export cppcall \ No newline at end of file From c550db08cb2df88e8082c7357eab4f3b793bc6da Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 20:12:04 +0100 Subject: [PATCH 68/71] [WINDOWS] redefined const iterator dereferencing --- .src/array_iterator.inl | 15 ++++---- include/array.hpp | 9 +++-- include/jluna.jl | 79 ----------------------------------------- 3 files changed, 11 insertions(+), 92 deletions(-) delete mode 100644 include/jluna.jl diff --git a/.src/array_iterator.inl b/.src/array_iterator.inl index 50701fd..9a002e5 100644 --- a/.src/array_iterator.inl +++ b/.src/array_iterator.inl @@ -59,17 +59,15 @@ namespace jluna } template - template - T Array::ConstIterator::operator*() const + auto Array::ConstIterator::operator*() { - static jl_function_t* getindex = jl_get_function(jl_base_module, "getindex"); - return unbox(jluna::safe_call(getindex, _owner->operator const jl_value_t *(), box(_index + 1))); + return Iterator(_index, const_cast*>(_owner)); } template - auto Array::ConstIterator::operator*() + auto Array::ConstIterator::operator*() const { - return Iterator(_index, const_cast*>(_owner)); + return *this; } template @@ -88,10 +86,11 @@ namespace jluna } template - template, bool>> + template, bool>> Array::ConstIterator::operator T() const { - return operator*(); + static jl_function_t* getindex = jl_get_function(jl_base_module, "getindex"); + return unbox(jluna::safe_call(getindex, _owner->operator const jl_value_t *(), box(_index + 1))); } template diff --git a/include/array.hpp b/include/array.hpp index c3da8f2..17dd8fa 100644 --- a/include/array.hpp +++ b/include/array.hpp @@ -174,16 +174,15 @@ namespace jluna /// @returns bool bool operator!=(const ConstIterator&) const; - /// @brief decays into value_type - template - T operator*() const; - /// @brief forward to self + auto operator*() const; + + /// @brief forward to assignable auto operator*(); /// @brief decay into unboxed value /// @tparam value-type, not necessarily the same as declared in the array type - template, bool> = true> + template, bool> = true> operator T() const; /// @brief decay into proxy diff --git a/include/jluna.jl b/include/jluna.jl deleted file mode 100644 index 4b9bb2e..0000000 --- a/include/jluna.jl +++ /dev/null @@ -1,79 +0,0 @@ -# -# Copyright 2021 Clemens Cords -# Created on 26.12.2021 by clem (mail@clemens-cords.com) -# - -""" -module with julia-functionality needed by the C++ side of jluna. -Most end-user should not call any function in this module, with `cppcall` being the only exception -""" -module jluna - - - - - - - - - - - -using Main.jluna; - -""" -`setindex!(::Proxy, <:Any, ::Symbol) -> Nothing` - -extend base.setindex! -""" -function Base.setindex!(proxy::Main.jluna.Proxy, value, key::Symbol) ::Nothing - - if (!haskey(proxy._value._fields, key)) - push!(proxy._value._fieldnames_in_order, key) - end - - proxy._value._fields[key] = value - return nothing -end -export setindex! - -""" -`getindex(::Proxy, ::Symbol) -> Any` - -extend base.getindex -""" -function Base.getindex(proxy::Main.jluna.Proxy, value, key::Symbol) #::Auto - return proxy._value._fields[key] -end -export getindex - -""" -`cppall(::Symbol, ::Any...) -> Any` - -Call a lambda registered via `jluna::State::register_function` using `xs...` as arguments. -After the C++-side function returns, return the resulting object -(or `nothing` if the C++ function returns `void`) - -This function is not thread-safe and should not be used in a parallel context -""" -function cppcall(function_name::Symbol, xs...) ::Any - - id = hash(function_name) - - if !ccall((:is_registered, jluna._cppcall._library_name), Bool, (Csize_t,), id) - throw(jluna._cppcall.UnregisteredFunctionNameException(function_name)) - end - - n_args_expected = ccall((:get_n_args, jluna._cppcall._library_name), Csize_t, (Csize_t,), id) - if length(xs) != n_args_expected - throw(jluna._cppcall.TupleSizeMismatchException(function_name, n_args_expected, length(xs))) - end - - jluna._cppcall.set_arguments(xs...) - jluna._cppcall.set_result(nothing) - - ccall((:call_function, jluna._cppcall._library_name), Cvoid, (Csize_t,), id) - - return jluna._cppcall.get_result() -end -export cppcall \ No newline at end of file From 3d7bc59917ebd7ab1730afe3be0360d31117a9c6 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 20:23:58 +0100 Subject: [PATCH 69/71] [WINDOWS] hardcoded shared libary name for now --- .src/include_julia.inl.in | 2 +- .src/state.cpp | 2 +- CMakeLists.txt | 7 +++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.src/include_julia.inl.in b/.src/include_julia.inl.in index 821ff2e..5b3e971 100644 --- a/.src/include_julia.inl.in +++ b/.src/include_julia.inl.in @@ -7,7 +7,7 @@ namespace jluna::detail { - static inline const char* c_adapter_path = "@C_ADAPTER_PATH@"; + static inline const char* c_adapter_path = "@C_ADAPTER_NAME@"; // source split like this because of: https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2026?view=msvc-160 diff --git a/.src/state.cpp b/.src/state.cpp index e65f5e7..4824aab 100644 --- a/.src/state.cpp +++ b/.src/state.cpp @@ -71,7 +71,7 @@ namespace jluna::State forward_last_exception(); std::stringstream str; - str << "jluna._cppcall.eval(:(_library_name = \"" << jluna::detail::c_adapter_path << "/libjluna_c_adapter.so\"))"; + str << "jluna._cppcall.eval(:(_library_name = \"" << jluna::detail::c_adapter_path << "\"))"; jl_eval_string(str.str().c_str()); forward_last_exception(); diff --git a/CMakeLists.txt b/CMakeLists.txt index ffcd2cf..78a397a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,14 @@ find_package(Julia 1.7.0 REQUIRED) ### Configure Files ### +# TODO: don't hardcode this, use CMAKE_LIBRARY_SUFFIX + set(C_ADAPTER_PATH "${CMAKE_INSTALL_PREFIX}") +if (WIN32) + set(C_ADAPTER_NAME "${CMAKE_INSTALL_PREFIX}/jluna_c_adapter.lib") +else() + set(C_ADAPTER_NAME "${CMAKE_INSTALL_PREFIX}/libjluna_c_adapter.so") +endif() file(READ include/julia/01_common.jl From 5bf595511b19dd1847e4289d799ebdddc29ab5fd Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 20:48:59 +0100 Subject: [PATCH 70/71] C_ADAPTER_NAMING updated for all platforms --- CMakeLists.txt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78a397a..e13d948 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,14 +40,9 @@ find_package(Julia 1.7.0 REQUIRED) ### Configure Files ### -# TODO: don't hardcode this, use CMAKE_LIBRARY_SUFFIX - +# TODO: don't hardcode these set(C_ADAPTER_PATH "${CMAKE_INSTALL_PREFIX}") -if (WIN32) - set(C_ADAPTER_NAME "${CMAKE_INSTALL_PREFIX}/jluna_c_adapter.lib") -else() - set(C_ADAPTER_NAME "${CMAKE_INSTALL_PREFIX}/libjluna_c_adapter.so") -endif() +set(C_ADAPTER_NAME "${C_ADAPTER_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}jluna_c_adapter${CMAKE_SHARED_LIBRARY_SUFFIX}") file(READ include/julia/01_common.jl @@ -203,7 +198,7 @@ endif() ### Declare Benchmark ### option(BUILD_BENCHMARK "Enable jluna_benchmark" ON) -if (BUILD_BENCHMARK) +if (BUILD_BENCHMARK AND NOT WIN32) add_executable( jluna_benchmark .benchmark/main.cpp From 65d4081c274a96d5bf0745747ff5e2780d990c00 Mon Sep 17 00:00:00 2001 From: clem Date: Fri, 18 Mar 2022 21:15:30 +0100 Subject: [PATCH 71/71] added override backdoor to allow for building on windows --- .src/include_julia.inl.in | 3 +++ .src/state.cpp | 9 ++++++++- docs/installation.md | 10 ++++++++++ include/state.hpp | 3 +++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.src/include_julia.inl.in b/.src/include_julia.inl.in index 5b3e971..80ce1d8 100644 --- a/.src/include_julia.inl.in +++ b/.src/include_julia.inl.in @@ -5,9 +5,12 @@ #pragma once +#include + namespace jluna::detail { static inline const char* c_adapter_path = "@C_ADAPTER_NAME@"; + static inline std::string c_adapter_path_override = ""; // source split like this because of: https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2026?view=msvc-160 diff --git a/.src/state.cpp b/.src/state.cpp index 4824aab..d2148c7 100644 --- a/.src/state.cpp +++ b/.src/state.cpp @@ -29,6 +29,11 @@ namespace jluna::detail namespace jluna::State { + void set_c_adapter_path(const std::string& path) + { + jluna::detail::c_adapter_path_override = path; + } + void initialize() { initialize(""); @@ -71,7 +76,9 @@ namespace jluna::State forward_last_exception(); std::stringstream str; - str << "jluna._cppcall.eval(:(_library_name = \"" << jluna::detail::c_adapter_path << "\"))"; + str << "jluna._cppcall.eval(:(_library_name = \""; + str << (jluna::detail::c_adapter_path_override.empty() ? jluna::detail::c_adapter_path : jluna::detail::c_adapter_path_override); + str << "\"))"; jl_eval_string(str.str().c_str()); forward_last_exception(); diff --git a/docs/installation.md b/docs/installation.md index f3da3ca..0a36c01 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -267,6 +267,16 @@ To fix this, recompile jluna, as detailed [above](#make-install). The C-adapter library is always installed into the directory specified by `CMAKE_INSTALL_PREFIX`, regardless of cmake presets used. Be aware of this. +> **HACK**: Some IDEs and modern versions of cmake may override `CMAKE_INSTALL_PREFIX` between the time of configuration and build. As a hacky fix (March, 2022), you can override the C-adapter shared library location manually, **before calling `State::initialize`**, using `State::set_c_adapter_path`: +> ```cpp +> int main() +> { +> State::set_c_adapter_path("C:/actual/path/to/jluna_c_adapter.dll") +> State::initialize(); +> (...) +> ``` +> A future release of `jluna` will provide a proper solution for this. + --- If your particular problem was not addressed in this section, feel free to [open an issue on GitHub](https://github.com/Clemapfel/jluna/issues). diff --git a/include/state.hpp b/include/state.hpp index 821e369..16e3182 100644 --- a/include/state.hpp +++ b/include/state.hpp @@ -28,6 +28,9 @@ namespace jluna namespace jluna::State { + /// @brief manually set the C-adapter path + void set_c_adapter_path(const std::string& path); + /// @brief initialize environment void initialize();