rules_xcodeproj icon indicating copy to clipboard operation
rules_xcodeproj copied to clipboard

Feature Request: Xcode SwiftUI Preview Support

Open karim-alweheshy opened this issue 8 months ago • 6 comments

Custom Toolchain and Library Linking Implementation

The Problem

The generated projects had critical issues preventing Xcode Preview App (XOJIT) functionality because it depends on:

  1. Missing Library Dependencies: Preview App couldn't find required static libraries (.a, .dylib.. ect) during linking, causing build failures. It parses it from the build phase.
  2. Missing Search Paths: Library search paths weren't properly configured, leading to linker errors. After adding the above, we need to add the search paths for the PreviewApp to find the .a files.
  3. Toolchain Misalignment: SwiftUI Preview prevents us from injecting swiftc stub. We need to geenrate an entire new xctoolchain.

The Solution

Implement a comprehensive custom toolchain system and enhanced library linking through several interconnected components:

1. Custom Toolchain Generation System

Create a fully functional Xcode toolchain that mirrors the system toolchain but allows for specific tool overrides.

2. Enhanced Library Detection and Linking

Improve library discovery to properly detect and collect library dependencies from compilation providers.

3. Build Phase Enhancement

Ensure discovered libraries are properly included in Xcode targets' build phases.

4. Project-Level Configuration

Update project settings to use custom toolchains and proper search paths to find the libs.

Implementation Progress

Custom Toolchain System

  • [x] Toolchain Discovery: Automatic Xcode version detection and version-specific toolchain identifiers (custom_toolchain.bzl)
  • [x] Symlink Creation: Complete toolchain structure using symlinks to system toolchain for compatibility
  • [x] Tool Override Mechanism: Flexible system allowing specific tools (swiftc, clang, etc.) to be replaced with custom implementations
  • [x] Two-Stage Process: Symlinked base toolchain creation followed by override application
  • [x] Template System: Shell script templates for toolchain creation (custom_toolchain_symlink.sh, custom_toolchain_override.sh)

Library Detection Enhancement

  • [x] Comprehensive Library Collection: Proper identification of static libraries (.a), dynamic libraries (.dylib), and frameworks from both Objective-C and C++ compilation providers (linker_input_files.bzl)
  • [x] Search Path Generation: Automatic generation of library search paths based on discovered library locations
  • [x] Dependency Filtering: Intelligent filtering to avoid circular dependencies by excluding target's own libraries
  • [x] Framework File Tracking: Detailed tracking of framework files and their paths for proper linking

Build Phase Integration

  • [x] Link Binary Build Phase: Enhanced CreateLinkBinaryWithLibrariesBuildPhaseObject.swift to generate proper PBXFrameworksBuildPhase
  • [x] Framework Object Creation: New CreateFrameworkObject.swift for framework references in Xcode project
  • [x] Build File Objects: CreateFrameworkBuildFileObject.swift for managing build file references

Runtime Library Support

  • [x] libclang_rt.iossim.a: Hardcoded inclusion of critical runtime library for iOS Simulator builds
  • [x] Search Path Configuration: Automatic addition of runtime library location to search paths
  • [x] Toolchain Integration: Proper integration into custom toolchain structure

Project Configuration

  • [x] Build Settings: Enhanced PBXProjectBuildSettings.swift for custom toolchain usage
  • [x] Toolchain Selection: Generated projects automatically point to custom toolchain
  • [x] Environment Setup: Proper environment configuration for consistent custom toolchain usage

Testing and Validation

  • [x] Unit Tests: Comprehensive test suite in test/internal/custom_toolchain/ for toolchain generation
  • [x] Integration Tests: Updated fixture tests ensuring generated projects work correctly
  • [x] Build Verification: Maintained compatibility with existing build processes

Project Size Optimization (High Priority)

  • [ ] Problem Analysis: Current implementation generates individual product/build file references per target dependency, causing bloated project files
  • [ ] Product Reference Deduplication: Implement global registry system where each unique library has exactly one product reference regardless of target usage
  • [ ] Shared Build File References: Update reference system to reuse existing references when multiple targets link same library
  • [ ] Search Path Consolidation: Move library search paths from target-level to project-level configuration
  • [ ] Reference Management System: Centralized tracking of target-dependency relationships without duplicating references
  • [ ] Testing with Large Projects: Validate improvements with complex project structures

Complexity: Medium (equivalent to 2-3 days focused development)

Dependency Detection Improvements (High Priority)

  • [ ] Root Cause Investigation: Analyze why certain dependency types aren't captured by current algorithm
  • [ ] Provider Analysis Enhancement: Expand logic to handle complex dependency scenarios, mixed language targets, and transitive dependencies
  • [ ] Filtering Logic Refinement: Make library filtering more precise to avoid excluding valid dependencies
  • [ ] Debugging Infrastructure: Add comprehensive logging and tracing for dependency discovery process
  • [ ] Fallback Mechanisms: Implement alternative discovery paths for edge cases where primary analysis fails
  • [ ] Validation System: Cross-reference discovered dependencies with actual linker requirements to identify gaps
  • [ ] Edge Case Testing: Create comprehensive test cases for problematic configurations

Complexity: High (equivalent to 3-4 days focused development)

Performance and Polish (Medium Priority)

  • [ ] Performance Profiling: Analyze toolchain generation performance and identify bottlenecks
  • [ ] File Operation Optimization: Optimize file operations and implement intelligent caching
  • [ ] Build Time Impact: Monitor and minimize impact on build times
  • [ ] Documentation Updates: Create comprehensive documentation for new features
  • [ ] Troubleshooting Guides: Develop guides for common issues and edge cases
  • [ ] Monitoring System: Establish monitoring for edge cases and validation failures

Implementation Strategy

Phase 1: Project Size Optimization (Priority: High)

Focus on architectural changes to reference generation system to improve developer experience with large project files.

Approach:

  • Implement shared product reference system across targets
  • Update build file reference generation to reuse existing references
  • Reorganize search paths to project-level configuration
  • Test with existing large projects to validate improvements

Phase 2: Dependency Detection Enhancement (Priority: High)

Systematic analysis and enhancement of dependency discovery to address core functionality gaps.

Approach:

  • Conduct deep investigation into dependency detection failures
  • Create comprehensive test cases for problematic edge cases
  • Implement enhanced dependency detection algorithms
  • Add debugging infrastructure for troubleshooting complex scenarios

Phase 3: Performance and Polish (Priority: Medium)

Performance and developer experience improvements.

Approach:

  • Profile toolchain generation performance and optimize bottlenecks
  • Optimize file operations and implement intelligent caching
  • Create comprehensive documentation and troubleshooting guides
  • Establish monitoring and validation for edge cases

Technical Details

Branch: karim/add-custom-toolchain-to-generated-project

Key Files:

  • xcodeproj/internal/custom_toolchain.bzl - Custom toolchain rule implementation
  • xcodeproj/internal/files/linker_input_files.bzl - Enhanced library detection
  • tools/generators/pbxnativetargets/src/Generator/CreateLinkBinaryWithLibrariesBuildPhaseObject.swift - Build phase generation
  • tools/generators/pbxnativetargets/src/Generator/CreateFrameworkObject.swift - Framework object creation
  • tools/generators/pbxproj_prefix/src/Generator/PBXProjectBuildSettings.swift - Project build settings

Current Status

This implementation provides foundational infrastructure that enables reliable Xcode Preview usage while maintaining Bazel build benefits. The system significantly improves Preview App functionality, with remaining work focused on optimization and edge case handling rather than fundamental architectural changes.

The completed work establishes a solid foundation for iOS development workflows, and the outstanding tasks will complete the feature set for production readiness.

karim-alweheshy avatar Jun 20 '25 15:06 karim-alweheshy

Hey @karim-alweheshy, is Xcode 16 compatibility included in the your solution? It seems Xcode 16 no longer uses the "traditional" previewing. "The executable target “XXX” needs the build setting “ENABLE_DEBUG_DYLIB” set to “YES” in order to preview. ", reported by Xcode 16, which likely means this new setting should be reflected in Bazel build process.

zlrs avatar Jul 22 '25 13:07 zlrs

@karim-alweheshy Hey thank you so much for getting this started! I am taking a stab at it this week, and am pushing my changes here: https://github.com/chrisballinger/rules_xcodeproj/pull/1

I had to grab some changes from main, and another patch for app intents (which is not a long term fix). the main thing you might find useful to cherry-pick into your branch is dynamically calculating the xcode path here: https://github.com/chrisballinger/rules_xcodeproj/pull/1/commits/76c8b90261f706dcbe85c2518626ea6f0911d262

chrisballinger avatar Jul 22 '25 18:07 chrisballinger

This might also be of interest to reduce the project size bloat: https://github.com/chrisballinger/rules_xcodeproj/pull/1/commits/c0572cd7e402d13e8b9df052251e9fcbe1ffebe5

chrisballinger avatar Jul 22 '25 21:07 chrisballinger

This somewhat speeds up custom_toolchain_symlink: https://github.com/chrisballinger/rules_xcodeproj/pull/1/commits/e19519acd120ba2573efd451a95ff4088f09f1c2

the parent branch for all of these commits is this PR here: https://github.com/MobileNativeFoundation/rules_xcodeproj/pull/3140

I was able to get your branch up and running for simple targets with minimal dependencies. So far I tried a pure Swift target, a pure Swift target with one Swift dependency, and a Swift target with both Swift and ObjC dependency. Haven't tried a mixed target yet.

Unfortunately for more complicated targets, I am stuck on JIT runtime linking failure. e.g.

[Remote] JITError: Runtime linking failure
    
    Additional Link Time Errors:
    Symbols not found: [ ___isPlatformVersionAtLeast ]
    In static-example_module, failed to materialize { _$s17example_module11ExampleTypeC7withDataOAFSQADWl }, due to unsatisfied dependencies { (static-example_module, { _$s17example_module11ExampleTypeCMn }) } (dependencies removed or in error state)

I have tried a lot of different things to force the JIT linker to find/recognize the libraries it needs, but none of them have panned out.

chrisballinger avatar Jul 27 '25 03:07 chrisballinger

Following up on this Feature Request and couple PRs inflight. Any update re: this effort for SwiftUI preview support? ❤️ @karim-alweheshy @chrisballinger you the best for starting the work on this. Thank you!!

jeffhodsdon avatar Nov 18 '25 04:11 jeffhodsdon

I'm also hopping this is finished, I'm using Playgrounds framework and new Xcode 26 #Playground quite a lot, and I need to keep a separate xcodeproj for that

talesp avatar Dec 11 '25 14:12 talesp