depends.nim 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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. sub[^1] = '2'
  52. sub.add '/'
  53. start = s.find(sub) # /pkgs2
  54. if start < 0:
  55. return s
  56. start += sub.len
  57. start += skipUntil(s, '/', start)
  58. start += 1
  59. result = pkgPrefix & s[start..^1]
  60. proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
  61. doAssert n.kind == nkSym, $n.kind
  62. let path = splitFile(toProjPath(g.config, n.sym.position.FileIndex))
  63. let modulePath = splitFile(toProjPath(g.config, g.module.position.FileIndex))
  64. let parent = nativeToUnixPath(modulePath.dir / modulePath.name).toNimblePath(belongsToStdlib(g.graph, g.module))
  65. let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym))
  66. addDependencyAux(b, parent, child)
  67. proc addDotDependency(c: PPassContext, n: PNode): PNode =
  68. result = n
  69. let g = PGen(c)
  70. let b = Backend(g.graph.backend)
  71. case n.kind
  72. of nkImportStmt:
  73. for i in 0..<n.len:
  74. addDependency(c, g, b, n[i])
  75. of nkFromStmt, nkImportExceptStmt:
  76. addDependency(c, g, b, n[0])
  77. of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
  78. for i in 0..<n.len: discard addDotDependency(c, n[i])
  79. else:
  80. discard
  81. proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
  82. let b = Backend(graph.backend)
  83. discard writeRope("digraph $1 {$n$2}$n" % [
  84. rope(project.splitFile.name), b.dotGraph],
  85. changeFileExt(project, "dot"))
  86. when not defined(nimHasSinkInference):
  87. {.pragma: nosinks.}
  88. proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
  89. var g: PGen
  90. new(g)
  91. g.module = module
  92. g.config = graph.config
  93. g.graph = graph
  94. if graph.backend == nil:
  95. graph.backend = Backend(dotGraph: nil)
  96. result = g
  97. const gendependPass* = makePass(open = myOpen, process = addDotDependency)