将使用 Julia 的 PackageCompiler 演示创建的库连接到 c# 程序



用Julia语言编写的程序可以在PackageCompiler包的帮助下编译。jl转换为一个库,方便外部(非julian)程序的链接和使用。在packagecomcompiler的帮助页面中。Jl是一个非常简单的演示,关于如何为integer和long类型的变量导出两个增量方法。

在编译这个演示库之后,创建了一个包含增量方法的libinc.dll库文件,以及53个dll文件和一个可执行文件。首先,我尝试将所有55个文件复制到.net可执行文件所在的文件夹中。(bin/debug/net7.0-windows文件夹。)我得到了错误:

无法加载依赖库myfolder bin 调试 net7.0-windows . ./bin/libopenlibm.dll

所以我把所有的库文件,除了libc .dll复制到。net可执行文件文件夹下面的bin文件夹。现在我得到了错误:

无法加载DLL 'libinc.dll'或其依赖项之一找不到指定的模块。(0 x8007007e)

我看不到什么dll文件丢失了。因此,为了使程序工作,我必须在两个地方有54个dll文件:一个单独的bin文件夹和程序文件夹。

我怎么能有一个。net程序只使用一个julia库的副本?最好不要放在程序文件夹下面的bin文件夹?

下面是控制台程序:

// See https://aka.ms/new-console-template for more information
using System.ComponentModel;
using System.Runtime.InteropServices;

Wrapper.init_julia(0, new string[1] { "" });
int start = 1;
int ret = Wrapper.increment32(start);
Console.WriteLine($"When you add 1 to {start} you get: {ret}.");
Console.ReadKey();
Wrapper.shutdown_julia(0);
public static class Wrapper
{
[DllImport("libinc.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void init_julia(int argc, string[] argv);
[DllImport("libinc.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void shutdown_julia(int retcode);
[DllImport("libinc.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int increment32(int value);
[DllImport("libinc.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern long increment64(long value);
}

项目文件:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
</Project>

我在Github上找到了这个问题的解决方案。解决方案删除带有"../bin/"在生成的libjulia.dll文件中。这不是最优雅的解决方案,但它目前有效。下面您将看到我是如何更改构建的。

using PackageCompiler
target_dir = get(ENV, "OUTDIR", "$(@__DIR__)/../../MyLibCompiled")
target_dir = replace(target_dir, "\" => "/")       # Change Windows paths to use "/"
println("Creating library in $target_dir")
PackageCompiler.create_library(".", target_dir;
lib_name="libinc",
precompile_execution_file=["$(@__DIR__)/generate_precompile.jl"],
precompile_statements_file=["$(@__DIR__)/additional_precompile.jl"],
incremental=false,
filter_stdlibs=true,
header_files=["$(@__DIR__)/mylib.h"]
)
libjulia_path = joinpath(target_dir,"bin/libjulia.dll")
libjulia_path = replace(libjulia_path, "\" => "/")       # Change Windows paths to use "/"
if !isfile(libjulia_path)
error("Unable to open libjulia.dll at $(libjulia_path)")
end
open(libjulia_path, read=true, write=true) do io
# Search for ../bin/ string:
needle = "../bin/"
readuntil(io, needle)
skip(io, -length(needle))
libpath_offset = position(io)
libpath = split(String(readuntil(io, UInt8(0))), ":")
@info("Found embedded libpath", libpath, libpath_offset)
# Get rid of `../bin/` prefix:
libpath = map(libpath) do l
if startswith(l, "../bin/")
return l[8:end]
end
if startswith(l, "@../bin/")
return "@" * l[9:end]
end
end
@info("Filtered libpath", libpath)
# Write filtered libpath out to the file, terminate with NULL.
seek(io, libpath_offset)
libspath = join(libpath, ":")
Base.write(io, libspath)
Base.write(io, UInt8(0))
end