From 2c904039fa7efac5603802f03c54238d9df5b7f6 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 1 Jul 2018 10:29:59 +0900 Subject: [PATCH 1/3] Make main functions static so they are visible only within main module --- compiler/cgen.nim | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 928d1fd22..4cbc3d3b1 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -953,13 +953,13 @@ proc genMainProc(m: BModule) = # prevents inlining of the NimMainInner function and dependent # functions, which might otherwise merge their stack frames. PreMainBody = - "void PreMainInner(void) {$N" & + "static void PreMainInner(void) {$N" & "\tsystemInit000();$N" & "$1" & "$2" & "$3" & "}$N$N" & - "void PreMain(void) {$N" & + "static void PreMain(void) {$N" & "\tvoid (*volatile inner)(void);$N" & "\tsystemDatInit000();$N" & "\tinner = PreMainInner;$N" & @@ -973,12 +973,12 @@ proc genMainProc(m: BModule) = MainProcsWithResult = MainProcs & "\treturn nim_program_result;$N" - NimMainInner = "N_CDECL(void, NimMainInner)(void) {$N" & + NimMainInner = "N_CDECL(static void, NimMainInner)(void) {$N" & "$1" & "}$N$N" NimMainProc = - "N_CDECL(void, NimMain)(void) {$N" & + "N_CDECL(static void, NimMain)(void) {$N" & "\tvoid (*volatile inner)(void);$N" & "\tPreMain();$N" & "\tinner = NimMainInner;$N" & @@ -1026,7 +1026,7 @@ proc genMainProc(m: BModule) = PosixNimDllMain = WinNimDllMain PosixCDllMain = - "void NIM_POSIX_INIT NimMainInit(void) {$N" & + "static void NIM_POSIX_INIT NimMainInit(void) {$N" & MainProcs & "}$N$N" @@ -1117,7 +1117,10 @@ proc registerModuleToMain(g: BModuleList; m: PSym) = var init = m.getInitName datInit = m.getDatInitName - addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) + if sfMainModule in m.flags: + addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(static void, $1)(void);$N", [init]) + else: + addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit]) if sfSystemModule notin m.flags: addf(g.mainDatInit, "\t$1();$N", [datInit]) @@ -1129,7 +1132,11 @@ proc registerModuleToMain(g: BModuleList; m: PSym) = proc genInitCode(m: BModule) = var initname = getInitName(m.module) - var prc = "N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N" % [initname] + var prc: Rope + if sfMainModule in m.module.flags: + prc = "N_LIB_PRIVATE N_NIMCALL(static void, $1)(void) {$N" % [initname] + else: + prc = "N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N" % [initname] if m.typeNodes > 0: appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", [m.typeNodesName, rope(m.typeNodes)]) From 13c6491b1048272780acf7841de53f0341a9d3e6 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 2 Jul 2018 11:01:04 +0900 Subject: [PATCH 2/3] Add compiler flag that makes NimMain function unique. --- compiler/cgen.nim | 14 +++++++++++--- compiler/commands.nim | 4 ++++ compiler/options.nim | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 4cbc3d3b1..dc2c4483f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -947,8 +947,16 @@ proc genFilenames(m: BModule): Rope = for i in 0.. Date: Mon, 2 Jul 2018 11:33:08 +0900 Subject: [PATCH 3/3] Add docs for compiler switch --- changelog.md | 3 +++ doc/advopt.txt | 2 ++ doc/nimc.rst | 31 +++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/changelog.md b/changelog.md index bbe526124..7c5c70ecf 100644 --- a/changelog.md +++ b/changelog.md @@ -185,4 +185,7 @@ - Nintendo Switch was added as a new platform target. See [the compiler user guide](https://nim-lang.org/docs/nimc.html) for more info. +- Compiler switch ``--uniqueMain`` was added. See [the compiler user guide](https://nim-lang.org/docs/nimc.html#linking-a-nim-generated-static-library-in-nim) for more info. + + ### Bugfixes diff --git a/doc/advopt.txt b/doc/advopt.txt index 685c8127d..c2d894976 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -34,6 +34,8 @@ Advanced options: -c, --compileOnly compile Nim files only; do not assemble or link --noLinking compile Nim and generated files but do not link --noMain do not generate a main procedure + --uniqueMain generate a unique main function call which is usefull + for linking to static libaries written in Nim --genScript generate a compile script (in the 'nimcache' subdirectory named 'compile_$$project$$scriptext'), implies --compileOnly diff --git a/doc/nimc.rst b/doc/nimc.rst index a3adcc143..a03687684 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -430,6 +430,37 @@ on Linux:: nim c --dynlibOverride:lua --passL:liblua.lib program.nim +Linking a Nim generated static library in Nim +============================================= + +By default, Nim generates a publicly visible main function in C that is always +named the same thing (NimMain) in order to make it easy for clients written in +other languages to link to Nim generated code. However, this causes issues +when Nim clients want to link to Nim static libraries because of multiple +definitions of the same function, which C doesn't allow. + +In order to work around this issue, a compiler flag exists that generates a +unique name for ``NimMain`` by hashing the name of the module it's in and +appending it to the end of the ``NimMain``, separated by an underscore. + +An example to compile a static library on Linux and then link it is as follows:: + + nim --noMain --uniqueMain --app:staticLib c static.nim + nim --passL:libstatic.a c main.nim + +Where an example of ``static.nim`` could be: + +.. code-block:: Nim + proc testing*(testInt: int): int {.cdecl, exportc.} = + return testInt + 100 + +and an example of ``main.nim`` could be: + +.. code-block:: Nim + proc testing*(testInt: int): int {.importc, cdecl.} + + echo testing(50) # Should output "150" + Backend language options ========================