From 5e7a21cad23336b9ffe080b1499974bb6dc87643 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:29:36 +0200 Subject: [PATCH] fix: make nimble build succeed on Linux (#128) Before this commit, running `nimble build` on Linux would error at link time with: /usr/bin/ld: /home/runner/.cache/nim/test_r/@merr@soutput.nim.c.o: in function `customValidationError__errZoutput_u909': @merr@soutput.nim.c:(.text+0x28c1): undefined reference to `find_string_at' /usr/bin/ld: /home/runner/.cache/nim/test_r/@mztypes@sfunction.nim.c.o: in function `foreign_z_call': @mztypes@sfunction.nim.c:(.text+0x52d): undefined reference to `run_0c00l_vm' collect2: error: ld returned 1 exit status This happened only when building `test`, and occurred because: - `find_string_at` is defined in codegen.nim - `run_0c00l_vm` is defined in vm.nim and on Linux neither file was compiled when building `test`, which was an item in `bin` in the nimutils nimble file. From the docs [1]: `bin` - A list of files which should be built separated by commas with no file extension required. This option turns your package into a binary package. Nimble will build the files specified and install them appropriately. `nimble build` did work on macOS, but I believe that's only because applyCommonLinkOptions() in nimutils enabled link time optimization (LTO) for macOS only [2]: when defined(macosx): switch("cpu", targetArch) switch("passc", "-flto -target " & targetStr) switch("passl", "-flto -w -target " & targetStr & "-Wl,-object_path_lto,lto.o") elif defined(linux): if staticLink: switch("passc", "-static") switch("passl", "-static") else: discard else: echo "Platform not supported." quit(1) which caused files to be compiled that otherwise wouldn't be. Restructure slightly to allow `nimble build` to succeed without LTO. This is much better than just enabling LTO on Linux, which dramatically increases compilation time with a typical setup. It also wouldn't be ideal for LTO to be _required_, especially for debug builds. Builds would probably be significantly faster with clang, but I tried to get clang builds working on Linux, and was unsuccessful with e.g. CC=clang nimble build \ -f \ --cc:env \ --clang.exe:musl-clang \ --clang.linkerexe:musl-clang \ --passC:-flto \ --passC:-Wno-implicit-function-declaration \ --passC:-Wno-int-conversion \ --passC:-Wno-incompatible-function-pointer-types -d:zippyNoSimd This commit adds a `vm` import in test.nim, and extracts the find_string_at proc to a separate module. It seemed like it wasn't possible to simply add some lines like: import codegen or from codegen import find_string_at due to Nim not supporting mutual imports yet, which is the reason for these importc and exportc in the first place. Closes: https://github.com/crashappsec/con4m/issues/122 [1] https://nim-lang.github.io/nimble/nimble-reference.html#optional [2] https://github.com/crashappsec/nimutils/blob/74130e392d9b/nimutils/nimscript.nim#L76-L89 --- src/codegen.nim | 7 +------ src/commands/objdump.nim | 2 +- src/err/output.nim | 3 +-- src/find_string.nim | 5 +++++ src/test.nim | 2 +- src/ztypes/function.nim | 2 -- 6 files changed, 9 insertions(+), 12 deletions(-) create mode 100644 src/find_string.nim diff --git a/src/codegen.nim b/src/codegen.nim index 92f2451..76c2ee4 100644 --- a/src/codegen.nim +++ b/src/codegen.nim @@ -18,7 +18,7 @@ # defer typing things at the top-level; this will be a subtlety we # deal with when we get to doing the REPL. -import "."/[irgen, compile] +import "."/[irgen, compile, find_string] import ztypes/api proc findAndLoadModule(ctx: CompileCtx, location, fname, ext: string): @@ -108,11 +108,6 @@ proc emitInstruction(ctx: CodeGenState, op: ZOp, arg: int = 0, typeInfo: tid.getTid()) ctx.mcur.objInfo.instructions.add(ins) -proc find_string_at*(mem: string, offset: int): string {.exportc, cdecl.} = - let endIx = mem.find('\0', offset) - - return mem[offset ..< endIx] - proc hex(x: int, minlen = 2): string = let bitlen = int(64 - clzll(cast[uint](x))) var outlen = ((bitlen + 7) div 8) * 2 diff --git a/src/commands/objdump.nim b/src/commands/objdump.nim index eb4cf05..4429ac4 100644 --- a/src/commands/objdump.nim +++ b/src/commands/objdump.nim @@ -1,4 +1,4 @@ -import ".."/common +import ".."/[common, find_string] import "."/cmd_base diff --git a/src/err/output.nim b/src/err/output.nim index 1956448..7b926a5 100644 --- a/src/err/output.nim +++ b/src/err/output.nim @@ -1,5 +1,5 @@ import "std"/terminal -import ".."/common +import ".."/[common, find_string] import "."/[messages, backtrace] proc lookupMsg(code: string): string = @@ -115,7 +115,6 @@ proc formatErrors*(errs: seq[Con4mError], verbose = true): Rope = var one = table + container(errs[i].getVerboseInfo()) result += one -proc find_string_at(mem: string, offset: int): string {.importc, cdecl.} proc toString(x: TypeId): string {.importc, cdecl.} proc location_from_instruction*(ctx: RuntimeState, diff --git a/src/find_string.nim b/src/find_string.nim new file mode 100644 index 0000000..4f8e157 --- /dev/null +++ b/src/find_string.nim @@ -0,0 +1,5 @@ +import std/strutils + +proc find_string_at*(mem: string, offset: int): string = + let endIx = mem.find('\0', offset) + return mem[offset ..< endIx] diff --git a/src/test.nim b/src/test.nim index 5f99f18..a84914d 100644 --- a/src/test.nim +++ b/src/test.nim @@ -1,5 +1,5 @@ import std/[re, algorithm] -import "."/compile +import "."/[compile, vm] template error(msg: Rope) = print(fgcolor("error: ", "red") + msg, file = stderr) diff --git a/src/ztypes/function.nim b/src/ztypes/function.nim index b9360df..411d5d4 100644 --- a/src/ztypes/function.nim +++ b/src/ztypes/function.nim @@ -204,8 +204,6 @@ proc run_callback_internal*(ctx: RuntimeState, cb: ptr ZCallback, else: return ctx.foreign_z_call(cast[int](cb.impl)) -proc find_string_at(mem: string, offset: int): string {.importc, cdecl.} - proc baseunify(id1, id2: TypeId): TypeId {.importc, cdecl.} proc run_callback*(ctx: RuntimeState,