Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static linking with a .lib file not working #15955

Closed
Aquachains opened this issue Nov 13, 2020 · 13 comments · Fixed by #20414
Closed

Static linking with a .lib file not working #15955

Aquachains opened this issue Nov 13, 2020 · 13 comments · Fixed by #20414

Comments

@Aquachains
Copy link

If i statically link a nim application with a .lib file, i get an error output.

Example

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)

Build and run with nim c -r main.nim

Current Output

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   '

Expected Output

15
-5

Possible Solution

Because of the error "mulitple definition of" the nim compiler should exclude runtime specific code in libraries. But i could also not link to a static .lib of a third party library. There could be a general problem with static linking.

Additional Information

Tested with Nim version 1.5.1, Windows 10 and reinstalled MingW.
I firstly reported this problem here: https://stackoverflow.com/questions/64677151/nim-use-a-static-library
Then here: https://forum.nim-lang.org/t/7080.
I tried the parameter --dynlibOverride:foo and --noMain:on
and also the pragma {.link: "foo.lib", passc:"-L foo".}
If i add the dynlib pragma to both files and create a .dll file with nim c --app:lib foo.nim it just works.

Thanks for every help.

@shirleyquirk
Copy link
Contributor

shirleyquirk commented Feb 5, 2021

One workaround is to instruct the linker to ignore the multiple definitions.
This will of course be highly platform-specific, does nothing to address the root problem, while possibly silently causing more. but here you go:
using gnu ld 2.35.1 and gcc on linux i was able to make the example work by changing main.nim to:

{.passL:"libfoo.a -Wl,--allow-multiple-definition".}
...

timotheecour added a commit to timotheecour/Nim that referenced this issue Feb 6, 2021
timotheecour added a commit to timotheecour/Nim that referenced this issue Feb 6, 2021
timotheecour added a commit to timotheecour/Nim that referenced this issue Feb 6, 2021
@timotheecour
Copy link
Member

timotheecour commented Feb 6, 2021

Is it normal to generate Main symbol on lib & staticlib compilation ?

yes, see why here https://nim-lang.github.io/Nim/backends.html#interfacing-backend-code-calling-nim

The Nim compiler can generate a C interface header through the --header command-line switch. The generated header will contain all the exported symbols and the NimMain proc which you need to call before any other Nim code.

pass --app:staticlib -d:nimLinkerWeakSymbols --nomain (see tests/misc/tapp_lib_staticlib.nim)

EDIT: works on posix, not yet on windows

@Clonkk
Copy link
Contributor

Clonkk commented Feb 6, 2021

Works on Linux with a warning on the C code generated :

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation Line :
../../Nim/bin/nim c --app:staticlib --noMain:on -d:nimLinkerWeakSymbols --clearNimblePath --skipCfg --skipUserCfg --skipProjCfg --skipParentCfg foo.nim
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
....
CC: stdlib_system.nim
CC: foo.nim
/home/sidger/.cache/nim/foo_d/stdlib_system.nim.c: In function ‘sysFatal__27U3EueEEOKabXYRrgiy5Asystem’:
/home/sidger/.cache/nim/foo_d/stdlib_system.nim.c:4517:1: warning: ‘noreturn’ function does return
 4517 | }
      | ^
/home/sidger/.cache/nim/foo_d/stdlib_system.nim.c: In function ‘sysFatal__pO9abt7E7FWB3DInHeLgZeQsystem’:
/home/sidger/.cache/nim/foo_d/stdlib_system.nim.c:4738:1: warning: ‘noreturn’ function does return
 4738 | }
      | ^
Hint:  [Link]
Hint: 14658 lines; 0.422s; 20.41MiB peakmem; Debug build; proj: /home/sidger/Workspace/Nim/BugStaticLib/static_linking_bug/static/foo.nim; out: /home/sidger/Workspace/Nim/BugStaticLib/static_linking_bug/static/libfoo.a [SuccessX]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation Line :
../../Nim/bin/nim c -r -d:nimLinkerWeakSymbols static_main.nim
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hint: used config file '/home/sidger/Workspace/Nim/BugStaticLib/Nim/config/nim.cfg' [Conf]
Hint: used config file '/home/sidger/Workspace/Nim/BugStaticLib/Nim/config/config.nims' [Conf]
Hint: used config file '/home/sidger/Workspace/Nim/BugStaticLib/static_linking_bug/static/config.nims' [Conf]
....
Hint:  [Link]
Hint: 30111 lines; 0.210s; 31.703MiB peakmem; Debug build; proj: /home/sidger/Workspace/Nim/BugStaticLib/static_linking_bug/static/static_main.nim; out: /home/sidger/Workspace/Nim/BugStaticLib/static_linking_bug/static/static_main [SuccessX]
Hint: /home/sidger/Workspace/Nim/BugStaticLib/static_linking_bug/static/static_main  [Exec]

I'll see if I can test on Windows later

timotheecour added a commit to timotheecour/Nim that referenced this issue Feb 8, 2021
timotheecour added a commit to timotheecour/Nim that referenced this issue Feb 8, 2021
@Clonkk
Copy link
Contributor

Clonkk commented Feb 10, 2021

Commit c79bde74a50bc54b9c1d1c968761b3a81a4c4d0e does not show the warning on Linux and works as expected.

Windows doesn't compile on the other hand. I used gcc.exe from MinGW. Here are the versions :

PS C:\Users\sidger\Workspace\staticLibBug\Nim> .\bin\nim.exe -v
Nim Compiler Version 1.5.1 [Windows: i386]
Compiled at 2021-02-10
Copyright (c) 2006-2021 by Andreas Rumpf

git hash: c79bde74a50bc54b9c1d1c968761b3a81a4c4d0e
active boot switches: -d:release

PS C:\Users\sidger\Workspace\staticLibBug\Nim> gcc.exe --version
gcc.exe (MinGW.org GCC-6.3.0-1) 6.3.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

The error message on powershell is rather long so I put it into a text file :

..\..\Nim\bin\nim.exe build 3>&1 2>&1 > windows_pr_fix_15955_log.txt

windows_pr_fix_15955_log.txt

Here's a preview because it basically repeat the same message on different places :

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../../Nim/bin/nim c --app:staticlib --noMain:on -d:nimLinkerWeakSymbols --clearNimblePath --skipCfg --skipUserCfg --skipProjCfg --skipParentCfg foo.nim
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CC: stdlib_io.nim
CC: stdlib_system.nim
CC: foo.nim
..\..\Nim\bin\nim.exe : ....C:\Users\sidger\nimcache\foo_d\stdlib_io.nim.c:42:1: error: 'selectany' attribute applies only to initialized variables with external linkage
Au caractère Ligne:1 : 1
+ ..\..\Nim\bin\nim.exe build 3>&1 2>&1 > windows_pr_fix_15955_log.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (....C:\Users\si...xternal linkage:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
 
 N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__mMRdr4sgmnykA9aWeM9aDZlw)(void);
 ^~~~~~~~~~~~~
C:\Users\sidger\nimcache\foo_d\stdlib_io.nim.c:76:1: error: 'selectany' attribute applies only to initialized variables with external linkage
 N_LIB_PRIVATE N_NIMCALL(void, stdlib_ioInit000)(void) {
 ^~~~~~~~~~~~~

Error: execution of an external compiler program 'gcc.exe -c    -IC:\Users\sidger\Workspace\staticLibBug\Nim\lib -IC:\Users\sidger\Workspace\staticLibBug\static_linking_bug\static -o 
C:\Users\sidger\nimcache\foo_d\stdlib_io.nim.c.o C:\Users\sidger\nimcache\foo_d\stdlib_io.nim.c' failed with exit code: 1


C:\Users\sidger\nimcache\foo_d\@mfoo.nim.c:38:1: error: 'selectany' attribute applies only to initialized variables with external linkage
 N_LIB_PRIVATE N_CDECL(NI, add)(NI a, NI b);
 ^~~~~~~~~~~~~
C:\Users\sidger\nimcache\foo_d\@mfoo.nim.c:39:1: error: 'selectany' attribute applies only to initialized variables with external linkage
 N_LIB_PRIVATE N_NOINLINE(void, raiseOverflow)(void);
 ^~~~~~~~~~~~~
C:\Users\sidger\nimcache\foo_d\@mfoo.nim.c:41:1: error: 'selectany' attribute applies only to initialized variables with external linkage
 N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__mMRdr4sgmnykA9aWeM9aDZlw)(void);
 ^~~~~~~~~~~~~
C:\Users\sidger\nimcache\foo_d\@mfoo.nim.c:43:1: error: 'selectany' attribute applies only to initialized variables with external linkage
 N_LIB_PRIVATE N_CDECL(NI, sub)(NI a, NI b);
 ^~~~~~~~~~~~~
C:\Users\sidger\nimcache\foo_d\@mfoo.nim.c:45:1: error: 'selectany' attribute applies only to initialized variables with external linkage
 N_LIB_PRIVATE N_NOINLINE(void, nimGC_setStackBottom)(void* theStackBottom);
 ^~~~~~~~~~~~~

Hope that helps you !

@waruqi
Copy link

waruqi commented Oct 21, 2021

I am trying to let xmake support building nim projects, xmake-io/xmake#1756

I also encountered a similar problem when compiling and generating static libraries. I also very much hope that this problem can be resolved.

But I now have a workaround solution, which is temporarily compatible and fixed, and I can successfully link the static library.

we can set "--passC:-DNimMain=NimMain_xxx" to rename _NimMain to avoid redefine conflict when we are building static libraries.

function buildargv(self, sourcefiles, targetkind, targetfile, flags)
    local flags_extra = {}
    if targetkind == "static" then
        -- fix multiple definition of `NimMain', it is only workaround solution
        -- we need to wait for this problem to be resolved
        --
        -- @see https://github.com/nim-lang/Nim/issues/15955
        local uniquekey = hash.uuid(targetfile):split("-", {plain = true})[1]
        table.insert(flags_extra, "--passC:-DNimMain=NimMain_" .. uniquekey)
        table.insert(flags_extra, "--passC:-DNimMainInner=NimMainInner_" .. uniquekey)
        table.insert(flags_extra, "--passC:-DNimMainModule=NimMainModule_" .. uniquekey)
        table.insert(flags_extra, "--passC:-DPreMain=PreMain_" .. uniquekey)
        table.insert(flags_extra, "--passC:-DPreMainInner=PreMainInner_" .. uniquekey)
    end
    return self:program(), table.join("c", flags, flags_extra, "-o:" .. targetfile, sourcefiles)
end

see https://github.com/xmake-io/xmake/blob/ae65d03b29b506c5cc7122214d9eb81ad1efdbcc/xmake/modules/core/tools/nim.lua#L102-L117

Now can we successfully compile and link it.

$ xmake -v
[ 33%]: linking.release libfoo.a
/usr/local/bin/nim c --opt:speed --nimcache:build/.gens/foo/macosx/x86_64/release/nimcache --app
:staticlib --noMain --passC:-DNimMain=NimMain_B6D5BD02 --passC:-DNimMainInner=NimMainInner_B6D5B
D02 --passC:-DNimMainModule=NimMainModule_B6D5BD02 --passC:-DPreMain=PreMain_B6D5BD02 --passC:-D
PreMainInner=PreMainInner_B6D5BD02 -o:build/macosx/x86_64/release/libfoo.a src/foo.nim
[ 66%]: linking.release test
/usr/local/bin/nim c --opt:speed --nimcache:build/.gens/test/macosx/x86_64/release/nimcache --pa
ssL:-Lbuild/macosx/x86_64/release --passL:-lfoo -o:build/macosx/x86_64/release/test src/main.nim
[100%]: build ok!

@zer0pwned
Copy link

I'm having the same issue and seems like the nim developers do not indent to resolve this (I guess it is more or less a linking issue rather than nim issue). Such a bummer I cannot use nim to generate a static binary library where other nim developer can use it.

@Araq
Copy link
Member

Araq commented Nov 20, 2021

The issue is open and PRs to fix it are welcome.

@Clonkk
Copy link
Contributor

Clonkk commented Nov 20, 2021

@timotheecour had commits that fixed this if I remember correctly.

Maybe his work could be merged?

@deech
Copy link
Contributor

deech commented Nov 21, 2021

I am also hitting this, I have a static archive generated with the CPP backend that externs some functions to be used with a program written with the C backend, both have NimMain, PreMain etc and so fails to link the executable. I can use -DPreMainInner=... workaround above because I don't think I'm using any stdlib modules with global initialization but if they do I'm blocked. A killer feature of Nim would be a way of easily packaging a library into a shared/static library that could be called from other languages.

@Araq
Copy link
Member

Araq commented Nov 22, 2021

Maybe his work could be merged?

Got a link handy?

@ghost
Copy link

ghost commented Nov 22, 2021

@Araq I think they were mentioning #16945 which is still in a draft state it seems like

@Araq Araq closed this as completed in 7ff43d0 Dec 10, 2021
narimiran pushed a commit that referenced this issue Dec 10, 2021
PMunch pushed a commit to PMunch/Nim that referenced this issue Mar 28, 2022
@ringabout ringabout reopened this Jun 10, 2022
@ringabout
Copy link
Member

ringabout commented Jun 10, 2022

related: #19830

It wasn't fixed. It is still broken with 1.6.6.

@deech
Copy link
Contributor

deech commented Jun 10, 2022

Compiling to CPP with a namespace addressed the immediate problem. The real fix as mentioned in the linked issue is to have the compiler add prefixes to visible symbols. However looking through the compiler this seems like a daunting change.

quantimnot added a commit to quantimnot/Nim that referenced this issue Jun 30, 2022
Expand `--nimMainPrefix` semantics to include prefixing these symbols
for the C, C++ and ObjC backends:
* `cmdCount`
* `cmdLine`
* `gEnv`
* `PreMain`
* `PreMainInner`
* `NimMainInner`
* `NimMainModule`

Fixes nim-lang#15955
Fixes nim-lang#19830
ringabout added a commit that referenced this issue Sep 23, 2022
capocasa pushed a commit to capocasa/Nim that referenced this issue Mar 31, 2023
narimiran pushed a commit that referenced this issue Apr 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
9 participants