From 22b6a339a7561086e4f556b9e26b3bbde3b43a65 Mon Sep 17 00:00:00 2001 From: JX-Master Date: Thu, 3 Apr 2025 12:06:48 +0800 Subject: Add new native xcode generator (xcode2). --- xmake/plugins/project/xcode2/pbxproj.lua | 239 +++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 xmake/plugins/project/xcode2/pbxproj.lua (limited to 'xmake/plugins/project/xcode2/pbxproj.lua') diff --git a/xmake/plugins/project/xcode2/pbxproj.lua b/xmake/plugins/project/xcode2/pbxproj.lua new file mode 100644 index 000000000..d7f5a559a --- /dev/null +++ b/xmake/plugins/project/xcode2/pbxproj.lua @@ -0,0 +1,239 @@ +--!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, TBOOX Open Source Group. +-- +-- @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 + table.insert(lines, "\t\t\t\t" .. child .. ",") + 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 .. ";") + table.insert(lines, "\t\t\tproductReference = " .. obj.productReference .. ";") + 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 = { + ENABLE_USER_SCRIPT_SANDBOXING = NO; + }; + 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 \ No newline at end of file -- cgit v1.3.1 From 8b48aee3110ea81162a66c6909ec07de24ba3e90 Mon Sep 17 00:00:00 2001 From: JX-Master Date: Mon, 28 Apr 2025 11:33:38 +0800 Subject: Add macOS application bundle (.app) generation support. --- xmake/plugins/project/xcode2/get_xcode_info.lua | 62 ++++++++++++++++++------- xmake/plugins/project/xcode2/pbxproj.lua | 42 +++++++++++++++-- 2 files changed, 83 insertions(+), 21 deletions(-) (limited to 'xmake/plugins/project/xcode2/pbxproj.lua') diff --git a/xmake/plugins/project/xcode2/get_xcode_info.lua b/xmake/plugins/project/xcode2/get_xcode_info.lua index 388b273bf..d95834998 100644 --- a/xmake/plugins/project/xcode2/get_xcode_info.lua +++ b/xmake/plugins/project/xcode2/get_xcode_info.lua @@ -64,25 +64,38 @@ function _add_PBXGroup(xcinfo, name, sourceTree) return uuid end -function _add_XCBuildConfiguration(xcinfo, mode) +-- target may be nil. +function _add_XCBuildConfiguration(xcinfo, mode, target) local obj = {} obj.name = mode obj.buildSettings = {} -- This allows scripts to read/write files that are not in the Input/Output list of -- the phase. obj.buildSettings.ENABLE_USER_SCRIPT_SANDBOXING = false + if target then + local rules = target:rules() + local is_app_bundle = false + if rules["xcode.application"] ~= nil then + is_app_bundle = true + end + if is_app_bundle then + obj.buildSettings.GENERATE_INFOPLIST_FILE = true + obj.buildSettings.PRODUCT_NAME = "$(TARGET_NAME)" + end + end local uuid = xcinfo:gen_uuid() xcinfo.sections.XCBuildConfiguration = xcinfo.sections.XCBuildConfiguration or {} xcinfo.sections.XCBuildConfiguration[uuid] = obj return uuid end -function _add_XCConfigurationList(xcinfo) +-- target may be nil. +function _add_XCConfigurationList(xcinfo, target) local obj = {} local modes = _get_project_modes() obj.buildConfigurations = {} for _, mode in ipairs(modes) do - table.insert(obj.buildConfigurations, _add_XCBuildConfiguration(xcinfo, mode)) + table.insert(obj.buildConfigurations, _add_XCBuildConfiguration(xcinfo, mode, target)) end local uuid = xcinfo:gen_uuid() xcinfo.sections.XCConfigurationList = xcinfo.sections.XCConfigurationList or {} @@ -98,19 +111,16 @@ XMAKE_BIN=\"]] .. os.programfile() .. [[\" # Running xmake scripts. ${XMAKE_BIN} f -y -m ${CONFIGURATION} -p ${PLATFORM_NAME} -a ${NATIVE_ARCH} -o ${BUILD_DIR} ${XMAKE_BIN} build ${TARGET_NAME}\n# Running xmake install scripts. -${XMAKE_BIN} install -o ${CONFIGURATION_TEMP_DIR}/Install ${TARGET_NAME} +XMAKE_BUILD_DIR=${BUILD_DIR}/${PLATFORM_NAME}/${NATIVE_ARCH}/${CONFIGURATION} # Copy files to build path. -if test -e ${CONFIGURATION_TEMP_DIR}/Install/bin +if test -e ${CONFIGURATION_BUILD_DIR} then - cp -r ${CONFIGURATION_TEMP_DIR}/Install/bin/* ${CONFIGURATION_BUILD_DIR} + rm -r ${CONFIGURATION_BUILD_DIR}/* fi -if test -e ${CONFIGURATION_TEMP_DIR}/Install/lib +if test -e ${XMAKE_BUILD_DIR} then - cp -r ${CONFIGURATION_TEMP_DIR}/Install/lib/* ${CONFIGURATION_BUILD_DIR} + cp -r ${XMAKE_BUILD_DIR}/* ${CONFIGURATION_BUILD_DIR} fi -cp -r ${CONFIGURATION_TEMP_DIR}/Install/*.app ${CONFIGURATION_BUILD_DIR} -# Remove install dir. -rm -r ${CONFIGURATION_TEMP_DIR}/Install\n\n ]] local uuid = xcinfo:gen_uuid() xcinfo.sections.PBXShellScriptBuildPhase = xcinfo.sections.PBXShellScriptBuildPhase or {} @@ -137,6 +147,8 @@ function _add_target_files(xcinfo, group, files) file_info.lastKnownFileType = "sourcecode.cpp.cpp" elseif ext == ".mm" then file_info.lastKnownFileType = "sourcecode.cpp.objcpp" + elseif ext == ".plist" then + file_info.lastKnownFileType = "text.plist" end table.insert(group.children, _add_PBXFileReference(xcinfo, file_info)) end @@ -146,6 +158,11 @@ function _add_PBXNativeTarget(xcinfo, target_name, target) local obj = {} obj.name = target_name obj.productName = target_name + local rules = target:rules() + local is_app_bundle = false + if rules["xcode.application"] ~= nil then + is_app_bundle = true + end -- Add product file. local product_file = {} if target:kind() == "static" then @@ -153,14 +170,27 @@ function _add_PBXNativeTarget(xcinfo, target_name, target) elseif target:kind() == "shared" then product_file.explicitFileType = "com.apple.product-type.library.dynamic" elseif target:kind() == "binary" then - product_file.explicitFileType = "com.apple.product-type.tool" + if is_app_bundle then + product_file.explicitFileType = "wrapper.application" + else + product_file.explicitFileType = "com.apple.product-type.tool" + end end - product_file.path = target:filename() + if is_app_bundle then + product_file.name = target:filename() .. ".app" + else + product_file.name = target:filename() + end + product_file.path = product_file.name product_file.sourceTree = "BUILT_PRODUCTS_DIR" product_file.includeInIndex = 0 obj.productReference = _add_PBXFileReference(xcinfo, product_file) - obj.productType = product_file.explicitFileType - -- Add product file to product group. + if is_app_bundle then + obj.productType = "com.apple.product-type.application" + else + obj.productType = product_file.explicitFileType + end + -- Add product file to product group. local project_obj = xcinfo.sections.PBXProject[xcinfo.root_object] local product_group = xcinfo.sections.PBXGroup[project_obj.productRefGroup] table.insert(product_group.children, obj.productReference) @@ -179,7 +209,7 @@ function _add_PBXNativeTarget(xcinfo, target_name, target) table.insert(main_group.children, obj.headerFileGroup) table.insert(main_group.children, obj.sourceFileGroup) -- Add configuration list for target. - obj.buildConfigurationList = _add_XCConfigurationList(xcinfo) + obj.buildConfigurationList = _add_XCConfigurationList(xcinfo, target) -- Add build phases. obj.buildPhases = {} table.insert(obj.buildPhases, _add_PBXShellScriptBuildPhase(xcinfo, target)) diff --git a/xmake/plugins/project/xcode2/pbxproj.lua b/xmake/plugins/project/xcode2/pbxproj.lua index d7f5a559a..3f66bcd20 100644 --- a/xmake/plugins/project/xcode2/pbxproj.lua +++ b/xmake/plugins/project/xcode2/pbxproj.lua @@ -70,7 +70,18 @@ function _write_section_PBXGroup(info, lines) end table.insert(lines, "\t\t\tchildren = (") for _, child in ipairs(obj.children) do - table.insert(lines, "\t\t\t\t" .. child .. ",") + 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 .. "\";") @@ -98,7 +109,15 @@ function _write_section_PBXNativeTarget(info, lines) table.insert(lines, "\t\t\tpackageProductDependencies = (") table.insert(lines, "\t\t\t);") table.insert(lines, "\t\t\tproductName = " .. obj.productName .. ";") - table.insert(lines, "\t\t\tproductReference = " .. obj.productReference .. ";") + 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 @@ -173,9 +192,22 @@ function _write_section_XCBuildConfiguration(info, lines) table.insert(lines, "\t\t" .. uuid .. " /* " .. obj.name .. " */ = {") table.insert(lines, [[ isa = XCBuildConfiguration; - buildSettings = { - ENABLE_USER_SCRIPT_SANDBOXING = NO; - }; + 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 -- cgit v1.3.1 From 5659468ff81b1c80576a03a88b0402483b436172 Mon Sep 17 00:00:00 2001 From: JX-Master Date: Fri, 27 Jun 2025 12:00:04 +0800 Subject: Fix product name issue. Add SDKROOT build settings. --- xmake/plugins/project/xcode2/get_xcode_info.lua | 9 ++++++++- xmake/plugins/project/xcode2/pbxproj.lua | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'xmake/plugins/project/xcode2/pbxproj.lua') diff --git a/xmake/plugins/project/xcode2/get_xcode_info.lua b/xmake/plugins/project/xcode2/get_xcode_info.lua index d95834998..05fe21895 100644 --- a/xmake/plugins/project/xcode2/get_xcode_info.lua +++ b/xmake/plugins/project/xcode2/get_xcode_info.lua @@ -80,8 +80,15 @@ function _add_XCBuildConfiguration(xcinfo, mode, target) end if is_app_bundle then obj.buildSettings.GENERATE_INFOPLIST_FILE = true - obj.buildSettings.PRODUCT_NAME = "$(TARGET_NAME)" + obj.buildSettings.PRODUCT_NAME = "\"$(TARGET_NAME)\"" end + else + -- This is for root project. + obj.buildSettings.SUPPORTED_PLATFORMS = "\"macosx iphoneos\"" + obj.buildSettings.SDKROOT = "macosx" + obj.buildSettings["\"SDKROOT[sdk=macosx*]\""] = "macosx" + obj.buildSettings["\"SDKROOT[sdk=iphoneos]\""] = "iphoneos" + end local uuid = xcinfo:gen_uuid() xcinfo.sections.XCBuildConfiguration = xcinfo.sections.XCBuildConfiguration or {} diff --git a/xmake/plugins/project/xcode2/pbxproj.lua b/xmake/plugins/project/xcode2/pbxproj.lua index 3f66bcd20..b9cddd3ae 100644 --- a/xmake/plugins/project/xcode2/pbxproj.lua +++ b/xmake/plugins/project/xcode2/pbxproj.lua @@ -200,7 +200,7 @@ function _write_section_XCBuildConfiguration(info, lines) elseif v == false then string_value = "NO" elseif type(v) == "string" then - string_value = "\"" .. v .. "\"" + string_value = v elseif type(v) == "number" then string_value = tostring(v) end -- cgit v1.3.1 From da18ca701757c653587831d13e57e772b96edad2 Mon Sep 17 00:00:00 2001 From: ruki Date: Wed, 2 Jul 2025 10:03:07 +0800 Subject: Update pbxproj.lua --- xmake/plugins/project/xcode2/pbxproj.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'xmake/plugins/project/xcode2/pbxproj.lua') diff --git a/xmake/plugins/project/xcode2/pbxproj.lua b/xmake/plugins/project/xcode2/pbxproj.lua index b9cddd3ae..ef2d73abf 100644 --- a/xmake/plugins/project/xcode2/pbxproj.lua +++ b/xmake/plugins/project/xcode2/pbxproj.lua @@ -162,7 +162,7 @@ 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, "\t\t" .. uuid .. " /* Run Xmake Build Command */ = {") table.insert(lines, [[ isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -173,7 +173,7 @@ function _write_section_PBXShellScriptBuildPhase(info, lines) ); inputPaths = ( ); - name = "xmake build"; + name = "Xmake Build"; outputFileListPaths = ( ); outputPaths = ( @@ -257,7 +257,7 @@ function _write_pbxproj(info) write_section(info, lines) end - table.insert(lines, + table.insert(lines, [[ }; rootObject = ]] .. info.root_object .. [[ /* Project object */; }]]) @@ -268,4 +268,4 @@ 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 \ No newline at end of file +end -- cgit v1.3.1