vs2005_solution.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. --
  2. -- vs2005_solution.lua
  3. -- Generate a Visual Studio 2005+ solution.
  4. -- Copyright (c) Jason Perkins and the Premake project
  5. --
  6. local p = premake
  7. p.vstudio.sln2005 = {}
  8. local vstudio = p.vstudio
  9. local sln2005 = p.vstudio.sln2005
  10. local project = p.project
  11. local tree = p.tree
  12. ---
  13. -- Add namespace for element definition lists for p.callArray()
  14. ---
  15. sln2005.elements = {}
  16. --
  17. -- Return the list of sections contained in the solution.
  18. -- TODO: Get rid of this when the MonoDevelop module no longer needs it
  19. --
  20. function sln2005.solutionSections(wks)
  21. return {
  22. "ConfigurationPlatforms",
  23. "SolutionProperties",
  24. "NestedProjects",
  25. "ExtensibilityGlobals"
  26. }
  27. end
  28. --
  29. -- Generate a Visual Studio 200x solution, with support for the new platforms API.
  30. --
  31. function sln2005.generate(wks)
  32. -- Mark the file as Unicode
  33. p.utf8()
  34. p.outln('')
  35. sln2005.reorderProjects(wks)
  36. sln2005.header()
  37. sln2005.projects(wks)
  38. p.push('Global')
  39. sln2005.sections(wks)
  40. p.pop('EndGlobal')
  41. p.w()
  42. end
  43. --
  44. -- Generate the solution header. Each Visual Studio action definition
  45. -- should include its own version.
  46. --
  47. function sln2005.header()
  48. local action = p.action.current()
  49. p.w('Microsoft Visual Studio Solution File, Format Version %d.00', action.vstudio.solutionVersion)
  50. p.w('# Visual Studio %s', action.vstudio.versionName)
  51. end
  52. --
  53. -- If a startup project is specified, move it (and any enclosing groups)
  54. -- to the front of the project list. This will make Visual Studio treat
  55. -- it like a startup project.
  56. --
  57. -- I force the new ordering into the tree so that it will get applied to
  58. -- all sections of the solution; otherwise the first change to the solution
  59. -- in the IDE will cause the orderings to get rewritten.
  60. --
  61. function sln2005.reorderProjects(wks)
  62. if wks.startproject then
  63. local np
  64. local tr = p.workspace.grouptree(wks)
  65. tree.traverse(tr, {
  66. onleaf = function(n)
  67. if n.project.name == wks.startproject then
  68. np = n
  69. end
  70. end
  71. })
  72. while np and np.parent do
  73. local p = np.parent
  74. local i = table.indexof(p.children, np)
  75. table.remove(p.children, i)
  76. table.insert(p.children, 1, np)
  77. np = p
  78. end
  79. end
  80. end
  81. --
  82. -- Build a relative path from the solution file to the project file
  83. --
  84. function sln2005.buildRelativePath(prj)
  85. local prjpath = vstudio.projectfile(prj)
  86. prjpath = vstudio.path(prj.workspace, prjpath)
  87. -- Unlike projects, solutions must use old-school %...% DOS style
  88. -- for environment variables.
  89. return prjpath:gsub("$%((.-)%)", "%%%1%%")
  90. end
  91. --
  92. -- Write out the list of projects and groups contained by the solution.
  93. --
  94. function sln2005.projects(wks)
  95. local tr = p.workspace.grouptree(wks)
  96. tree.traverse(tr, {
  97. onleaf = function(n)
  98. local prj = n.project
  99. p.x('Project("{%s}") = "%s", "%s", "{%s}"', vstudio.tool(prj), prj.name, sln2005.buildRelativePath(prj), prj.uuid)
  100. p.push()
  101. sln2005.projectdependencies(prj)
  102. p.pop('EndProject')
  103. end,
  104. onbranch = function(n)
  105. p.push('Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "%s", "%s", "{%s}"', n.name, n.name, n.uuid)
  106. p.pop('EndProject')
  107. end,
  108. })
  109. end
  110. --
  111. -- Write out the list of project dependencies for a particular project.
  112. --
  113. function sln2005.projectdependencies(prj)
  114. local deps = project.getdependencies(prj, 'dependOnly')
  115. if #deps > 0 then
  116. p.push('ProjectSection(ProjectDependencies) = postProject')
  117. for _, dep in ipairs(deps) do
  118. p.w('{%s} = {%s}', dep.uuid, dep.uuid)
  119. end
  120. p.pop('EndProjectSection')
  121. end
  122. end
  123. --
  124. -- Write out the list of shared project files and their links
  125. --
  126. function sln2005.sharedProjects(wks)
  127. local contents = p.capture(function ()
  128. local tr = p.workspace.grouptree(wks)
  129. p.tree.traverse(tr, {
  130. onleaf = function(n)
  131. local prj = n.project
  132. -- SharedItems projects reference their own UUID with a "9"
  133. -- SharedItems projects reference the UUID of projects that link them with a "4"
  134. if prj.kind == p.SHAREDITEMS then
  135. p.w('%s*{%s}*SharedItemsImports = %s', sln2005.buildRelativePath(prj), prj.uuid:lower(), "9")
  136. else
  137. local deps = p.project.getdependencies(prj, 'linkOnly')
  138. for _, dep in ipairs(deps) do
  139. if dep.kind == p.SHAREDITEMS then
  140. p.w('%s*{%s}*SharedItemsImports = %s', sln2005.buildRelativePath(dep), prj.uuid:lower(), "4")
  141. end
  142. end
  143. end
  144. end,
  145. })
  146. end)
  147. if #contents > 0 then
  148. p.push('GlobalSection(SharedMSBuildProjectFiles) = preSolution')
  149. p.outln(contents)
  150. p.pop('EndGlobalSection')
  151. end
  152. end
  153. --
  154. -- Write out the list of project configuration platforms.
  155. --
  156. sln2005.elements.projectConfigurationPlatforms = function(cfg, context)
  157. return {
  158. sln2005.activeCfg,
  159. sln2005.build0,
  160. }
  161. end
  162. function sln2005.projectConfigurationPlatforms(wks, sorted, descriptors)
  163. p.w("GlobalSection(ProjectConfigurationPlatforms) = postSolution")
  164. local tr = p.workspace.grouptree(wks)
  165. tree.traverse(tr, {
  166. onleaf = function(n)
  167. local prj = n.project
  168. -- SharedItems projects don't have any configuration platform entries
  169. if prj.kind == p.SHAREDITEMS then
  170. return
  171. end
  172. table.foreachi(sorted, function(cfg)
  173. local context = {}
  174. -- Look up the matching project configuration. If none exist, this
  175. -- configuration has been excluded from the project, and should map
  176. -- to closest available project configuration instead.
  177. context.prj = prj
  178. context.prjCfg = project.getconfig(prj, cfg.buildcfg, cfg.platform)
  179. context.excluded = (context.prjCfg == nil or context.prjCfg.flags.ExcludeFromBuild)
  180. if context.prjCfg == nil then
  181. context.prjCfg = project.findClosestMatch(prj, cfg.buildcfg, cfg.platform)
  182. end
  183. context.descriptor = descriptors[cfg]
  184. context.platform = vstudio.projectPlatform(context.prjCfg)
  185. context.architecture = vstudio.archFromConfig(context.prjCfg, true)
  186. p.push()
  187. p.callArray(sln2005.elements.projectConfigurationPlatforms, cfg, context)
  188. p.pop()
  189. end)
  190. end
  191. })
  192. p.w("EndGlobalSection")
  193. end
  194. function sln2005.activeCfg(cfg, context)
  195. p.w('{%s}.%s.ActiveCfg = %s|%s', context.prj.uuid, context.descriptor, context.platform, context.architecture)
  196. end
  197. function sln2005.build0(cfg, context)
  198. if not context.excluded and context.prjCfg.kind ~= p.NONE then
  199. p.w('{%s}.%s.Build.0 = %s|%s', context.prj.uuid, context.descriptor, context.platform, context.architecture)
  200. end
  201. end
  202. --
  203. -- Write out the tables that map solution configurations to project configurations.
  204. --
  205. function sln2005.configurationPlatforms(wks)
  206. local descriptors = {}
  207. local sorted = {}
  208. for cfg in p.workspace.eachconfig(wks) do
  209. -- Create a Visual Studio solution descriptor (i.e. Debug|Win32) for
  210. -- this solution configuration. I need to use it in a few different places
  211. -- below so it makes sense to precompute it up front.
  212. local platform = vstudio.solutionPlatform(cfg)
  213. descriptors[cfg] = string.format("%s|%s", cfg.buildcfg, platform)
  214. -- Also add the configuration to an indexed table which I can sort below
  215. table.insert(sorted, cfg)
  216. end
  217. -- Sort the solution configurations to match Visual Studio's preferred
  218. -- order, which appears to be a simple alpha sort on the descriptors.
  219. table.sort(sorted, function(cfg0, cfg1)
  220. return descriptors[cfg0]:lower() < descriptors[cfg1]:lower()
  221. end)
  222. -- Now I can output the sorted list of solution configuration descriptors
  223. -- Visual Studio assumes the first configurations as the defaults.
  224. if wks.defaultplatform then
  225. p.push('GlobalSection(SolutionConfigurationPlatforms) = preSolution')
  226. table.foreachi(sorted, function (cfg)
  227. if cfg.platform == wks.defaultplatform then
  228. p.w('%s = %s', descriptors[cfg], descriptors[cfg])
  229. end
  230. end)
  231. p.pop("EndGlobalSection")
  232. end
  233. p.push('GlobalSection(SolutionConfigurationPlatforms) = preSolution')
  234. table.foreachi(sorted, function (cfg)
  235. if not wks.defaultplatform or cfg.platform ~= wks.defaultplatform then
  236. p.w('%s = %s', descriptors[cfg], descriptors[cfg])
  237. end
  238. end)
  239. p.pop("EndGlobalSection")
  240. -- For each project in the solution...
  241. sln2005.projectConfigurationPlatforms(wks, sorted, descriptors)
  242. end
  243. --
  244. -- Write out contents of the SolutionProperties section; currently unused.
  245. --
  246. function sln2005.properties(wks)
  247. p.push('GlobalSection(SolutionProperties) = preSolution')
  248. p.w('HideSolutionNode = FALSE')
  249. p.pop('EndGlobalSection')
  250. end
  251. --
  252. -- Write out the NestedProjects block, which describes the structure of
  253. -- any solution groups.
  254. --
  255. function sln2005.nestedProjects(wks)
  256. local tr = p.workspace.grouptree(wks)
  257. if tree.hasbranches(tr) then
  258. p.push('GlobalSection(NestedProjects) = preSolution')
  259. tree.traverse(tr, {
  260. onnode = function(n)
  261. if n.parent.uuid then
  262. p.w('{%s} = {%s}', (n.project or n).uuid, n.parent.uuid)
  263. end
  264. end
  265. })
  266. p.pop('EndGlobalSection')
  267. end
  268. end
  269. --
  270. -- Write out the ExtensibilityGlobals block, which embeds some data for the
  271. -- Visual Studio PremakeExtension.
  272. --
  273. function sln2005.premakeExtensibilityGlobals(wks)
  274. if wks.editorintegration then
  275. -- we need to filter out the 'file' argument, since we already output
  276. -- the script separately.
  277. local args = {}
  278. for _, arg in ipairs(_ARGV) do
  279. if not (arg:startswith("--file") or arg:startswith("/file")) then
  280. table.insert(args, arg);
  281. end
  282. end
  283. p.w('PremakeBinary = %s', _PREMAKE_COMMAND)
  284. p.w('PremakeScript = %s', p.workspace.getrelative(wks, _MAIN_SCRIPT))
  285. p.w('PremakeArguments = %s', table.concat(args, ' '))
  286. end
  287. end
  288. --
  289. -- Map ExtensibilityGlobals to output functions.
  290. --
  291. sln2005.elements.extensibilityGlobals = function(wks)
  292. return {
  293. sln2005.premakeExtensibilityGlobals,
  294. }
  295. end
  296. --
  297. -- Output the ExtensibilityGlobals section.
  298. --
  299. function sln2005.extensibilityGlobals(wks)
  300. local contents = p.capture(function ()
  301. p.push()
  302. p.callArray(sln2005.elements.extensibilityGlobals, wks)
  303. p.pop()
  304. end)
  305. if #contents > 0 then
  306. p.push('GlobalSection(ExtensibilityGlobals) = postSolution')
  307. p.outln(contents)
  308. p.pop('EndGlobalSection')
  309. end
  310. end
  311. --
  312. -- Map solution sections to output functions. Tools that aren't listed will
  313. -- be ignored.
  314. --
  315. sln2005.elements.sections = function(wks)
  316. return {
  317. sln2005.sharedProjects,
  318. sln2005.configurationPlatforms,
  319. sln2005.properties,
  320. sln2005.nestedProjects,
  321. sln2005.extensibilityGlobals,
  322. }
  323. end
  324. --
  325. -- Write out all of the workspace sections.
  326. --
  327. function sln2005.sections(wks)
  328. p.callArray(sln2005.elements.sections, wks)
  329. end