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/compiler/cgen.nim b/compiler/cgen.nim index 928d1fd22..dc2c4483f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -947,19 +947,27 @@ proc genFilenames(m: BModule): Rope = for i in 0.. 0: appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", [m.typeNodesName, rope(m.typeNodes)]) diff --git a/compiler/commands.nim b/compiler/commands.nim index 866405f9f..7d781e57d 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -246,6 +246,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool of "compileonly", "c": result = contains(conf.globalOptions, optCompileOnly) of "nolinking": result = contains(conf.globalOptions, optNoLinking) of "nomain": result = contains(conf.globalOptions, optNoMain) + of "uniquemain": result = contains(conf.globalOptions, optUniqueMain) of "forcebuild", "f": result = contains(conf.globalOptions, optForceFullMake) of "warnings", "w": result = contains(conf.options, optWarns) of "hints": result = contains(conf.options, optHints) @@ -416,6 +417,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "nomain": expectNoArg(conf, switch, arg, pass, info) incl(conf.globalOptions, optNoMain) + of "uniquemain": + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optUniqueMain) of "forcebuild", "f": expectNoArg(conf, switch, arg, pass, info) incl(conf.globalOptions, optForceFullMake) diff --git a/compiler/options.nim b/compiler/options.nim index 2aa515e35..9cd1a1a5a 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -60,6 +60,7 @@ type # please make sure we have under 32 options optSkipUserConfigFile, # skip the users's config file optSkipParentConfigFiles, # skip parent dir's config files optNoMain, # do not generate a "main" proc + optUniqueMain, # generate a unique name for the NimMain function optUseColors, # use colors for hints, warnings, and errors optThreads, # support for multi-threading optStdout, # output to stdout 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 ========================