vstudio.lua 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. --
  2. -- vstudio.lua
  3. -- Define the Visual Studio 200x actions.
  4. -- Copyright (c) Jason Perkins and the Premake project
  5. --
  6. local p = premake
  7. p.modules.vstudio = p.modules.vstudio or {}
  8. p.modules.vstudio._VERSION = p._VERSION
  9. -- for backwards compatibility.
  10. p.vstudio = p.modules.vstudio
  11. local vstudio = p.vstudio
  12. local project = p.project
  13. local config = p.config
  14. --
  15. -- Mapping tables from Premake systems and architectures to Visual Studio
  16. -- identifiers. Broken out as tables so new values can be pushed in by
  17. -- add-ons.
  18. --
  19. vstudio.vs200x_architectures =
  20. {
  21. win32 = "x86",
  22. x86 = "x86",
  23. x86_64 = "x64",
  24. ARM = "ARM",
  25. ARM64 = "ARM64",
  26. }
  27. vstudio.vs2010_architectures =
  28. {
  29. win32 = "x86",
  30. }
  31. local function architecture(system, arch)
  32. local result
  33. if _ACTION >= "vs2010" then
  34. result = vstudio.vs2010_architectures[arch] or vstudio.vs2010_architectures[system]
  35. end
  36. return result or vstudio.vs200x_architectures[arch] or vstudio.vs200x_architectures[system]
  37. end
  38. --
  39. -- Mapping from ISO locales to MS culture identifiers.
  40. -- http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo%28v=vs.85%29.ASPX
  41. --
  42. vstudio._cultures = {
  43. ["af"] = 0x0036,
  44. ["af-ZA"] = 0x0436,
  45. ["sq"] = 0x001C,
  46. ["sq-AL"] = 0x041C,
  47. ["ar"] = 0x0001,
  48. ["ar-DZ"] = 0x1401,
  49. ["ar-BH"] = 0x3C01,
  50. ["ar-EG"] = 0x0C01,
  51. ["ar-IQ"] = 0x0801,
  52. ["ar-JO"] = 0x2C01,
  53. ["ar-KW"] = 0x3401,
  54. ["ar-LB"] = 0x3001,
  55. ["ar-LY"] = 0x1001,
  56. ["ar-MA"] = 0x1801,
  57. ["ar-OM"] = 0x2001,
  58. ["ar-QA"] = 0x4001,
  59. ["ar-SA"] = 0x0401,
  60. ["ar-SY"] = 0x2801,
  61. ["ar-TN"] = 0x1C01,
  62. ["ar-AE"] = 0x3801,
  63. ["ar-YE"] = 0x2401,
  64. ["hy"] = 0x002B,
  65. ["hy-AM"] = 0x042B,
  66. ["az"] = 0x002C,
  67. ["az-Cyrl-AZ"] = 0x082C,
  68. ["az-Latn-AZ"] = 0x042C,
  69. ["eu"] = 0x002D,
  70. ["eu-ES"] = 0x042D,
  71. ["be"] = 0x0023,
  72. ["be-BY"] = 0x0423,
  73. ["bg"] = 0x0002,
  74. ["bg-BG"] = 0x0402,
  75. ["ca"] = 0x0003,
  76. ["ca-ES"] = 0x0403,
  77. ["zh-HK"] = 0x0C04,
  78. ["zh-MO"] = 0x1404,
  79. ["zh-CN"] = 0x0804,
  80. ["zh-Hans"] = 0x0004,
  81. ["zh-SG"] = 0x1004,
  82. ["zh-TW"] = 0x0404,
  83. ["zh-Hant"] = 0x7C04,
  84. ["hr"] = 0x001A,
  85. ["hr-HR"] = 0x041A,
  86. ["cs"] = 0x0005,
  87. ["cs-CZ"] = 0x0405,
  88. ["da"] = 0x0006,
  89. ["da-DK"] = 0x0406,
  90. ["dv"] = 0x0065,
  91. ["dv-MV"] = 0x0465,
  92. ["nl"] = 0x0013,
  93. ["nl-BE"] = 0x0813,
  94. ["nl-NL"] = 0x0413,
  95. ["en"] = 0x0009,
  96. ["en-AU"] = 0x0C09,
  97. ["en-BZ"] = 0x2809,
  98. ["en-CA"] = 0x1009,
  99. ["en-029"] = 0x2409,
  100. ["en-IE"] = 0x1809,
  101. ["en-JM"] = 0x2009,
  102. ["en-NZ"] = 0x1409,
  103. ["en-PH"] = 0x3409,
  104. ["en-ZA"] = 0x1C09,
  105. ["en-TT"] = 0x2C09,
  106. ["en-GB"] = 0x0809,
  107. ["en-US"] = 0x0409,
  108. ["en-ZW"] = 0x3009,
  109. ["et"] = 0x0025,
  110. ["et-EE"] = 0x0425,
  111. ["fo"] = 0x0038,
  112. ["fo-FO"] = 0x0438,
  113. ["fa"] = 0x0029,
  114. ["fa-IR"] = 0x0429,
  115. ["fi"] = 0x000B,
  116. ["fi-FI"] = 0x040B,
  117. ["fr"] = 0x000C,
  118. ["fr-BE"] = 0x080C,
  119. ["fr-CA"] = 0x0C0C,
  120. ["fr-FR"] = 0x040C,
  121. ["fr-LU"] = 0x140C,
  122. ["fr-MC"] = 0x180C,
  123. ["fr-CH"] = 0x100C,
  124. ["gl"] = 0x0056,
  125. ["gl-ES"] = 0x0456,
  126. ["ka"] = 0x0037,
  127. ["ka-GE"] = 0x0437,
  128. ["de"] = 0x0007,
  129. ["de-AT"] = 0x0C07,
  130. ["de-DE"] = 0x0407,
  131. ["de-LI"] = 0x1407,
  132. ["de-LU"] = 0x1007,
  133. ["de-CH"] = 0x0807,
  134. ["el"] = 0x0008,
  135. ["el-GR"] = 0x0408,
  136. ["gu"] = 0x0047,
  137. ["gu-IN"] = 0x0447,
  138. ["he"] = 0x000D,
  139. ["he-IL"] = 0x040D,
  140. ["hi"] = 0x0039,
  141. ["hi-IN"] = 0x0439,
  142. ["hu"] = 0x000E,
  143. ["hu-HU"] = 0x040E,
  144. ["is"] = 0x000F,
  145. ["is-IS"] = 0x040F,
  146. ["id"] = 0x0021,
  147. ["id-ID"] = 0x0421,
  148. ["it"] = 0x0010,
  149. ["it-IT"] = 0x0410,
  150. ["it-CH"] = 0x0810,
  151. ["ja"] = 0x0011,
  152. ["ja-JP"] = 0x0411,
  153. ["kn"] = 0x004B,
  154. ["kn-IN"] = 0x044B,
  155. ["kk"] = 0x003F,
  156. ["kk-KZ"] = 0x043F,
  157. ["kok"] = 0x0057,
  158. ["kok-IN"] = 0x0457,
  159. ["ko"] = 0x0012,
  160. ["ko-KR"] = 0x0412,
  161. ["ky"] = 0x0040,
  162. ["ky-KG"] = 0x0440,
  163. ["lv"] = 0x0026,
  164. ["lv-LV"] = 0x0426,
  165. ["lt"] = 0x0027,
  166. ["lt-LT"] = 0x0427,
  167. ["mk"] = 0x002F,
  168. ["mk-MK"] = 0x042F,
  169. ["ms"] = 0x003E,
  170. ["ms-BN"] = 0x083E,
  171. ["ms-MY"] = 0x043E,
  172. ["mr"] = 0x004E,
  173. ["mr-IN"] = 0x044E,
  174. ["mn"] = 0x0050,
  175. ["mn-MN"] = 0x0450,
  176. ["no"] = 0x0014,
  177. ["nb-NO"] = 0x0414,
  178. ["nn-NO"] = 0x0814,
  179. ["pl"] = 0x0015,
  180. ["pl-PL"] = 0x0415,
  181. ["pt"] = 0x0016,
  182. ["pt-BR"] = 0x0416,
  183. ["pt-PT"] = 0x0816,
  184. ["pa"] = 0x0046,
  185. ["pa-IN"] = 0x0446,
  186. ["ro"] = 0x0018,
  187. ["ro-RO"] = 0x0418,
  188. ["ru"] = 0x0019,
  189. ["ru-RU"] = 0x0419,
  190. ["sa"] = 0x004F,
  191. ["sa-IN"] = 0x044F,
  192. ["sr-Cyrl-CS"] = 0x0C1A,
  193. ["sr-Latn-CS"] = 0x081A,
  194. ["sk"] = 0x001B,
  195. ["sk-SK"] = 0x041B,
  196. ["sl"] = 0x0024,
  197. ["sl-SI"] = 0x0424,
  198. ["es"] = 0x000A,
  199. ["es-AR"] = 0x2C0A,
  200. ["es-BO"] = 0x400A,
  201. ["es-CL"] = 0x340A,
  202. ["es-CO"] = 0x240A,
  203. ["es-CR"] = 0x140A,
  204. ["es-DO"] = 0x1C0A,
  205. ["es-EC"] = 0x300A,
  206. ["es-SV"] = 0x440A,
  207. ["es-GT"] = 0x100A,
  208. ["es-HN"] = 0x480A,
  209. ["es-MX"] = 0x080A,
  210. ["es-NI"] = 0x4C0A,
  211. ["es-PA"] = 0x180A,
  212. ["es-PY"] = 0x3C0A,
  213. ["es-PE"] = 0x280A,
  214. ["es-PR"] = 0x500A,
  215. ["es-ES"] = 0x0C0A,
  216. ["es-ES_tradnl"]= 0x040A,
  217. ["es-UY"] = 0x380A,
  218. ["es-VE"] = 0x200A,
  219. ["sw"] = 0x0041,
  220. ["sw-KE"] = 0x0441,
  221. ["sv"] = 0x001D,
  222. ["sv-FI"] = 0x081D,
  223. ["sv-SE"] = 0x041D,
  224. ["syr"] = 0x005A,
  225. ["syr-SY"] = 0x045A,
  226. ["ta"] = 0x0049,
  227. ["ta-IN"] = 0x0449,
  228. ["tt"] = 0x0044,
  229. ["tt-RU"] = 0x0444,
  230. ["te"] = 0x004A,
  231. ["te-IN"] = 0x044A,
  232. ["th"] = 0x001E,
  233. ["th-TH"] = 0x041E,
  234. ["tr"] = 0x001F,
  235. ["tr-TR"] = 0x041F,
  236. ["uk"] = 0x0022,
  237. ["uk-UA"] = 0x0422,
  238. ["ur"] = 0x0020,
  239. ["ur-PK"] = 0x0420,
  240. ["uz"] = 0x0043,
  241. ["uz-Cyrl-UZ"] = 0x0843,
  242. ["uz-Latn-UZ"] = 0x0443,
  243. ["vi"] = 0x002A,
  244. ["vi-VN"] = 0x042A,
  245. }
  246. --
  247. -- Translate the system and architecture settings from a configuration
  248. -- into a corresponding Visual Studio identifier. If no settings are
  249. -- found in the configuration, a default value is returned, based on
  250. -- the project settings.
  251. --
  252. -- @param cfg
  253. -- The configuration to translate.
  254. -- @param win32
  255. -- If true, enables the "Win32" symbol. If false, uses "x86" instead.
  256. -- @return
  257. -- A Visual Studio architecture identifier.
  258. --
  259. function vstudio.archFromConfig(cfg, win32)
  260. local isnative = project.isnative(cfg.project)
  261. local arch = architecture(cfg.system, cfg.architecture)
  262. if not arch then
  263. arch = iif(isnative, "x86", "Any CPU")
  264. end
  265. if win32 and isnative and arch == "x86" then
  266. arch = "Win32"
  267. end
  268. return arch
  269. end
  270. --
  271. -- Attempt to translate a platform identifier into a corresponding
  272. -- Visual Studio architecture identifier.
  273. --
  274. -- @param platform
  275. -- The platform identifier to translate.
  276. -- @return
  277. -- A Visual Studio architecture identifier, or nil if no mapping
  278. -- could be made.
  279. --
  280. function vstudio.archFromPlatform(platform)
  281. local system = p.api.checkValue(p.fields.system, platform)
  282. local arch = p.api.checkValue(p.fields.architecture, platform)
  283. return architecture(system, arch or platform:lower())
  284. end
  285. ---
  286. -- Given an ISO locale identifier, return an MS culture code.
  287. ---
  288. function vstudio.cultureForLocale(locale)
  289. if locale then
  290. local culture = vstudio._cultures[locale]
  291. if not culture then
  292. p.warnOnce("Locale" .. locale, 'Unsupported locale "%s"', locale)
  293. end
  294. return culture
  295. end
  296. end
  297. ---
  298. -- Assemble the list of links just the way Visual Studio likes them.
  299. --
  300. -- @param cfg
  301. -- The active configuration.
  302. -- @param explicit
  303. -- True to explicitly include sibling project libraries; if false Visual
  304. -- Studio's default implicit linking will be used.
  305. -- @return
  306. -- The list of linked libraries, ready to be used in Visual Studio's
  307. -- AdditionalDependencies element.
  308. ---
  309. function vstudio.getLinks(cfg, explicit)
  310. return p.tools.msc.getlinks(cfg, not explicit)
  311. end
  312. --
  313. -- Return true if the configuration kind is one of "Makefile" or "None". The
  314. -- latter is generated like a Makefile project and excluded from the solution.
  315. --
  316. function vstudio.isMakefile(cfg)
  317. return (cfg.kind == p.MAKEFILE or cfg.kind == p.NONE)
  318. end
  319. --
  320. -- If a dependency of a project configuration is excluded from that particular
  321. -- build configuration or platform, Visual Studio will still try to link it.
  322. -- This function detects that case, so that the individual actions can work
  323. -- around it by switching to external linking.
  324. --
  325. -- @param cfg
  326. -- The configuration to test.
  327. -- @return
  328. -- True if the configuration excludes one or more dependencies.
  329. --
  330. function vstudio.needsExplicitLink(cfg)
  331. if not cfg._needsExplicitLink then
  332. local ex = cfg.flags.NoImplicitLink
  333. if not ex then
  334. local prjdeps = project.getdependencies(cfg.project, "linkOnly")
  335. local cfgdeps = config.getlinks(cfg, "dependencies", "object")
  336. ex = #prjdeps ~= #cfgdeps
  337. end
  338. cfg._needsExplicitLink = ex
  339. end
  340. return cfg._needsExplicitLink
  341. end
  342. ---
  343. -- Prepare a path value for output in a Visual Studio project or solution.
  344. -- Converts path separators to backslashes, and makes relative to the project.
  345. --
  346. -- @param cfg
  347. -- The project or configuration which contains the path.
  348. -- @param value
  349. -- The path to be prepared.
  350. -- @return
  351. -- The prepared path.
  352. ---
  353. function vstudio.path(cfg, value)
  354. cfg = cfg.project or cfg
  355. local dirs = path.translate(project.getrelative(cfg, value))
  356. if type(dirs) == 'table' then
  357. dirs = table.filterempty(dirs)
  358. end
  359. return dirs
  360. end
  361. --
  362. -- Returns the Visual Studio project configuration identifier corresponding
  363. -- to the given Premake configuration.
  364. --
  365. -- @param cfg
  366. -- The configuration to query.
  367. -- @param arch
  368. -- An optional architecture identifier, to override the configuration.
  369. -- @return
  370. -- A project configuration identifier of the form
  371. -- <project platform name>|<architecture>.
  372. --
  373. function vstudio.projectConfig(cfg, arch)
  374. local platform = vstudio.projectPlatform(cfg)
  375. local architecture = arch or vstudio.archFromConfig(cfg, true)
  376. return platform .. "|" .. architecture
  377. end
  378. ---
  379. -- Generates a Visual Studio project element for the current action.
  380. ---
  381. function vstudio.projectElement()
  382. p.push('<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">')
  383. end
  384. --
  385. -- Returns the full, absolute path to the Visual Studio project file
  386. -- corresponding to a particular project object.
  387. --
  388. -- @param prj
  389. -- The project object.
  390. -- @return
  391. -- The absolute path to the corresponding Visual Studio project file.
  392. --
  393. function vstudio.projectfile(prj)
  394. local extension
  395. if project.iscsharp(prj) then
  396. extension = ".csproj"
  397. elseif project.isfsharp(prj) then
  398. extension = ".fsproj"
  399. elseif project.isc(prj) or project.iscpp(prj) then
  400. if prj.kind == p.SHAREDITEMS then
  401. extension = ".vcxitems"
  402. else
  403. extension = iif(_ACTION > "vs2008", ".vcxproj", ".vcproj")
  404. end
  405. end
  406. return p.filename(prj, extension)
  407. end
  408. --
  409. -- Returns a project configuration name corresponding to the given
  410. -- Premake configuration. This is just the solution build configuration
  411. -- and platform identifiers concatenated.
  412. --
  413. function vstudio.projectPlatform(cfg)
  414. local platform = cfg.platform
  415. if platform then
  416. local pltarch = vstudio.archFromPlatform(cfg.platform) or platform
  417. local cfgarch = vstudio.archFromConfig(cfg)
  418. if pltarch == cfgarch then
  419. platform = nil
  420. end
  421. end
  422. if platform then
  423. return cfg.buildcfg .. " " .. platform
  424. else
  425. return cfg.buildcfg
  426. end
  427. end
  428. --
  429. -- Determine the appropriate Visual Studio platform identifier for a
  430. -- solution-level configuration.
  431. --
  432. -- @param cfg
  433. -- The configuration to be identified.
  434. -- @return
  435. -- A corresponding Visual Studio platform identifier.
  436. --
  437. function vstudio.solutionPlatform(cfg)
  438. local platform = cfg.platform
  439. -- if a platform is specified use it, translating to the corresponding
  440. -- Visual Studio identifier if appropriate
  441. local platarch
  442. if platform then
  443. platform = vstudio.archFromPlatform(platform) or platform
  444. -- Value for 32-bit arch is different depending on whether this solution
  445. -- contains C++ or C# projects or both
  446. if platform ~= "x86" then
  447. return platform
  448. end
  449. end
  450. -- scan the contained projects to identify the platform
  451. local hasnative = false
  452. local hasnet = false
  453. local slnarch
  454. for prj in p.workspace.eachproject(cfg.workspace) do
  455. hasnative = hasnative or project.isnative(prj)
  456. hasnet = hasnet or project.isdotnet(prj)
  457. -- get a VS architecture identifier for this project
  458. local prjcfg = project.getconfig(prj, cfg.buildcfg, cfg.platform)
  459. if prjcfg then
  460. local prjarch = vstudio.archFromConfig(prjcfg)
  461. if not slnarch then
  462. slnarch = prjarch
  463. elseif slnarch ~= prjarch then
  464. slnarch = "Mixed Platforms"
  465. end
  466. end
  467. end
  468. if platform then
  469. return iif(hasnet, "x86", "Win32")
  470. elseif slnarch then
  471. return iif(slnarch == "x86" and not hasnet, "Win32", slnarch)
  472. elseif hasnet and hasnative then
  473. return "Mixed Platforms"
  474. elseif hasnet then
  475. return "Any CPU"
  476. else
  477. return "Win32"
  478. end
  479. end
  480. --
  481. -- Attempt to determine an appropriate Visual Studio architecture identifier
  482. -- for a solution configuration.
  483. --
  484. -- @param cfg
  485. -- The configuration to query.
  486. -- @return
  487. -- A best guess at the corresponding Visual Studio architecture identifier.
  488. --
  489. function vstudio.solutionarch(cfg)
  490. local hasnative = false
  491. local hasdotnet = false
  492. -- if the configuration has a platform identifier, use that as default
  493. local arch = cfg.platform
  494. -- if the platform identifier matches a known system or architecture,
  495. --
  496. for prj in p.workspace.eachproject(cfg.workspace) do
  497. hasnative = hasnative or project.isnative(prj)
  498. hasnet = hasnet or project.isdotnet(prj)
  499. if hasnative and hasdotnet then
  500. return "Mixed Platforms"
  501. end
  502. if not arch then
  503. local prjcfg = project.getconfig(prj, cfg.buildcfg, cfg.platform)
  504. if prjcfg then
  505. if prjcfg.architecture then
  506. arch = vstudio.archFromConfig(prjcfg)
  507. end
  508. end
  509. end
  510. end
  511. -- use a default if no other architecture was specified
  512. arch = arch or iif(hasnative, "Win32", "Any CPU")
  513. return arch
  514. end
  515. --
  516. -- Returns the Visual Studio solution configuration identifier corresponding
  517. -- to the given Premake configuration.
  518. --
  519. -- @param cfg
  520. -- The configuration to query.
  521. -- @return
  522. -- A solution configuration identifier of the format BuildCfg|Platform,
  523. -- corresponding to the Premake values of the same names. If no platform
  524. -- was specified by the script, the architecture is used instead.
  525. --
  526. function vstudio.solutionconfig(cfg)
  527. local platform = cfg.platform
  528. -- if no platform name was specified, use the architecture instead;
  529. -- since architectures are defined in the projects and not at the
  530. -- solution level, need to poke around to figure this out
  531. if not platform then
  532. platform = vstudio.solutionarch(cfg)
  533. end
  534. return string.format("%s|%s", cfg.buildcfg, platform)
  535. end
  536. --
  537. -- Returns the Visual Studio tool ID for a given project type.
  538. --
  539. function vstudio.tool(prj)
  540. if project.iscsharp(prj) then
  541. return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"
  542. elseif project.isfsharp(prj) then
  543. return "F2A71F9B-5D33-465A-A702-920D77279786"
  544. elseif project.isc(prj) or project.iscpp(prj) then
  545. return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
  546. end
  547. end
  548. --
  549. -- Load all required code, and return the module.
  550. --
  551. include("vs200x_vcproj.lua")
  552. include("vs200x_vcproj_user.lua")
  553. include("vs2005_solution.lua")
  554. include("vs2005_dotnetbase.lua")
  555. include("vs2005_csproj.lua")
  556. include("vs2005_csproj_user.lua")
  557. include("vs2005_fsproj.lua")
  558. include("vs2005_fsproj_user.lua")
  559. include("vs2010_nuget.lua")
  560. include("vs2010_vcxproj.lua")
  561. include("vs2010_vcxproj_user.lua")
  562. include("vs2010_vcxproj_filters.lua")
  563. include("vs2010_rules_props.lua")
  564. include("vs2010_rules_targets.lua")
  565. include("vs2010_rules_xml.lua")
  566. include("vs2013_vcxitems.lua")
  567. return p.modules.vstudio