Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/prepare-testing/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ runs:
git submodule update --init --depth 1 project/test/util/json_assert

- name: Download artifact
uses: actions/download-artifact@v4
uses: actions/download-artifact@v7
with:
name: sentry-godot-gdextension
path: project/
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/build_gdextension.yml
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ jobs:
scons platform=${{matrix.platform}} target=${{matrix.target}} arch=${{matrix.arch}} ${{matrix.scons-flags}}

- name: Upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: sentry.${{matrix.platform}}.${{matrix.target}}.${{matrix.arch}}${{ contains(matrix.scons-flags, 'threads=no') && '.nothreads' || '' }}
path: |
Expand All @@ -319,7 +319,7 @@ jobs:
run: ./gradlew assemble

- name: Upload artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: sentry.android.godot_plugin
# NOTE: Include-exclude pattern forces archive to start with project/ as root directory.
Expand All @@ -341,7 +341,7 @@ jobs:
submodules: recursive

- name: Download iOS artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v7
with:
pattern: sentry.ios.*
path: project/
Expand All @@ -366,7 +366,7 @@ jobs:
rm -rf project/addons/sentry/bin/ios/temp/

- name: Upload artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: sentry.ios-framework
# NOTE: Include-exclude pattern forces archive to start with project/ as root directory.
Expand All @@ -386,7 +386,7 @@ jobs:
needs: [build, android-plugin, ios-framework]
steps:
- name: Merge artifacts
uses: actions/upload-artifact/merge@v4
uses: actions/upload-artifact/merge@v6
with:
name: sentry-godot-gdextension
pattern: sentry.*
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
uses: actions/checkout@v4

- name: Download artifact
uses: actions/download-artifact@v4
uses: actions/download-artifact@v7
with:
name: sentry-godot-gdextension
path: artifact/
Expand Down Expand Up @@ -108,7 +108,7 @@ jobs:
zip -r ${GITHUB_WORKSPACE}/out/${archive_file} ./*

- name: Upload artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: ${{github.sha}}
path: out/*
11 changes: 9 additions & 2 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ arch = env["arch"]
env.Tool("copy")
env.Tool("separate_debug_symbols")
env.Tool("plist")
env.Tool("link_bundle")

# Restore original ARGUMENTS and add custom options to environment
ARGUMENTS.clear()
Expand Down Expand Up @@ -225,13 +226,14 @@ elif platform == "macos":
# *** Build macOS shared library.

lib_name = f"libsentry.{platform}.{build_type}{extra}"
lib_path = f"{out_dir}/{lib_name}.framework/{lib_name}"
lib_path = f"{out_dir}/{lib_name}.framework/Versions/A/{lib_name}"

library = env.SharedLibrary(lib_path, source=sources)
Default(library)

# Create Info.plist
plist_path = f"{out_dir}/{lib_name}.framework/Resources/Info.plist"
res_path = f"{out_dir}/{lib_name}.framework/Versions/A/Resources"
plist_path = f"{res_path}/Info.plist"
plist = env.FrameworkPlist(File(plist_path), File("SConstruct"),
bundle_executable=lib_name,
bundle_identifier=f"io.sentry.SentryForGodot.{build_type}",
Expand All @@ -241,6 +243,11 @@ elif platform == "macos":
Depends(plist, library)
Default(plist)

# Framework
framework_done = env.Alias('framework_done', [plist, library])
Default(framework_done)
env.LinkBundle(f"{out_dir}/{lib_name}.framework/", framework_done)

else:
# *** Build shared library on other platforms.

Expand Down
80 changes: 8 additions & 72 deletions modules/sentry-cocoa.SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -73,70 +73,6 @@ def detect_xcode():
Exit(1)


def flatten_framework(framework_path):
"""Flatten macOS framework by removing symlinks and versioned structure"""
framework_path = Path(framework_path)
if not framework_path.exists():
print(f"ERROR: Framework not found at {framework_path}")
Exit(1)

versions_dir = framework_path / "Versions"
if not versions_dir.exists():
# Framework doesn't need flattening.
return

print(f"Flattening framework structure: {framework_path}")

# 1. Remove all symlinks from the root of the framework
for item_path in framework_path.iterdir():
if item_path.is_symlink():
print(f" Removing symlink: {item_path.name}")
item_path.unlink()

# 2. Move Versions/A/* to root of the framework
version_a_dir = versions_dir / "A"
if version_a_dir.exists():
print(" Moving contents from Versions/A/ to root")
for item_path in version_a_dir.iterdir():
dest_path = framework_path / item_path.name

# Handle potential conflicts
if dest_path.exists():
print(f" WARNING: {item_path.name} already exists at root, removing old version")
remove_if_exists(dest_path)

shutil.move(str(item_path), str(dest_path))
print(f" Moved: {item_path.name}")
else:
print(f" WARNING: Versions/A directory not found in {framework_path}")

# 3. Remove Versions/ directory
print(" Removing Versions directory")
shutil.rmtree(versions_dir)

# 4. Patch the binary's install name for flattened structure
binary_name = framework_path.name.replace('.framework', '')
binary_path = framework_path / binary_name

if not binary_path.exists():
print(f"ERROR: Framework binary not found at {binary_path}")
Exit(1)

print(f" Patching install name for binary: {binary_name}")
install_name = f"@rpath/{binary_name}.framework/{binary_name}"
cmd = ["install_name_tool", "-id", install_name, str(binary_path)]

try:
subprocess.run(cmd, capture_output=True, text=True, check=True)
print(f" Successfully updated install name to: {install_name}")
except subprocess.CalledProcessError as e:
print(f" WARNING: Failed to update install name: {e}")
print(f" stdout: {e.stdout}")
print(f" stderr: {e.stderr}")

print(f"Framework flattening completed: {framework_path}")


def update_cocoa_framework():
"""Updates Sentry Cocoa to the latest version."""
project_root = Path(env.Dir("#").abspath)
Expand Down Expand Up @@ -184,9 +120,6 @@ def update_cocoa_framework():
print(f"Extracting {zip_path}")
extract_zip_with_symlinks(zip_path, cocoa_dir)

# NOTE: We need to flatten macOS slice due to issues with symlinks on Windows.
flatten_framework(cocoa_dir / "Sentry-Dynamic.xcframework" / "macos-arm64_x86_64" / "Sentry.framework")

zip_path.unlink() # delete file
version_file.write_text(cocoa_version)

Expand Down Expand Up @@ -242,7 +175,7 @@ if platform in ["macos", "ios"]:
"-framework", "Sentry",
"-F" + str(framework_container_dir),
# Allow extension to find framework in addons/sentry/ directory.
"-Wl,-rpath,@loader_path/..",
"-Wl,-rpath,@loader_path/../../..",
]
)

Expand Down Expand Up @@ -405,11 +338,14 @@ def DeploySentryCocoa(self, target_dir):
target_framework = target_dir_path / "Sentry.framework"

# Copy only the binary and "Resources" dir -- we don't need to export headers or modules.
# commands.append(
# env.Copy(File(target_framework / "Sentry"), File(source_framework / "Sentry"))
# )
# commands.append(
# env.Copy(Dir(target_framework / "Resources"), Dir(source_framework / "Resources"))
# )
commands.append(
env.Copy(File(target_framework / "Sentry"), File(source_framework / "Sentry"))
)
commands.append(
env.Copy(Dir(target_framework / "Resources"), Dir(source_framework / "Resources"))
env.Copy(Dir(target_framework), Dir(source_framework))
)

# Debug symbols
Expand Down
74 changes: 74 additions & 0 deletions site_scons/site_tools/link_bundle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""
Tool to create framework symlinks as post-process action.

Usage: env.LinkBundle(FRAMEWORK_PATH, FRAMEWORK_TARGET)

This tool expects the framework path to contain a Versions/A subdirectory
with complete bundle resources after the specified targets are built.

Example:
env.LinkBundle("mylib.framework/", [framework_resources])
"""

import os
from SCons.Script import Action


def link_bundle_action(target, source, env, framework_path):
"""Post-process action to create framework symlinks"""
framework_dir = os.path.abspath(framework_path)
version_dir = f"{framework_dir}/Versions/A"

if not os.path.exists(version_dir):
print(f"Versions/A directory does not exist: {version_dir}")
return False

original_cwd = os.getcwd()
os.chdir(framework_dir)

try:
# Create Current -> A symlink in Versions directory
versions_dir = os.path.dirname(version_dir)
current_link = os.path.join(versions_dir, "Current")
version_name = os.path.basename(version_dir)

if os.path.islink(current_link):
os.unlink(current_link)

os.chdir(versions_dir)
os.symlink(version_name, "Current")
print(f"Created symlink: Current -> {version_name}")

os.chdir(framework_dir)

# Create symlinks in framework root that point to Versions/Current/*
for item in os.listdir(version_dir):
link_name = item
relative_target = os.path.join("Versions", "Current", item)

if os.path.islink(link_name):
os.unlink(link_name)

os.symlink(relative_target, link_name)
print(f"Created symlink: {link_name} -> {relative_target}")
finally:
os.chdir(original_cwd)

return True


def command(env, framework_path, target):
# Closure captures framework_path
def action(target, source, env):
link_bundle_action(target, source, env, framework_path)

env.AddPostAction(target, Action(action, cmdstr=f"Creating framework symlinks in {framework_path}"))
return target


def generate(env):
env.AddMethod(command, "LinkBundle")


def exists(env):
return True
Loading