depends.nim 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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, parseutils]
  13. import 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. doAssert false
  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. result = s
  55. else:
  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: "")
  96. result = g
  97. const gendependPass* = makePass(open = myOpen, process = addDotDependency)