diff options
Diffstat (limited to '3rdparty/genie/src/actions/xcode')
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/_xcode.lua | 88 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode10.lua | 116 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode4_workspace.lua | 100 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode6_config.lua | 10 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode6_project.lua | 247 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode8.lua | 362 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode9.lua | 107 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode_common.lua | 726 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode_project.lua | 71 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode_scheme.lua | 239 | ||||
-rw-r--r-- | 3rdparty/genie/src/actions/xcode/xcode_workspace.lua | 145 |
11 files changed, 1461 insertions, 750 deletions
diff --git a/3rdparty/genie/src/actions/xcode/_xcode.lua b/3rdparty/genie/src/actions/xcode/_xcode.lua index f14e8d7300e..406486f796a 100644 --- a/3rdparty/genie/src/actions/xcode/_xcode.lua +++ b/3rdparty/genie/src/actions/xcode/_xcode.lua @@ -5,8 +5,6 @@ -- premake.xcode = { } - premake.xcode.xcode6 = { } - -- -- Verify only single target kind for Xcode project @@ -15,7 +13,7 @@ -- Project to be analyzed -- - local function checkproject(prj) + function premake.xcode.checkproject(prj) -- Xcode can't mix target kinds within a project local last for cfg in premake.eachconfig(prj) do @@ -31,87 +29,3 @@ -- premake.xcode.toolset = "macosx" - - newaction - { - trigger = "xcode3", - shortname = "Xcode 3", - description = "Generate Apple Xcode 3 project files (experimental)", - os = "macosx", - - valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, - - valid_languages = { "C", "C++" }, - - valid_tools = { - cc = { "gcc" }, - }, - - valid_platforms = { - Native = "Native", - x32 = "Native 32-bit", - x64 = "Native 64-bit", - Universal32 = "32-bit Universal", - Universal64 = "64-bit Universal", - Universal = "Universal", - }, - - default_platform = "Universal", - - onsolution = function(sln) - -- Assign IDs needed for inter-project dependencies - premake.xcode.preparesolution(sln) - end, - - onproject = function(prj) - premake.generate(prj, "%%.xcodeproj/project.pbxproj", premake.xcode.project) - end, - - oncleanproject = function(prj) - premake.clean.directory(prj, "%%.xcodeproj") - end, - - oncheckproject = checkproject, - } - - newaction - { - trigger = "xcode4", - shortname = "Xcode 4", - description = "Generate Apple Xcode 4 project files (experimental)", - os = "macosx", - - valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, - - valid_languages = { "C", "C++" }, - - valid_tools = { - cc = { "gcc" }, - }, - - valid_platforms = { - Native = "Native", - x32 = "Native 32-bit", - x64 = "Native 64-bit", - Universal32 = "32-bit Universal", - Universal64 = "64-bit Universal", - Universal = "Universal", - }, - - default_platform = "Universal", - - onsolution = function(sln) - premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", premake.xcode4.workspace_generate) - end, - - onproject = function(prj) - premake.generate(prj, "%%.xcodeproj/project.pbxproj", premake.xcode.project) - end, - - oncleanproject = function(prj) - premake.clean.directory(prj, "%%.xcodeproj") - premake.clean.directory(prj, "%%.xcworkspace") - end, - - oncheckproject = checkproject, - } diff --git a/3rdparty/genie/src/actions/xcode/xcode10.lua b/3rdparty/genie/src/actions/xcode/xcode10.lua new file mode 100644 index 00000000000..f8ae0b42cac --- /dev/null +++ b/3rdparty/genie/src/actions/xcode/xcode10.lua @@ -0,0 +1,116 @@ +-- +-- xcode10.lua +-- Define the Apple XCode 10.0 action and support functions. +-- + + local premake = premake + premake.xcode10 = { } + + local xcode = premake.xcode + local xcode8 = premake.xcode8 + local xcode9 = premake.xcode9 + local xcode10 = premake.xcode10 + + function xcode10.XCBuildConfiguration_Project(tr, prj, cfg) + local options = xcode9.XCBuildConfiguration_Project(tr, prj, cfg) + + return table.merge(options, { + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = "YES", + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = "YES", + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = "YES", + CLANG_WARN_COMMA = "YES", + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = "YES", + CLANG_WARN_OBJC_LITERAL_CONVERSION = "YES", + CLANG_WARN_RANGE_LOOP_ANALYSIS = "YES", + CLANG_WARN_STRICT_PROTOTYPES = "YES", + }) + end + + function xcode10.XCBuildConfiguration_Target(tr, target, cfg) + local options = xcode8.XCBuildConfiguration_Target(tr, target, cfg) + + if not cfg.flags.ObjcARC then + options.CLANG_ENABLE_OBJC_WEAK = "YES" + end + + return options + end + + function xcode10.project(prj) + local tr = xcode.buildprjtree(prj) + xcode.Header(tr, 48) + xcode.PBXBuildFile(tr) + xcode.PBXContainerItemProxy(tr) + xcode.PBXFileReference(tr,prj) + xcode.PBXFrameworksBuildPhase(tr) + xcode.PBXGroup(tr) + xcode.PBXNativeTarget(tr) + xcode.PBXProject(tr, "8.0") + xcode.PBXReferenceProxy(tr) + xcode.PBXResourcesBuildPhase(tr) + xcode.PBXShellScriptBuildPhase(tr) + xcode.PBXCopyFilesBuildPhase(tr) + xcode.PBXSourcesBuildPhase(tr,prj) + xcode.PBXVariantGroup(tr) + xcode.PBXTargetDependency(tr) + xcode.XCBuildConfiguration(tr, prj, { + ontarget = xcode10.XCBuildConfiguration_Target, + onproject = xcode10.XCBuildConfiguration_Project, + }) + xcode.XCBuildConfigurationList(tr) + xcode.Footer(tr) + end + + +-- +-- xcode10 action +-- + + newaction + { + trigger = "xcode10", + shortname = "Xcode 10", + description = "Generate Apple Xcode 10 project files (experimental)", + os = "macosx", + + valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, + + valid_languages = { "C", "C++" }, + + valid_tools = { + cc = { "gcc" }, + }, + + valid_platforms = { + Native = "Native", + x32 = "Native 32-bit", + x64 = "Native 64-bit", + Universal = "Universal", + }, + + default_platform = "Native", + + onsolution = function(sln) + premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate) + premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings) + premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme) + end, + + onproject = function(prj) + premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode10.project) + xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes") + end, + + oncleanproject = function(prj) + premake.clean.directory(prj, "%%.xcodeproj") + premake.clean.directory(prj, "%%.xcworkspace") + end, + + oncheckproject = xcode.checkproject, + + xcode = { + iOSTargetPlatformVersion = nil, + macOSTargetPlatformVersion = nil, + tvOSTargetPlatformVersion = nil, + }, + } diff --git a/3rdparty/genie/src/actions/xcode/xcode4_workspace.lua b/3rdparty/genie/src/actions/xcode/xcode4_workspace.lua deleted file mode 100644 index 726a306dc6f..00000000000 --- a/3rdparty/genie/src/actions/xcode/xcode4_workspace.lua +++ /dev/null @@ -1,100 +0,0 @@ -premake.xcode4 = {} - -local xcode4 = premake.xcode4 - -function xcode4.workspace_head() - _p('<?xml version="1.0" encoding="UTF-8"?>') - _p('<Workspace') - _p(1,'version = "1.0">') - -end - -function xcode4.workspace_tail() - _p('</Workspace>') -end - -function xcode4.workspace_file_ref(prj, indent) - - local projpath = path.getrelative(prj.solution.location, prj.location) - if projpath == '.' then projpath = '' - else projpath = projpath ..'/' - end - _p(indent, '<FileRef') - _p(indent + 1, 'location = "group:%s">', projpath .. prj.name .. '.xcodeproj') - _p(indent, '</FileRef>') -end - -function xcode4.workspace_group(grp, indent) - _p(indent, '<Group') - _p(indent + 1, 'location = "container:"') - _p(indent + 1, 'name = "%s">', grp.name) - - for _, child in ipairs(grp.groups) do - xcode4.workspace_group(child, indent + 1) - end - - for _, prj in ipairs(grp.projects) do - xcode4.workspace_file_ref(prj, indent + 1) - end - - _p(indent, '</Group>') -end - -function xcode4.workspace_generate(sln) - premake.xcode.preparesolution(sln) - - xcode4.workspace_head() - - xcode4.reorderProjects(sln) - - for grp in premake.solution.eachgroup(sln) do - if grp.parent == nil then - xcode4.workspace_group(grp, 1) - end - end - - for prj in premake.solution.eachproject(sln) do - if prj.group == nil then - xcode4.workspace_file_ref(prj, 1) - end - end - - xcode4.workspace_tail() -end - --- --- If a startup project is specified, move it to the front of the project list. --- This will make Visual Studio treat it like a startup project. --- - -function xcode4.reorderProjects(sln) - if sln.startproject then - for i, prj in ipairs(sln.projects) do - if sln.startproject == prj.name then - -- Move group tree containing the project to start of group list - local cur = prj.group - while cur ~= nil do - -- Remove group from array - for j, group in ipairs(sln.groups) do - if group == cur then - table.remove(sln.groups, j) - break - end - end - - -- Add back at start - table.insert(sln.groups, 1, cur) - cur = cur.parent - end - -- Move the project itself to start - table.remove(sln.projects, i) - table.insert(sln.projects, 1, prj) - break - end - end - end -end - - - - diff --git a/3rdparty/genie/src/actions/xcode/xcode6_config.lua b/3rdparty/genie/src/actions/xcode/xcode6_config.lua deleted file mode 100644 index 74be0e16f06..00000000000 --- a/3rdparty/genie/src/actions/xcode/xcode6_config.lua +++ /dev/null @@ -1,10 +0,0 @@ -local xcode6 = premake.xcode.xcode6 - -function xcode6.generate_project_config(prj) - _p("PRODUCT_NAME = $(TARGET_NAME)") - - if premake.isswiftproject(prj) then - _p("OTHER_SWIFT_FLAGS = -DXcode") - _p("USE_HEADERMAP = NO") - end -end
\ No newline at end of file diff --git a/3rdparty/genie/src/actions/xcode/xcode6_project.lua b/3rdparty/genie/src/actions/xcode/xcode6_project.lua deleted file mode 100644 index 3ee73127e2a..00000000000 --- a/3rdparty/genie/src/actions/xcode/xcode6_project.lua +++ /dev/null @@ -1,247 +0,0 @@ --- --- xcode4_project.lua --- Generate an Xcode4 C/C++ project. --- Copyright (c) 2009 Jason Perkins and the Premake project --- - -local xcode = premake.xcode -local xcode6 = xcode.xcode6 -local tree = premake.tree - --- --- Create a tree corresponding to what is shown in the Xcode project browser --- pane, with nodes for files and folders, resources, frameworks, and products. --- --- @param prj --- The project being generated. --- @returns --- A tree, loaded with metadata, which mirrors Xcode's view of the project. --- - -function xcode6.buildprjtree(prj) - local tr = premake.project.buildsourcetree(prj) - - -- create a list of build configurations and assign IDs - tr.configs = {} - for _, cfgname in ipairs(prj.solution.configurations) do - for _, platform in ipairs(prj.solution.xcode.platforms) do - local cfg = premake.getconfig(prj, cfgname, platform) - cfg.xcode = {} - cfg.xcode.targetid = xcode.newid(prj.xcode.projectnode, cfgname) - cfg.xcode.projectid = xcode.newid(tr, cfgname) - table.insert(tr.configs, cfg) - end - end - - -- convert localized resources from their filesystem layout (English.lproj/MainMenu.xib) - -- to Xcode's display layout (MainMenu.xib/English). - tree.traverse(tr, { - onbranch = function(node) - if path.getextension(node.name) == ".lproj" then - local lang = path.getbasename(node.name) -- "English", "French", etc. - - -- create a new language group for each file it contains - for _, filenode in ipairs(node.children) do - local grpnode = node.parent.children[filenode.name] - if not grpnode then - grpnode = tree.insert(node.parent, tree.new(filenode.name)) - grpnode.kind = "vgroup" - end - - -- convert the file node to a language node and add to the group - filenode.name = path.getbasename(lang) - tree.insert(grpnode, filenode) - end - - -- remove this directory from the tree - tree.remove(node) - end - end - }) - - -- fix .xcassets files, they should be treated as a file, not a folder - tree.traverse(tr, { - onbranch = function(node) - if path.getextension(node.name) == ".xcassets" then - node.children = {} - end - end - }) - - -- the special folder "Frameworks" lists all linked frameworks - tr.frameworks = tree.new("Frameworks") - for cfg in premake.eachconfig(prj) do - for _, link in ipairs(premake.getlinks(cfg, "system", "fullpath")) do - local name = path.getname(link) - if xcode.isframework(name) and not tr.frameworks.children[name] then - node = tree.insert(tr.frameworks, tree.new(name)) - node.path = link - end - end - end - - -- only add it to the tree if there are frameworks to link - if #tr.frameworks.children > 0 then - tree.insert(tr, tr.frameworks) - end - - -- the special folder "Products" holds the target produced by the project; this - -- is populated below - tr.products = tree.insert(tr, tree.new("Products")) - - -- the special folder "Projects" lists sibling project dependencies - tr.projects = tree.new("Projects") - for _, dep in ipairs(premake.getdependencies(prj, "sibling", "object")) do - -- create a child node for the dependency's xcodeproj - local xcpath = xcode.getxcodeprojname(dep) - local xcnode = tree.insert(tr.projects, tree.new(path.getname(xcpath))) - xcnode.path = xcpath - xcnode.project = dep - xcnode.productgroupid = xcode.newid(xcnode, "prodgrp") - xcnode.productproxyid = xcode.newid(xcnode, "prodprox") - xcnode.targetproxyid = xcode.newid(xcnode, "targprox") - xcnode.targetdependid = xcode.newid(xcnode, "targdep") - - -- create a grandchild node for the dependency's link target - local cfg = premake.getconfig(dep, prj.configurations[1]) - node = tree.insert(xcnode, tree.new(cfg.linktarget.name)) - node.path = cfg.linktarget.fullpath - node.cfg = cfg - end - - if #tr.projects.children > 0 then - tree.insert(tr, tr.projects) - end - - -- Final setup - tree.traverse(tr, { - onnode = function(node) - -- assign IDs to every node in the tree - node.id = xcode.newid(node) - - -- assign build IDs to buildable files - if xcode.getbuildcategory(node) then - node.buildid = xcode.newid(node, "build") - end - - -- remember key files that are needed elsewhere - if string.endswith(node.name, "Info.plist") then - tr.infoplist = node - end - if string.endswith(node.name, ".entitlements") then - tr.entitlements = node - end - end - }, true) - - -- Plug in the product node into the Products folder in the tree. The node - -- was built in xcode.preparesolution() in xcode_common.lua; it contains IDs - -- that are necessary for inter-project dependencies - node = tree.insert(tr.products, prj.xcode.projectnode) - node.kind = "product" - node.path = node.cfg.buildtarget.fullpath - node.cfgsection = xcode.newid(node, "cfg") - node.resstageid = xcode.newid(node, "rez") - node.sourcesid = xcode.newid(node, "src") - node.fxstageid = xcode.newid(node, "fxs") - - return tr -end - - --- --- Generate an Xcode4 .xcodeproj for a Premake project. --- --- @param prj --- The Premake project to generate. --- - -function xcode6.project(prj) - local tr = xcode6.buildprjtree(prj) - - xcode6.Header(tr) - xcode6.PBXProject(tr) - - xcode.PBXBuildFile(tr) - xcode.PBXContainerItemProxy(tr) - xcode.PBXFileReference(tr,prj) - xcode.PBXFrameworksBuildPhase(tr) - xcode.PBXGroup(tr) - xcode.PBXNativeTarget(tr) - xcode.PBXReferenceProxy(tr) - xcode.PBXResourcesBuildPhase(tr) - xcode.PBXShellScriptBuildPhase(tr) - xcode.PBXSourcesBuildPhase(tr,prj) - xcode.PBXVariantGroup(tr) - xcode.PBXTargetDependency(tr) - xcode.XCBuildConfiguration(tr) - xcode.XCBuildConfigurationList(tr) - - xcode6.PBXConfigsGroup() - xcode6.Footer(tr) -end - ---------------------------------------------------------------------------- --- Section generator functions, in the same order in which they appear --- in the .pbxproj file ---------------------------------------------------------------------------- - -function xcode6.Header() - _p('// !$*UTF8*$!') - _p('{') - _p(1,'archiveVersion = 1;') - _p(1,'classes = {}') - _p(1,'objectVersion = 46;') - _p(1,'rootObject = __RootObject_;') - _p(1,'objects = {') -end - -function xcode6.PBXProject(tr) - _p(2,'__RootObject_ = {') - _p(3,'isa = PBXProject;') - _p(3,'attributes = {LastUpgradeCheck = 9999;};') - _p(3,'buildConfigurationList = ___RootConfs_;', tr.name) - _p(3,'compatibilityVersion = "Xcode 3.2";') - _p(3,'developmentRegion = English;') - _p(3,'hasScannedForEncodings = 0;') - _p(3,'knownRegions = (en);') - _p(3,'mainGroup = ___RootGroup_;') - _p(3,'projectDirPath = "";') - _p(3,'projectRoot = "";') - - _p(3,'targets = (') - for _, node in ipairs(tr.products.children) do - _p(4,'%s /* %s */,', node.targetid, node.name) - end - _p(3,');') - - if #tr.projects.children > 0 then - _p(3,'projectReferences = (') - for _, node in ipairs(tr.projects.children) do - _p(4,'{') - _p(5,'ProductGroup = %s /* Products */;', node.productgroupid) - _p(5,'ProjectRef = %s /* %s */;', node.id, path.getname(node.path)) - _p(4,'},') - end - _p(3,');') - end - - _p(2,'};') - _p('') -end - -function xcode6.PBXConfigsGroup() - _p(2, "_____Configs_ = {") - _p(3, "isa = PBXGroup;") - _p(3, "children = (") - -- '__PBXFileRef_SGLMath.xcodeproj/Configs/Project.xcconfig' - _p(3, ");") - _p(3, "name = Configs;") - _p(3, "sourceTree = '<group>';") - _p(2, "};") -end - -function xcode6.Footer() - _p(1,'};') - _p('}') -end diff --git a/3rdparty/genie/src/actions/xcode/xcode8.lua b/3rdparty/genie/src/actions/xcode/xcode8.lua new file mode 100644 index 00000000000..5a658c992fd --- /dev/null +++ b/3rdparty/genie/src/actions/xcode/xcode8.lua @@ -0,0 +1,362 @@ +-- +-- _xcode8.lua +-- Define the Apple XCode 8.0 action and support functions. +-- + + local premake = premake + premake.xcode8 = { } + + local xcode = premake.xcode + local xcode8 = premake.xcode8 + + function xcode8.XCBuildConfiguration_Target(tr, target, cfg) + local cfgname = xcode.getconfigname(cfg) + local installpaths = { + ConsoleApp = "/usr/local/bin", + WindowedApp = "$(HOME)/Applications", + SharedLib = "/usr/local/lib", + StaticLib = "/usr/local/lib", + Bundle = "$(LOCAL_LIBRARY_DIR)/Bundles", + } + + -- options table to return + local options = { + ALWAYS_SEARCH_USER_PATHS = "NO", + GCC_DYNAMIC_NO_PIC = "NO", + GCC_MODEL_TUNING = "G5", + INSTALL_PATH = installpaths[cfg.kind], + PRODUCT_NAME = cfg.buildtarget.basename, + } + + if not cfg.flags.Symbols then + options.DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym" + end + + if cfg.kind ~= "StaticLib" and cfg.buildtarget.prefix ~= "" then + options.EXECUTABLE_PREFIX = cfg.buildtarget.prefix + end + + if cfg.targetextension then + local ext = cfg.targetextension + options.EXECUTABLE_EXTENSION = iif(ext:startswith("."), ext:sub(2), ext) + end + + if cfg.flags.ObjcARC then + options.CLANG_ENABLE_OBJC_ARC = "YES" + end + + local outdir = path.getdirectory(cfg.buildtarget.bundlepath) + if outdir ~= "." then + options.CONFIGURATION_BUILD_DIR = outdir + end + + if tr.infoplist then + options.INFOPLIST_FILE = tr.infoplist.cfg.name + end + + local infoplist_file = nil + + for _, v in ipairs(cfg.files) do + -- for any file named *info.plist, use it as the INFOPLIST_FILE + if (string.find (string.lower (v), 'info.plist') ~= nil) then + infoplist_file = string.format('$(SRCROOT)/%s', v) + end + end + + if infoplist_file ~= nil then + options.INFOPLIST_FILE = infoplist_file + end + + local action = premake.action.current() + local get_opt = function(opt, def) + return (opt and #opt > 0) and opt or def + end + + local iosversion = get_opt(cfg.iostargetplatformversion, action.xcode.iOSTargetPlatformVersion) + local macosversion = get_opt(cfg.macostargetplatformversion, action.xcode.macOSTargetPlatformVersion) + local tvosversion = get_opt(cfg.tvostargetplatformversion, action.xcode.tvOSTargetPlatformVersion) + + if iosversion then + options.IPHONEOS_DEPLOYMENT_TARGET = iosversion + elseif macosversion then + options.MACOSX_DEPLOYMENT_TARGET = macosversion + elseif tvosversion then + options.TVOS_DEPLOYMENT_TARGET = tvosversion + end + + if cfg.kind == "Bundle" and not cfg.options.SkipBundling then + options.PRODUCT_BUNDLE_IDENTIFIER = "genie." .. cfg.buildtarget.basename:gsub("%s+", ".") --replace spaces with . + local ext = cfg.targetextension + if ext then + options.WRAPPER_EXTENSION = iif(ext:startswith("."), ext:sub(2), ext) + else + options.WRAPPER_EXTENSION = "bundle" + end + end + + return options + end + + function xcode8.XCBuildConfiguration_Project(tr, prj, cfg) + local cfgname = xcode.getconfigname(cfg) + local archs = { + Native = nil, + x32 = "i386", + x64 = "x86_64", + Universal32 = "$(ARCHS_STANDARD_32_BIT)", + Universal64 = "$(ARCHS_STANDARD_64_BIT)", + Universal = "$(ARCHS_STANDARD_32_64_BIT)", + } + + -- build list of "other" C/C++ flags + local checks = { + ["-ffast-math"] = cfg.flags.FloatFast, + ["-ffloat-store"] = cfg.flags.FloatStrict, + ["-fomit-frame-pointer"] = cfg.flags.NoFramePointer, + } + + local cflags = { } + for flag, check in pairs(checks) do + if check then + table.insert(cflags, flag) + end + end + + -- build list of "other" linked flags. All libraries that aren't frameworks + -- are listed here, so I don't have to try and figure out if they are ".a" + -- or ".dylib", which Xcode requires to list in the Frameworks section + local ldflags = { } + for _, lib in ipairs(premake.getlinks(cfg, "system")) do + if not xcode.isframework(lib) then + table.insert(ldflags, "-l" .. lib) + end + end + + -- options table to return + local options = { + ARCHS = archs[cfg.platform], + CLANG_WARN__DUPLICATE_METHOD_MATCH = "YES", + CLANG_WARN_BOOL_CONVERSION = "YES", + CLANG_WARN_CONSTANT_CONVERSION = "YES", + CLANG_WARN_EMPTY_BODY = "YES", + CLANG_WARN_ENUM_CONVERSION = "YES", + CLANG_WARN_INFINITE_RECURSION = "YES", + CLANG_WARN_INT_CONVERSION = "YES", + CLANG_WARN_SUSPICIOUS_MOVE = "YES", + CLANG_WARN_UNREACHABLE_CODE = "YES", + CONFIGURATION_TEMP_DIR = "$(OBJROOT)", + ENABLE_STRICT_OBJC_MSGSEND = "YES", + ENABLE_TESTABILITY = "YES", + GCC_C_LANGUAGE_STANDARD = "gnu99", + GCC_NO_COMMON_BLOCKS = "YES", + GCC_PREPROCESSOR_DEFINITIONS = cfg.defines, + GCC_SYMBOLS_PRIVATE_EXTERN = "NO", + GCC_WARN_64_TO_32_BIT_CONVERSION = "YES", + GCC_WARN_ABOUT_RETURN_TYPE = "YES", + GCC_WARN_UNDECLARED_SELECTOR = "YES", + GCC_WARN_UNINITIALIZED_AUTOS = "YES", + GCC_WARN_UNUSED_FUNCTION = "YES", + GCC_WARN_UNUSED_VARIABLE = "YES", + HEADER_SEARCH_PATHS = table.join(cfg.includedirs, cfg.systemincludedirs), + LIBRARY_SEARCH_PATHS = cfg.libdirs, + OBJROOT = cfg.objectsdir, + ONLY_ACTIVE_ARCH = "YES", + OTHER_CFLAGS = table.join(cflags, cfg.buildoptions, cfg.buildoptions_c), + OTHER_CPLUSPLUSFLAGS = table.join(cflags, cfg.buildoptions, cfg.buildoptions_cpp), + OTHER_LDFLAGS = table.join(ldflags, cfg.linkoptions), + SDKROOT = xcode.toolset, + USER_HEADER_SEARCH_PATHS = cfg.userincludedirs, + } + + if tr.entitlements then + options.CODE_SIGN_ENTITLEMENTS = tr.entitlements.cfg.name + end + + local targetdir = path.getdirectory(cfg.buildtarget.bundlepath) + if targetdir ~= "." then + options.CONFIGURATION_BUILD_DIR = "$(SYMROOT)" + options.SYMROOT = targetdir + end + + if cfg.flags.Symbols then + options.COPY_PHASE_STRIP = "NO" + end + + local excluded = xcode.cfg_excluded_files(prj, cfg) + if #excluded > 0 then + options.EXCLUDED_SOURCE_FILE_NAMES = excluded + end + + if cfg.flags.NoExceptions then + options.GCC_ENABLE_CPP_EXCEPTIONS = "NO" + end + + if cfg.flags.NoRTTI then + options.GCC_ENABLE_CPP_RTTI = "NO" + end + + if cfg.flags.Symbols and not cfg.flags.NoEditAndContinue then + options.GCC_ENABLE_FIX_AND_CONTINUE = "YES" + end + + if cfg.flags.NoExceptions then + options.GCC_ENABLE_OBJC_EXCEPTIONS = "NO" + end + + if cfg.flags.Optimize or cfg.flags.OptimizeSize then + options.GCC_OPTIMIZATION_LEVEL = "s" + elseif cfg.flags.OptimizeSpeed then + options.GCC_OPTIMIZATION_LEVEL = 3 + else + options.GCC_OPTIMIZATION_LEVEL = 0 + end + + if cfg.pchheader and not cfg.flags.NoPCH then + options.GCC_PRECOMPILE_PREFIX_HEADER = "YES" + + -- Visual Studio requires the PCH header to be specified in the same way + -- it appears in the #include statements used in the source code; the PCH + -- source actual handles the compilation of the header. GCC compiles the + -- header file directly, and needs the file's actual file system path in + -- order to locate it. + + -- To maximize the compatibility between the two approaches, see if I can + -- locate the specified PCH header on one of the include file search paths + -- and, if so, adjust the path automatically so the user doesn't have + -- add a conditional configuration to the project script. + + local pch = cfg.pchheader + for _, incdir in ipairs(cfg.includedirs) do + + -- convert this back to an absolute path for os.isfile() + local abspath = path.getabsolute(path.join(cfg.project.location, incdir)) + + local testname = path.join(abspath, pch) + if os.isfile(testname) then + pch = path.getrelative(cfg.location, testname) + break + end + end + + options.GCC_PREFIX_HEADER = pch + end + + if cfg.flags.FatalWarnings then + options.GCC_TREAT_WARNINGS_AS_ERRORS = "YES" + end + + if cfg.kind == "Bundle" then + options.MACH_O_TYPE = "mh_bundle" + end + + if cfg.flags.StaticRuntime then + options.STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = "static" + end + + if cfg.flags.PedanticWarnings or cfg.flags.ExtraWarnings then + options.WARNING_CFLAGS = "-Wall" + end + + if cfg.flags.Cpp11 then + options.CLANG_CXX_LANGUAGE_STANDARD = "c++11" + elseif cfg.flags.Cpp14 or cfg.flags.CppLatest then + options.CLANG_CXX_LANGUAGE_STANDARD = "c++14" + elseif cfg.flags.Cpp17 then + -- XCode8 does not support C++17, but other actions use this as + -- base that *do* support C++17, so check if this is the current + -- action before erroring. + if premake.action.current() == premake.action.get("xcode8") then + error("XCode8 does not support C++17.") + end + end + + for _, val in ipairs(premake.xcode.parameters) do + local eqpos = string.find(val, "=") + if eqpos ~= nil then + local key = string.trim(string.sub(val, 1, eqpos - 1)) + local value = string.trim(string.sub(val, eqpos + 1)) + options[key] = value + end + end + + return options + end + + function xcode8.project(prj) + local tr = xcode.buildprjtree(prj) + xcode.Header(tr, 48) + xcode.PBXBuildFile(tr) + xcode.PBXContainerItemProxy(tr) + xcode.PBXFileReference(tr,prj) + xcode.PBXFrameworksBuildPhase(tr) + xcode.PBXGroup(tr) + xcode.PBXNativeTarget(tr) + xcode.PBXProject(tr, "8.0") + xcode.PBXReferenceProxy(tr) + xcode.PBXResourcesBuildPhase(tr) + xcode.PBXShellScriptBuildPhase(tr) + xcode.PBXCopyFilesBuildPhase(tr) + xcode.PBXSourcesBuildPhase(tr,prj) + xcode.PBXVariantGroup(tr) + xcode.PBXTargetDependency(tr) + xcode.XCBuildConfiguration(tr, prj, { + ontarget = xcode8.XCBuildConfiguration_Target, + onproject = xcode8.XCBuildConfiguration_Project, + }) + xcode.XCBuildConfigurationList(tr) + xcode.Footer(tr) + end + + +-- +-- xcode8 action +-- + + newaction + { + trigger = "xcode8", + shortname = "Xcode 8", + description = "Generate Apple Xcode 8 project files", + os = "macosx", + + valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, + + valid_languages = { "C", "C++" }, + + valid_tools = { + cc = { "gcc" }, + }, + + valid_platforms = { + Native = "Native", + x32 = "Native 32-bit", + x64 = "Native 64-bit", + Universal = "Universal", + }, + + default_platform = "Native", + + onsolution = function(sln) + premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate) + premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings) + premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme) + end, + + onproject = function(prj) + premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode8.project) + xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes") + end, + + oncleanproject = function(prj) + premake.clean.directory(prj, "%%.xcodeproj") + premake.clean.directory(prj, "%%.xcworkspace") + end, + + oncheckproject = xcode.checkproject, + + xcode = { + iOSTargetPlatformVersion = nil, + macOSTargetPlatformVersion = nil, + tvOSTargetPlatformVersion = nil, + }, + } diff --git a/3rdparty/genie/src/actions/xcode/xcode9.lua b/3rdparty/genie/src/actions/xcode/xcode9.lua new file mode 100644 index 00000000000..aa70275bdda --- /dev/null +++ b/3rdparty/genie/src/actions/xcode/xcode9.lua @@ -0,0 +1,107 @@ +-- +-- xcode9.lua +-- Define the Apple XCode 9.0 action and support functions. +-- + + local premake = premake + premake.xcode9 = { } + + local xcode = premake.xcode + local xcode8 = premake.xcode8 + local xcode9 = premake.xcode9 + + function xcode9.XCBuildConfiguration_Project(tr, prj, cfg) + local options = xcode8.XCBuildConfiguration_Project(tr, prj, cfg) + + if cfg.flags.Cpp17 or cfg.flags.CppLatest then + options.CLANG_CXX_LANGUAGE_STANDARD = "c++17" + end + + return table.merge(options, { + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = "YES", + CLANG_WARN_COMMA = "YES", + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = "YES", + CLANG_WARN_OBJC_LITERAL_CONVERSION = "YES", + CLANG_WARN_RANGE_LOOP_ANALYSIS = "YES", + CLANG_WARN_STRICT_PROTOTYPES = "YES", + }) + end + + function xcode9.project(prj) + local tr = xcode.buildprjtree(prj) + xcode.Header(tr, 48) + xcode.PBXBuildFile(tr) + xcode.PBXContainerItemProxy(tr) + xcode.PBXFileReference(tr,prj) + xcode.PBXFrameworksBuildPhase(tr) + xcode.PBXGroup(tr) + xcode.PBXNativeTarget(tr) + xcode.PBXProject(tr, "8.0") + xcode.PBXReferenceProxy(tr) + xcode.PBXResourcesBuildPhase(tr) + xcode.PBXShellScriptBuildPhase(tr) + xcode.PBXCopyFilesBuildPhase(tr) + xcode.PBXSourcesBuildPhase(tr,prj) + xcode.PBXVariantGroup(tr) + xcode.PBXTargetDependency(tr) + xcode.XCBuildConfiguration(tr, prj, { + ontarget = xcode8.XCBuildConfiguration_Target, + onproject = xcode9.XCBuildConfiguration_Project, + }) + xcode.XCBuildConfigurationList(tr) + xcode.Footer(tr) + end + + +-- +-- xcode9 action +-- + + newaction + { + trigger = "xcode9", + shortname = "Xcode 9", + description = "Generate Apple Xcode 9 project files", + os = "macosx", + + valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, + + valid_languages = { "C", "C++" }, + + valid_tools = { + cc = { "gcc" }, + }, + + valid_platforms = { + Native = "Native", + x32 = "Native 32-bit", + x64 = "Native 64-bit", + Universal = "Universal", + }, + + default_platform = "Native", + + onsolution = function(sln) + premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate) + premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings) + premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme) + end, + + onproject = function(prj) + premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode9.project) + xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes") + end, + + oncleanproject = function(prj) + premake.clean.directory(prj, "%%.xcodeproj") + premake.clean.directory(prj, "%%.xcworkspace") + end, + + oncheckproject = xcode.checkproject, + + xcode = { + iOSTargetPlatformVersion = nil, + macOSTargetPlatformVersion = nil, + tvOSTargetPlatformVersion = nil, + }, + } diff --git a/3rdparty/genie/src/actions/xcode/xcode_common.lua b/3rdparty/genie/src/actions/xcode/xcode_common.lua index b3f925273b8..762c27aada1 100644 --- a/3rdparty/genie/src/actions/xcode/xcode_common.lua +++ b/3rdparty/genie/src/actions/xcode/xcode_common.lua @@ -18,10 +18,16 @@ function xcode.getbuildcategory(node) local categories = { [".a"] = "Frameworks", + [".h"] = "Headers", + [".hh"] = "Headers", + [".hpp"] = "Headers", + [".hxx"] = "Headers", + [".inl"] = "Headers", [".c"] = "Sources", [".cc"] = "Sources", [".cpp"] = "Sources", [".cxx"] = "Sources", + [".c++"] = "Sources", [".dylib"] = "Frameworks", [".bundle"] = "Frameworks", [".framework"] = "Frameworks", @@ -39,7 +45,8 @@ [".xcdatamodeld"] = "Sources", [".swift"] = "Sources", } - return categories[path.getextension(node.name)] + return categories[path.getextension(node.name)] or + categories[string.lower(path.getextension(node.name))] end @@ -78,12 +85,17 @@ [".cpp"] = "sourcecode.cpp.cpp", [".css"] = "text.css", [".cxx"] = "sourcecode.cpp.cpp", + [".c++"] = "sourcecode.cpp.cpp", [".entitlements"] = "text.xml", [".bundle"] = "wrapper.cfbundle", [".framework"] = "wrapper.framework", [".tbd"] = "sourcecode.text-based-dylib-definition", [".gif"] = "image.gif", [".h"] = "sourcecode.c.h", + [".hh"] = "sourcecode.cpp.h", + [".hpp"] = "sourcecode.cpp.h", + [".hxx"] = "sourcecode.cpp.h", + [".inl"] = "sourcecode.cpp.h", [".html"] = "text.html", [".lua"] = "sourcecode.lua", [".m"] = "sourcecode.c.objc", @@ -101,7 +113,8 @@ [".xcdatamodeld"] = "wrapper.xcdatamodeld", [".swift"] = "sourcecode.swift", } - return types[path.getextension(node.path)] or "text" + return types[path.getextension(node.path)] or + (types[string.lower(path.getextension(node.path))] or "text") end -- @@ -120,12 +133,17 @@ [".cpp"] = "sourcecode.cpp.cpp", [".css"] = "text.css", [".cxx"] = "sourcecode.cpp.cpp", + [".c++"] = "sourcecode.cpp.cpp", [".entitlements"] = "text.xml", [".bundle"] = "wrapper.cfbundle", [".framework"] = "wrapper.framework", [".tbd"] = "wrapper.framework", [".gif"] = "image.gif", [".h"] = "sourcecode.cpp.h", + [".hh"] = "sourcecode.cpp.h", + [".hpp"] = "sourcecode.cpp.h", + [".hxx"] = "sourcecode.cpp.h", + [".inl"] = "sourcecode.cpp.h", [".html"] = "text.html", [".lua"] = "sourcecode.lua", [".m"] = "sourcecode.cpp.objcpp", @@ -142,7 +160,8 @@ [".xcdatamodeld"] = "wrapper.xcdatamodeld", [".swift"] = "sourcecode.swift", } - return types[path.getextension(node.path)] or "text" + return types[path.getextension(node.path)] or + (types[string.lower(path.getextension(node.path))] or "text") end -- -- Return the Xcode product type, based target kind. @@ -156,10 +175,10 @@ function xcode.getproducttype(node) local types = { ConsoleApp = "com.apple.product-type.tool", - WindowedApp = "com.apple.product-type.application", + WindowedApp = node.cfg.options.SkipBundling and "com.apple.product-type.tool" or "com.apple.product-type.application", StaticLib = "com.apple.product-type.library.static", SharedLib = "com.apple.product-type.library.dynamic", - Bundle = "com.apple.product-type.bundle", + Bundle = node.cfg.options.SkipBundling and "com.apple.product-type.tool" or "com.apple.product-type.bundle", } return types[node.cfg.kind] end @@ -177,10 +196,10 @@ function xcode.gettargettype(node) local types = { ConsoleApp = "\"compiled.mach-o.executable\"", - WindowedApp = "wrapper.application", + WindowedApp = node.cfg.options.SkipBundling and "\"compiled.mach-o.executable\"" or "wrapper.application", StaticLib = "archive.ar", SharedLib = "\"compiled.mach-o.dylib\"", - Bundle = "wrapper.cfbundle", + Bundle = node.cfg.options.SkipBundling and "\"compiled.mach-o.bundle\"" or "wrapper.cfbundle", } return types[node.cfg.kind] end @@ -216,6 +235,16 @@ return (path.getextension(fname) == ".framework" or path.getextension(fname) == ".tbd") end +-- +-- Generates a unique 12 byte ID. +-- Parameter is optional +-- +-- @returns +-- A 24-character string representing the 12 byte ID. +-- + function xcode.uuid(param) + return os.uuid(param):upper():gsub('-',''):sub(0,24) + end -- -- Retrieves a unique 12 byte ID for an object. This function accepts and ignores two @@ -226,14 +255,77 @@ -- A 24-character string representing the 12 byte ID. -- - function xcode.newid() - return string.format("%04X%04X%04X%04X%04X%04X", - math.random(0, 32767), - math.random(0, 32767), - math.random(0, 32767), - math.random(0, 32767), - math.random(0, 32767), - math.random(0, 32767)) + function xcode.newid(node, usage) + local base = '' + + -- Seed the uuid with the project name and a project-specific counter. + -- This is to prevent matching strings from generating the same uuid, + -- while still generating the same uuid for the same properties across + -- runs. + local prj = node.project + + if prj == nil then + local parent = node.parent + while parent ~= nil do + if parent.project ~= nil then + prj = parent.project + break + end + parent = parent.parent + end + end + + if prj ~= nil then + prj.uuidcounter = (prj.uuidcounter or 0) + 1 + base = base .. prj.name .. "$" .. prj.uuidcounter .. "$" + end + + base = base .. "$" .. (node.path or node.name or "") + base = base .. "$" .. (usage or "") + return xcode.uuid(base) + end + +-- +-- Creates a label for a given scriptphase +-- based on command and config +-- such as the result looks like this: +-- 'Script Phase <number> [cmd] (Config)', e.g. 'Script Phase 1 [rsync] (Debug)' +-- +-- This function is used for generating `PBXShellScriptBuildPhase` from `xcodescriptphases`. +-- (Thus required in more than 1 place). +-- +-- @param cmd +-- The command itself +-- @param count +-- counter to avoid having duplicate label names +-- @param cfg +-- The configuration the command is generated for +-- + + function xcode.getscriptphaselabel(cmd, count, cfg) + return string.format("\"Script Phase %s [%s] (%s)\"", count, cmd:match("(%w+)(.+)"), iif(cfg, xcode.getconfigname(cfg), "all")) + end + + +-- +-- Creates a label for a given copy phase +-- based on target +-- such as the result looks like this: +-- 'Copy <type> <number> [target]', e.g. 'Copy Files 1 [assets]' +-- +-- This function is used for generating `PBXCopyFilesPhase` from `xcodecopyresources`. +-- (Thus required in more than 1 place). +-- +-- @param type +-- The copy type ('Resources' for now) +-- @param count +-- counter to avoid having duplicate label names +-- @param target +-- The target subfolder +-- + + function xcode.getcopyphaselabel(type, count, target) + return string.format("\"Copy %s %s [%s]\"", type, count, target) end @@ -276,11 +368,14 @@ -- The Xcode specific list tag. -- - function xcode.printlist(list, tag) + function xcode.printlist(list, tag, sort) if #list > 0 then + if sort ~= nil and sort == true then + table.sort(list) + end _p(4,'%s = (', tag) for _, item in ipairs(list) do - local escaped_item = item:gsub("\"", "\\\"") + local escaped_item = item:gsub("\"", "\\\\\\\""):gsub("'", "\\\\'") _p(5, '"%s",', escaped_item) end _p(4,');') @@ -288,24 +383,66 @@ end +-- +-- Escape a string for use in an Xcode project file. +-- + + function xcode.quotestr(str) + -- simple strings don't need quotes + if str:match("[^a-zA-Z0-9$._/]") == nil then + return str + end + + return "\"" .. str:gsub("[\"\\\"]", "\\%0") .. "\"" + end + + + --------------------------------------------------------------------------- -- Section generator functions, in the same order in which they appear -- in the .pbxproj file --------------------------------------------------------------------------- - function xcode.Header() - _p('// !$*UTF8*$!') - _p('{') - _p(1,'archiveVersion = 1;') - _p(1,'classes = {') - _p(1,'};') - _p(1,'objectVersion = 45;') - _p(1,'objects = {') - _p('') - end +function xcode.Header(tr, objversion) + _p('// !$*UTF8*$!') + _p('{') + _p(1,'archiveVersion = 1;') + _p(1,'classes = {') + _p(1,'};') + _p(1,'objectVersion = %d;', objversion) + _p(1,'objects = {') + _p('') +end function xcode.PBXBuildFile(tr) + local function gatherCopyFiles(which) + local copyfiles = {} + local targets = tr.project[which] + if #targets > 0 then + for _, t in ipairs(targets) do + for __, tt in ipairs(t) do + table.insertflat(copyfiles, tt[2]) + end + end + end + return table.translate(copyfiles, path.getname) + end + + local function gatherCopyFrameworks(which) + local copyfiles = {} + local targets = tr.project[which] + if #targets > 0 then + table.insertflat(copyfiles, targets) + end + return table.translate(copyfiles, path.getname) + end + + local copyfiles = table.flatten({ + gatherCopyFiles('xcodecopyresources'), + gatherCopyFrameworks('xcodecopyframeworks') + }) + _p('/* Begin PBXBuildFile section */') tree.traverse(tr, { onnode = function(node) @@ -313,6 +450,15 @@ _p(2,'%s /* %s in %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; };', node.buildid, node.name, xcode.getbuildcategory(node), node.id, node.name) end + + -- adds duplicate PBXBuildFile file entry as 'CopyFiles' for files marked to be copied + -- for frameworks: add signOnCopy flag + if table.icontains(copyfiles, node.name) then + _p(2,'%s /* %s in %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; %s };', + xcode.uuid(node.name .. 'in CopyFiles'), node.name, 'CopyFiles', node.id, node.name, + iif(xcode.isframework(node.name), "settings = {ATTRIBUTES = (CodeSignOnCopy, ); };", "") + ) + end end }) _p('/* End PBXBuildFile section */') @@ -381,7 +527,8 @@ end if string.find(nodePath,'/') then if string.find(nodePath,'^%.')then - error('relative paths are not currently supported for frameworks') + --error('relative paths are not currently supported for frameworks') + nodePath = path.getabsolute(path.join(tr.project.location, nodePath)) end pth = nodePath elseif path.getextension(nodePath)=='.tbd' then @@ -404,9 +551,13 @@ -- something else; probably a source code file src = "<group>" - -- if the parent node is virtual, it won't have a local path - -- of its own; need to use full relative path from project - if node.parent.isvpath then + if node.location then + pth = node.location + elseif node.parent.isvpath then + -- if the parent node is virtual, it won't have a local path + -- of its own; need to use full relative path from project + -- (in fact, often almost all paths are virtual because vpath + -- trims the leading dots from the full path) pth = node.cfg.name else pth = tree.getlocalpath(node) @@ -486,7 +637,10 @@ _p(3,'name = Products;') else _p(3,'name = "%s";', node.name) - if node.path and not node.isvpath then + + if node.location then + _p(3,'path = "%s";', node.location) + elseif node.path and not node.isvpath then local p = node.path if node.parent.path then p = path.getrelative(node.parent.path, node.path) @@ -527,22 +681,85 @@ end end + local function dobuildblock(id, label, which, action) + if hasBuildCommands(which) then + local commandcount = 0 + for _, cfg in ipairs(tr.configs) do + commandcount = commandcount + #cfg[which] + end + if commandcount > 0 then + action(id, label) + end + end + end + + local function doscriptphases(which, action) + local i = 0 + for _, cfg in ipairs(tr.configs) do + local cfgcmds = cfg[which] + if cfgcmds ~= nil then + for __, scripts in ipairs(cfgcmds) do + for ___, script in ipairs(scripts) do + local cmd = script[1] + local label = xcode.getscriptphaselabel(cmd, i, cfg) + local id = xcode.uuid(label) + action(id, label) + i = i + 1 + end + end + end + end + end + + local function docopyresources(which, action) + if hasBuildCommands(which) then + local targets = tr.project[which] + if #targets > 0 then + local i = 0 + for _, t in ipairs(targets) do + for __, tt in ipairs(t) do + local label = xcode.getcopyphaselabel('Resources', i, tt[1]) + local id = xcode.uuid(label) + action(id, label) + i = i + 1 + end + end + end + end + end + + local function docopyframeworks(which, action) + if hasBuildCommands(which) then + local targets = tr.project[which] + if #targets > 0 then + local label = "Copy Frameworks" + local id = xcode.uuid(label) + action(id, label) + end + end + end + + local function _p_label(id, label) + _p(4, '%s /* %s */,', id, label) + end + + _p(2,'%s /* %s */ = {', node.targetid, name) _p(3,'isa = PBXNativeTarget;') _p(3,'buildConfigurationList = %s /* Build configuration list for PBXNativeTarget "%s" */;', node.cfgsection, name) _p(3,'buildPhases = (') - if hasBuildCommands('prebuildcommands') then - _p(4,'9607AE1010C857E500CD1376 /* Prebuild */,') - end + dobuildblock('9607AE1010C857E500CD1376', 'Prebuild', 'prebuildcommands', _p_label) _p(4,'%s /* Resources */,', node.resstageid) _p(4,'%s /* Sources */,', node.sourcesid) - if hasBuildCommands('prelinkcommands') then - _p(4,'9607AE3510C85E7E00CD1376 /* Prelink */,') - end + dobuildblock('9607AE3510C85E7E00CD1376', 'Prelink', 'prelinkcommands', _p_label) _p(4,'%s /* Frameworks */,', node.fxstageid) - if hasBuildCommands('postbuildcommands') then - _p(4,'9607AE3710C85E8F00CD1376 /* Postbuild */,') + dobuildblock('9607AE3710C85E8F00CD1376', 'Postbuild', 'postbuildcommands', _p_label) + doscriptphases("xcodescriptphases", _p_label) + docopyresources("xcodecopyresources", _p_label) + if tr.project.kind == "WindowedApp" then + docopyframeworks("xcodecopyframeworks", _p_label) end + _p(3,');') _p(3,'buildRules = (') _p(3,');') @@ -575,12 +792,12 @@ end - function xcode.PBXProject(tr) + function xcode.PBXProject(tr, compatVersion) _p('/* Begin PBXProject section */') _p(2,'__RootObject_ /* Project object */ = {') _p(3,'isa = PBXProject;') _p(3,'buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "%s" */;', tr.name) - _p(3,'compatibilityVersion = "Xcode 3.2";') + _p(3,'compatibilityVersion = "Xcode %s";', compatVersion) _p(3,'hasScannedForEncodings = 1;') _p(3,'mainGroup = %s /* %s */;', tr.id, tr.name) _p(3,'projectDirPath = "";') @@ -653,47 +870,91 @@ function xcode.PBXShellScriptBuildPhase(tr) local wrapperWritten = false - local function doblock(id, name, which) + local function doblock(id, name, commands, files) + if commands ~= nil then + commands = table.flatten(commands) + end + if #commands > 0 then + if not wrapperWritten then + _p('/* Begin PBXShellScriptBuildPhase section */') + wrapperWritten = true + end + _p(2,'%s /* %s */ = {', id, name) + _p(3,'isa = PBXShellScriptBuildPhase;') + _p(3,'buildActionMask = 2147483647;') + _p(3,'files = (') + _p(3,');') + _p(3,'inputPaths = ('); + if files ~= nil then + files = table.flatten(files) + if #files > 0 then + for _, file in ipairs(files) do + _p(4, '"%s",', file) + end + end + end + _p(3,');'); + _p(3,'name = %s;', name); + _p(3,'outputPaths = ('); + _p(3,');'); + _p(3,'runOnlyForDeploymentPostprocessing = 0;'); + _p(3,'shellPath = /bin/sh;'); + _p(3,'shellScript = "%s";', table.concat(commands, "\\n"):gsub('"', '\\"')) + _p(2,'};') + end + end + + local function wrapcommands(cmds, cfg) + local commands = {} + if #cmds > 0 then + table.insert(commands, 'if [ "${CONFIGURATION}" = "' .. xcode.getconfigname(cfg) .. '" ]; then') + for i = 1, #cmds do + local cmd = cmds[i] + cmd = cmd:gsub('\\','\\\\') + table.insert(commands, cmd) + end + table.insert(commands, 'fi') + end + return commands + end + + local function dobuildblock(id, name, which) -- see if there are any commands to add for each config local commands = {} for _, cfg in ipairs(tr.configs) do - local cfgcmds = cfg[which] + local cfgcmds = wrapcommands(cfg[which], cfg) if #cfgcmds > 0 then - table.insert(commands, 'if [ "${CONFIGURATION}" = "' .. xcode.getconfigname(cfg) .. '" ]; then') - for i = 1, #cfgcmds do - local cmd = cfgcmds[i] - cmd = cmd:gsub('\\','\\\\') + for i, cmd in ipairs(cfgcmds) do table.insert(commands, cmd) end - table.insert(commands, 'fi') end end + doblock(id, name, commands) + end - if #commands > 0 then - if not wrapperWritten then - _p('/* Begin PBXShellScriptBuildPhase section */') - wrapperWritten = true + local function doscriptphases(which) + local i = 0 + for _, cfg in ipairs(tr.configs) do + local cfgcmds = cfg[which] + if cfgcmds ~= nil then + for __, scripts in ipairs(cfgcmds) do + for ___, script in ipairs(scripts) do + local cmd = script[1] + local files = script[2] + local label = xcode.getscriptphaselabel(cmd, i, cfg) + local id = xcode.uuid(label) + doblock(id, label, wrapcommands({cmd}, cfg), files) + i = i + 1 + end + end end - _p(2,'%s /* %s */ = {', id, name) - _p(3,'isa = PBXShellScriptBuildPhase;') - _p(3,'buildActionMask = 2147483647;') - _p(3,'files = (') - _p(3,');') - _p(3,'inputPaths = ('); - _p(3,');'); - _p(3,'name = %s;', name); - _p(3,'outputPaths = ('); - _p(3,');'); - _p(3,'runOnlyForDeploymentPostprocessing = 0;'); - _p(3,'shellPath = /bin/sh;'); - _p(3,'shellScript = "%s";', table.concat(commands, "\\n"):gsub('"', '\\"')) - _p(2,'};') end end - doblock("9607AE1010C857E500CD1376", "Prebuild", "prebuildcommands") - doblock("9607AE3510C85E7E00CD1376", "Prelink", "prelinkcommands") - doblock("9607AE3710C85E8F00CD1376", "Postbuild", "postbuildcommands") + dobuildblock("9607AE1010C857E500CD1376", "Prebuild", "prebuildcommands") + dobuildblock("9607AE3510C85E7E00CD1376", "Prelink", "prelinkcommands") + dobuildblock("9607AE3710C85E8F00CD1376", "Postbuild", "postbuildcommands") + doscriptphases("xcodescriptphases") if wrapperWritten then _p('/* End PBXShellScriptBuildPhase section */') @@ -725,6 +986,82 @@ _p('') end + -- copyresources leads to this + -- xcodeembedframeworks + function xcode.PBXCopyFilesBuildPhase(tr) + local wrapperWritten = false + + local function doblock(id, name, folderSpec, path, files) + -- note: folder spec: + -- 0: Absolute Path + -- 1: Wrapper + -- 6: Executables + -- 7: Resources + -- 10: Frameworks + -- 16: Products Directory + -- category: 'Frameworks' or 'CopyFiles' + + if #files > 0 then + if not wrapperWritten then + _p('/* Begin PBXCopyFilesBuildPhase section */') + wrapperWritten = true + end + _p(2,'%s /* %s */ = {', id, name) + _p(3,'isa = PBXCopyFilesBuildPhase;') + _p(3,'buildActionMask = 2147483647;') + _p(3,'dstPath = \"%s\";', path) + _p(3,'dstSubfolderSpec = \"%s\";', folderSpec) + _p(3,'files = (') + tree.traverse(tr, { + onleaf = function(node) + -- print(node.name) + if table.icontains(files, node.name) then + _p(4,'%s /* %s in %s */,', + xcode.uuid(node.name .. 'in CopyFiles'), node.name, 'CopyFiles') + end + end + }) + _p(3,');') + _p(3,'runOnlyForDeploymentPostprocessing = 0;'); + _p(2,'};') + end + end + + local function docopyresources(which) + local targets = tr.project[which] + if #targets > 0 then + local i = 0 + for _, t in ipairs(targets) do + for __, tt in ipairs(t) do + local label = xcode.getcopyphaselabel('Resources', i, tt[1]) + local id = xcode.uuid(label) + local files = table.translate(table.flatten(tt[2]), path.getname) + doblock(id, label, 7, tt[1], files) + i = i + 1 + end + end + end + end + + local function docopyframeworks(which) + local targets = tr.project[which] + if #targets > 0 then + local label = "Copy Frameworks" + local id = xcode.uuid(label) + local files = table.translate(table.flatten(targets), path.getname) + doblock(id, label, 10, "", files) + end + end + + docopyresources("xcodecopyresources") + if tr.project.kind == "WindowedApp" then + docopyframeworks("xcodecopyframeworks") + end + + if wrapperWritten then + _p('/* End PBXCopyFilesBuildPhase section */') + end + end function xcode.PBXVariantGroup(tr) _p('/* Begin PBXVariantGroup section */') @@ -767,83 +1104,7 @@ end - function xcode.XCBuildConfiguration_Target(tr, target, cfg) - local cfgname = xcode.getconfigname(cfg) - - _p(2,'%s /* %s */ = {', cfg.xcode.targetid, cfgname) - _p(3,'isa = XCBuildConfiguration;') - _p(3,'buildSettings = {') - _p(4,'ALWAYS_SEARCH_USER_PATHS = NO;') - - if not cfg.flags.Symbols then - _p(4,'DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";') - end - - if cfg.kind ~= "StaticLib" and cfg.buildtarget.prefix ~= "" then - _p(4,'EXECUTABLE_PREFIX = %s;', cfg.buildtarget.prefix) - end - - if cfg.targetextension then - local ext = cfg.targetextension - ext = iif(ext:startswith("."), ext:sub(2), ext) - _p(4,'EXECUTABLE_EXTENSION = %s;', ext) - end - - if cfg.flags.ObjcARC then - _p(4,'CLANG_ENABLE_OBJC_ARC = YES;') - end - - local outdir = path.getdirectory(cfg.buildtarget.bundlepath) - if outdir ~= "." then - _p(4,'CONFIGURATION_BUILD_DIR = %s;', outdir) - end - - _p(4,'GCC_DYNAMIC_NO_PIC = NO;') - _p(4,'GCC_MODEL_TUNING = G5;') - - if tr.infoplist then - _p(4,'INFOPLIST_FILE = "%s";', tr.infoplist.cfg.name) - end - - installpaths = { - ConsoleApp = '/usr/local/bin', - WindowedApp = '"$(HOME)/Applications"', - SharedLib = '/usr/local/lib', - StaticLib = '/usr/local/lib', - Bundle = '"$(LOCAL_LIBRARY_DIR)/Bundles"', - } - _p(4,'INSTALL_PATH = %s;', installpaths[cfg.kind]) - - local infoplist_file = nil - - for _, v in ipairs(cfg.files) do - -- for any file named *info.plist, use it as the INFOPLIST_FILE - if (string.find (string.lower (v), 'info.plist') ~= nil) then - infoplist_file = string.format('$(SRCROOT)/%s', v) - end - end - - if infoplist_file ~= nil then - _p(4,'INFOPLIST_FILE = "%s";', infoplist_file) - end - - if cfg.kind == "Bundle" then - _p(4, 'PRODUCT_BUNDLE_IDENTIFIER = "genie.%s";', cfg.buildtarget.basename:gsub("%s+", '.')) --replace spaces with . - end - - _p(4,'PRODUCT_NAME = "%s";', cfg.buildtarget.basename) - - if cfg.kind == "Bundle" then - _p(4, 'WRAPPER_EXTENSION = bundle;') - end - - _p(3,'};') - _p(3,'name = "%s";', cfgname) - _p(2,'};') - end - - - local function cfg_excluded_files(prj, cfg) + function xcode.cfg_excluded_files(prj, cfg) local excluded = {} -- Converts a file path to a pattern with no relative parts, prefixed with `*`. @@ -902,161 +1163,76 @@ end - function xcode.XCBuildConfiguration_Project(tr, prj, cfg) + function xcode.XCBuildConfiguration_Impl(tr, id, opts, cfg) local cfgname = xcode.getconfigname(cfg) - _p(2,'%s /* %s */ = {', cfg.xcode.projectid, cfgname) + _p(2,'%s /* %s */ = {', id, cfgname) _p(3,'isa = XCBuildConfiguration;') _p(3,'buildSettings = {') - local archs = { - Native = "$(NATIVE_ARCH_ACTUAL)", - x32 = "i386", - x64 = "x86_64", - Universal32 = "$(ARCHS_STANDARD_32_BIT)", - Universal64 = "$(ARCHS_STANDARD_64_BIT)", - Universal = "$(ARCHS_STANDARD_32_64_BIT)", - } - _p(4,'ARCHS = "%s";', archs[cfg.platform]) - - _p(4,'SDKROOT = "%s";', xcode.toolset) - - if tr.entitlements then - _p(4,'CODE_SIGN_ENTITLEMENTS = "%s";', tr.entitlements.cfg.name) - end - - local targetdir = path.getdirectory(cfg.buildtarget.bundlepath) - if targetdir ~= "." then - _p(4,'CONFIGURATION_BUILD_DIR = "$(SYMROOT)";'); - end - - _p(4,'CONFIGURATION_TEMP_DIR = "$(OBJROOT)";') + for k, v in table.sortedpairs(opts) do + if type(v) == "table" then + if #v > 0 then + _p(4,'%s = (', k) - if cfg.flags.Symbols then - _p(4,'COPY_PHASE_STRIP = NO;') - end + for i, v2 in ipairs(v) do + _p(5,'%s,', xcode.quotestr(tostring(v2))) + end - local excluded = cfg_excluded_files(prj, cfg) - if #excluded > 0 then - _p(4, 'EXCLUDED_SOURCE_FILE_NAMES = (') - for _, file in ipairs(excluded) do - _p(5, '"' .. file .. '",') + _p(4,');') + end + else + _p(4,'%s = %s;', k, xcode.quotestr(tostring(v))) end - _p(4, ');') - end - - _p(4,'GCC_C_LANGUAGE_STANDARD = gnu99;') - - if cfg.flags.NoExceptions then - _p(4,'GCC_ENABLE_CPP_EXCEPTIONS = NO;') - end - - if cfg.flags.NoRTTI then - _p(4,'GCC_ENABLE_CPP_RTTI = NO;') - end - - if _ACTION ~= "xcode4" and cfg.flags.Symbols and not cfg.flags.NoEditAndContinue then - _p(4,'GCC_ENABLE_FIX_AND_CONTINUE = YES;') - end - - if cfg.flags.NoExceptions then - _p(4,'GCC_ENABLE_OBJC_EXCEPTIONS = NO;') - end - - if cfg.flags.Optimize or cfg.flags.OptimizeSize then - _p(4,'GCC_OPTIMIZATION_LEVEL = s;') - elseif cfg.flags.OptimizeSpeed then - _p(4,'GCC_OPTIMIZATION_LEVEL = 3;') - else - _p(4,'GCC_OPTIMIZATION_LEVEL = 0;') - end - - if cfg.pchheader and not cfg.flags.NoPCH then - _p(4,'GCC_PRECOMPILE_PREFIX_HEADER = YES;') - _p(4,'GCC_PREFIX_HEADER = "%s";', cfg.pchheader) - end - - xcode.printlist(cfg.defines, 'GCC_PREPROCESSOR_DEFINITIONS') - - _p(4,'GCC_SYMBOLS_PRIVATE_EXTERN = NO;') - - if cfg.flags.FatalWarnings then - _p(4,'GCC_TREAT_WARNINGS_AS_ERRORS = YES;') end - _p(4,'GCC_WARN_ABOUT_RETURN_TYPE = YES;') - _p(4,'GCC_WARN_UNUSED_VARIABLE = YES;') - - xcode.printlist(cfg.includedirs, 'HEADER_SEARCH_PATHS') - xcode.printlist(cfg.userincludedirs, 'USER_HEADER_SEARCH_PATHS') - xcode.printlist(cfg.libdirs, 'LIBRARY_SEARCH_PATHS') - - _p(4,'OBJROOT = "%s";', cfg.objectsdir) - - _p(4,'ONLY_ACTIVE_ARCH = %s;',iif(premake.config.isdebugbuild(cfg),'YES','NO')) - - -- build list of "other" C/C++ flags - local checks = { - ["-ffast-math"] = cfg.flags.FloatFast, - ["-ffloat-store"] = cfg.flags.FloatStrict, - ["-fomit-frame-pointer"] = cfg.flags.NoFramePointer, - } + _p(3,'};') + _p(3,'name = %s;', xcode.quotestr(cfgname)) + _p(2,'};') + end - local flags = { } - for flag, check in pairs(checks) do - if check then - table.insert(flags, flag) + local function add_options(options, extras) + for _, tbl in ipairs(extras) do + for tkey, tval in pairs(tbl) do + options[tkey] = tval end end + end - for _, val in ipairs(premake.xcode.parameters) do - _p(4, val ..';') - end - - xcode.printlist(table.join(flags, cfg.buildoptions, cfg.buildoptions_c), 'OTHER_CFLAGS') - xcode.printlist(table.join(flags, cfg.buildoptions, cfg.buildoptions_cpp), 'OTHER_CPLUSPLUSFLAGS') + local function add_wholearchive_links(opts, cfg) + if #cfg.wholearchive > 0 then + local linkopts = {} - -- build list of "other" linked flags. All libraries that aren't frameworks - -- are listed here, so I don't have to try and figure out if they are ".a" - -- or ".dylib", which Xcode requires to list in the Frameworks section - flags = { } - for _, lib in ipairs(premake.getlinks(cfg, "system")) do - if not xcode.isframework(lib) then - table.insert(flags, "-l" .. lib) + for _, depcfg in ipairs(premake.getlinks(cfg, "siblings", "object")) do + if table.icontains(cfg.wholearchive, depcfg.project.name) then + local linkpath = path.rebase(depcfg.linktarget.fullpath, depcfg.location, cfg.location) + table.insert(linkopts, "-force_load") + table.insert(linkopts, linkpath) + end end - end - flags = table.join(flags, cfg.linkoptions) - xcode.printlist(flags, 'OTHER_LDFLAGS') - - if cfg.flags.StaticRuntime then - _p(4,'STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = static;') - end - if targetdir ~= "." then - _p(4,'SYMROOT = "%s";', targetdir) - end + if opts.OTHER_LDFLAGS then + linkopts = table.join(linkopts, opts.OTHER_LDFLAGS) + end - if cfg.flags.PedanticWarnings - or cfg.flags.ExtraWarnings - then - _p(4,'WARNING_CFLAGS = "-Wall";') + opts.OTHER_LDFLAGS = linkopts end - - _p(3,'};') - _p(3,'name = "%s";', cfgname) - _p(2,'};') end - - function xcode.XCBuildConfiguration(tr, prj) + function xcode.XCBuildConfiguration(tr, prj, opts) _p('/* Begin XCBuildConfiguration section */') for _, target in ipairs(tr.products.children) do for _, cfg in ipairs(tr.configs) do - xcode.XCBuildConfiguration_Target(tr, target, cfg) + local values = opts.ontarget(tr, target, cfg) + add_options(values, cfg.xcodetargetopts) + xcode.XCBuildConfiguration_Impl(tr, cfg.xcode.targetid, values, cfg) end end for _, cfg in ipairs(tr.configs) do - xcode.XCBuildConfiguration_Project(tr, prj, cfg) + local values = opts.onproject(tr, prj, cfg) + add_options(values, cfg.xcodeprojectopts) + add_wholearchive_links(values, cfg) + xcode.XCBuildConfiguration_Impl(tr, cfg.xcode.projectid, values, cfg) end _p('/* End XCBuildConfiguration section */') _p('') diff --git a/3rdparty/genie/src/actions/xcode/xcode_project.lua b/3rdparty/genie/src/actions/xcode/xcode_project.lua index 5a54d53ff5c..3a461ebdc16 100644 --- a/3rdparty/genie/src/actions/xcode/xcode_project.lua +++ b/3rdparty/genie/src/actions/xcode/xcode_project.lua @@ -26,8 +26,8 @@ for _, platform in ipairs(prj.solution.xcode.platforms) do local cfg = premake.getconfig(prj, cfgname, platform) cfg.xcode = {} - cfg.xcode.targetid = xcode.newid(prj.xcode.projectnode, cfgname) - cfg.xcode.projectid = xcode.newid(tr, cfgname) + cfg.xcode.targetid = xcode.newid(prj.xcode.projectnode, "tgt:"..platform..cfgname) + cfg.xcode.projectid = xcode.newid(tr, "prj:"..platform..cfgname) table.insert(tr.configs, cfg) end end @@ -112,6 +112,44 @@ tree.insert(tr, tr.projects) end + -- Add intermediate paths so groups have sensible locations + + -- find common prefixes going up the tree + tree.traverse(tr, { + onbranchexit = function(node) + for _, child in ipairs(node.children) do + if (child.location) then + if (node.location) then + while (not string.startswith(child.location, node.location)) do + node.location = path.getdirectory(node.location) + end + else + node.location = path.getdirectory(child.location) + end + end + end + end, + onleaf = function(node) + if (node.cfg) then + node.location = node.cfg.name + end + end + }, true) + + -- now convert to relative where possible + tree.traverse(tr, { + onbranchexit = function(node, depth) + if (node.location and node.parent and node.parent.location) then + node.location = path.getrelative(node.parent.location, node.location) + end + end, + onleaf = function(node, depth) + if (node.location and node.parent and node.parent.location) then + node.location = path.getrelative(node.parent.location, node.location) + end + end + }, true) + -- Final setup tree.traverse(tr, { onnode = function(node) @@ -146,32 +184,3 @@ return tr end - - --- --- Generate an Xcode .xcodeproj for a Premake project. --- --- @param prj --- The Premake project to generate. --- - - function premake.xcode.project(prj) - local tr = xcode.buildprjtree(prj) - xcode.Header(tr) - xcode.PBXBuildFile(tr) - xcode.PBXContainerItemProxy(tr) - xcode.PBXFileReference(tr,prj) - xcode.PBXFrameworksBuildPhase(tr) - xcode.PBXGroup(tr) - xcode.PBXNativeTarget(tr) - xcode.PBXProject(tr) - xcode.PBXReferenceProxy(tr) - xcode.PBXResourcesBuildPhase(tr) - xcode.PBXShellScriptBuildPhase(tr) - xcode.PBXSourcesBuildPhase(tr,prj) - xcode.PBXVariantGroup(tr) - xcode.PBXTargetDependency(tr) - xcode.XCBuildConfiguration(tr, prj) - xcode.XCBuildConfigurationList(tr) - xcode.Footer(tr) - end diff --git a/3rdparty/genie/src/actions/xcode/xcode_scheme.lua b/3rdparty/genie/src/actions/xcode/xcode_scheme.lua new file mode 100644 index 00000000000..662582e2afb --- /dev/null +++ b/3rdparty/genie/src/actions/xcode/xcode_scheme.lua @@ -0,0 +1,239 @@ +-- +-- xcode_scheme.lua +-- + +local premake = premake +local xcode = premake.xcode + + +-- +-- Print a BuildableReference element. +-- + + local function buildableref(indent, prj, cfg) + cfg = cfg or premake.eachconfig(prj)() + + _p(indent + 0, '<BuildableReference') + _p(indent + 1, 'BuildableIdentifier = "primary"') + _p(indent + 1, 'BlueprintIdentifier = "%s"', prj.xcode.projectnode.targetid) + _p(indent + 1, 'BuildableName = "%s"', cfg.buildtarget.name) + _p(indent + 1, 'BlueprintName = "%s"', prj.name) + _p(indent + 1, 'ReferencedContainer = "container:%s.xcodeproj">', prj.name) + _p(indent + 0, '</BuildableReference>') + end + + +-- +-- Print a CommandLineArgs element, if needed by the provided config. +-- + + local function cmdlineargs(indent, cfg) + if #cfg.debugargs > 0 then + _p(indent, '<CommandLineArguments>') + for _, arg in ipairs(cfg.debugargs) do + _p(indent + 1, '<CommandLineArgument') + _p(indent + 2, 'argument = "%s"', arg) + _p(indent + 2, 'isEnabled = "YES">') + _p(indent + 1, '</CommandLineArgument>') + end + _p(indent, '</CommandLineArguments>') + end + end + + +-- +-- Print an EnvironmentVariables element, if needed by the provided config. + + local function envvars(indent, cfg) + if #cfg.debugenvs > 0 then + _p(indent, '<EnvironmentVariables>') + for _, arg in ipairs(cfg.debugenvs) do + local eq = arg:find("=") + local k = arg:sub(1, eq) + local v = arg:sub(eq + 1) + _p(indent + 1, '<EnvironmentVariable') + _p(indent + 2, 'key = "%s"', arg:sub(1, eq)) + _p(indent + 2, 'value = "%s"', arg:sub(eq)) + _p(indent + 2, 'isEnabled = "YES">') + _p(indent + 1, '</EnvironmentVariable>') + end + _p(indent, '</EnvironmentVariables>') + end + end + + +-- +-- Generate the customWorkingDir path from the given dir. +-- + + local function workingdir(dir) + if not path.isabsolute(dir) then + dir = "$PROJECT_DIR/" .. dir + end + return dir + end + + +-- +-- Determine the best matching configuration. +-- +-- @param fordebug +-- True to find a debug configuration. +-- + + local function bestconfig(prj, fordebug) + local bestcfg = nil + local bestscore = -1 + + for cfg in premake.eachconfig(prj) do + local score = 0 + + if cfg.platform == "Native" then + score = score + 10 + end + + if fordebug and cfg.name == "Debug" then + score = score + 1 + end + + if not fordebug and cfg.name == "Release" then + score = score + 1 + end + + if score > bestscore then + bestcfg = cfg + bestscore = score + end + end + + return bestcfg + end + + +-- +-- Print out an xcscheme file. +-- +-- @param tobuild +-- The list of targets to build. Assumed to be sorted. +-- @param primary +-- The target to set as test/profile/launch target. +-- + + function xcode.scheme(tobuild, primary, schemecfg) + _p('<?xml version="1.0" encoding="UTF-8"?>') + _p('<Scheme') + _p(1, 'LastUpgradeVersion = "0940"') + _p(1, 'version = "1.3">') + _p(1, '<BuildAction') + _p(2, 'parallelizeBuildables = "YES"') + _p(2, 'buildImplicitDependencies = "YES">') + _p(2, '<BuildActionEntries>') + + for _, prj in ipairs(tobuild) do + _p(3, '<BuildActionEntry') + _p(4, 'buildForTesting = "YES"') + _p(4, 'buildForRunning = "YES"') + _p(4, 'buildForProfiling = "YES"') + _p(4, 'buildForArchiving = "YES"') + _p(4, 'buildForAnalyzing = "YES">') + buildableref(4, prj) + _p(3, '</BuildActionEntry>') + end + + local debugcfg = schemecfg or bestconfig(primary, true) + local releasecfg = schemecfg or bestconfig(primary, false) + local debugname = xcode.getconfigname(debugcfg) + local releasename = xcode.getconfigname(releasecfg) + + _p(2, '</BuildActionEntries>') + _p(1, '</BuildAction>') + _p(1, '<TestAction') + _p(2, 'buildConfiguration = "%s"', debugname) + _p(2, 'selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"') + _p(2, 'selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"') + _p(2, 'shouldUseLaunchSchemeArgsEnv = "YES">') + _p(2, '<Testables>') + _p(2, '</Testables>') + _p(2, '<MacroExpansion>') + buildableref(3, primary, debugcfg) + _p(2, '</MacroExpansion>') + _p(2, '<AdditionalOptions>') + _p(2, '</AdditionalOptions>') + _p(1, '</TestAction>') + _p(1, '<LaunchAction') + _p(2, 'buildConfiguration = "%s"', debugname) + _p(2, 'selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"') + _p(2, 'selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"') + _p(2, 'launchStyle = "0"') + if debugcfg.debugdir then + _p(2, 'useCustomWorkingDirectory = "YES"') + _p(2, 'customWorkingDirectory = "%s"', workingdir(debugcfg.debugdir)) + else + _p(2, 'useCustomWorkingDirectory = "NO"') + end + _p(2, 'ignoresPersistentStateOnLaunch = "NO"') + _p(2, 'debugDocumentVersioning = "YES"') + _p(2, 'debugServiceExtension = "internal"') + _p(2, 'allowLocationSimulation = "YES">') + if debugcfg.debugcmd then + _p(2, '<PathRunnable') + _p(3, 'runnableDebuggingMode = "0"') + _p(3, 'FilePath = "%s">', debugcfg.debugcmd) + _p(2, '</PathRunnable>') + else + _p(2, '<BuildableProductRunnable') + _p(3, 'runnableDebuggingMode = "0">') + buildableref(3, primary, debugcfg) + _p(2, '</BuildableProductRunnable>') + end + cmdlineargs(2, debugcfg) + envvars(2, debugcfg) + _p(2, '<AdditionalOptions>') + _p(2, '</AdditionalOptions>') + _p(1, '</LaunchAction>') + _p(1, '<ProfileAction') + _p(2, 'buildConfiguration = "%s"', releasename) + _p(2, 'shouldUseLaunchSchemeArgsEnv = "YES"') + _p(2, 'savedToolIdentifier = ""') + if releasecfg.debugdir then + _p(2, 'useCustomWorkingDirectory = "YES"') + _p(2, 'customWorkingDirectory = "%s"', workingdir(releasecfg.debugdir)) + else + _p(2, 'useCustomWorkingDirectory = "NO"') + end + _p(2, 'debugDocumentVersioning = "YES">') + _p(2, '<BuildableProductRunnable') + _p(3, 'runnableDebuggingMode = "0">') + buildableref(3, primary, releasecfg) + _p(2, '</BuildableProductRunnable>') + cmdlineargs(2, releasecfg) + envvars(2, releasecfg) + _p(1, '</ProfileAction>') + _p(1, '<AnalyzeAction') + _p(2, 'buildConfiguration = "%s">', debugname) + _p(1, '</AnalyzeAction>') + _p(1, '<ArchiveAction') + _p(2, 'buildConfiguration = "%s"', releasename) + _p(2, 'revealArchiveInOrganizer = "YES">') + _p(1, '</ArchiveAction>') + _p('</Scheme>') + end + +-- +-- Generate XCode schemes for the given project. +-- + + function xcode.generate_schemes(prj, base_path) + if (prj.kind == "ConsoleApp" or prj.kind == "WindowedApp") or (prj.options and prj.options.XcodeLibrarySchemes) then + + if prj.options and prj.options.XcodeSchemeNoConfigs then + premake.generate(prj, path.join(base_path, "%%.xcscheme"), + function(prj) xcode.scheme({prj}, prj) end) + else + for cfg in premake.eachconfig(prj) do + premake.generate(prj, path.join(base_path, "%% " .. cfg.name .. ".xcscheme"), + function(prj) xcode.scheme({prj}, prj, cfg) end) + end + end + end + end diff --git a/3rdparty/genie/src/actions/xcode/xcode_workspace.lua b/3rdparty/genie/src/actions/xcode/xcode_workspace.lua new file mode 100644 index 00000000000..ed0542258e7 --- /dev/null +++ b/3rdparty/genie/src/actions/xcode/xcode_workspace.lua @@ -0,0 +1,145 @@ +local premake = premake +local xcode = premake.xcode + +xcode.allscheme = false + +function xcode.workspace_head() + _p('<?xml version="1.0" encoding="UTF-8"?>') + _p('<Workspace') + _p(1,'version = "1.0">') +end + +function xcode.workspace_tail() + _p('</Workspace>') +end + +function xcode.workspace_file_ref(prj, indent) + local projpath = path.getrelative(prj.solution.location, prj.location) + if projpath == '.' then projpath = '' + else projpath = projpath ..'/' + end + _p(indent, '<FileRef') + _p(indent + 1, 'location = "group:%s">', projpath .. prj.name .. '.xcodeproj') + _p(indent, '</FileRef>') +end + +function xcode.workspace_group(grp, indent) + _p(indent, '<Group') + _p(indent + 1, 'location = "container:"') + _p(indent + 1, 'name = "%s">', grp.name) + + local function comparenames(a, b) + return a.name < b.name + end + + local groups = table.join(grp.groups) + local projects = table.join(grp.projects) + table.sort(groups, comparenames) + table.sort(projects, comparenames) + + for _, child in ipairs(groups) do + xcode.workspace_group(child, indent + 1) + end + + for _, prj in ipairs(projects) do + xcode.workspace_file_ref(prj, indent + 1) + end + + _p(indent, '</Group>') +end + +function xcode.workspace_generate(sln) + xcode.preparesolution(sln) + xcode.workspace_head() + xcode.reorderProjects(sln) + + for grp in premake.solution.eachgroup(sln) do + if grp.parent == nil then + xcode.workspace_group(grp, 1) + end + end + + for prj in premake.solution.eachproject(sln) do + if prj.group == nil then + xcode.workspace_file_ref(prj, 1) + end + end + + xcode.workspace_tail() +end + + +-- +-- Generate the `-ALL` scheme, building all targets. +-- + +function xcode.workspace_scheme(sln) + if not xcode.allscheme then + return false + end + + local projects = {} + local primary = nil + + for prj in premake.solution.eachproject(sln) do + if not primary or (sln.startproject == prj.name) then + primary = prj + end + table.insert(projects, prj) + end + + xcode.scheme(projects, primary) +end + +-- +-- Generate the workspace settings file, preventing xcode from auto-generating +-- schemes we have manually provided. +-- + +function xcode.workspace_settings(sln) + _p('<?xml version="1.0" encoding="UTF-8"?>') + _p('<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">') + _p('<plist version="1.0">') + _p('<dict>') + _p(1, '<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>') + _p(1, '<false/>') + _p('</dict>') + _p('</plist>') +end + +-- +-- If a startup project is specified, move it to the front of the project list. +-- This will make Visual Studio treat it like a startup project. +-- + +function xcode.reorderProjects(sln) + if sln.startproject then + for i, prj in ipairs(sln.projects) do + if sln.startproject == prj.name then + -- Move group tree containing the project to start of group list + local cur = prj.group + while cur ~= nil do + -- Remove group from array + for j, group in ipairs(sln.groups) do + if group == cur then + table.remove(sln.groups, j) + break + end + end + + -- Add back at start + table.insert(sln.groups, 1, cur) + cur = cur.parent + end + -- Move the project itself to start + table.remove(sln.projects, i) + table.insert(sln.projects, 1, prj) + break + end + end + end +end + + + + |