depends.nim 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # This module implements a dependency file generator.
  10. import options, ast, ropes, pathutils, msgs, lineinfos
  11. import modulegraphs
  12. import std/[os, parseutils]
  13. import std/strutils except addf
  14. import std/private/globs
  15. when defined(nimPreviewSlimSystem):
  16. import std/assertions
  17. type
  18. TGen = object of PPassContext
  19. module: PSym
  20. config: ConfigRef
  21. graph: ModuleGraph
  22. PGen = ref TGen
  23. Backend = ref object of RootRef
  24. dotGraph: Rope
  25. proc addDependencyAux(b: Backend; importing, imported: string) =
  26. b.dotGraph.addf("\"$1\" -> \"$2\";$n", [rope(importing), rope(imported)])
  27. # s1 -> s2_4[label="[0-9]"];
  28. proc toNimblePath(s: string, isStdlib: bool): string =
  29. const stdPrefix = "std/"
  30. const pkgPrefix = "pkg/"
  31. if isStdlib:
  32. let sub = "lib/"
  33. var start = s.find(sub)
  34. if start < 0:
  35. raiseAssert "unreachable"
  36. else:
  37. start += sub.len
  38. let base = s[start..^1]
  39. if base.startsWith("system") or base.startsWith("std"):
  40. result = base
  41. else:
  42. for dir in stdlibDirs:
  43. if base.startsWith(dir):
  44. return stdPrefix & base.splitFile.name
  45. result = stdPrefix & base
  46. else:
  47. var sub = getEnv("NIMBLE_DIR")
  48. if sub.len == 0:
  49. sub = ".nimble/pkgs/"
  50. else:
  51. sub.add "/pkgs/"
  52. var start = s.find(sub)
  53. if start < 0:
  54. sub[^1] = '2'
  55. sub.add '/'
  56. start = s.find(sub) # /pkgs2
  57. if start < 0:
  58. return s
  59. start += sub.len
  60. start += skipUntil(s, '/', start)
  61. start += 1
  62. result = pkgPrefix & s[start..^1]
  63. proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
  64. doAssert n.kind == nkSym, $n.kind
  65. let path = splitFile(toProjPath(g.config, n.sym.position.FileIndex))
  66. let modulePath = splitFile(toProjPath(g.config, g.module.position.FileIndex))
  67. let parent = nativeToUnixPath(modulePath.dir / modulePath.name).toNimblePath(belongsToStdlib(g.graph, g.module))
  68. let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym))
  69. addDependencyAux(b, parent, child)
  70. proc addDotDependency*(c: PPassContext, n: PNode): PNode =
  71. result = n
  72. let g = PGen(c)
  73. let b = Backend(g.graph.backend)
  74. case n.kind
  75. of nkImportStmt:
  76. for i in 0..<n.len:
  77. addDependency(c, g, b, n[i])
  78. of nkFromStmt, nkImportExceptStmt:
  79. addDependency(c, g, b, n[0])
  80. of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
  81. for i in 0..<n.len: discard addDotDependency(c, n[i])
  82. else:
  83. discard
  84. proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
  85. let b = Backend(graph.backend)
  86. discard writeRope("digraph $1 {$n$2}$n" % [
  87. rope(project.splitFile.name), b.dotGraph],
  88. changeFileExt(project, "dot"))
  89. proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
  90. result = PGen(module: module, config: graph.config, graph: graph)
  91. if graph.backend == nil:
  92. graph.backend = Backend(dotGraph: "")