Skip to content

Update USAGE.md for iOS and macOS #249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 20 commits into from
Closed

Update USAGE.md for iOS and macOS #249

wants to merge 20 commits into from

Conversation

frogcjn
Copy link

@frogcjn frogcjn commented Feb 14, 2025

Update iOS and macOS usage for Swift and PythonKit

Solve the problem which usage.md is outdated for path settings, and how to edit Python.framework to fit Swift module requirements.

Fixs #234

PR Checklist:

  • All new features have been tested
  • All new features have been documented
  • I have read the CONTRIBUTING.md file
  • I will abide by the code of conduct

@frogcjn
Copy link
Author

frogcjn commented Feb 14, 2025

I have updated README.md to a more clear structure, and described a better way to fit the swift module requirement, instead of changing target - build settings - search path - Header Search Paths: $(BUILT_PRODUCTS_DIR)/Python.framework/Headers

@freakboy3742

@freakboy3742
Copy link
Member

Thanks for the PR; however, I merged a fix for #234 about 5 minutes before you submitted this PR. As a result, at the very least, this PR currently contains merge conflicts.

However, even allowing for that, I'm not sure I agree the rest of the changes you've made are entirely beneficial.

  1. The details you've got here don't take into account the other change that I made in Improve support for PythonKit, and update usage guide #248 - the support packages now include a modulemap file.
  2. Suggestions to move files in the Python framework aren't viable as a solution, because those files are part of Python itself. For those to be acceptable changes, they'd need to be made upstream in CPython - including a change in the documentation. At the very least, such changes would need to be candidates for being merged upstream.
  3. I'm not convinced making a separate case for "non-PythonKit" makes sense in the way you've described here. The "non-PythonKit Swift" option is really just "use the Embedded C API", which is what option 1 in that section describes.

There's probably a case for splitting out the non PythonKit parts into a "The manual way, but with Swift" option earlier in the usage guide, and then making the PythonKit discussion just about Pythonkit. However, that's quite a way from what this PR currently has, so I'm going to close this PR and tackle that refactor as a separate update.

@frogcjn
Copy link
Author

frogcjn commented Feb 15, 2025

@freakboy3742 happy to see you update the Usage.md in more clear structure.

  1. module.modulemap location
    module.modulemap should be in the Python.framework/Module/ folder, as documented in clang doc, and change its first line from module Python { to framework module Python {

    In this case, when you add Python.xcframework to macOS project and iOS project, there is no need to adjust Target - Build settings - Search path - Header Search Paths to $(BUILT_PRODUCTS_DIR)/Python.framework/Headers

    This is the right location to put module.modulemap in the framework. But we have to pay attention to fix a relative path bug in Headers/cpython/pyatomic.h

    • edit Headers/cpython/pyatomic.h, in the file:
      • replace cpython/pyatomic_gcc.h with pyatomic_gcc.h
      • replace cpython/pyatomic_std.h with pyatomic_std.h
      • replace cpython/pyatomic_msc.h with pyatomic_msc.h

    With these two change, we just create an empty macOS project, just drag this fixed version Python.xcframework in, and everything works, no more steps to change the build settings.

    As documented in my Notion note:
    https://frogcjn.notion.site/Swift-with-Python-Step-by-Step-1984959764ca80999f25cf9897df83bc

  2. Swift Code to test Python framework without PythonKit package

    import Foundation
    import Python
    
    func setEnvs() {
        #if os(macOS)
        print("macOS do not need set envs")
        #else
        guard let pythonHome = Bundle.main.path(forResource: "python", ofType: nil) else { return }
        setenv("PYTHONHOME", pythonHome, 1)
    
        /*
             The PYTHONPATH for the interpreter includes:
             the python/lib/python3.X subfolder of your app’s bundle,
             the python/lib/python3.X/lib-dynload subfolder of your app’s bundle, and
             the app subfolder of your app’s bundle
        */
        guard let pythonPath = Bundle.main.path(forResource: "python/lib/python3.13", ofType: nil) else { return }
        guard let libDynLoad = Bundle.main.path(forResource: "python/lib/python3.13/lib-dynload", ofType: nil) else { return }
        let appPath = Bundle.main.path(forResource: "app", ofType: nil)
        setenv("PYTHONPATH", [pythonPath, libDynLoad, appPath].compactMap { $0 }.joined(separator: ":"), 1)
        #endif
    }
    
    setEnvs()
    Py_Initialize()
    let version = String(cString: Py_GetVersion())
    print(version)
    // we now have a Python interpreter ready to be used

@freakboy3742
Copy link
Member

modulemap.module should be in the Python.framework/Module/modulemap.module, and change its first line from module Python { to framework module Python {

That's not what your original comment described.

Can you clarify the difference between framework module Python { in a Module folder, and module Python { in the Headers folder?

In this case, when you add Python.xcframework to macOS project and iOS project, there is no need to adjust Target - Build settings - Search path - Header Search Paths to $(BUILT_PRODUCTS_DIR)/Python.framework/Headers

This is the right location to put modulemap.module in the framework. But we have to pay attention to fix a relative path bug in Headers/cpython/pyatomic.h

With these two change, we just create an empty macOS project, just drag this fixed version Python.xcframework in, and everything works, no more steps to change the build settings.

I understand that, and I agree that "just drop it in" would be preferable. However, the files you're proposing to move around are part of CPython.

I'm happy to add a modulemap because that's a capability that doesn't exist in the official CPython sources, but it's plausible that it could be added. I'm not going to make arbitrary changes to the locations of files just to make one specific use case easier. They're in that location for a reason, and we can't arbitrarily move them without consequences.

This might indicate there's a problem with CPython itself - in which case, the place to fix this is in CPython. I'm a member of the CPython core team, so I'm open to suggestions on things should be fixed, and I'm in a position to ensure those fixes are applied. In the meantime, I'm not going to deviate from what CPython is just for the convenience of this distribution project.

@frogcjn
Copy link
Author

frogcjn commented Feb 15, 2025

@freakboy3742
So the framework keyword mark the framework as Darwin-style framework, clang and Xcode will recognize it, know where its header location (Name.framework/Header), we do not need specify header search path in Xcode.

This is well documented in the clang doc

截屏2025-02-14 20 26 04

I also provided an update Swift Code to test Python framework without PythonKit package

Next step I'll try to wrap the Python.xcframework in a Swift Package

@freakboy3742
Copy link
Member

This is well documented in the clang doc

That explains what a framework module is, but it doesn't really explain the difference between that and a non-framework module.

Also - in my testing, whether I use the framework module or the non-framework module, I get over 100 warnings raised saying "Umbrella header for module 'Python' does not include header ..." for marshal.h, py_curses.h, errcode.h, (and over 100 others, many of which are in the internal folder). This seems to suggest that there are additional definitions required.

I also provided an update Swift Code to test Python framework without PythonKit package

The best way to contribute changes is as a pull request. Pointing me at a Notion document or referring to another project is very difficult for me to determine what change you're proposing to make.

Next step I'll try to wrap the Python.xcframework in a Swift Package

Sure - again, if there's something I can add to Python's generated framework that improves usage for Swift, I'm happy to consider those changes.

Also - if you've got suggestions for additional changes, it's a lot easier to open new tickets, or continue a discussion on an open pull request, rather than commenting on a ticket that has already been closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants