Hey check out this tool I made:
https://github.com/treeform/dumpincludes
Sometimes it's surprising where most of the code in your executable comes from. Simply use this tool to list out which module contributes how many bytes.
Nim and the C compiler strips out much of unused code in modules, so its hard to guess just from module line count on how big of a contributor it is. You might think this module is huge, but in really you only use one function and most of it gets compiled out.
On the other hand, in Nim you can also use macros, templates and generics to generate a lot of code. Sometimes the number of permutations can generate code that is very large. You might think its a little 5 line template, but it calls itself recursively creating megabytes of code.
And sometimes modules import other modules and they imports other modules, so you just don't know what really ends up getting compiled in.
This tool lets you see exactly whats in your executable.
Get this tool by running nimble install dumpincludes.
Compile your program with --debugger:native to get debugging symbols:
nim c --debugger:native .\tests\helloword.nim
dumpincludes -f:helloworld.exe
Sections:
code .......................................................................... 87,640 bytes
data .......................................................................... 87,920 bytes
debug ...................................................................... 1,400,641 bytes
Imports:
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim ............. 17,403 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/alloc.nim ............. 10,630 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/gc.nim ................. 6,753 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/arithmetics.nim ........ 4,067 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/cellseqs_v1.nim ........ 2,605 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/comparisons.nim ........ 1,960 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/cellsets.nim ........... 1,592 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/avltree.nim ............ 1,383 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/sysstr.nim ............. 1,372 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/gc_common.nim ............ 941 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/io.nim ................... 846 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/strmantle.nim ............ 814 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/osalloc.nim .............. 806 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/memory.nim ............... 775 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system.nim ...................... 568 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/fatal.nim ................ 479 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/dyncalls.nim ............. 346 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/std/private/miscdollars.nim ..... 247 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/iterators_1.nim .......... 166 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/mmdisp.nim ............... 138 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/indexerrors.nim ........... 95 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/chcks.nim ................. 68 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/ansi_c.nim ................ 65 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/iterators.nim ............. 50 bytes
C:/p/dumpincludes/tests/helloword.nim ............................................. 37 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/atomics.nim ............... 35 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/memalloc.nim ............... 9 bytes
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/integerops.nim ............. 2 bytes
other ......................................................................... 33,388 byte
Also works when linking with .c, .cpp, or using .h includes!
Make sure objdump utility from gcc/llvm is in your path. Does not work with VCC.
the first question is, is there any automatic way to ripe away all "MY_USER_NAME" in EXE file, except for an application for binary search&replace in EXE file.
Thanks
If using gcc, include it when compiling --passL:-s.
Example: nim c -d:danger --passL:-s example.nim
If I build helloworld.nim with -d:release I do get different output. Perhaps it is more expected?
Sections:
code ............................................................................ 60,776 bytes
data ............................................................................ 82,452 bytes
debug ........................................................................ 1,496,400 bytes
Imports:
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/alloc.nim .............. 8,481 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/gc.nim ................. 5,599 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/avltree.nim ............ 4,125 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/cellseqs_v1.nim ........ 1,568 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/sysstr.nim ............. 1,558 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim .............. 1,199 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/cellsets.nim ........... 1,187 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/memory.nim ............... 923 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system.nim ...................... 768 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/strmantle.nim ............ 678 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/osalloc.nim .............. 621 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/io.nim ................... 488 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/gc_common.nim ............ 414 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/iterators_1.nim .......... 405 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/arithmetics.nim .......... 362 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/fatal.nim ................ 323 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/dyncalls.nim ............. 285 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/indexerrors.nim ........... 70 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/ansi_c.nim ................ 60 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/mmdisp.nim ................ 50 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/std/private/miscdollars.nim ...... 38 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/atomics.nim ............... 19 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/chcks.nim ................. 19 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/memalloc.nim .............. 17 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/assertions.nim ............ 13 bytes
C:/Users/Ryan/Documents/GitHub/dumpincludes/tests/helloworld.nim .................... 12 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/iterators.nim .............. 9 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/comparisons.nim ............ 3 bytes
C:/Users/Ryan/.choosenim/toolchains/nim-#devel/lib/system/integerops.nim ............. 2 bytes
other ........................................................................... 31,480 bytes
@Araq, the excpt.nim adds a tons of code bytes after pretty much every nim line that makes it into the exe. Its just the default in debug mode. @Guzba correctly points out that compiling with -d:release excpt.nim mostly goes away.
This is disassembly of setPosition looks like, its mostly bits of excpt.nim code surrounded by tiny amount of setPosition code.
00000000004020b6 <setPosition__Fnam3HOmbq2ymF0tDBas5Q>:
setPosition__Fnam3HOmbq2ymF0tDBas5Q():
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/gc_common.nim:251
4020b6: 48 83 ec 58 sub $0x58,%rsp
4020ba: 48 8d 05 61 62 01 00 lea 0x16261(%rip),%rax # 418322 <.rdata+0x62>
4020c1: 48 89 44 24 28 mov %rax,0x28(%rsp)
4020c6: 48 8d 05 63 62 01 00 lea 0x16263(%rip),%rax # 418330 <.rdata+0x70>
4020cd: 48 89 44 24 38 mov %rax,0x38(%rsp)
4020d2: 48 c7 44 24 30 00 00 movq $0x0,0x30(%rsp)
4020d9: 00 00
4020db: 66 c7 44 24 40 00 00 movw $0x0,0x40(%rsp)
nimFrame():
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim:550
4020e2: 48 8b 05 37 4e 02 00 mov 0x24e37(%rip),%rax # 426f20 <framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw>
4020e9: 48 85 c0 test %rax,%rax
4020ec: 74 3c je 40212a <setPosition__Fnam3HOmbq2ymF0tDBas5Q+0x74>
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim:554
4020ee: 0f b7 48 22 movzwl 0x22(%rax),%ecx
4020f2: 8d 51 01 lea 0x1(%rcx),%edx
4020f5: 66 89 54 24 42 mov %dx,0x42(%rsp)
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim:556
4020fa: 48 89 44 24 20 mov %rax,0x20(%rsp)
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim:557
4020ff: 48 8d 44 24 20 lea 0x20(%rsp),%rax
402104: 48 89 05 15 4e 02 00 mov %rax,0x24e15(%rip) # 426f20 <framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw>
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim:558
40210b: 66 81 7c 24 42 d0 07 cmpw $0x7d0,0x42(%rsp)
402112: 74 1f je 402133 <setPosition__Fnam3HOmbq2ymF0tDBas5Q+0x7d>
popFrame():
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim:91
402114: 48 8b 05 05 4e 02 00 mov 0x24e05(%rip),%rax # 426f20 <framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw>
40211b: 48 8b 00 mov (%rax),%rax
40211e: 48 89 05 fb 4d 02 00 mov %rax,0x24dfb(%rip) # 426f20 <framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw>
setPosition__Fnam3HOmbq2ymF0tDBas5Q():
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/gc_common.nim:251
402125: 48 83 c4 58 add $0x58,%rsp
402129: c3 retq
nimFrame():
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim:551
40212a: 66 c7 44 24 42 00 00 movw $0x0,0x42(%rsp)
402131: eb c7 jmp 4020fa <setPosition__Fnam3HOmbq2ymF0tDBas5Q+0x44>
C:/Users/me/.choosenim/toolchains/nim-#devel/lib/system/excpt.nim:558
402133: e8 54 fe ff ff callq 401f8c <callDepthLimitReached__mMRdr4sgmnykA9aWeM9aDZlw>
402138: 90 nop
Looking at the generated C code we don't see much of excpt, but we see many popFrame()s which gets inlined and is part of excpt.nim. That is how excpt.nim makes it into the machine code byte counts.
N_LIB_PRIVATE N_NIMCALL(void, setPosition__Fnam3HOmbq2ymF0tDBas5Q)(tyObject_GcStack__7fytPA5bBsob6See21YMRA* stack, void* position) { nimfr_("setPosition", "C:\\Users\\me\\.choosenim\\toolchains\\nim-#devel\\lib\\system\\gc_comm"
"on.nim"); popFrame();}
#line 254 "C:\\Users\\me\\.choosenim\\toolchains\\nim-#devel\\lib\\system\\gc_common.nim"
N_LIB_PRIVATE N_NIMCALL(tyObject_GcStack__7fytPA5bBsob6See21YMRA*, getActiveStack__muO7WGG730PTJWpoUnluHg)(tyObject_GcHeap__1TRH1TZMaVZTnLNcIHuNFQ* gch) { tyObject_GcStack__7fytPA5bBsob6See21YMRA* result; nimfr_("getActiveStack", "C:\\Users\\me\\.choosenim\\toolchains\\nim-#devel\\lib\\system\\gc_comm"
"on.nim"); result = (tyObject_GcStack__7fytPA5bBsob6See21YMRA*)0;
#line 254 "C:\\Users\\me\\.choosenim\\toolchains\\nim-#devel\\lib\\system\\gc_common.nim"
nimln_(254, "C:\\Users\\me\\.choosenim\\toolchains\\nim-#devel\\lib\\system\\gc_comm"
"on.nim"); result = (&(*gch).stack); popFrame(); return result;}
#line 255 "C:\\Users\\me\\.choosenim\\toolchains\\nim-#devel\\lib\\system\\gc_common.nim"
N_LIB_PRIVATE N_NIMCALL(NIM_BOOL, isActiveStack__c6NLIYJQ5DIKtQqRJH8S7w)(tyObject_GcStack__7fytPA5bBsob6See21YMRA* stack) { NIM_BOOL result; nimfr_("isActiveStack", "C:\\Users\\me\\.choosenim\\toolchains\\nim-#devel\\lib\\system\\gc_comm"
"on.nim"); result = (NIM_BOOL)0;
#line 255 "C:\\Users\\me\\.choosenim\\toolchains\\nim-#devel\\lib\\system\\gc_common.nim"
nimln_(255, "C:\\Users\\me\\.choosenim\\toolchains\\nim-#devel\\lib\\system\\gc_comm"
"on.nim"); result = NIM_TRUE; popFrame(); return result;}
Does this make sense?
Nim Compiler Version 1.6.10 [MacOSX: amd64] Compiled at 2022-11-21 Copyright (c) 2006-2021 by Andreas Rumpf active boot switches: -d:release -d:nimUseLinenoise
import algorithm, itertools, sequtils, times
let
a = @[1, 2, 5, 2, 7, 5, 1, 2]
b = ['a', 'b', 'b', 'a', 'b', 'a', 'n', 'd']
c = [
"2001-Jan-01",
"2002-Jan-05",
"2003-Feb-13",
"2003-Jun-21",
"2003-Feb-27",
].mapIt(it.parse("yyyy-MMM-dd"))
proc monthNo(date: DateTime): int = date.month.ord
proc main() =
var s1: seq[tuple[k: int, v: seq[int]]] = @[]
var s2: seq[tuple[k: char, v: seq[char]]] = @[]
var s3: seq[tuple[k: int, v: seq[DateTime]]] = @[]
for x in groupBy a: s1.add x
for x in groupBy b: s2.add x
for x in groupBy(c, monthNo): s3.add x
echo "\ns1:", s1.sortedByIt it.k
echo "\ns2:", s2.sortedByIt it.k
echo "\ns3:", s3.sortedByIt it.k
if isMainModule: main()
nim c -d:release --debugger:native test.nim
dumpincludes -f:test
Sections:
code .......................................... 0 bytes
data .......................................... 0 bytes
debug ......................................... 0 bytes
Imports:
other ......................................... 0 bytes
Was test compiled with --debugger:native?