英文:
Connect library created with Julia's PackageCompiler demo to a c# program
问题
Julia语言编写的程序可以使用PackageCompiler.jl软件包编译成库,以便外部(非Julia)程序进行链接和使用。在PackageCompiler.jl的帮助页面中,有一个非常简单的演示,展示了如何导出两个整数和长整数类型的变量的增量方法。
在编译此演示库之后,会创建一个名为libinc.dll的库文件,其中包含增量方法,以及53个dll文件和一个可执行文件。
首先,我尝试将这55个文件复制到与.NET可执行文件相同的文件夹中(bin/debug/.net7.0-windows文件夹)。我遇到了以下错误:
无法加载依赖库
myfolder\bin\Debug\net7.0-windows../bin/libopenlibm.dll
所以我将所有库文件都复制到与.NET可执行文件下方的一个bin文件夹中,除了libinc.dll。现在我遇到了以下错误:
无法加载DLL 'libinc.dll' 或其依赖项之一:指定的模块无法找到(0x8007007E)
我看不出缺少哪个dll文件。
因此,为了使程序正常工作,我必须在两个地方都拥有这54个dll文件:一个是单独的bin文件夹,另一个是程序文件夹。
如何才能使.NET程序仅使用Julia库的一个副本?最好不是在程序文件夹下方的bin文件夹吗?
以下是控制台程序:
// 有关更多信息,请参阅https://aka.ms/new-console-template
using System.ComponentModel;
using System.Runtime.InteropServices;
Wrapper.init_julia(0, new string[1] { "" });
int start = 1;
int ret = Wrapper.increment32(start);
Console.WriteLine($"当你将1添加到{start}时,你将得到:{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>
英文:
Programs written in the Julia language can be compiled with the help of the package PackageCompiler.jl to a library that facilitates linking and use by external (non-Julian) programs. In the help pages of PackageCompiler.jl is a very simple demonstration about how to export two increment methods for variables of type integer and long.
After compiling this demonstration library a libinc.dll library file is created containing the increment methods, together with 53 dll files and one executable.
First I tried copying all 55 files to the same folder as the .net executable. (The bin/debug/.net7.0-windows folder.) I got the error:
> Unable to load dependent library
> myfolder\bin\Debug\net7.0-windows../bin/libopenlibm.dll
So I copied all library files except libinc.dll to a bin folder below the folder with the .net executable. Now I get the error:
> Unable to load DLL 'libinc.dll' or one of its dependencies: The
> specified module could not be found. (0x8007007E)
I can't see what dll file is missing.
So for the program to work I must have the 54 dll files in two places: A separate bin folder and the program folder.
How can I have a .net program that uses only one copy of the julia library? And preferably not a bin folder below the program folder?
Here's the console program:
// 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);
}
Here's The project file:
<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>
答案1
得分: 0
我在Github上找到了这个问题,它提供了一个解决方案,可以解决我的问题。该解决方案会删除生成的libjulia.dll文件中包含“../bin/”的行。虽然不是最优雅的解决方案,但目前可以正常工作。下面是我如何更改示例项目的build.jl文件的方式。
using PackageCompiler
target_dir = get(ENV, "OUTDIR", "$(@__DIR__)/../../MyLibCompiled")
target_dir = replace(target_dir, "\" => "/") # 将Windows路径更改为使用"/"
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, "\" => "/") # 将Windows路径更改为使用"/"
if !isfile(libjulia_path)
error("无法打开$(libjulia_path)处的libjulia.dll")
end
open(libjulia_path, read=true, write=true) do io
# 搜索../bin/字符串:
needle = "../bin/"
readuntil(io, needle)
skip(io, -length(needle))
libpath_offset = position(io)
libpath = split(String(readuntil(io, UInt8(0)), ":")
@info("找到嵌入的libpath", libpath, libpath_offset)
# 去掉`../bin/`前缀:
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("筛选后的libpath", libpath)
# 将筛选后的libpath写入文件,以NULL终止。
seek(io, libpath_offset)
libspath = join(libpath, ":")
Base.write(io, libspath)
Base.write(io, UInt8(0))
end
英文:
I found this issue on Github that had a solution for my problem. The solution removes the lines that have "../bin/" in the generated libjulia.dll file. It's not the most elegant solution but it works for now. Below you see how I've changed the build.jl file of the example project.
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论