visuald.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. --
  2. -- d/actions/visuald.lua
  3. -- Generate a VisualD .visualdproj project.
  4. -- Copyright (c) 2012-2015 Manu Evans and the Premake project
  5. --
  6. local p = premake
  7. local m = p.modules.d
  8. m.visuald = {}
  9. require ("vstudio")
  10. local vstudio = p.vstudio
  11. local workspace = p.workspace
  12. local project = p.project
  13. local config = p.config
  14. local tree = p.tree
  15. --
  16. -- Patch the vstudio actions with D support...
  17. --
  18. for k,v in pairs({ "vs2005", "vs2008", "vs2010", "vs2012", "vs2013", "vs2015", "vs2017", "vs2019" }) do
  19. local vs = p.action.get(v)
  20. if vs ~= nil then
  21. table.insert( vs.valid_languages, p.D )
  22. vs.valid_tools.dc = { "dmd", "gdc", "ldc" }
  23. p.override(vs, "onProject", function(oldfn, prj)
  24. oldfn(prj)
  25. if project.isd(prj) then
  26. p.generate(prj, ".visualdproj", m.visuald.generate)
  27. end
  28. end)
  29. end
  30. end
  31. --
  32. -- Patch a bunch of other functions
  33. --
  34. p.override(project, "isnative", function(oldfn, prj)
  35. return project.isd(prj) or oldfn(prj)
  36. end)
  37. p.override(vstudio, "projectfile", function(oldfn, prj)
  38. if project.isd(prj) then
  39. return p.filename(prj, ".visualdproj")
  40. end
  41. return oldfn(prj)
  42. end)
  43. p.override(vstudio, "tool", function(oldfn, prj)
  44. if project.isd(prj) then
  45. return "002A2DE9-8BB6-484D-9802-7E4AD4084715"
  46. end
  47. return oldfn(prj)
  48. end)
  49. --
  50. -- Generate a Visual D project.
  51. --
  52. m.elements.project = function(prj)
  53. return {
  54. m.visuald.header,
  55. m.visuald.globals,
  56. m.visuald.projectConfigurations,
  57. m.visuald.files,
  58. }
  59. end
  60. function m.visuald.generate(prj)
  61. p.eol("\r\n")
  62. p.indent(" ")
  63. p.callArray(m.elements.project, prj)
  64. _p('</DProject>')
  65. end
  66. function m.visuald.header(prj)
  67. -- for some reason Visual D projects don't seem to have an xml header
  68. --_p('<?xml version="1.0" encoding="utf-8"?>')
  69. _p('<DProject>')
  70. end
  71. function m.visuald.globals(prj)
  72. _p(1,'<ProjectGuid>{%s}</ProjectGuid>', prj.uuid)
  73. end
  74. --
  75. -- Write out the list of project configurations, which pairs build
  76. -- configurations with architectures.
  77. --
  78. function m.visuald.projectConfigurations(prj)
  79. -- build a list of all architectures used in this project
  80. for cfg in project.eachconfig(prj) do
  81. local prjPlatform = p.esc(vstudio.projectPlatform(cfg))
  82. local slnPlatform = vstudio.solutionPlatform(cfg)
  83. local is64bit = slnPlatform == "x64" -- TODO: this seems like a hack
  84. _p(1,'<Config name="%s" platform="%s">', prjPlatform, slnPlatform)
  85. _p(2,'<obj>0</obj>')
  86. _p(2,'<link>0</link>')
  87. local isWindows = false
  88. local isDebug = string.find(cfg.buildcfg, 'Debug') ~= nil
  89. local isOptimised = config.isOptimizedBuild(cfg)
  90. if cfg.kind == p.CONSOLEAPP then
  91. _p(2,'<lib>0</lib>')
  92. _p(2,'<subsystem>1</subsystem>')
  93. elseif cfg.kind == p.STATICLIB then
  94. _p(2,'<lib>1</lib>')
  95. _p(2,'<subsystem>0</subsystem>')
  96. elseif cfg.kind == p.SHAREDLIB then
  97. _p(2,'<lib>2</lib>')
  98. _p(2,'<subsystem>0</subsystem>') -- SHOULD THIS BE '2' (windows)??
  99. else
  100. _p(2,'<lib>0</lib>')
  101. _p(2,'<subsystem>2</subsystem>')
  102. isWindows = true
  103. end
  104. _p(2,'<multiobj>0</multiobj>')
  105. _p(2,'<singleFileCompilation>0</singleFileCompilation>')
  106. _p(2,'<oneobj>0</oneobj>')
  107. _p(2,'<trace>%s</trace>', iif(cfg.flags.Profile, '1', '0'))
  108. _p(2,'<quiet>%s</quiet>', iif(cfg.flags.Quiet, '1', '0'))
  109. _p(2,'<verbose>%s</verbose>', iif(cfg.flags.Verbose, '1', '0'))
  110. _p(2,'<vtls>0</vtls>')
  111. _p(2,'<symdebug>%s</symdebug>', iif(cfg.symbols == p.ON or cfg.symbols == "FastLink" or cfg.symbols == "Full", iif(cfg.flags.SymbolsLikeC, '2', '1'), '0'))
  112. _p(2,'<optimize>%s</optimize>', iif(isOptimised, '1', '0'))
  113. _p(2,'<cpu>0</cpu>')
  114. _p(2,'<isX86_64>%s</isX86_64>', iif(is64bit, '1', '0'))
  115. _p(2,'<isLinux>0</isLinux>')
  116. _p(2,'<isOSX>0</isOSX>')
  117. _p(2,'<isWindows>%s</isWindows>', iif(isWindows, '1', '0'))
  118. _p(2,'<isFreeBSD>0</isFreeBSD>')
  119. _p(2,'<isSolaris>0</isSolaris>')
  120. _p(2,'<scheduler>0</scheduler>')
  121. _p(2,'<useDeprecated>%s</useDeprecated>', iif(cfg.deprecatedfeatures == "Allow", '1', '0'))
  122. _p(2,'<errDeprecated>0</errDeprecated>')
  123. _p(2,'<useAssert>0</useAssert>')
  124. _p(2,'<useInvariants>0</useInvariants>')
  125. _p(2,'<useIn>0</useIn>')
  126. _p(2,'<useOut>0</useOut>')
  127. _p(2,'<useArrayBounds>0</useArrayBounds>')
  128. _p(2,'<noboundscheck>%s</noboundscheck>', iif(cfg.boundscheck == "Off", '1', '0'))
  129. _p(2,'<useSwitchError>0</useSwitchError>')
  130. _p(2,'<useUnitTests>%s</useUnitTests>', iif(cfg.flags.UnitTest, '1', '0'))
  131. _p(2,'<useInline>%s</useInline>', iif(cfg.flags.Inline or isOptimised, '1', '0'))
  132. _p(2,'<release>%s</release>', iif(cfg.flags.Release or not isDebug, '1', '0'))
  133. _p(2,'<preservePaths>0</preservePaths>')
  134. _p(2,'<warnings>%s</warnings>', iif(cfg.flags.FatalCompileWarnings, '1', '0'))
  135. _p(2,'<infowarnings>%s</infowarnings>', iif(cfg.warnings and cfg.warnings ~= "Off", '1', '0'))
  136. _p(2,'<checkProperty>0</checkProperty>')
  137. _p(2,'<genStackFrame>0</genStackFrame>')
  138. _p(2,'<pic>%s</pic>', iif(cfg.pic == "On", '1', '0'))
  139. _p(2,'<cov>%s</cov>', iif(cfg.flags.CodeCoverage, '1', '0'))
  140. _p(2,'<nofloat>%s</nofloat>', iif(cfg.floatingpoint and cfg.floatingpoint == "None", '1', '0'))
  141. _p(2,'<Dversion>2</Dversion>')
  142. _p(2,'<ignoreUnsupportedPragmas>0</ignoreUnsupportedPragmas>')
  143. local compiler = { dmd="0", gdc="1", ldc="2" }
  144. local compilerName, err = p.api.checkValue(p.fields.toolset, _OPTIONS.dc or cfg.toolset or "dmd")
  145. if err then
  146. error { msg=err }
  147. end
  148. m.visuald.element(2, "compiler", compiler[compilerName])
  149. m.visuald.element(2, "otherDMD", '0')
  150. m.visuald.element(2, "program", '$(DMDInstallDir)windows\\bin\\dmd.exe')
  151. local impdirs
  152. if #cfg.importdirs > 0 then
  153. impdirs = vstudio.path(cfg, cfg.importdirs)
  154. end
  155. m.visuald.element(2, "imppath", impdirs)
  156. m.visuald.element(2, "fileImppath")
  157. m.visuald.element(2, "outdir", path.translate(project.getrelative(cfg.project, cfg.buildtarget.directory)))
  158. m.visuald.element(2, "objdir", path.translate(project.getrelative(cfg.project, cfg.objdir)))
  159. m.visuald.element(2, "objname")
  160. m.visuald.element(2, "libname")
  161. m.visuald.element(2, "doDocComments", iif(cfg.flags.Documentation, '1', '0'))
  162. m.visuald.element(2, "docdir", cfg.docdir)
  163. m.visuald.element(2, "docname", cfg.docname)
  164. m.visuald.element(2, "modules_ddoc")
  165. m.visuald.element(2, "ddocfiles")
  166. m.visuald.element(2, "doHdrGeneration", iif(cfg.flags.GenerateHeader, '1', '0'))
  167. m.visuald.element(2, "hdrdir", cfg.headerdir)
  168. m.visuald.element(2, "hdrname", cfg.headername)
  169. m.visuald.element(2, "doXGeneration", iif(cfg.flags.GenerateJSON, '1', '0'))
  170. m.visuald.element(2, "xfilename", '$(IntDir)\\$(TargetName).json')
  171. m.visuald.element(2, "debuglevel", iif(cfg.debuglevel, tostring(cfg.debuglevel), '0'))
  172. m.visuald.element(2, "debugids", cfg.debugconstants)
  173. m.visuald.element(2, "versionlevel", iif(cfg.versionlevel, tostring(cfg.versionlevel), '0'))
  174. m.visuald.element(2, "versionids", cfg.versionconstants)
  175. _p(2,'<dump_source>0</dump_source>')
  176. _p(2,'<mapverbosity>0</mapverbosity>')
  177. _p(2,'<createImplib>%s</createImplib>', iif(cfg.kind ~= p.SHAREDLIB or cfg.flags.NoImportLib, '0', '1'))
  178. _p(2,'<defaultlibname />')
  179. _p(2,'<debuglibname />')
  180. _p(2,'<moduleDepsFile />')
  181. _p(2,'<run>0</run>')
  182. _p(2,'<runargs />')
  183. -- _p(2,'<runCv2pdb>%s</runCv2pdb>', iif(cfg.symbols == p.ON, '1', '0'))
  184. _p(2,'<runCv2pdb>1</runCv2pdb>') -- we will just leave this always enabled, since it's ignored if no debuginfo is written
  185. _p(2,'<pathCv2pdb>$(VisualDInstallDir)cv2pdb\\cv2pdb.exe</pathCv2pdb>')
  186. _p(2,'<cv2pdbPre2043>0</cv2pdbPre2043>')
  187. _p(2,'<cv2pdbNoDemangle>0</cv2pdbNoDemangle>')
  188. _p(2,'<cv2pdbEnumType>0</cv2pdbEnumType>')
  189. _p(2,'<cv2pdbOptions />')
  190. _p(2,'<objfiles />')
  191. _p(2,'<linkswitches />')
  192. local links
  193. local explicit = vstudio.needsExplicitLink(cfg)
  194. -- check to see if this project uses an external toolset. If so, let the
  195. -- toolset define the format of the links
  196. local toolset = config.toolset(cfg)
  197. if toolset then
  198. links = toolset.getlinks(cfg, not explicit)
  199. else
  200. local scope = iif(explicit, "all", "system")
  201. links = config.getlinks(cfg, scope, "fullpath")
  202. end
  203. m.visuald.element(2, "libfiles", table.concat(links, " "))
  204. m.visuald.element(2, "libpaths", cfg.libdirs)
  205. _p(2,'<deffile />')
  206. _p(2,'<resfile />')
  207. local target = config.gettargetinfo(cfg)
  208. _p(2,'<exefile>$(OutDir)\\%s</exefile>', target.name)
  209. _p(2,'<useStdLibPath>1</useStdLibPath>')
  210. local runtime = 0
  211. if not cfg.flags.OmitDefaultLibrary then
  212. if config.isDebugBuild(cfg) then
  213. runtime = iif(cfg.flags.StaticRuntime, "2", "4")
  214. else
  215. runtime = iif(cfg.flags.StaticRuntime, "1", "3")
  216. end
  217. end
  218. m.visuald.element(2, "cRuntime", runtime)
  219. local additionalOptions
  220. if #cfg.buildoptions > 0 then
  221. additionalOptions = table.concat(cfg.buildoptions, " ")
  222. end
  223. if #cfg.linkoptions > 0 then
  224. local linkOpts = table.implode(cfg.linkoptions, "-L", "", " ")
  225. if additionalOptions then
  226. additionalOptions = additionalOptions .. " " .. linkOpts
  227. else
  228. additionalOptions = linkOpts
  229. end
  230. end
  231. m.visuald.element(2, "additionalOptions", additionalOptions)
  232. if #cfg.prebuildcommands > 0 then
  233. _p(2,'<preBuildCommand>%s</preBuildCommand>',p.esc(table.implode(cfg.prebuildcommands, "", "", "\r\n")))
  234. else
  235. _p(2,'<preBuildCommand />')
  236. end
  237. if #cfg.postbuildcommands > 0 then
  238. _p(2,'<postBuildCommand>%s</postBuildCommand>',p.esc(table.implode(cfg.postbuildcommands, "", "", "\r\n")))
  239. else
  240. _p(2,'<postBuildCommand />')
  241. end
  242. _p(2,'<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep;*.o</filesToClean>')
  243. _p(1,'</Config>')
  244. end
  245. end
  246. --
  247. -- Write out the source file tree.
  248. --
  249. function m.visuald.files(prj)
  250. _p(1,'<Folder name="%s">', prj.name)
  251. local tr = project.getsourcetree(prj)
  252. tree.traverse(tr, {
  253. -- folders, virtual or otherwise, are handled at the internal nodes
  254. onbranchenter = function(node, depth)
  255. _p(depth, '<Folder name="%s">', node.name)
  256. end,
  257. onbranchexit = function(node, depth)
  258. _p(depth, '</Folder>')
  259. end,
  260. -- source files are handled at the leaves
  261. onleaf = function(node, depth)
  262. _p(depth, '<File path="%s" />', path.translate(node.relpath))
  263. -- _p(depth, '<File path="%s">', path.translate(node.relpath))
  264. -- m.visuald.fileConfiguration(prj, node, depth + 1)
  265. -- _p(depth, '</File>')
  266. end
  267. }, false, 2)
  268. _p(1,'</Folder>')
  269. end
  270. function m.visuald.fileConfiguration(prj, node, depth)
  271. -- maybe we'll need this in the future...
  272. end
  273. --
  274. -- Output an individual project XML element.
  275. --
  276. function m.visuald.element(depth, name, value, ...)
  277. local isTable = type(value) == "table"
  278. if not value or (isTable and #value == 0) then
  279. _p(depth, '<%s />', name)
  280. else
  281. if isTable then
  282. value = p.esc(table.implode(value, "", "", ";"))
  283. _p(depth, '<%s>%s</%s>', name, value, name)
  284. else
  285. if select('#',...) == 0 then
  286. value = p.esc(value)
  287. end
  288. _x(depth, string.format('<%s>%s</%s>', name, value, name), ...)
  289. end
  290. end
  291. end