dmd.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. --
  2. -- d/tools/dmd.lua
  3. -- Provides dmd-specific configuration strings.
  4. -- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project
  5. --
  6. local tdmd = {}
  7. local p = premake
  8. local project = p.project
  9. local config = p.config
  10. local d = p.modules.d
  11. --
  12. -- Set default tools
  13. --
  14. tdmd.gcc = {}
  15. tdmd.gcc.dc = "dmd"
  16. tdmd.optlink = {}
  17. tdmd.optlink.dc = "dmd"
  18. -- /////////////////////////////////////////////////////////////////////////
  19. -- dmd + GCC toolchain
  20. -- /////////////////////////////////////////////////////////////////////////
  21. --
  22. -- Return a list of LDFLAGS for a specific configuration.
  23. --
  24. tdmd.gcc.ldflags = {
  25. architecture = {
  26. x86 = { "-m32" },
  27. x86_64 = { "-m64" },
  28. },
  29. kind = {
  30. SharedLib = "-shared",
  31. StaticLib = "-lib",
  32. }
  33. }
  34. function tdmd.gcc.getldflags(cfg)
  35. local flags = config.mapFlags(cfg, tdmd.gcc.ldflags)
  36. return flags
  37. end
  38. --
  39. -- Return a list of decorated additional libraries directories.
  40. --
  41. tdmd.gcc.libraryDirectories = {
  42. architecture = {
  43. x86 = "-L-L/usr/lib",
  44. x86_64 = "-L-L/usr/lib64",
  45. }
  46. }
  47. function tdmd.gcc.getLibraryDirectories(cfg)
  48. local flags = config.mapFlags(cfg, tdmd.gcc.libraryDirectories)
  49. -- Scan the list of linked libraries. If any are referenced with
  50. -- paths, add those to the list of library search paths
  51. for _, dir in ipairs(config.getlinks(cfg, "system", "directory")) do
  52. table.insert(flags, '-L-L' .. project.getrelative(cfg.project, dir))
  53. end
  54. return flags
  55. end
  56. --
  57. -- Return the list of libraries to link, decorated with flags as needed.
  58. --
  59. function tdmd.gcc.getlinks(cfg, systemonly)
  60. local result = {}
  61. local links
  62. if not systemonly then
  63. links = config.getlinks(cfg, "siblings", "object")
  64. for _, link in ipairs(links) do
  65. -- skip external project references, since I have no way
  66. -- to know the actual output target path
  67. if not link.project.external then
  68. if link.kind == p.STATICLIB then
  69. -- Don't use "-l" flag when linking static libraries; instead use
  70. -- path/libname.a to avoid linking a shared library of the same
  71. -- name if one is present
  72. table.insert(result, "-L" .. project.getrelative(cfg.project, link.linktarget.abspath))
  73. else
  74. table.insert(result, "-L-l" .. link.linktarget.basename)
  75. end
  76. end
  77. end
  78. end
  79. -- The "-l" flag is fine for system libraries
  80. links = config.getlinks(cfg, "system", "fullpath")
  81. for _, link in ipairs(links) do
  82. if path.isframework(link) then
  83. table.insert(result, "-framework " .. path.getbasename(link))
  84. elseif path.isobjectfile(link) then
  85. table.insert(result, "-L" .. link)
  86. else
  87. table.insert(result, "-L-l" .. path.getbasename(link))
  88. end
  89. end
  90. return result
  91. end
  92. -- /////////////////////////////////////////////////////////////////////////
  93. -- tdmd + OPTLINK toolchain
  94. -- /////////////////////////////////////////////////////////////////////////
  95. --
  96. -- Return a list of LDFLAGS for a specific configuration.
  97. --
  98. tdmd.optlink.ldflags = {
  99. architecture = {
  100. x86 = { "-m32" },
  101. x86_64 = { "-m64" },
  102. },
  103. kind = {
  104. SharedLib = "-shared",
  105. StaticLib = "-lib",
  106. }
  107. }
  108. function tdmd.optlink.getldflags(cfg)
  109. local flags = config.mapFlags(cfg, tdmd.optlink.ldflags)
  110. return flags
  111. end
  112. --
  113. -- Return a list of decorated additional libraries directories.
  114. --
  115. function tdmd.optlink.getLibraryDirectories(cfg)
  116. local flags = {}
  117. -- Scan the list of linked libraries. If any are referenced with
  118. -- paths, add those to the list of library search paths
  119. for _, dir in ipairs(config.getlinks(cfg, "system", "directory")) do
  120. table.insert(flags, '-Llib "' .. project.getrelative(cfg.project, dir) .. '"')
  121. end
  122. return flags
  123. end
  124. --
  125. -- Returns a list of linker flags for library names.
  126. --
  127. function tdmd.optlink.getlinks(cfg)
  128. local result = {}
  129. local links = config.getlinks(cfg, "dependencies", "object")
  130. for _, link in ipairs(links) do
  131. -- skip external project references, since I have no way
  132. -- to know the actual output target path
  133. if not link.project.externalname then
  134. local linkinfo = config.getlinkinfo(link)
  135. if link.kind == p.STATICLIB then
  136. table.insert(result, project.getrelative(cfg.project, linkinfo.abspath))
  137. end
  138. end
  139. end
  140. -- The "-l" flag is fine for system libraries
  141. links = config.getlinks(cfg, "system", "basename")
  142. for _, link in ipairs(links) do
  143. if path.isobjectfile(link) then
  144. table.insert(result, link)
  145. elseif path.hasextension(link, p.systems[cfg.system].staticlib.extension) then
  146. table.insert(result, link)
  147. end
  148. end
  149. return result
  150. end
  151. -- /////////////////////////////////////////////////////////////////////////
  152. -- common dmd code (either toolchain)
  153. -- /////////////////////////////////////////////////////////////////////////
  154. -- if we are compiling on windows, we need to specialise to OPTLINK as the linker
  155. -- OR!!! if cfg.system ~= p.WINDOWS then
  156. if string.match( os.getversion().description, "Windows" ) ~= nil then
  157. -- TODO: on windows, we may use OPTLINK or MSLINK (for Win64)...
  158. -- printf("TODO: select proper linker for 32/64 bit code")
  159. p.tools.dmd = tdmd.optlink
  160. else
  161. p.tools.dmd = tdmd.gcc
  162. end
  163. local dmd = p.tools.dmd
  164. --
  165. -- Returns list of D compiler flags for a configuration.
  166. --
  167. dmd.dflags = {
  168. architecture = {
  169. x86 = "-m32mscoff",
  170. x86_64 = "-m64",
  171. },
  172. flags = {
  173. OmitDefaultLibrary = "-mscrtlib=",
  174. CodeCoverage = "-cov",
  175. Color = "-color",
  176. Documentation = "-D",
  177. FatalWarnings = "-w",
  178. GenerateHeader = "-H",
  179. GenerateJSON = "-X",
  180. GenerateMap = "-map",
  181. LowMem = "-lowmem",
  182. Profile = "-profile",
  183. Quiet = "-quiet",
  184. RetainPaths = "-op",
  185. SymbolsLikeC = "-gc",
  186. UnitTest = "-unittest",
  187. Verbose = "-v",
  188. ProfileGC = "-profile=gc",
  189. StackFrame = "-gs",
  190. StackStomp = "-gx",
  191. AllInstantiate = "-allinst",
  192. BetterC = "-betterC",
  193. Main = "-main",
  194. PerformSyntaxCheckOnly = "-o-",
  195. ShowTLS = "-vtls",
  196. ShowGC = "-vgc",
  197. IgnorePragma = "-ignore",
  198. ShowDependencies = "-deps",
  199. },
  200. boundscheck = {
  201. Off = "-boundscheck=off",
  202. On = "-boundscheck=on",
  203. SafeOnly = "-boundscheck=safeonly",
  204. },
  205. checkaction = {
  206. D = "-checkaction=D",
  207. C = "-checkaction=C",
  208. Halt = "-checkaction=halt",
  209. Context = "-checkaction=context",
  210. },
  211. cppdialect = {
  212. ["C++latest"] = "-extern-std=c++20", -- TODO: keep this up to date >_<
  213. ["C++98"] = "-extern-std=c++98",
  214. ["C++0x"] = "-extern-std=c++11",
  215. ["C++11"] = "-extern-std=c++11",
  216. ["C++1y"] = "-extern-std=c++14",
  217. ["C++14"] = "-extern-std=c++14",
  218. ["C++1z"] = "-extern-std=c++17",
  219. ["C++17"] = "-extern-std=c++17",
  220. ["C++2a"] = "-extern-std=c++20",
  221. ["C++20"] = "-extern-std=c++20",
  222. ["gnu++98"] = "-extern-std=c++98",
  223. ["gnu++0x"] = "-extern-std=c++11",
  224. ["gnu++11"] = "-extern-std=c++11",
  225. ["gnu++1y"] = "-extern-std=c++14",
  226. ["gnu++14"] = "-extern-std=c++14",
  227. ["gnu++1z"] = "-extern-std=c++17",
  228. ["gnu++17"] = "-extern-std=c++17",
  229. ["gnu++2a"] = "-extern-std=c++20",
  230. ["gnu++20"] = "-extern-std=c++20",
  231. },
  232. deprecatedfeatures = {
  233. Allow = "-d",
  234. Warn = "-dw",
  235. Error = "-de",
  236. },
  237. floatingpoint = {
  238. None = "-nofloat",
  239. },
  240. optimize = {
  241. On = "-O -inline",
  242. Full = "-O -inline",
  243. Size = "-O -inline",
  244. Speed = "-O -inline",
  245. },
  246. pic = {
  247. On = "-fPIC",
  248. },
  249. symbols = {
  250. On = "-g",
  251. FastLink = "-g",
  252. Full = "-g",
  253. },
  254. vectorextensions = {
  255. AVX = "-mcpu=avx",
  256. AVX2 = "-mcpu=avx2",
  257. },
  258. warnings = {
  259. Default = "-wi",
  260. High = "-wi",
  261. Extra = "-wi",
  262. Everything = "-wi",
  263. },
  264. }
  265. function dmd.getdflags(cfg)
  266. local flags = config.mapFlags(cfg, dmd.dflags)
  267. if config.isDebugBuild(cfg) then
  268. table.insert(flags, "-debug")
  269. else
  270. table.insert(flags, "-release")
  271. end
  272. if not cfg.flags.OmitDefaultLibrary then
  273. local releaseruntime = not config.isDebugBuild(cfg)
  274. local staticruntime = true
  275. if cfg.staticruntime == "Off" then
  276. staticruntime = false
  277. end
  278. if cfg.runtime == "Debug" then
  279. releaseruntime = false
  280. elseif cfg.runtime == "Release" then
  281. releaseruntime = true
  282. end
  283. if (cfg.staticruntime and cfg.staticruntime ~= "Default") or (cfg.runtime and cfg.runtime ~= "Default") then
  284. if staticruntime == true and releaseruntime == true then
  285. table.insert(flags, "-mscrtlib=libcmt")
  286. elseif staticruntime == true and releaseruntime == false then
  287. table.insert(flags, "-mscrtlib=libcmtd")
  288. elseif staticruntime == false and releaseruntime == true then
  289. table.insert(flags, "-mscrtlib=msvcrt")
  290. elseif staticruntime == false and releaseruntime == false then
  291. table.insert(flags, "-mscrtlib=msvcrtd")
  292. end
  293. end
  294. end
  295. if cfg.flags.Documentation then
  296. if cfg.docname then
  297. table.insert(flags, "-Df" .. p.quoted(cfg.docname))
  298. end
  299. if cfg.docdir then
  300. table.insert(flags, "-Dd" .. p.quoted(cfg.docdir))
  301. end
  302. end
  303. if cfg.flags.GenerateHeader then
  304. if cfg.headername then
  305. table.insert(flags, "-Hf" .. p.quoted(cfg.headername))
  306. end
  307. if cfg.headerdir then
  308. table.insert(flags, "-Hd" .. p.quoted(cfg.headerdir))
  309. end
  310. end
  311. if #cfg.preview > 0 then
  312. for _, opt in ipairs(cfg.preview) do
  313. table.insert(flags, "-preview=" .. opt)
  314. end
  315. end
  316. if #cfg.revert > 0 then
  317. for _, opt in ipairs(cfg.revert) do
  318. table.insert(flags, "-revert=" .. opt)
  319. end
  320. end
  321. if #cfg.transition > 0 then
  322. for _, opt in ipairs(cfg.transition) do
  323. table.insert(flags, "-transition=" .. opt)
  324. end
  325. end
  326. return flags
  327. end
  328. --
  329. -- Decorate versions for the DMD command line.
  330. --
  331. function dmd.getversions(versions, level)
  332. local result = {}
  333. for _, version in ipairs(versions) do
  334. table.insert(result, '-version=' .. version)
  335. end
  336. if level then
  337. table.insert(result, '-version=' .. level)
  338. end
  339. return result
  340. end
  341. --
  342. -- Decorate debug constants for the DMD command line.
  343. --
  344. function dmd.getdebug(constants, level)
  345. local result = {}
  346. for _, constant in ipairs(constants) do
  347. table.insert(result, '-debug=' .. constant)
  348. end
  349. if level then
  350. table.insert(result, '-debug=' .. level)
  351. end
  352. return result
  353. end
  354. --
  355. -- Decorate import file search paths for the DMD command line.
  356. --
  357. function dmd.getimportdirs(cfg, dirs)
  358. local result = {}
  359. for _, dir in ipairs(dirs) do
  360. dir = project.getrelative(cfg.project, dir)
  361. table.insert(result, '-I' .. p.quoted(dir))
  362. end
  363. return result
  364. end
  365. --
  366. -- Decorate string import file search paths for the DMD command line.
  367. --
  368. function dmd.getstringimportdirs(cfg, dirs)
  369. local result = {}
  370. for _, dir in ipairs(dirs) do
  371. dir = project.getrelative(cfg.project, dir)
  372. table.insert(result, '-J' .. p.quoted(dir))
  373. end
  374. return result
  375. end
  376. --
  377. -- Returns the target name specific to compiler
  378. --
  379. function dmd.gettarget(name)
  380. return "-of" .. name
  381. end
  382. --
  383. -- Returns makefile-specific configuration rules.
  384. --
  385. dmd.makesettings = {
  386. }
  387. function dmd.getmakesettings(cfg)
  388. local settings = config.mapFlags(cfg, dmd.makesettings)
  389. return table.concat(settings)
  390. end
  391. --
  392. -- Retrieves the executable command name for a tool, based on the
  393. -- provided configuration and the operating environment.
  394. --
  395. -- @param cfg
  396. -- The configuration to query.
  397. -- @param tool
  398. -- The tool to fetch, one of "dc" for the D compiler, or "ar" for the static linker.
  399. -- @return
  400. -- The executable command name for a tool, or nil if the system's
  401. -- default value should be used.
  402. --
  403. dmd.tools = {
  404. -- dmd will probably never support any foreign architectures...?
  405. }
  406. function dmd.gettoolname(cfg, tool)
  407. local names = dmd.tools[cfg.architecture] or dmd.tools[cfg.system] or {}
  408. local name = names[tool]
  409. return name or dmd[tool]
  410. end