Abstract apple framework creation behind a tool, which will `lipo` the input binaries together and create an appropriate `Info.plist`.
parent
47f11bc5c7
commit
3bfe5fd1e5
|
@ -18,29 +18,29 @@ if env["target"] in ["editor", "template_debug"]:
|
||||||
doc_data = env.GodotCPPDocData("src/gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml"))
|
doc_data = env.GodotCPPDocData("src/gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml"))
|
||||||
sources.append(doc_data)
|
sources.append(doc_data)
|
||||||
|
|
||||||
if env["platform"] == "macos":
|
library_targets = env.SharedLibrary(
|
||||||
library = env.SharedLibrary(
|
|
||||||
"project/bin/libgdexample.{}.{}.framework/libgdexample.{}.{}".format(
|
|
||||||
env["platform"], env["target"], env["platform"], env["target"]
|
|
||||||
),
|
|
||||||
source=sources,
|
|
||||||
)
|
|
||||||
elif env["platform"] == "ios":
|
|
||||||
if env["ios_simulator"]:
|
|
||||||
library = env.StaticLibrary(
|
|
||||||
"project/bin/libgdexample.{}.{}.simulator.a".format(env["platform"], env["target"]),
|
|
||||||
source=sources,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
library = env.StaticLibrary(
|
|
||||||
"project/bin/libgdexample.{}.{}.a".format(env["platform"], env["target"]),
|
|
||||||
source=sources,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
library = env.SharedLibrary(
|
|
||||||
"project/bin/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
|
"project/bin/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
|
||||||
source=sources,
|
source=sources,
|
||||||
)
|
)
|
||||||
|
|
||||||
env.NoCache(library)
|
if env["platform"] == "macos" or env["platform"] == "ios":
|
||||||
Default(library)
|
# The app store requires signed .framework bundles for dependencies.
|
||||||
|
# We do not sign the test framework bundles, but for consistency
|
||||||
|
# (and testing) we will always generate the .framework anyway.
|
||||||
|
framework_tool = Tool("apple_framework", toolpath=["../tools"])
|
||||||
|
|
||||||
|
framework_name = f"gdexample.{env['platform']}.{env['target']}"
|
||||||
|
library_targets = framework_tool.generate(
|
||||||
|
f"project/bin/{framework_name}.framework",
|
||||||
|
env=env,
|
||||||
|
source=library_targets,
|
||||||
|
plist_entries=dict(
|
||||||
|
CFBundleIdentifier=f"org.godotengine.{framework_name}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Keep the final build intact for as long as possible.
|
||||||
|
env.Precious(library_targets)
|
||||||
|
|
||||||
|
env.NoCache(library_targets)
|
||||||
|
Default(library_targets)
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>libgdexample.template_debug</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>org.godotengine.libgdexample</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>libgdexample.macos.template_debug</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>FMWK</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.0.0</string>
|
|
||||||
<key>CFBundleSupportedPlatforms</key>
|
|
||||||
<array>
|
|
||||||
<string>MacOSX</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1.0.0</string>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>10.12</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>libgdexample.template_release</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>org.godotengine.libgdexample</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>libgdexample.macos.template_release</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>FMWK</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.0.0</string>
|
|
||||||
<key>CFBundleSupportedPlatforms</key>
|
|
||||||
<array>
|
|
||||||
<string>MacOSX</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1.0.0</string>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>10.12</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -5,8 +5,8 @@ compatibility_minimum = "4.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
|
||||||
macos.debug = "res://bin/libgdexample.macos.template_debug.framework"
|
macos.debug = "res://bin/gdexample.macos.template_debug.framework"
|
||||||
macos.release = "res://bin/libgdexample.macos.template_release.framework"
|
macos.release = "res://bin/gdexample.macos.template_release.framework"
|
||||||
windows.debug.x86_32 = "res://bin/libgdexample.windows.template_debug.x86_32.dll"
|
windows.debug.x86_32 = "res://bin/libgdexample.windows.template_debug.x86_32.dll"
|
||||||
windows.release.x86_32 = "res://bin/libgdexample.windows.template_release.x86_32.dll"
|
windows.release.x86_32 = "res://bin/libgdexample.windows.template_release.x86_32.dll"
|
||||||
windows.debug.x86_64 = "res://bin/libgdexample.windows.template_debug.x86_64.dll"
|
windows.debug.x86_64 = "res://bin/libgdexample.windows.template_debug.x86_64.dll"
|
||||||
|
@ -27,17 +27,17 @@ android.debug.x86_64 = "res://bin/libgdexample.android.template_debug.x86_64.so"
|
||||||
android.release.x86_64 = "res://bin/libgdexample.android.template_release.x86_64.so"
|
android.release.x86_64 = "res://bin/libgdexample.android.template_release.x86_64.so"
|
||||||
android.debug.arm64 = "res://bin/libgdexample.android.template_debug.arm64.so"
|
android.debug.arm64 = "res://bin/libgdexample.android.template_debug.arm64.so"
|
||||||
android.release.arm64 = "res://bin/libgdexample.android.template_release.arm64.so"
|
android.release.arm64 = "res://bin/libgdexample.android.template_release.arm64.so"
|
||||||
ios.debug = "res://bin/libgdexample.ios.template_debug.xcframework"
|
ios.debug = "res://bin/libgdexample.ios.template_debug.framework"
|
||||||
ios.release = "res://bin/libgdexample.ios.template_release.xcframework"
|
ios.release = "res://bin/libgdexample.ios.template_release.framework"
|
||||||
web.debug.threads.wasm32 = "res://bin/libgdexample.web.template_debug.wasm32.wasm"
|
web.debug.threads.wasm32 = "res://bin/gdexample.web.template_debug.wasm32.wasm"
|
||||||
web.release.threads.wasm32 = "res://bin/libgdexample.web.template_release.wasm32.wasm"
|
web.release.threads.wasm32 = "res://bin/gdexample.web.template_release.wasm32.wasm"
|
||||||
web.debug.wasm32 = "res://bin/libgdexample.web.template_debug.wasm32.nothreads.wasm"
|
web.debug.wasm32 = "res://bin/libgdexample.web.template_debug.wasm32.nothreads.wasm"
|
||||||
web.release.wasm32 = "res://bin/libgdexample.web.template_release.wasm32.nothreads.wasm"
|
web.release.wasm32 = "res://bin/libgdexample.web.template_release.wasm32.nothreads.wasm"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ios.debug = {
|
ios.debug = {
|
||||||
"res://bin/libgodot-cpp.ios.template_debug.xcframework": ""
|
"res://bin/libgodot-cpp.ios.template_debug.framework": ""
|
||||||
}
|
}
|
||||||
ios.release = {
|
ios.release = {
|
||||||
"res://bin/libgodot-cpp.ios.template_release.xcframework": ""
|
"res://bin/libgodot-cpp.ios.template_release.framework": ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
|
||||||
|
def exists(env):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def options(opts):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def generate(
|
||||||
|
target,
|
||||||
|
*,
|
||||||
|
env,
|
||||||
|
source,
|
||||||
|
min_macos_version="10.12",
|
||||||
|
min_ios_version="12.0",
|
||||||
|
plist_entries=None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Generates an Apple .framework folder, containing the binary and metadata.
|
||||||
|
Framework structures are required to be able to sign binaries.
|
||||||
|
Signing binaries is required to avoid the apple gatekeeper, and to be accepted into the App Store.
|
||||||
|
See https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html
|
||||||
|
|
||||||
|
:param target: Folder name of the framework, usually ending in `.framework`.
|
||||||
|
:param env: The environment.
|
||||||
|
:param source: A list of binary sources to generate.
|
||||||
|
:param min_macos_version: The minimum macOS version supported by the framework, if the platform is macos.
|
||||||
|
:param min_ios_version: The minimum iOS version supported by the framework, if the platform is iOS.
|
||||||
|
:param plist_entries: Additional keys to send to the plist generator.
|
||||||
|
:return: Targets for framework creation, where the first item is the binary generator.
|
||||||
|
"""
|
||||||
|
if env["platform"] == "macos":
|
||||||
|
dt_platform_name = "macosx"
|
||||||
|
min_os_part = f"LSMinimumSystemVersion={min_macos_version}"
|
||||||
|
elif env["platform"] == "ios":
|
||||||
|
dt_platform_name = "iphoneos"
|
||||||
|
min_os_part = f"MinimumOSVersion={min_ios_version}"
|
||||||
|
else:
|
||||||
|
raise ValueError("Unsupported platform.")
|
||||||
|
|
||||||
|
framework_path = pathlib.Path(target)
|
||||||
|
assert framework_path.suffix == ".framework"
|
||||||
|
framework_name = framework_path.name.removesuffix(".framework")
|
||||||
|
|
||||||
|
parent_path = pathlib.Path(__file__).parent
|
||||||
|
plist_creation_script_path = (parent_path / "create_apple_framework_plist.sh").relative_to(os.getcwd())
|
||||||
|
plist_command = f"{plist_creation_script_path} $TARGET --entry CFBundleExecutable={framework_name} --entry DTPlatformName={dt_platform_name} --entry {min_os_part}"
|
||||||
|
if plist_entries:
|
||||||
|
for key, value in plist_entries.items():
|
||||||
|
plist_command += f' --entry "{key}={value}"'
|
||||||
|
|
||||||
|
return [
|
||||||
|
# Create the binary itself.
|
||||||
|
env.Command(
|
||||||
|
str(framework_path / framework_name),
|
||||||
|
source,
|
||||||
|
action="lipo -create $SOURCE -output $TARGET",
|
||||||
|
),
|
||||||
|
# Create the Info.plist.
|
||||||
|
env.Command(
|
||||||
|
str(framework_path / "Resources" / "Info.plist"),
|
||||||
|
[str(plist_creation_script_path)],
|
||||||
|
action=plist_command,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,128 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
USAGE_STRING="Usage: $0 plist_path --entry CFBundleExecutable=executable [--entry key=value]..."
|
||||||
|
|
||||||
|
PLIST_PATH=""
|
||||||
|
PLIST_ENTRIES=()
|
||||||
|
|
||||||
|
# Parse the command line arguments.
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--entry)
|
||||||
|
IFS='=' read -r key value <<< "$2"
|
||||||
|
# Replace if key exists, otherwise add new key-value.
|
||||||
|
found=false
|
||||||
|
for ((i=0; i<${#PLIST_ENTRIES[@]}; i++)); do
|
||||||
|
if [[ "${PLIST_ENTRIES[i]}" =~ ^$key= ]]; then
|
||||||
|
PLIST_ENTRIES[i]="$key=$value"
|
||||||
|
found=true
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$found" = false ]; then
|
||||||
|
PLIST_ENTRIES+=("$key=$value")
|
||||||
|
fi
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Assume positional argument is the plist path.
|
||||||
|
if [ -n "$PLIST_PATH" ]; then
|
||||||
|
# Cannot generate more than one plist; this was likely an error.
|
||||||
|
echo "$USAGE_STRING"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
PLIST_PATH="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Extract known keys from PLIST_ENTRIES, for defaults and mandatory arguments.
|
||||||
|
for ((i=0; i<${#PLIST_ENTRIES[@]}; i++)); do
|
||||||
|
IFS='=' read -r key value <<< "${PLIST_ENTRIES[$i]}"
|
||||||
|
case $key in
|
||||||
|
CFBundleInfoDictionaryVersion)
|
||||||
|
CFBundleInfoDictionaryVersion="$value"
|
||||||
|
;;
|
||||||
|
CFBundlePackageType)
|
||||||
|
CFBundlePackageType="$value"
|
||||||
|
;;
|
||||||
|
CFBundleName)
|
||||||
|
CFBundleName="$value"
|
||||||
|
;;
|
||||||
|
CFBundleExecutable)
|
||||||
|
CFBundleExecutable="$value"
|
||||||
|
;;
|
||||||
|
CFBundleIdentifier)
|
||||||
|
CFBundleIdentifier="$value"
|
||||||
|
;;
|
||||||
|
CFBundleVersion)
|
||||||
|
CFBundleVersion="$value"
|
||||||
|
;;
|
||||||
|
CFBundleShortVersionString)
|
||||||
|
CFBundleShortVersionString="$value"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check for mandatory arguments.
|
||||||
|
if [ -z "$PLIST_PATH" ] || [ -z "$CFBundleExecutable" ]; then
|
||||||
|
echo "$USAGE_STRING"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add defaults for missing arguments.
|
||||||
|
if [ -z "$CFBundleInfoDictionaryVersion" ]; then
|
||||||
|
CFBundleInfoDictionaryVersion="6.0"
|
||||||
|
PLIST_ENTRIES+=("CFBundleInfoDictionaryVersion=$CFBundleInfoDictionaryVersion")
|
||||||
|
fi
|
||||||
|
if [ -z "$CFBundlePackageType" ]; then
|
||||||
|
CFBundlePackageType="FMWK"
|
||||||
|
PLIST_ENTRIES+=("CFBundlePackageType=$CFBundlePackageType")
|
||||||
|
fi
|
||||||
|
if [ -z "$CFBundleName" ]; then
|
||||||
|
CFBundleName="$CFBundleExecutable"
|
||||||
|
PLIST_ENTRIES+=("CFBundleName=$CFBundleName")
|
||||||
|
fi
|
||||||
|
if [ -z "$CFBundleIdentifier" ]; then
|
||||||
|
CFBundleIdentifier="com.example.$CFBundleName"
|
||||||
|
PLIST_ENTRIES+=("CFBundleIdentifier=$CFBundleIdentifier")
|
||||||
|
fi
|
||||||
|
if [ -z "$CFBundleVersion" ]; then
|
||||||
|
CFBundleVersion="1.0.0"
|
||||||
|
PLIST_ENTRIES+=("CFBundleVersion=$CFBundleVersion")
|
||||||
|
fi
|
||||||
|
if [ -z "$CFBundleShortVersionString" ]; then
|
||||||
|
CFBundleShortVersionString="$CFBundleVersion"
|
||||||
|
PLIST_ENTRIES+=("CFBundleShortVersionString=$CFBundleShortVersionString")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure the directory exists.
|
||||||
|
mkdir -p "$(dirname "$PLIST_PATH")"
|
||||||
|
|
||||||
|
# Create the Info.plist file.
|
||||||
|
{
|
||||||
|
echo '<?xml version="1.0" encoding="UTF-8"?>'
|
||||||
|
echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
|
||||||
|
echo '<plist version="1.0">'
|
||||||
|
echo '<dict>'
|
||||||
|
|
||||||
|
for ((i=0; i<${#PLIST_ENTRIES[@]}; i++)); do
|
||||||
|
IFS='=' read -r key value <<< "${PLIST_ENTRIES[$i]}"
|
||||||
|
if [[ -n "$value" ]]; then
|
||||||
|
echo " <key>$key</key>"
|
||||||
|
echo " <string>$value</string>"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo '</dict>'
|
||||||
|
echo '</plist>'
|
||||||
|
} > "$PLIST_PATH"
|
||||||
|
|
||||||
|
# Confirm Info.plist was created.
|
||||||
|
if [ -s "$PLIST_PATH" ]; then
|
||||||
|
echo "$PLIST_PATH"
|
||||||
|
else
|
||||||
|
echo "Failed to create $PLIST_PATH."
|
||||||
|
exit 1
|
||||||
|
fi
|
Loading…
Reference in New Issue