Compare commits

...
Sign in to create a new pull request.

3 commits

Author SHA1 Message Date
Joey Yakimowich-Payne
2482eeeed4 Add docs for compiler switch 2018-07-02 11:33:08 +09:00
Joey Yakimowich-Payne
13c6491b10 Add compiler flag that makes NimMain function unique. 2018-07-02 11:01:04 +09:00
Joey Yakimowich-Payne
2c904039fa Make main functions static so they are visible only within main module 2018-07-01 10:29:59 +09:00
6 changed files with 65 additions and 9 deletions

View file

@ -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

View file

@ -947,19 +947,27 @@ proc genFilenames(m: BModule): Rope =
for i in 0..<m.config.m.fileInfos.len:
result.addf("dbgRegisterFilename($1);$N", [m.config.m.fileInfos[i].projPath.makeCString])
proc genHashName(m: PSym, name: string): string =
name & $hashProc(m)
proc maybeHashMain(m: BModule, name: string): string =
result = name
if optUniqueMain in m.config.globalOptions:
result = m.module.genHashName(name)
proc genMainProc(m: BModule) =
const
let
# The use of a volatile function pointer to call Pre/NimMainInner
# 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" &
@ -968,17 +976,17 @@ proc genMainProc(m: BModule) =
"}$N$N"
MainProcs =
"\tNimMain();$N"
"\t" & m.maybeHashMain("NimMain") & "();$N"
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(void, " & m.maybeHashMain("NimMain") & ")(void) {$N" &
"\tvoid (*volatile inner)(void);$N" &
"\tPreMain();$N" &
"\tinner = NimMainInner;$N" &
@ -1026,7 +1034,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,6 +1125,9 @@ proc registerModuleToMain(g: BModuleList; m: PSym) =
var
init = m.getInitName
datInit = m.getDatInitName
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:
@ -1129,7 +1140,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)])

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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
========================