Hello. I'm new to the nim language and wasn't able to find an working example or a tutorial for this task. I need help to get a .lib file statically linked. I know that most libraries use the "compile" pragma with all c files but in my case this would be too much work. Here is an simple example that didnt work for me:
foo.nim
proc add*(a, b: int): int {.cdecl, exportc.} =
a + b
proc sub*(a, b: int): int {.cdecl, exportc.} =
a - b
Build with nim c --app:staticlib foo.nim to generate the "foo.lib" file
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)
Simply build and run with nim c -r main.nim
But the output is this and there is no .exe file generated
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 '
if i add "dynlib" pragmas to the procedures in "foo.nim" and "main.nim" i can simply export it as dll with nim c --app:lib foo.nim and it just works with "foo.dll". I dont understand what to do for statically linking. I've tried to add {.deadCodeElim:on.} on top of each file or build "foo.nim" with --noMain:on parameter or use the pragmas {.link: "foo.lib", passL:"foo.lib".} in "main.nim". But it doesnt work. I also converted the .lib file to an .a file but its not working either.
If you are interested in what i exactly try to archive, it is described here: https://stackoverflow.com/questions/64677151/nim-use-a-static-library. I'm thankfull for every help and sorry for my bad english.
I was able to reproduce the same issue on Windows with Nim 1.4.0. I am starting to suspect it might be a Windows only issue (are you working on windows @Aquachain? can anyone on Linux reproduce?). I think the issue is tied to the fact that noMain option is not working correctly (since in c file we see all sort of Main stuff appearing even when noMain is called).
Checking how the noMain option is processed (see here) I see this condition for osWindows (other oses do not have this type of conditions):
if m.config.target.targetOS == osWindows and
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
is it possible that we are missing optGenStaticLib in the set we are joining with globalOptions?
I did test with the following commands (and removing pragma passL from main.nim) and the issue is still there:
nim c --nimcache:. --verbosity:3 --clearNimblePath --skipCfg --skipUserCfg --skipProjCfg --skipParentCfg --app:staticLib --noMain --header foo
nim c --nimcache:. --verbosity:3 --clearNimblePath --skipCfg --skipUserCfg --skipProjCfg --skipParentCfg --skipUserCfg --passL:foo.lib main
I do have to say that I do not think my guess above is correct since if I substitute --app:staticLib with --app:lib in first command I do still see all the Main, PreMain, ... stuff in the c generated file.
I was able to reproduce on WSL2 so it might not be a Windows only problem. I do think it's a bug that should be reported.
Using nm libfoo.a or nm libfoo.so, it shows that main / premain etc. gets generated for both static & dynamic library but it's only a problem for static library.