vsandroid_vcxproj.lua 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. --
  2. -- android/vsandroid_vcxproj.lua
  3. -- vs-android integration for vstudio.
  4. -- Copyright (c) 2012-2015 Manu Evans and the Premake project
  5. --
  6. local p = premake
  7. p.modules.vsandroid = { }
  8. local android = p.modules.android
  9. local vsandroid = p.modules.vsandroid
  10. local vc2010 = p.vstudio.vc2010
  11. local vstudio = p.vstudio
  12. local project = p.project
  13. local config = p.config
  14. --
  15. -- Utility functions
  16. --
  17. local function setBoolOption(optionName, flag, value)
  18. if flag ~= nil then
  19. vc2010.element(optionName, nil, value)
  20. end
  21. end
  22. --
  23. -- Add android tools to vstudio actions.
  24. --
  25. if vstudio.vs2010_architectures ~= nil then
  26. if _ACTION >= "vs2015" then
  27. vstudio.vs2010_architectures.arm = "ARM"
  28. else
  29. vstudio.vs2010_architectures.android = "Android"
  30. end
  31. end
  32. --
  33. -- Extend global properties
  34. --
  35. premake.override(vc2010.elements, "globals", function (oldfn, prj)
  36. local elements = oldfn(prj)
  37. if prj.system == premake.ANDROID and prj.kind ~= premake.PACKAGING then
  38. -- Remove "IgnoreWarnCompileDuplicatedFilename".
  39. local pos = table.indexof(elements, vc2010.ignoreWarnDuplicateFilename)
  40. table.remove(elements, pos)
  41. elements = table.join(elements, {
  42. android.androidApplicationType
  43. })
  44. end
  45. return elements
  46. end)
  47. premake.override(vc2010.elements, "globalsCondition", function (oldfn, prj, cfg)
  48. local elements = oldfn(prj, cfg)
  49. if cfg.system == premake.ANDROID and cfg.system ~= prj.system and cfg.kind ~= premake.PACKAGING then
  50. elements = table.join(elements, {
  51. android.androidApplicationType
  52. })
  53. end
  54. return elements
  55. end)
  56. function android.androidApplicationType(cfg)
  57. vc2010.element("Keyword", nil, "Android")
  58. vc2010.element("RootNamespace", nil, "%s", cfg.project.name)
  59. if _ACTION >= "vs2019" then
  60. vc2010.element("MinimumVisualStudioVersion", nil, "16.0")
  61. elseif _ACTION >= "vs2017" then
  62. vc2010.element("MinimumVisualStudioVersion", nil, "15.0")
  63. elseif _ACTION >= "vs2015" then
  64. vc2010.element("MinimumVisualStudioVersion", nil, "14.0")
  65. end
  66. vc2010.element("ApplicationType", nil, "Android")
  67. if _ACTION >= "vs2017" then
  68. vc2010.element("ApplicationTypeRevision", nil, "3.0")
  69. elseif _ACTION >= "vs2015" then
  70. vc2010.element("ApplicationTypeRevision", nil, "2.0")
  71. else
  72. vc2010.element("ApplicationTypeRevision", nil, "1.0")
  73. end
  74. end
  75. --
  76. -- Extend configurationProperties.
  77. --
  78. premake.override(vc2010.elements, "configurationProperties", function(oldfn, cfg)
  79. local elements = oldfn(cfg)
  80. if cfg.kind ~= p.UTILITY and cfg.kind ~= p.PACKAGING and cfg.system == premake.ANDROID then
  81. table.remove(elements, table.indexof(elements, vc2010.characterSet))
  82. table.remove(elements, table.indexof(elements, vc2010.wholeProgramOptimization))
  83. table.remove(elements, table.indexof(elements, vc2010.windowsSDKDesktopARMSupport))
  84. elements = table.join(elements, {
  85. android.androidAPILevel,
  86. android.androidStlType,
  87. })
  88. if _ACTION >= "vs2015" then
  89. elements = table.join(elements, {
  90. android.thumbMode,
  91. })
  92. end
  93. end
  94. return elements
  95. end)
  96. function android.androidAPILevel(cfg)
  97. if cfg.androidapilevel ~= nil then
  98. vc2010.element("AndroidAPILevel", nil, "android-" .. cfg.androidapilevel)
  99. end
  100. end
  101. function android.androidStlType(cfg)
  102. if cfg.stl ~= nil then
  103. local stlType = {
  104. ["none"] = "system",
  105. ["gabi++"] = "gabi++",
  106. ["stlport"] = "stlport",
  107. ["gnu"] = "gnustl",
  108. ["libc++"] = "c++",
  109. }
  110. local postfix = iif(cfg.staticruntime == "On", "_static", "_shared")
  111. local runtimeLib = iif(cfg.stl == "none", "system", stlType[cfg.stl] .. postfix)
  112. if _ACTION >= "vs2015" then
  113. vc2010.element("UseOfStl", nil, runtimeLib)
  114. else
  115. vc2010.element("AndroidStlType", nil, runtimeLib)
  116. end
  117. end
  118. end
  119. function android.thumbMode(cfg)
  120. if cfg.thumbmode ~= nil then
  121. local thumbMode =
  122. {
  123. thumb = "Thumb",
  124. arm = "ARM",
  125. disabled = "Disabled",
  126. }
  127. vc2010.element("ThumbMode", nil, thumbMode[cfg.thumbmode])
  128. end
  129. end
  130. -- Note: this function is already patched in by vs2012...
  131. premake.override(vc2010, "platformToolset", function(oldfn, cfg)
  132. if cfg.system ~= premake.ANDROID then
  133. return oldfn(cfg)
  134. end
  135. if _ACTION >= "vs2015" then
  136. local gcc_map = {
  137. ["4.6"] = "GCC_4_6",
  138. ["4.8"] = "GCC_4_8",
  139. ["4.9"] = "GCC_4_9",
  140. }
  141. local clang_map = {
  142. ["3.4"] = "Clang_3_4",
  143. ["3.5"] = "Clang_3_5",
  144. ["3.6"] = "Clang_3_6",
  145. ["3.8"] = "Clang_3_8",
  146. ["5.0"] = "Clang_5_0",
  147. }
  148. if cfg.toolchainversion ~= nil then
  149. local map = iif(cfg.toolset == "gcc", gcc_map, clang_map)
  150. local ts = map[cfg.toolchainversion]
  151. if ts == nil then
  152. p.error('Invalid toolchainversion for the selected toolset (%s).', cfg.toolset or "clang")
  153. end
  154. vc2010.element("PlatformToolset", nil, ts)
  155. end
  156. else
  157. local archMap = {
  158. arm = "armv5te", -- should arm5 be default? vs-android thinks so...
  159. arm5 = "armv5te",
  160. arm7 = "armv7-a",
  161. mips = "mips",
  162. x86 = "x86",
  163. }
  164. local arch = cfg.architecture or "arm"
  165. if (cfg.architecture ~= nil or cfg.toolchainversion ~= nil) and archMap[arch] ~= nil then
  166. local defaultToolsetMap = {
  167. arm = "arm-linux-androideabi-",
  168. armv5 = "arm-linux-androideabi-",
  169. armv7 = "arm-linux-androideabi-",
  170. aarch64 = "aarch64-linux-android-",
  171. mips = "mipsel-linux-android-",
  172. mips64 = "mips64el-linux-android-",
  173. x86 = "x86-",
  174. x86_64 = "x86_64-",
  175. }
  176. local toolset = defaultToolsetMap[arch]
  177. if cfg.toolset == "clang" then
  178. error("The clang toolset is not yet supported by vs-android", 2)
  179. toolset = toolset .. "clang"
  180. elseif cfg.toolset and cfg.toolset ~= "gcc" then
  181. error("Toolset not supported by the android NDK: " .. cfg.toolset, 2)
  182. end
  183. local version = cfg.toolchainversion or iif(cfg.toolset == "clang", "3.5", "4.9")
  184. vc2010.element("PlatformToolset", nil, toolset .. version)
  185. vc2010.element("AndroidArch", nil, archMap[arch])
  186. end
  187. end
  188. end)
  189. --
  190. -- Extend clCompile.
  191. --
  192. premake.override(vc2010.elements, "clCompile", function(oldfn, cfg)
  193. local elements = oldfn(cfg)
  194. if cfg.system == premake.ANDROID then
  195. elements = table.join(elements, {
  196. android.debugInformation,
  197. android.strictAliasing,
  198. android.fpu,
  199. android.pic,
  200. android.shortEnums,
  201. android.cStandard,
  202. android.cppStandard,
  203. })
  204. if _ACTION >= "vs2015" then
  205. table.remove(elements, table.indexof(elements, vc2010.debugInformationFormat))
  206. -- Android has C[pp]LanguageStandard instead.
  207. table.remove(elements, table.indexof(elements, vc2010.languageStandard))
  208. -- Ignore multiProcessorCompilation for android projects, they use UseMultiToolTask instead.
  209. table.remove(elements, table.indexof(elements, vc2010.multiProcessorCompilation))
  210. -- minimalRebuild also ends up in android projects somehow.
  211. table.remove(elements, table.indexof(elements, vc2010.minimalRebuild))
  212. -- VS has NEON support through EnableNeonCodegen.
  213. table.replace(elements, vc2010.enableEnhancedInstructionSet, android.enableEnhancedInstructionSet)
  214. -- precompiledHeaderFile support.
  215. table.replace(elements, vc2010.precompiledHeaderFile, android.precompiledHeaderFile)
  216. end
  217. end
  218. return elements
  219. end)
  220. function android.precompiledHeaderFile(fileName, cfg)
  221. -- Doesn't work for project-relative paths.
  222. vc2010.element("PrecompiledHeaderFile", nil, "%s", path.getabsolute(path.rebase(fileName, cfg.basedir, cfg.location)))
  223. end
  224. function android.debugInformation(cfg)
  225. if cfg.flags.Symbols then
  226. _p(3,'<GenerateDebugInformation>true</GenerateDebugInformation>')
  227. end
  228. end
  229. function android.strictAliasing(cfg)
  230. if cfg.strictaliasing ~= nil then
  231. vc2010.element("StrictAliasing", nil, iif(cfg.strictaliasing == "Off", "false", "true"))
  232. end
  233. end
  234. function android.fpu(cfg)
  235. if cfg.fpu ~= nil then
  236. _p(3,'<SoftFloat>true</SoftFloat>', iif(cfg.fpu == "Software", "true", "false"))
  237. end
  238. end
  239. function android.pic(cfg)
  240. if cfg.pic ~= nil then
  241. vc2010.element("PositionIndependentCode", nil, iif(cfg.pic == "On", "true", "false"))
  242. end
  243. end
  244. function android.verboseCompiler(cfg)
  245. setBoolOption("Verbose", cfg.flags.VerboseCompiler, "true")
  246. end
  247. function android.undefineAllPreprocessorDefinitions(cfg)
  248. setBoolOption("UndefineAllPreprocessorDefinitions", cfg.flags.UndefineAllPreprocessorDefinitions, "true")
  249. end
  250. function android.showIncludes(cfg)
  251. setBoolOption("ShowIncludes", cfg.flags.ShowIncludes, "true")
  252. end
  253. function android.dataLevelLinking(cfg)
  254. setBoolOption("DataLevelLinking", cfg.flags.DataLevelLinking, "true")
  255. end
  256. function android.shortEnums(cfg)
  257. setBoolOption("UseShortEnums", cfg.flags.UseShortEnums, "true")
  258. end
  259. function android.cStandard(cfg)
  260. local c_langmap = {
  261. ["C98"] = "c98",
  262. ["C99"] = "c99",
  263. ["C11"] = "c11",
  264. ["gnu99"] = "gnu99",
  265. ["gnu11"] = "gnu11",
  266. }
  267. if c_langmap[cfg.cdialect] ~= nil then
  268. vc2010.element("CLanguageStandard", nil, c_langmap[cfg.cdialect])
  269. end
  270. end
  271. function android.cppStandard(cfg)
  272. local cpp_langmap = {
  273. ["C++98"] = "c++98",
  274. ["C++11"] = "c++11",
  275. ["C++14"] = "c++1y",
  276. ["C++17"] = "c++1z",
  277. ["C++latest"] = "c++1z",
  278. ["gnu++98"] = "gnu++98",
  279. ["gnu++11"] = "gnu++11",
  280. ["gnu++14"] = "gnu++1y",
  281. ["gnu++17"] = "gnu++1z",
  282. }
  283. if cpp_langmap[cfg.cppdialect] ~= nil then
  284. vc2010.element("CppLanguageStandard", nil, cpp_langmap[cfg.cppdialect])
  285. end
  286. end
  287. p.override(vc2010, "additionalCompileOptions", function(oldfn, cfg, condition)
  288. if cfg.system == p.ANDROID then
  289. local opts = cfg.buildoptions
  290. if cfg.disablewarnings and #cfg.disablewarnings > 0 then
  291. for _, warning in ipairs(cfg.disablewarnings) do
  292. table.insert(opts, '-Wno-' .. warning)
  293. end
  294. end
  295. -- -fvisibility=<>
  296. if cfg.visibility ~= nil then
  297. table.insert(opts, p.tools.gcc.cxxflags.visibility[cfg.visibility])
  298. end
  299. if #opts > 0 then
  300. opts = table.concat(opts, " ")
  301. vc2010.element("AdditionalOptions", condition, '%s %%(AdditionalOptions)', opts)
  302. end
  303. else
  304. oldfn(cfg, condition)
  305. end
  306. end)
  307. p.override(vc2010, "warningLevel", function(oldfn, cfg)
  308. if _ACTION >= "vs2015" and cfg.system == p.ANDROID and cfg.warnings and cfg.warnings ~= "Off" then
  309. vc2010.element("WarningLevel", nil, "EnableAllWarnings")
  310. elseif (_ACTION >= "vs2015" and cfg.system == p.ANDROID and cfg.warnings) or not (_ACTION >= "vs2015" and cfg.system == p.ANDROID) then
  311. oldfn(cfg)
  312. end
  313. end)
  314. premake.override(vc2010, "clCompilePreprocessorDefinitions", function(oldfn, cfg, condition)
  315. if cfg.system == p.ANDROID then
  316. vc2010.preprocessorDefinitions(cfg, cfg.defines, false, condition)
  317. else
  318. oldfn(cfg, condition)
  319. end
  320. end)
  321. premake.override(vc2010, "exceptionHandling", function(oldfn, cfg, condition)
  322. if cfg.system == p.ANDROID then
  323. -- Note: Android defaults to 'off'
  324. local exceptions = {
  325. On = "Enabled",
  326. Off = "Disabled",
  327. UnwindTables = "UnwindTables",
  328. }
  329. if _ACTION >= "vs2015" then
  330. if exceptions[cfg.exceptionhandling] ~= nil then
  331. vc2010.element("ExceptionHandling", condition, exceptions[cfg.exceptionhandling])
  332. end
  333. else
  334. if cfg.exceptionhandling == premake.ON then
  335. vc2010.element("GccExceptionHandling", condition, "true")
  336. end
  337. end
  338. else
  339. oldfn(cfg, condition)
  340. end
  341. end)
  342. function android.enableEnhancedInstructionSet(cfg)
  343. if cfg.vectorextensions == "NEON" then
  344. vc2010.element("EnableNeonCodegen", nil, "true")
  345. end
  346. end
  347. premake.override(vc2010, "runtimeTypeInfo", function(oldfn, cfg, condition)
  348. if cfg.system == premake.ANDROID then
  349. -- Note: Android defaults to 'off'
  350. if cfg.rtti == premake.ON then
  351. vc2010.element("RuntimeTypeInfo", condition, "true")
  352. end
  353. else
  354. oldfn(cfg, condition)
  355. end
  356. end)
  357. --
  358. -- Extend Link.
  359. --
  360. premake.override(vc2010, "generateDebugInformation", function(oldfn, cfg)
  361. -- Note: Android specifies the debug info in the clCompile section
  362. if cfg.system ~= premake.ANDROID then
  363. oldfn(cfg)
  364. end
  365. end)
  366. --
  367. -- Add android tools to vstudio actions.
  368. --
  369. premake.override(vc2010.elements, "itemDefinitionGroup", function(oldfn, cfg)
  370. local elements = oldfn(cfg)
  371. if cfg.system == premake.ANDROID and _ACTION < "vs2015" then
  372. elements = table.join(elements, {
  373. android.antBuild,
  374. })
  375. end
  376. return elements
  377. end)
  378. function android.antPackage(cfg)
  379. p.push('<AntPackage>')
  380. if cfg.androidapplibname ~= nil then
  381. vc2010.element("AndroidAppLibName", nil, cfg.androidapplibname)
  382. else
  383. vc2010.element("AndroidAppLibName", nil, "$(RootNamespace)")
  384. end
  385. p.pop('</AntPackage>')
  386. end
  387. function android.antBuild(cfg)
  388. if cfg.kind == premake.STATICLIB or cfg.kind == premake.SHAREDLIB then
  389. return
  390. end
  391. _p(2,'<AntBuild>')
  392. _p(3,'<AntBuildType>%s</AntBuildType>', iif(premake.config.isDebugBuild(cfg), "Debug", "Release"))
  393. _p(2,'</AntBuild>')
  394. end
  395. premake.override(vc2010, "additionalCompileOptions", function(oldfn, cfg, condition)
  396. if cfg.system == premake.ANDROID then
  397. vsandroid.additionalOptions(cfg, condition)
  398. end
  399. return oldfn(cfg, condition)
  400. end)
  401. premake.override(vc2010.elements, "user", function(oldfn, cfg)
  402. if cfg.system == p.ANDROID then
  403. return {}
  404. else
  405. return oldfn(cfg)
  406. end
  407. end)
  408. --
  409. -- Add options unsupported by vs-android UI to <AdvancedOptions>.
  410. --
  411. function vsandroid.additionalOptions(cfg)
  412. if _ACTION >= "vs2015" then
  413. else
  414. local function alreadyHas(t, key)
  415. for _, k in ipairs(t) do
  416. if string.find(k, key) then
  417. return true
  418. end
  419. end
  420. return false
  421. end
  422. if not cfg.architecture or string.startswith(cfg.architecture, "arm") then
  423. -- we might want to define the arch to generate better code
  424. -- if not alreadyHas(cfg.buildoptions, "-march=") then
  425. -- if cfg.architecture == "armv6" then
  426. -- table.insert(cfg.buildoptions, "-march=armv6")
  427. -- elseif cfg.architecture == "armv7" then
  428. -- table.insert(cfg.buildoptions, "-march=armv7")
  429. -- end
  430. -- end
  431. -- ARM has a comprehensive set of floating point options
  432. if cfg.fpu ~= "Software" and cfg.floatabi ~= "soft" then
  433. if cfg.architecture == "armv7" then
  434. -- armv7 always has VFP, may not have NEON
  435. if not alreadyHas(cfg.buildoptions, "-mfpu=") then
  436. if cfg.vectorextensions == "NEON" then
  437. table.insert(cfg.buildoptions, "-mfpu=neon")
  438. elseif cfg.fpu == "Hardware" or cfg.floatabi == "softfp" or cfg.floatabi == "hard" then
  439. table.insert(cfg.buildoptions, "-mfpu=vfpv3-d16") -- d16 is the lowest common denominator
  440. end
  441. end
  442. if not alreadyHas(cfg.buildoptions, "-mfloat-abi=") then
  443. if cfg.floatabi == "hard" then
  444. table.insert(cfg.buildoptions, "-mfloat-abi=hard")
  445. else
  446. -- Android should probably use softfp by default for compatibility
  447. table.insert(cfg.buildoptions, "-mfloat-abi=softfp")
  448. end
  449. end
  450. else
  451. -- armv5/6 may not have VFP
  452. if not alreadyHas(cfg.buildoptions, "-mfpu=") then
  453. if cfg.fpu == "Hardware" or cfg.floatabi == "softfp" or cfg.floatabi == "hard" then
  454. table.insert(cfg.buildoptions, "-mfpu=vfp")
  455. end
  456. end
  457. if not alreadyHas(cfg.buildoptions, "-mfloat-abi=") then
  458. if cfg.floatabi == "softfp" then
  459. table.insert(cfg.buildoptions, "-mfloat-abi=softfp")
  460. elseif cfg.floatabi == "hard" then
  461. table.insert(cfg.buildoptions, "-mfloat-abi=hard")
  462. end
  463. end
  464. end
  465. elseif cfg.floatabi == "soft" then
  466. table.insert(cfg.buildoptions, "-mfloat-abi=soft")
  467. end
  468. if cfg.endian == "Little" then
  469. table.insert(cfg.buildoptions, "-mlittle-endian")
  470. elseif cfg.endian == "Big" then
  471. table.insert(cfg.buildoptions, "-mbig-endian")
  472. end
  473. elseif cfg.architecture == "mips" then
  474. -- TODO...
  475. if cfg.vectorextensions == "MXU" then
  476. table.insert(cfg.buildoptions, "-mmxu")
  477. end
  478. elseif cfg.architecture == "x86" then
  479. -- TODO...
  480. end
  481. end
  482. end
  483. --
  484. -- Disable subsystem.
  485. --
  486. p.override(vc2010, "subSystem", function(oldfn, cfg)
  487. if cfg.system ~= p.ANDROID then
  488. return oldfn(cfg)
  489. end
  490. end)
  491. --
  492. -- Remove .lib and list in LibraryDependencies instead of AdditionalDependencies.
  493. --
  494. p.override(vc2010, "additionalDependencies", function(oldfn, cfg, explicit)
  495. if cfg.system == p.ANDROID then
  496. local links = {}
  497. -- If we need sibling projects to be listed explicitly, grab them first
  498. if explicit then
  499. links = config.getlinks(cfg, "siblings", "fullpath")
  500. end
  501. -- Then the system libraries, which come undecorated
  502. local system = config.getlinks(cfg, "system", "name")
  503. for i = 1, #system do
  504. local link = system[i]
  505. table.insert(links, link)
  506. end
  507. -- TODO: When to use LibraryDependencies vs AdditionalDependencies
  508. if #links > 0 then
  509. links = path.translate(table.concat(links, ";"))
  510. vc2010.element("LibraryDependencies", nil, "%%(LibraryDependencies);%s", links)
  511. end
  512. else
  513. return oldfn(cfg, explicit)
  514. end
  515. end)
  516. function android.useMultiToolTask(cfg)
  517. -- Android equivalent of 'MultiProcessorCompilation'
  518. if cfg.flags.MultiProcessorCompile then
  519. vc2010.element("UseMultiToolTask", nil, "true")
  520. end
  521. end
  522. premake.override(vc2010.elements, "outputProperties", function(oldfn, cfg)
  523. if cfg.system == p.ANDROID then
  524. return table.join(oldfn(cfg), {
  525. android.useMultiToolTask,
  526. })
  527. else
  528. return oldfn(cfg)
  529. end
  530. end)
  531. --
  532. -- Disable override of OutDir. This is breaking deployment.
  533. --
  534. p.override(vc2010, "outDir", function(oldfn, cfg)
  535. if cfg.system ~= p.ANDROID then
  536. return oldfn(cfg)
  537. end
  538. end)