Skip to content
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

Adding missing rpath to Python on Apple Silicon #1467

Merged
merged 3 commits into from
Sep 6, 2023

Conversation

colincornaby
Copy link
Contributor

On Apple Silicon, Homebrew has moved the location its installed its libraries. That means if you are installing a version of Cairo from Homebrew, Python/python3-cairosvg cannot find Cairo, and vcpkg will fail to build python3-cairosvg.

Homebrew's version of Python passes an additional rpath to the configuration phase of the Python build to fix this:
https://github.com/carlocab/homebrew-core/blob/d83d8d4665518494ef7fc3e5a64ba937e69cb06c/Formula/python%403.9.rb#L150

This patch to our Python port also introduces the same patch. I'm still pretty new with vcpkg so I possibly haven't defined this correctly from a maintainable vcpkg perspective. But this fix does block Apple Silicon builds out of the box. I've had to do some manual patching each vcpkg update to work around it.

@dpogue
Copy link
Member

dpogue commented Aug 16, 2023

Two things I'm wondering here:

  1. This should have no ill-effects if the Homebrew directory does not exist?

  2. This does not somehow introduce a potential security hole whereby the game Python interpreter can load modules from the homebrew path? (I assume not, but good to make sure)

I seem to recall that on Windows, we have to build Python as a dynamic library so that we get a working interpreter at build-time that can load the cairo module. I know you're trying to make sure Python is built as a static library on macOS, but do we run into the same issue there when trying to use it at build time?
(grumble grumble back to #1423 and the inability of CMake to find a host Python interpreter and a target Python library)

@colincornaby
Copy link
Contributor Author

It should not cause any failure if the Homebrew path does not exist.

To answer 2 and your follow on question…. It gets weird.

The rpath argument is embedded into the binary and parsed by the dynamic linker. But we build a static version of Python, so this rpath does absolutely nothing for the static library built for Plasma. In since Python is a static library I’m not even sure dynamic loader commands could be embedded at all. What it does effect is the Python executable that is built by vcpkg - which is what the Python Cairo package uses to test it’s integration.

@dpogue
Copy link
Member

dpogue commented Aug 16, 2023

Interesting... okay. So to confirm, on macOS we're able to build both a working Python interpreter executable and a Python static library from vcpkg at the same time?

@colincornaby
Copy link
Contributor Author

That seems to be what is occurring. In the vcpkg output there is also an interpreter that the Cairo module is executing tests against. On Apple Silicon the Cairo module fails during it’s test phase.

@dgelessus
Copy link
Contributor

Hmm, I don't understand why anything should be pulled in from Homebrew when using vcpkg to build the dependencies... Shouldn't Cairo also come from vcpkg in that case?

@Hoikas
Copy link
Member

Hoikas commented Aug 17, 2023

PSF seems to think this is incorrect https://bugs.python.org/issue46381

@colincornaby
Copy link
Contributor Author

Reading the full thread, it seems ok because we use LDFLAGS_NODIST which is the intended mechanism.

python/cpython#90539 (comment)

@Hoikas
Copy link
Member

Hoikas commented Aug 17, 2023

Ok, in that case, it would probably be better to, instead of patching the Python build, pass through the configure option CONFIGURE_LDFLAGS_NODIST from the triplet. That way, we could (potentially) de-vendor the port someday. So, in the triplet, you'll want to do something like:

if(PORT STREQUAL python3)
    set(VCPKG_MAKE_CONFIGURE_OPTIONS "CONFIGURE_LDFLAGS_NODIST=-rpath /opt/homebrew/lib")
endif()

and toss the patch.

@colincornaby
Copy link
Contributor Author

Oooooo thanks. That’s the sort of insight I was looking for. I’ll edit the commit history to reflect only this suggestion.

@colincornaby
Copy link
Contributor Author

That chunk is applying during the Python build - but the output isn't correct. I'm tinkering with it to see if I can figure out the issue.

@colincornaby
Copy link
Contributor Author

colincornaby commented Aug 17, 2023

Ok - there is an issue on the vcpkg side. I can submit a PR - but something is going to get broken possibly.

VCPKG_MAKE_CONFIGURE_OPTIONS is indeed a documented option:
https://learn.microsoft.com/en-us/vcpkg/users/triplets#vcpkg_make_configure_options

This change seems to have intentionally or unintentionally renamed that option to VCPKG_CONFIGURE_MAKE_OPTIONS - without updating the docs:
microsoft/vcpkg@5283cdb#diff-b92b07d5c0c681687d71463c6a368fae98e9ffedb241e2aadbde3aac688899a9L519

(Line 519, scripts/cmake/vcpkg_configure_make.cmake)

So that's why it wasn't working. I can use VCPKG_CONFIGURE_MAKE_OPTIONS for now. But something is not right.

@colincornaby
Copy link
Contributor Author

I've gone ahead and implemented the change through a history rewrite - accounting for the issue noted in the previous comment.

@dgelessus
Copy link
Contributor

Why do we need to add Homebrew paths to the linker flags at all though? If a library is missing, the proper fix would be to add it as a dependency in our vcpkg.json, not pull it in from a different package manager - right?

@dpogue
Copy link
Member

dpogue commented Aug 17, 2023

If a library is missing, the proper fix would be to add it as a dependency in our vcpkg.json, not pull it in from a different package manager - right?

For the case of cairo, since it's an optional dependency used only on the host system to generate resource.dat at build time, we've been pulling it from package managers on macOS and Linux. On Windows we do pull it in with vcpkg though, so that's an option if it makes our lives easier:

Plasma/vcpkg.json

Lines 55 to 59 in d863078

{
"name": "cairo",
"platform": "windows",
"default-features": false
},

@colincornaby
Copy link
Contributor Author

I'm not completely sure that would work on macOS - but I could try. When vcpkg builds the library it won't add it to a search path, taking us right back where we started. The Python interpreter won't be able to use Cairo because it won't be in a known path.

@dgelessus
Copy link
Contributor

For the case of cairo, [...], we've been pulling it from package managers on macOS and Linux.

On Linux it's not a problem in practice, because often you already have Cairo installed system-wide as a dependency of the usual GUI environments. On macOS you usually need to install it manually, and when you do, it will be in a location that isn't searched by default by many things, which is suboptimal.

since it's an optional dependency used only on the host system to generate resource.dat at build time

Ah okay, that makes some sense. But is there any disadvantage to using vcpkg for such dependencies as well (especially if we already do that on Windows)? There's even already some code in VcpkgToolchain.cmake that skips installing Cairo if you turn off PLASMA_BUILD_RESOURCE_DAT, so you can always do that if the extra dependency is an issue.

When vcpkg builds the library it won't add it to a search path, taking us right back where we started. The Python interpreter won't be able to use Cairo because it won't be in a known path.

That would make things more difficult... but in that case, I'd argue that the right fix/workaround is to put vcpkg's directories onto the Python search path, rather than depending on Homebrew.

(Side note: I personally use MacPorts and don't even have Homebrew installed, so I get a bit peeved when things have special defaults that only work for Homebrew 🙂 But regardless of that, I think we shouldn't depend on more than one package manager, unless there's a very good reason for it.)

@Hoikas
Copy link
Member

Hoikas commented Aug 17, 2023

I'm not completely sure that would work on macOS - but I could try. When vcpkg builds the library it won't add it to a search path, taking us right back where we started. The Python interpreter won't be able to use Cairo because it won't be in a known path.

If we went this route, we would need to copy the cairo DLL into the Python site-packages in the install step in our python3-cairosvg port.

@colincornaby
Copy link
Contributor Author

colincornaby commented Aug 18, 2023

I think I probably could just point the rpath at the vcpkg dir instead of the Homebrew dir.

Overall what would be required is:

  • Building Cairo as a dylib instead of as a static library (easy)
  • Building Cairo for the host architecture instead of the destination architecture (easy)
  • Getting the path to Cairo lib folder within the triplet (not sure how to do this)

@Hoikas
Copy link
Member

Hoikas commented Aug 18, 2023

Building Cairo for the host architecture instead of the destination architecture (easy)

python3-cairosvg should probably be marked "host": true

@colincornaby
Copy link
Contributor Author

Alright - let's try this approach. :)

This pulls Cairo from vcpkg. It also sets up the rpath to look for Cairo within the vcpkg installed directory. Cairo is no longer required from Homebrew.

I didn't remove the Homebrew install from Github actions yet. If this builds successfully in Github Actions I'll go ahead and do so.

@colincornaby colincornaby changed the title Adding missing Homebrew rpath to Python on Apple Silicon Adding missing rpath to Python on Apple Silicon Aug 19, 2023
@@ -13,3 +13,7 @@ if(PORT STREQUAL cairo)
set(VCPKG_BUILD_TYPE release)
endif()

if(PORT STREQUAL python3)
set(VCPKG_CONFIGURE_MAKE_OPTIONS "LDFLAGS_NODIST=-rpath ${CURRENT_INSTALLED_DIR}/lib")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Python documentation says that this should be CONFIGURE_LDFLAGS_NODIST

@@ -12,3 +12,7 @@ if(PORT STREQUAL cairo)
set(VCPKG_LIBRARY_LINKAGE dynamic)
set(VCPKG_BUILD_TYPE release)
endif()

if(PORT STREQUAL python3)
set(VCPKG_CONFIGURE_MAKE_OPTIONS "LDFLAGS_NODIST=-rpath ${CURRENT_INSTALLED_DIR}/lib")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Python documentation says that this should be CONFIGURE_LDFLAGS_NODIST

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CONFIGURE_LDFLAGS_NODIST does not seem to work. Build fails when I switch to that argument.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the same error this is trying to fix in the Python Cairo module. It's as if no configure arguments are applied at all.

vcpkg.json Outdated
"platform": "windows",
"default-features": false
"default-features": false,
"host": true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be removed from here and put into the manifest for python3-cairosvg, then host: true should cascade properly.

"platform": "windows",
"default-features": false
"default-features": false,
"host": true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python3-cairosvg in the project's manifest should probably be "host": true so that it will cascade properly. What you seem to be asking for here, in my mind, if you're on x64 macOS cross-compiling for ARM, x64 cairo and ARM python3.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a bit of breakage going on in vcpkg that I've talked about with @dpogue that may be at play here. But - just to clarify - is Cairo only used for Resource.dat generation? I think it's only needed by the host.

What's actually needed in a cross compile (that might be broken right now):

  • Client architecture Python
  • Host architecture Python for build processes
  • Host architecture Cairo
  • Host architecture python3-cairo

(The above assumes that my understanding of Cairo as a build related tool is correct and not part of the client.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct. We want for cairo to cascade to host arch by marking python3-cairosvg as host.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be confused because I feel like this is the opposite of this comment here:
#1467 (comment)

I think I'm confused on whats being asked for.

Copy link
Member

@Hoikas Hoikas Aug 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the root vcpkg.json:

{
    "name": "python3-cairosvg",
    "host": true
}

In python3-cairosvg's json, cairo is a regular dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I understand what you're asking and I edited the last commit. Let me know if thats what you were thinking. I removed Cairo from the root manifest and am allowing python3-cairosvg to pull it through.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you do need to remove the "platform": "windows" line in python3-cairosvg's config file though, otherwise it's going to skip installing cairo on macOS: https://github.com/H-uru/Plasma/blob/master/Scripts/Ports/python3-cairosvg/vcpkg.json#L9

@colincornaby
Copy link
Contributor Author

I've updated the commit to remove the Windows gate for the Cairo dependency.

@Hoikas Hoikas merged commit 4285442 into H-uru:master Sep 6, 2023
14 checks passed
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.

4 participants