【问题标题】:nim: Use a static librarynim:使用静态库
【发布时间】:2021-02-16 23:24:38
【问题描述】:

我尝试将音频库静态链接到我的程序。我使用this灵活包。为了让它运行,我必须按照here 的描述构建 soloud 库。下载后不久,我在“build”文件夹中运行了“genie --with-miniaudio-only --platform=x64 vs2017”,并获得了生成动态和静态库的源代码。现在,我可以从 nimble 包中运行以下演示程序,并附带生成的 dll:

import solouddotnim, times, os

var i, spin = 0

var sl : ptr Soloud

sl = Soloud_create()

discard Soloud_init(sl)

Soloud_setGlobalVolume(sl, 1)


var stream = WavStream_create()
discard WavStream_load(cast[ptr Wav](stream), "test.ogg")

let currentTime = epochTime()
let length = WavStream_getLength(stream)
discard Soloud_play(cast[ptr Soloud](sl), cast[ptr Wav](stream))

while epochTime() - currentTime <= length:
  sleep(100)

Soloud_deinit(sl)

Soloud_destroy(sl)

现在到静态链接部分。在我使用的 nimble 包的 solouddotnim.nim 文件中,我看到了这一部分:

when defined(windows):
  const
    libname* = "libsoloud.dll"
elif ...

所以我简单地将windows部分更改为以下内容,重新安装nimble-package并将“soloud_static_x64.lib”放在testproject的“main.nim”旁边:

when defined(windows):
  const
    libname* = "soloud_static_x64.lib"
elif ...

但这并没有成功。 (构建时无法打开“soloud_static_x64.lib”错误) 使用常量“libname”的任何地方都有编译指示“cdecl”、“importc”和“dynlib”。例如:

proc Soloud_create*(): ptr Soloud {.cdecl, importc: "Soloud_create", dynlib: libname.}

所以“dynlib”告诉 nim 在 Windows 上使用 dll。但是是静态库的编译指示吗? 在 nim 文档中,我只发现 DynlibOverride 链接到静态库,但我不理解这个例子,这就是我卡住的地方。我尝试了以下方法:

nim c --dynlibOverride:libname --passL:soloud_static_x64.lib "examples\00-ogg\Example00_ogg.nim"

nim c --dynlibOverride:soloudtotnim --passL:soloud_static_x64.lib "examples\00-ogg\Example00_ogg.nim"

首先我不知道 dynlibOverride 期望什么参数,其次都编译,但不工作。它需要与 exe 一起使用的动态库。 我最后一次尝试是从 nimble 包中删除所有 dynlib 编译指示。但是现在我编译不出来了。

undefined reference to `Soloud_create'
...
Error: execution of an external program failed: 'gcc.exe...

我的知识到此结束。有人能帮我吗? 提前致谢。

编辑: 我无法让您的任何解决方案发挥作用。我将问题分解为尽可能小,以便每个人都可以重现: “foo.nim”包含以下内容:

proc add*(a, b: int): int {.cdecl, exportc.} = 
    a + b
proc sub*(a, b: int): int {.cdecl, exportc.} = 
    a - b

.lib 是使用以下命令简单生成的:“nim c --app:staticlib foo.nim”

现在为了使用它,我创建了一个包含以下内容的文件“main.nim”:

{.passL:"foo.lib".}
proc add*(a, b: int):int {.cdecl, importc.}
proc sub*(a, b: int):int {.cdecl, importc.}

echo add(10, 5)
echo sub(10, 5)

如果我只是用“nim c -r main.nim”构建它,我会得到以下输出和错误:

P:\Nim\LearnCBinding>nim c -r main.nim
Hint: used config file 'C:\nim-1.5.1\config\nim.cfg' [Conf]    
Hint: used config file 'C:\nim-1.5.1\config\config.nims' [Conf]
....CC: stdlib_io.nim
CC: stdlib_system.nim
CC: main.nim

Hint:  [Link]
foo.lib(@mfoo.nim.c.o):@mfoo.nim.c:(.text+0x1f6): multiple definition of `PreMainInner'     
C:\Users\Peter\nimcache\main_d\@mmain.nim.c.o:@mmain.nim.c:(.text+0x120): first defined here
foo.lib(@mfoo.nim.c.o):@mfoo.nim.c:(.text+0x20a): multiple definition of `PreMain'
C:\Users\Peter\nimcache\main_d\@mmain.nim.c.o:@mmain.nim.c:(.text+0x134): first defined here
foo.lib(@mfoo.nim.c.o):@mfoo.nim.c:(.text+0x240): multiple definition of `NimMainInner'     
C:\Users\Peter\nimcache\main_d\@mmain.nim.c.o:@mmain.nim.c:(.text+0x16f): first defined here
foo.lib(@mfoo.nim.c.o):@mfoo.nim.c:(.text+0x254): multiple definition of `NimMain'
C:\Users\Peter\nimcache\main_d\@mmain.nim.c.o:@mmain.nim.c:(.text+0x183): first defined here
foo.lib(@mfoo.nim.c.o):@mfoo.nim.c:(.text+0x285): multiple definition of `main'
C:\Users\Peter\nimcache\main_d\@mmain.nim.c.o:@mmain.nim.c:(.text+0x1b4): first defined here
foo.lib(@mfoo.nim.c.o):@mfoo.nim.c:(.text+0x2da): multiple definition of `NimMainModule'
C:\Users\Peter\nimcache\main_d\@mmain.nim.c.o:@mmain.nim.c:(.text+0x209): first defined here
collect2.exe: error: ld returned 1 exit status
Error: execution of an external program failed: 'C:\nim-1.5.1\dist\mingw64\bin\gcc.exe   -o P:\Nim\LearnCBinding\main.exe  C:\Users\Peter\nimcache\main_d\stdlib_io.nim.c.o C:\Users\Peter\nimcache\main_d\stdlib_system.nim.c.o C:\Users\Peter\nimcache\main_d\@mmain.nim.c.o  foo.lib   '

由于多重定义错误,我也尝试使用参数“--noMain:on”构建 foo.lib,但没有任何区别。

你有同样的问题吗?顺便说一句,我使用当前版本的 Nim“nim-1.5.1”并使用来自 nim 的 finish.exe 重新安装了 MingW。

【问题讨论】:

  • 使用 passC 将选项传递给 C 编译器,使用 passL 将选项传递给链接器。有 clib 链接 C 库。 Yopu 几乎可以将库与您在 C 中使用它做的完全一样。
  • 如果您还没有找到它,它会记录在手册中;) nim-lang.org/docs/….
  • 谢谢。但我没有那么多经验。这对绑定意味着什么?我是否必须用“passc”和“link”pragma(如{.link: "soloud_static_x64.lib", passc:"-L soloud_static_x64".})替换所有“dynlib”pragma?
  • 删除所有 {.dynlib.},保留 {.importc.} 并添加一个链接库的单个 {.passL.}。
  • 现在它看起来像一个错误。我在这里报告了它forum.nim-lang.org/t/7080。在这些答案之后,我在这里打开了一个错误报告github.com/nim-lang/Nim/issues/15955

标签: static-libraries static-linking nim-lang


【解决方案1】:

我会尽力帮助您解决您遇到的以下错误:

undefined reference to `Soloud_create'

但我会假设您已经配置了环境,因此您可以使用 Visual Studio 编译器编译您的 nim 程序(通过将 --cc:vcc 添加到您的编译命令) 这是因为您似乎已经拥有了 Visual Studio 2017,并且正在用它编译 soloud 静态库。我认为当您同时使用一个编译器进行编译时,这是最好的选择:静态库和将使用它的可执行文件。

使用一些文本/十六进制编辑器打开您的静态库 (soloud_static_x64.lib) 并搜索“Soloud_create”。我猜你什么也找不到。那为什么?因为出于某种原因,作者决定不在静态库项目中包含“C 接口”。所以它只包含 C++ 符号,而不包含我们的 solouddotnim.nim 模块所需的纯 C 符号。

让我们试着找出我们需要什么 .cpp 文件。我在 Soloud 的官方网站上注意到了这个信息 - http://sol.gfxile.net/soloud/c_api.html
所以我想我们只需要一个文件:soloud_c.cpp
让我们尝试将它包含在您使用 Genie 生成的 SoloudStatic.vcxproj 文件中。像这样:

..
<ClCompile Include="..\..\src\c_api\soloud_c.cpp">
</ClCompile>
..

并重新编译我们的静态库。我在 powershell 中使用这个命令:

& 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\Bin\MSBuild.exe' /p:PlatformToolset=v142`;WindowsTargetPlatformVersion=10`;Configuration=Release`;Platform=x64 .\SoloudStatic.vcxproj

但是你可以编译你想要的。只要确保它的架构真的是 x64。你可以用这个命令检查它:

dumpbin /headers soloud_static_x64.lib | more

最后只需将它与您的 nim 文件链接即可。将此行添加到顶部:

{.link:"soloud_static_x64.lib".}

并使用以下命令编译 nim 文件:

nim c --cc:vcc --dynlibOverride:libsoloud.dll -r "examples\00-ogg\Example00_ogg.nim"

【讨论】:

    猜你喜欢
    • 2022-12-23
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多