Передать массив в двоичный код Джулии так же, как в C / C ++ - PullRequest
2 голосов
/ 07 апреля 2020

(я редактирую свой первоначальный пост, чтобы добавить дополнительную информацию)

Я недавно переехал в Джулию из-за ее прекрасной способности создавать двоичные файлы из кода.

Хотя я После этой документации Мне удалось создать двоичный файл.
Теперь я собираюсь передать массив в этот двоичный файл. Как упомянуто в документации, аргументы можно передавать с помощью глобальной переменной ARGS.
Я не уверен, как это может помочь в получении / возврате массива.

Чтобы быть более точным c, я хотел бы:

  1. написать мой алгоритм в Julia (который получает массив, выполняет некоторые вычисления и возвращает новый массив)
  2. выполните прекомпиляцию
  3. создайте sysimage
  4. создайте общую библиотеку
    и затем вызовите ее так же, как в документации

РЕДАКТИРОВАТЬ: Хотя вышеприведенное выглядело довольно сложно, я подумал, что мог бы последовать примеру здесь , но просто создать свой собственный модуль. Это не сработало.

Вот что я попробовал:

Я создал "my_test.jl"

module my_test

export real_main
export julia_main

function real_main(x::Float64, y::Float64)
        println("from main " , x, " " , y)
end

Base.@ccallable function julia_main(x::Float64, y::Float64)::Cint
    try
        real_main(x,y)
    return 0
    catch
        Base.invokelatest(Base.display_error, Base.catch_stack())
        return 1
    end
    return 0
end

if abspath(PROGRAM_FILE) == @__FILE__

    julia_main(3.,4.)
end

end

, а затем предварительно скомпилировал его, используя:

julia --startup-file=no --trace-compile=app_precompile.jl my_test.jl

Как только прекомпиляция прошла успешно, я создал create_sysimage.jl:

Base.init_depot_path()
Base.init_load_path()

@eval Module() begin
    Base.include(@__MODULE__, "my_test.jl")
    for (pkgid, mod) in Base.loaded_modules
        if !(pkgid.name in ("Main", "Core", "Base"))
            eval(@__MODULE__, :(const $(Symbol(mod)) = $mod))
        end
    end
    for statement in readlines("app_precompile.jl")
        try
            Base.include_string(@__MODULE__, statement)
        catch
            # See julia issue #28808
            Core.println("failed to compile statement: ", statement)
        end
    end
end # module

empty!(LOAD_PATH)
empty!(DEPOT_PATH)

Затем я построил общую библиотеку на основе этого образа в 2 этапа:

julia --startup-file=no -J"$JULIA_DIR/lib/julia/sys.so" --output-o sys.o create_sysimage.jl
gcc -g -shared -o libsys.so  -Wl,--whole-archive sys.o -Wl,--no-whole-archive -L"$JULIA_DIR/lib" -ljulia

Как только это удастся, я создал файл cpp для использования библиотеки выше. Поэтому my_test. cpp:

#include <julia.h>

JULIA_DEFINE_FAST_TLS()

int main()
{

        libsupport_init();
        jl_options.use_compiled_modules = JL_OPTIONS_USE_COMPILED_MODULES_YES;
        jl_options.image_file = JULIAC_PROGRAM_LIBNAME;
        jl_options.image_file_specified = 1;
        jl_init_with_image(NULL,JULIAC_PROGRAM_LIBNAME);
//Enabling the below gives a better explanation of te failure
/*
        jl_eval_string("using Main.my_test.jl");
        if (jl_exception_occurred()) {
                jl_call2(jl_get_function(jl_base_module, "showerror"),
                         jl_stderr_obj(),
                         jl_exception_occurred());
                jl_printf(jl_stderr_stream(), "\n");
                jl_atexit_hook(2);
                exit(2);
        }       
        jl_module_t* LA = (jl_module_t *)jl_eval_string("Main.my_test");
        if (jl_exception_occurred()) {
                jl_call2(jl_get_function(jl_base_module, "showerror"),
                         jl_stderr_obj(),
                         jl_exception_occurred());
                jl_printf(jl_stderr_stream(), "\n");
                jl_atexit_hook(3);
                exit(3);
        }
*/

        jl_function_t *func1 = jl_get_function(jl_main_module, "julia_main");
        if (jl_exception_occurred()) {
                jl_call2(jl_get_function(jl_base_module, "showerror"),
                         jl_stderr_obj(),
                         jl_exception_occurred());
                jl_printf(jl_stderr_stream(), "\n");
                jl_atexit_hook(4);
                exit(4);
        }
        jl_value_t* in1 = jl_box_float64(12.);
        jl_value_t* in2 = jl_box_float64(24.);
        jl_value_t* ret = NULL;

        JL_GC_PUSH3(&in1,&in2,&ret);

        ret = jl_call2(func1, in1, in2);

        JL_GC_POP();

        jl_atexit_hook(0);
}

А затем скомпилируйте его следующим образом:

g++  -o pass_2_arrays_to_my_test_by_eval  -fPIC -I$JULIA_DIR/include/julia -L$JULIA_DIR/lib -ljulia  -L$CURRENT_FOLDER -lsys pass_2_arrays_to_my_test_by_eval.cpp  $JULIA_DIR/lib/julia/libstdc++.so.6

JULIA_DIR указывает на каталог установки Julia, а CURRENT_FOLDER указывает на текущий рабочий каталог.

Сбой вызова pass_2_arrays_to_my_test_by_eval с сообщением Segmentation Fault.
Насколько я понимаю, он не работает, потому что не может загрузить модуль (вы можете увидеть это, если откомментировать некоторые строки в cpp код).

Может ли кто-нибудь помочь с этим? Некоторые люди в прошлом, кажется, делают это без каких-либо проблем ( как здесь ).

Заранее большое спасибо!

...