depends.nim 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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, passes, pathutils, msgs, lineinfos
  11. import modulegraphs
  12. import std/[os, strutils, parseutils]
  13. import std/private/globs
  14. type
  15. TGen = object of PPassContext
  16. module: PSym
  17. config: ConfigRef
  18. graph: ModuleGraph
  19. PGen = ref TGen
  20. Backend = ref object of RootRef
  21. dotGraph: Rope
  22. proc addDependencyAux(b: Backend; importing, imported: string) =
  23. b.dotGraph.addf("\"$1\" -> \"$2\";$n", [rope(importing), rope(imported)])
  24. # s1 -> s2_4[label="[0-9]"];
  25. proc toNimblePath(s: string, isStdlib: bool): string =
  26. const stdPrefix = "std/"
  27. const pkgPrefix = "pkg/"
  28. if isStdlib:
  29. let sub = "lib/"
  30. var start = s.find(sub)
  31. if start < 0:
  32. doAssert false
  33. else:
  34. start += sub.len
  35. let base = s[start..^1]
  36. if base.startsWith("system") or base.startsWith("std"):
  37. result = base
  38. else:
  39. for dir in stdlibDirs:
  40. if base.startsWith(dir):
  41. return stdPrefix & base.splitFile.name
  42. result = stdPrefix & base
  43. else:
  44. var sub = getEnv("NIMBLE_DIR")
  45. if sub.len == 0:
  46. sub = ".nimble/pkgs/"
  47. else:
  48. sub.add "/pkgs/"
  49. var start = s.find(sub)
  50. if start < 0:
  51. result = s
  52. else:
  53. start += sub.len
  54. start += skipUntil(s, '/', start)
  55. start += 1
  56. result = pkgPrefix & s[start..^1]
  57. proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
  58. doAssert n.kind == nkSym, $n.kind
  59. let path = splitFile(toProjPath(g.config, n.sym.position.FileIndex))
  60. let modulePath = splitFile(toProjPath(g.config, g.module.position.FileIndex))
  61. let parent = nativeToUnixPath(modulePath.dir / modulePath.name).toNimblePath(belongsToStdlib(g.graph, g.module))
  62. let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym))
  63. addDependencyAux(b, parent, child)
  64. proc addDotDependency(c: PPassContext, n: PNode): PNode =
  65. result = n
  66. let g = PGen(c)
  67. let b = Backend(g.graph.backend)
  68. case n.kind
  69. of nkImportStmt:
  70. for i in 0..<n.len:
  71. addDependency(c, g, b, n[i])
  72. of nkFromStmt, nkImportExceptStmt:
  73. addDependency(c, g, b, n[0])
  74. of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
  75. for i in 0..<n.len: discard addDotDependency(c, n[i])
  76. else:
  77. discard
  78. proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
  79. let b = Backend(graph.backend)
  80. discard writeRope("digraph $1 {$n$2}$n" % [
  81. rope(project.splitFile.name), b.dotGraph],
  82. changeFileExt(project, "dot"))
  83. when not defined(nimHasSinkInference):
  84. {.pragma: nosinks.}
  85. proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
  86. var g: PGen
  87. new(g)
  88. g.module = module
  89. g.config = graph.config
  90. g.graph = graph
  91. if graph.backend == nil:
  92. graph.backend = Backend(dotGraph: nil)
  93. result = g
  94. const gendependPass* = makePass(open = myOpen, process = addDotDependency)