Skip to content

Instantly share code, notes, and snippets.

@ctreffs
Forked from keith/README.md
Created October 28, 2021 10:15
Show Gist options
  • Save ctreffs/bcc127db10a7f050314ff2323990dc05 to your computer and use it in GitHub Desktop.
Save ctreffs/bcc127db10a7f050314ff2323990dc05 to your computer and use it in GitHub Desktop.

Revisions

  1. @keith keith revised this gist Jan 17, 2021. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -7,8 +7,9 @@

    # Notes

    1. Passing `-Xfrontend -enable-implicit-dynamic` removes you from having to add `dynamic` to everything you want to be replacable
    2. Passing `-enable-private-imports` to the `main.swift` build, and then `-Xfrontend -disable-access-control` to the dylib build stops you from having to make things `public` unnecessarily. Depending on the use case if the symbols are `public` already you could remove these flags
    3. The dylib compilation depends on the main module. I was hoping I could use a string or something instead and specify `main.Foo.bar` explicitly instead of having to depend `main` directly for building.
    - Passing `-Xfrontend -enable-implicit-dynamic` removes you from having to add `dynamic` to everything you want to be replacable
    - Passing `-enable-private-imports` to the `main.swift` build, and then `-Xfrontend -disable-access-control` to the dylib build stops you from having to make things `public` unnecessarily. Depending on the use case if the symbols are `public` already you could remove these flags
    - The dylib compilation depends on the main module. I was hoping I could use a string or something instead and specify `main.Foo.bar` explicitly instead of having to depend `main` directly for building
    - There must be a better way than passing `-undefined suppress -flat_namespace` to the linker for the dylib compilation. You could pass `-U SYMBOL` but I think that's a bit more annoying to track down and maintain

    Useful reference: https://tech.guardsquare.com/posts/swift-native-method-swizzling
  2. @keith keith revised this gist Jan 17, 2021. 2 changed files with 7 additions and 7 deletions.
    10 changes: 5 additions & 5 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,14 +1,14 @@
    # Usage

    1. `swiftc main.swift -emit-module-path main.swiftmodule -emit-executable`
    1. `swiftc main.swift -emit-module-path main.swiftmodule -emit-executable -enable-private-imports -Xfrontend -enable-implicit-dynamic`
    2. `./main` -> prints `From original bar()`
    3. `swiftc -emit-library inject.swift -o inject.dylib -I . -Xlinker -undefined -Xlinker suppress -Xlinker -flat_namespace`
    3. `swiftc -emit-library inject.swift -o inject.dylib -I . -Xlinker -undefined -Xlinker suppress -Xlinker -flat_namespace -Xfrontend -disable-access-control`
    4. `DYLD_INSERT_LIBRARIES=inject.dylib ./main` -> prints `From replacement bar()`

    # Notes

    1. The symbols in `main.swift` have to be public even though I don't think they should. I tried using `-Xfrontend -disable-access-control` when building the dylib, which works for the build, but the symbol fails to be found at runtime because it's local not external. Besides marking the type / function as `public` I don't see any compiler or linker flags to force these external (Using `-exported_symbol '_$s4main3FooV3baryyFTx'` throws this warning: `ld: warning: cannot export hidden symbol ...`)
    2. The dylib compilation depends on the main module. I was hoping I could use a string or something instead and specify `main.Foo.bar` explicitly instead of having to depend `main` directly for building.
    3. You can remove the explicit `dynamic` on `Foo.bar` if you pass `-Xfrontend -enable-implicit-dynamic`
    1. Passing `-Xfrontend -enable-implicit-dynamic` removes you from having to add `dynamic` to everything you want to be replacable
    2. Passing `-enable-private-imports` to the `main.swift` build, and then `-Xfrontend -disable-access-control` to the dylib build stops you from having to make things `public` unnecessarily. Depending on the use case if the symbols are `public` already you could remove these flags
    3. The dylib compilation depends on the main module. I was hoping I could use a string or something instead and specify `main.Foo.bar` explicitly instead of having to depend `main` directly for building.

    Useful reference: https://tech.guardsquare.com/posts/swift-native-method-swizzling
    4 changes: 2 additions & 2 deletions main.swift
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    public struct Foo {
    public dynamic func bar() {
    struct Foo {
    func bar() {
    print("From original bar()")
    }
    }
  3. @keith keith revised this gist Jan 17, 2021. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -8,4 +8,7 @@
    # Notes

    1. The symbols in `main.swift` have to be public even though I don't think they should. I tried using `-Xfrontend -disable-access-control` when building the dylib, which works for the build, but the symbol fails to be found at runtime because it's local not external. Besides marking the type / function as `public` I don't see any compiler or linker flags to force these external (Using `-exported_symbol '_$s4main3FooV3baryyFTx'` throws this warning: `ld: warning: cannot export hidden symbol ...`)
    2. The dylib compilation depends on the main module. I was hoping I could use a string or something instead and specify `main.Foo.bar` explicitly instead of having to depend `main` directly for building.
    2. The dylib compilation depends on the main module. I was hoping I could use a string or something instead and specify `main.Foo.bar` explicitly instead of having to depend `main` directly for building.
    3. You can remove the explicit `dynamic` on `Foo.bar` if you pass `-Xfrontend -enable-implicit-dynamic`

    Useful reference: https://tech.guardsquare.com/posts/swift-native-method-swizzling
  4. @keith keith revised this gist Jan 17, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -8,4 +8,4 @@
    # Notes

    1. The symbols in `main.swift` have to be public even though I don't think they should. I tried using `-Xfrontend -disable-access-control` when building the dylib, which works for the build, but the symbol fails to be found at runtime because it's local not external. Besides marking the type / function as `public` I don't see any compiler or linker flags to force these external (Using `-exported_symbol '_$s4main3FooV3baryyFTx'` throws this warning: `ld: warning: cannot export hidden symbol ...`)
    2. The dylib injection compilation depends on the main module. I was hoping I could use a string or something instead and specify `main.Foo.bar` explicitly instead of having to depend `main` directly for building.
    2. The dylib compilation depends on the main module. I was hoping I could use a string or something instead and specify `main.Foo.bar` explicitly instead of having to depend `main` directly for building.
  5. @keith keith created this gist Jan 17, 2021.
    11 changes: 11 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    # Usage

    1. `swiftc main.swift -emit-module-path main.swiftmodule -emit-executable`
    2. `./main` -> prints `From original bar()`
    3. `swiftc -emit-library inject.swift -o inject.dylib -I . -Xlinker -undefined -Xlinker suppress -Xlinker -flat_namespace`
    4. `DYLD_INSERT_LIBRARIES=inject.dylib ./main` -> prints `From replacement bar()`

    # Notes

    1. The symbols in `main.swift` have to be public even though I don't think they should. I tried using `-Xfrontend -disable-access-control` when building the dylib, which works for the build, but the symbol fails to be found at runtime because it's local not external. Besides marking the type / function as `public` I don't see any compiler or linker flags to force these external (Using `-exported_symbol '_$s4main3FooV3baryyFTx'` throws this warning: `ld: warning: cannot export hidden symbol ...`)
    2. The dylib injection compilation depends on the main module. I was hoping I could use a string or something instead and specify `main.Foo.bar` explicitly instead of having to depend `main` directly for building.
    8 changes: 8 additions & 0 deletions inject.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    import main

    extension Foo {
    @_dynamicReplacement(for: bar)
    func replacementBar() {
    print("From replacement bar()")
    }
    }
    7 changes: 7 additions & 0 deletions main.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    public struct Foo {
    public dynamic func bar() {
    print("From original bar()")
    }
    }

    Foo().bar()