--!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author JXMaster -- @file pbxproj.lua -- -- imports import("core.project.config") import("core.project.project") function _write_file_if_needed(file, content) if os.isfile(file) and io.readfile(file) == content then dprint("skipped file %s since the file has the same content", path.relative(file)) return end -- we need utf8 with bom encoding for unicode -- @see https://github.com/xmake-io/xmake/issues/1689 io.writefile(file, content, {encoding = "utf8"}) end function _write_section_PBXFileReference(info, lines) table.insert(lines, "/* Begin PBXFileReference section */") for uuid, obj in table.orderpairs(info.sections.PBXFileReference) do table.insert(lines, "\t\t" .. uuid .. " = {") table.insert(lines, "\t\t\tisa = PBXFileReference;") if obj.explicitFileType then table.insert(lines, "\t\t\texplicitFileType = \"" .. obj.explicitFileType .. "\";") end if obj.lastKnownFileType then table.insert(lines, "\t\t\tlastKnownFileType = \"" .. obj.lastKnownFileType .. "\";") end if obj.includeInIndex then table.insert(lines, "\t\t\tincludeInIndex = " .. obj.includeInIndex .. ";") end if obj.name then table.insert(lines, "\t\t\tname = \"" .. obj.name .. "\";") end if obj.path then table.insert(lines, "\t\t\tpath = \"" .. obj.path .. "\";") end if obj.sourceTree then table.insert(lines, "\t\t\tsourceTree = " .. obj.sourceTree .. ";") end table.insert(lines, "\t\t};") end table.insert(lines, "/* End PBXFileReference section */") end function _write_section_PBXGroup(info, lines) table.insert(lines, "/* Begin PBXGroup section */") for uuid, obj in table.orderpairs(info.sections.PBXGroup) do table.insert(lines, "\t\t" .. uuid .. " = {") table.insert(lines, "\t\t\tisa = PBXGroup;") if obj.name then table.insert(lines, "\t\t\tname = \"" .. obj.name .. "\";") end table.insert(lines, "\t\t\tchildren = (") for _, child in ipairs(obj.children) do local child_obj = info.sections.PBXFileReference[child] if child_obj == nil then child_obj = info.sections.PBXGroup[child] end local child_name if child_obj then child_name = child_obj.name end if child_name == nil then child_name = "" end table.insert(lines, "\t\t\t\t" .. child .. " /* " .. child_name .. " */,") end table.insert(lines, "\t\t\t);") table.insert(lines, "\t\t\tsourceTree = \"" .. obj.sourceTree .. "\";") table.insert(lines, "\t\t};") end table.insert(lines, "/* End PBXGroup section */") end function _write_section_PBXNativeTarget(info, lines) table.insert(lines, "/* Begin PBXNativeTarget section */") for uuid, obj in table.orderpairs(info.sections.PBXNativeTarget) do table.insert(lines, "\t\t" .. uuid .. " /* " .. obj.name .. " */ = {") table.insert(lines, "\t\t\tisa = PBXNativeTarget;") table.insert(lines, "\t\t\tbuildConfigurationList = " .. obj.buildConfigurationList .. " /* Build configuration list for PBXNativeTarget \"" .. obj.name .. "\" */;") table.insert(lines, "\t\t\tbuildPhases = (") for _, build_phase_uuid in ipairs(obj.buildPhases) do table.insert(lines, "\t\t\t\t" .. build_phase_uuid .. ",") end table.insert(lines, "\t\t\t);") table.insert(lines, "\t\t\tbuildRules = (") table.insert(lines, "\t\t\t);") table.insert(lines, "\t\t\tdependencies = (") table.insert(lines, "\t\t\t);") table.insert(lines, "\t\t\tname = " .. obj.name .. ";") table.insert(lines, "\t\t\tpackageProductDependencies = (") table.insert(lines, "\t\t\t);") table.insert(lines, "\t\t\tproductName = " .. obj.productName .. ";") local product_reference_name local product_reference_obj = info.sections.PBXFileReference[obj.productReference] if product_reference_obj then product_reference_name = product_reference_obj.name end if product_reference_name == nil then product_reference_name = "" end table.insert(lines, "\t\t\tproductReference = " .. obj.productReference .. " /* " .. product_reference_name .. " */;") table.insert(lines, "\t\t\tproductType = " .. obj.productType .. ";") table.insert(lines, "\t\t};") end table.insert(lines, "/* End PBXNativeTarget section */") end function _write_section_PBXProject(info, lines) table.insert(lines, "/* Begin PBXProject section */") for uuid, obj in table.orderpairs(info.sections.PBXProject) do table.insert(lines, "\t\t" .. uuid .. " /* Project object */ = {") table.insert(lines, "\t\t\tisa = PBXProject;") table.insert(lines, [[ attributes = { BuildIndependentTargetsInParallel = 1; };]]) table.insert(lines, "\t\t\tbuildConfigurationList = " .. obj.buildConfigurationList .. " /* Build configuration list for PBXProject */;") table.insert(lines, [[ developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, );]]) table.insert(lines, "mainGroup = " .. obj.mainGroup .. ";") table.insert(lines, [[ minimizedProjectReferenceProxies = 1; preferredProjectObjectVersion = 77;]]) table.insert(lines, "productRefGroup = " .. obj.productRefGroup .. ";") table.insert(lines, [[ projectDirPath = ""; projectRoot = "";]]) table.insert(lines, "\t\t\ttargets = (") for _, target_uuid in ipairs(obj.targets) do table.insert(lines, "\t\t\t\t" .. target_uuid .. " /* " .. info.sections.PBXNativeTarget[target_uuid].name .. " */,") end table.insert(lines, "\t\t\t);") table.insert(lines, "\t\t};") end table.insert(lines, "/* End PBXProject section */") end function _write_section_PBXShellScriptBuildPhase(info, lines) table.insert(lines, "/* Begin PBXShellScriptBuildPhase section */") for uuid, obj in table.orderpairs(info.sections.PBXShellScriptBuildPhase) do table.insert(lines, "\t\t" .. uuid .. " /* Run Xmake Build Command */ = {") table.insert(lines, [[ isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); name = "Xmake Build"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "]] .. obj.shellScript .. "\";") table.insert(lines, "\t\t};") end table.insert(lines, "/* End PBXShellScriptBuildPhase section */") end function _write_section_XCBuildConfiguration(info, lines) table.insert(lines, "/* Begin XCBuildConfiguration section */") for uuid, obj in table.orderpairs(info.sections.XCBuildConfiguration) do table.insert(lines, "\t\t" .. uuid .. " /* " .. obj.name .. " */ = {") table.insert(lines, [[ isa = XCBuildConfiguration; buildSettings = {]]) for k, v in pairs(obj.buildSettings) do local string_value = "" if v == true then string_value = "YES" elseif v == false then string_value = "NO" elseif type(v) == "string" then string_value = v elseif type(v) == "number" then string_value = tostring(v) end table.insert(lines, "\t\t\t\t" .. k .. " = " .. string_value .. ";") end table.insert(lines, [[ }; name = ]] .. obj.name .. ";") table.insert(lines, "\t\t};") end table.insert(lines, "/* End XCBuildConfiguration section */") end function _write_section_XCConfigurationList(info, lines) table.insert(lines, "/* Begin XCConfigurationList section */") for uuid, obj in table.orderpairs(info.sections.XCConfigurationList) do table.insert(lines, "\t\t" .. uuid .. " = {") table.insert(lines, [[ isa = XCConfigurationList; buildConfigurations = (]]) for _, build_config in ipairs(obj.buildConfigurations) do table.insert(lines, "\t\t\t\t" .. build_config .. " /* " .. info.sections.XCBuildConfiguration[build_config].name .. " */,") end table.insert(lines, [[ ); defaultConfigurationIsVisible = 0;]]) table.insert(lines, "\t\t};") end table.insert(lines, "/* End XCConfigurationList section */") end local write_section_funcs = { _write_section_PBXFileReference, _write_section_PBXGroup, _write_section_PBXNativeTarget, _write_section_PBXProject, _write_section_PBXShellScriptBuildPhase, _write_section_XCBuildConfiguration, _write_section_XCConfigurationList } function _write_pbxproj(info) local lines = {} table.insert(lines, [[// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 77; objects = { ]]) -- write sections. for _, write_section in ipairs(write_section_funcs) do write_section(info, lines) end table.insert(lines, [[ }; rootObject = ]] .. info.root_object .. [[ /* Project object */; }]]) return table.concat(lines, "\n") .. "\n" end function main(info) local content = _write_pbxproj(info) local file_name = path.join(info.project_dir, info.project_bundle, "project.pbxproj") _write_file_if_needed(file_name, content) end