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

brew.sh: create current symlink in pkgconfig directory #13664

Closed
wants to merge 6 commits into from

Conversation

carlocab
Copy link
Member

@carlocab carlocab commented Aug 7, 2022

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes? Here's an example.
  • Have you successfully run brew style with your changes locally?
  • Have you successfully run brew typecheck with your changes locally?
  • Have you successfully run brew tests with your changes locally?

pkg-config currently hardcodes the OS version it was built on in its
pc path in order to find the .pc files shipped with Homebrew. This
requires reinstallation of pkg-config with OS upgrades, which is
something we currently do not handle.

We can avoid this by automatically creating a current symlink that
points to the right directory whenever brew.sh runs. This will require
a rebuild of pkg-config that points it to the current directory.

In order to simplify identifying the right directory to symlink to, I've
dropped the patch version from HOMEBREW_OS_VERSION on Catalina and
earlier. I don't think this should break anything, but I can try a
different approach if this will cause problems.

`pkg-config` currently hardcodes the OS version it was built on in its
pc path in order to find the `.pc` files shipped with Homebrew. This
requires reinstallation of `pkg-config` with OS upgrades, which is
something we currently do not handle.

We can avoid this by automatically creating a `current` symlink that
points to the right directory whenever `brew.sh` runs. This will require
a rebuild of `pkg-config` that points it to the `current` directory.

In order to simplify identifying the right directory to symlink to, I've
dropped the patch version from `HOMEBREW_OS_VERSION` on Catalina and
earlier. I don't think this should break anything, but I can try a
different approach if this will cause problems.
@BrewTestBot
Copy link
Member

Review period will end on 2022-08-09 at 00:00:00 UTC.

@BrewTestBot BrewTestBot added the waiting for feedback Merging is blocked until sufficient time has passed for review label Aug 7, 2022
carlocab added a commit to carlocab/homebrew-core that referenced this pull request Aug 7, 2022
@carlocab
Copy link
Member Author

carlocab commented Aug 7, 2022

pkg-config rebuild: Homebrew/homebrew-core#107528

@carlocab carlocab requested a review from Bo98 August 7, 2022 15:51
else
HOMEBREW_OS_VERSION="macOS ${HOMEBREW_MACOS_VERSION}"
HOMEBREW_MACOS_VERSION_NUMBER="${HOMEBREW_MACOS_VERSION%.*}"
Copy link
Member

Choose a reason for hiding this comment

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

The name HOMEBREW_MACOS_VERSION_NUMBER feels too similar to HOMEBREW_MACOS_VERSION_NUMERIC.

This does slightly change how analytics work but I don't know if we actually have full access to patch versions there anyway or not (and if such data is useful or not).

Copy link
Member Author

@carlocab carlocab Aug 7, 2022

Choose a reason for hiding this comment

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

I can also just skip defining HOMEBREW_MACOS_VERSION_NUMBER and strip out the "macOS " from HOMEBREW_OS_VERSION. Would that be better?

As for patch information, I think we just end up throwing that away. We discard patch information in our analytics reporting, for example. I haven't checked if dropping the patch version breaks the aggregation.

Copy link
Member

@Bo98 Bo98 Aug 7, 2022

Choose a reason for hiding this comment

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

I honestly see no reason to strip patch information from HOMEBREW_OS_VERSION so it really could just be a constant "macOS ${HOMEBREW_MACOS_VERSION}" for that.

I'm not entirely sure why the original patch stripping was implemented. I believe it was when from when our analytics page had separate entries for each macOS full version but that is no longer the case as we merge them over on the homebrew-formula-analytics side.

Copy link
Member

@Bo98 Bo98 Aug 8, 2022

Choose a reason for hiding this comment

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

Yeah it was analytics (8af4895) so it should indeed no longer be an issue since Homebrew/homebrew-formula-analytics@3be1121 (the original commit was incomplete anyway).

Feel free to simplify and remove the special casing.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've removed the special casing from generating HOMEBREW_OS_VERSION, but we still need it to find the right pkgconfig directory.

I've also changed HOMEBREW_MACOS_VERSION_NUMBER.

Copy link
Member

@Rylan12 Rylan12 left a comment

Choose a reason for hiding this comment

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

From what I can tell, changing HOMEBREW_OS_VERSION will change the OS_VERSION constant. This is used at least in DevelopmentTools.build_system_info. Changing the would affect Tab#build_on for those macOS versions. Not sure that's actually used anywhere.

It also affects Utils::Analytics.os_arch_prefix_ci. Changing this affects the event label that's sent to the analytics, but it doesn't seem like we actually query that label anywhere so I kinda think it's fine as is unless you just want to be safe.

Library/Homebrew/brew.sh Outdated Show resolved Hide resolved
We now have better handling of macOS versions in our analytics, so this
is no longer needed.

We still need to strip the version conditional on the macOS version in
order to identify the right `pkgconfig` directory.

This partially reverts 8af4895.
Library/Homebrew/brew.sh Outdated Show resolved Hide resolved
Co-authored-by: Bo Anderson <mail@boanderson.me>
Copy link
Member

@Bo98 Bo98 left a comment

Choose a reason for hiding this comment

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

No idea if it's the right place to put this code or not, but functionally this looks good to me.

@MikeMcQuaid
Copy link
Member

This requires reinstallation of pkg-config with OS upgrades, which is something we currently do not handle.

@Bo98 had done some work in this direction. What's the latest here @Bo98?

No idea if it's the right place to put this code or not, but functionally this looks good to me.

Yeh, I'd rather this was something that was done inside Ruby-land rather than Bash here (given no Bash commands rely on this). Feels like perhaps in e.g. formula_installer.rb?

@Bo98
Copy link
Member

Bo98 commented Aug 8, 2022

@Bo98 had done some work in this direction. What's the latest here @Bo98?

The data is now all there (compare the built_on OS in the tab to the running OS). The two main things left was:

  • A DSL so that we could mark which formulae should have this behaviour.
  • Make brew upgrade actually work with formula that are marked as outdated like this, since it currently only supports pkg_version changing updates. My initial thought is this could be worked around by appending the macOS version to the formula version number. But this by chance happens to be the same problem as formula: ensure that kegs with version_scheme == -1 are outdated #13661 so maybe something more generic can be done instead.

Even if we end up not needing this for pkg-config, there are other formulae which would find this functionality useful.

@MikeMcQuaid
Copy link
Member

Even if we end up not needing this for pkg-config, there are other formulae which would find this functionality useful.

Agreed, feels like a general solution might be nice here.

@BrewTestBot BrewTestBot removed the waiting for feedback Merging is blocked until sufficient time has passed for review label Aug 9, 2022
@BrewTestBot
Copy link
Member

Review period ended.

@carlocab
Copy link
Member Author

carlocab commented Aug 11, 2022

Agreed, feels like a general solution might be nice here.

I agree with aiming for a general solution where we reinstall formulae with OS upgrades when needed.

However, the need to reinstall pkg-config is because we hardcode the OS version in its search path. A solution where we don't do that probably won't be general, but is better than reinstalling to fix the hard-coded OS version.

@carlocab
Copy link
Member Author

Yeh, I'd rather this was something that was done inside Ruby-land rather than Bash here (given no Bash commands rely on this). Feels like perhaps in e.g. formula_installer.rb?

We can move it into Ruby-land, but I don't think formula_installer is the right place.

The symlink can become stale due to things happening outside of brew, so waiting for another brew install before updating it means that users could be stuck with a stale symlink for longer than necessary.

My idea was that we want to make sure this symlink is updated with every brew invocation, and the closest I could come to that was putting it here.

@MikeMcQuaid
Copy link
Member

We can move it into Ruby-land, but I don't think formula_installer is the right place.

I'm fine with it being in a different place.

My idea was that we want to make sure this symlink is updated with every brew invocation, and the closest I could come to that was putting it here.

Do we have other things that e.g. make brew list make changes on disk? That feels a bit weird to me.

To me only brew install/upgrade/reinstall/uninstall/autoremove/cleanup are what I'd expect to write changes on disk like this. brew doctor could warn if it's missing.

@carlocab
Copy link
Member Author

I think of the symlink as part of the internal state of brew, it just so happens to live on-disk. We also write to the disk when modifying .git/config (e.g. when running a dev command, or on any invocation of brew where homebrew.analyticsmessage is true but homebrew.analyticsuuid is unset), and I view this as similar to those.

But I don't mind moving this into brew update. I'm going to do that.

Comment on lines 51 to 57
def symlink_current_pkgconfig_directory
return if OS.linux?

pkgconfig_dir = HOMEBREW_LIBRARY/"Homebrew/os/mac/pkgconfig"
FileUtils.rm_f pkgconfig_dir/"current"
pkgconfig_dir.install_symlink MacOS.version => "current"
end
Copy link
Member Author

Choose a reason for hiding this comment

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

This actually feels a bit more out of place for me here, since brew.sh seems more reasonable for setup code that makes sure brew is working properly.

Copy link
Member

Choose a reason for hiding this comment

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

This seems like a reasonable place to me. I'd suggest symlink_current_pkgconfig_directory be pulled into a helper function, though, and it also be called in install.rb or formula_installer.rb because you cannot rely on all users running brew update. It feels like it also warrants a brew doctor if missing.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd suggest symlink_current_pkgconfig_directory be pulled into a helper function, though, and it also be called in install.rb or formula_installer.rb because you cannot rely on all users running brew update. It feels like it also warrants a brew doctor if missing.

Yes, agreed.

Copy link
Member

Choose a reason for hiding this comment

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

Could actually even be a good candidate for one of the diagnostic pre-install mandatory checks that just refuses to continue if it's broken, runs as part of brew doctor and we can tell people to run brew update or whatever to fix.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added symlink creation to install.rb and a diagnostic.

Could actually even be a good candidate for one of the diagnostic pre-install mandatory checks that just refuses to continue if it's broken

I contemplated doing this, but am ambivalent. If @Bo98 thinks it's a good idea then I'm happy to do it though.

# Don't change this from Mac OS X to match what macOS itself does in Safari on 10.12
HOMEBREW_OS_USER_AGENT_VERSION="Mac OS X ${HOMEBREW_MACOS_VERSION}"

# Intentionally set this variable by exploding another.
# shellcheck disable=SC2086,SC2183
printf -v HOMEBREW_MACOS_VERSION_NUMERIC "%02d%02d%02d" ${HOMEBREW_MACOS_VERSION//./ }

# Don't include minor versions for Big Sur and later.
Copy link
Member

Choose a reason for hiding this comment

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

Why this change? Feels like we need to audit uses of HOMEBREW_OS_VERSION to check this won't have unintended effects.

Copy link
Member Author

Choose a reason for hiding this comment

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

This change grew out of the discussion here: #13664 (comment)

I can revert it, since it's not actually related to what I want to do here anymore (it was tangentially related to what I was trying to do in brew.sh earlier).

Copy link
Member

Choose a reason for hiding this comment

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

Ah, gotcha. I'm fine with it if you're happy with the various usages being fine 👍🏻

Copy link
Member Author

Choose a reason for hiding this comment

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

My understanding was this was done to fix our analytics not being able to handle it, but that's fixed now.

In any case, the previous code didn't strip enough on Big Sur, which still comes with patch versions these days (e.g. 11.5.1) but Monterey does not (e.g. 12.5), and that seemed to work ok (i.e. the rest of the code dealt with macOS 11.5 just fine). This suggests to me that keeping the entire version number doesn't hurt.

Comment on lines 51 to 57
def symlink_current_pkgconfig_directory
return if OS.linux?

pkgconfig_dir = HOMEBREW_LIBRARY/"Homebrew/os/mac/pkgconfig"
FileUtils.rm_f pkgconfig_dir/"current"
pkgconfig_dir.install_symlink MacOS.version => "current"
end
Copy link
Member

Choose a reason for hiding this comment

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

This seems like a reasonable place to me. I'd suggest symlink_current_pkgconfig_directory be pulled into a helper function, though, and it also be called in install.rb or formula_installer.rb because you cannot rely on all users running brew update. It feels like it also warrants a brew doctor if missing.

We can't always rely on users doing `brew update`, so let's do this for
`brew install`, `brew reinstall`, and `brew upgrade` too.
@@ -63,6 +63,8 @@ def sdk_path
nil
end

def symlink_current_pkgconfig_directory; end
Copy link
Member Author

Choose a reason for hiding this comment

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

@MikeMcQuaid I know you don't like these MacOS compat methods, so I can move this up into the OS module if preferred. It kinda makes sense for it to be here for me, though.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

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

Sorry for more comments, almost there 🤞🏻

@@ -15,6 +15,7 @@ module Install
module_function

def perform_preinstall_checks(all_fatal: false, cc: nil)
MacOS.symlink_current_pkgconfig_directory
Copy link
Member

Choose a reason for hiding this comment

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

Could maybe just make this a attempt_pkgconfig_directory_symlink below attempt_directory_creation?

Copy link
Member Author

Choose a reason for hiding this comment

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

Would that not restrict it to being run only inside install.rb, instead of also during brew update?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. I actively think it should not be run by brew update 😁. Could we try not doing it in brew update and ship a follow-up PR to add it there (with critical and self-merge without review if necessary) if we actually get any user reports that the brew update addition will fix?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think the opposite: it's weird, and probably wrong, to not do this during brew update.

The symlink is part of the internal state of brew; it even lives inside HOMEBREW_LIBRARY. A brew update should not leave that state out of sync.

Copy link
Member

Choose a reason for hiding this comment

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

The symlink is part of the internal state of brew; it even lives inside HOMEBREW_LIBRARY. A brew update should not leave that state out of sync.

What actually breaks if this is out of sync outside of installations?


# Avoid mandatory reinstalls of `pkg-config` upon OS upgrade.
sig { void }
def symlink_current_pkgconfig_directory
Copy link
Member

Choose a reason for hiding this comment

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

Yeh, I'm afraid this does feel weird to me in macOS, it doesn't seem to have anything to do with the OS other than the fact it's a no-op on Linux.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think it's that weird -- it's specific to macOS because that's where we want to provide .pc files to help find system libraries. We don't currently have a reliable set of system libraries that we need to ship .pc files for on Linux.

Copy link
Member

Choose a reason for hiding this comment

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

@carlocab Yeh, but it's not a function of the OS itself, it's just OS-specific code. It should be a function living somewhere else that's just a no-op on non-MacOS.

Comment on lines +499 to +500
rm -rf #{current_symlink} && \\
ln -sfn #{MacOS.version} #{current_symlink}
Copy link
Member

Choose a reason for hiding this comment

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

Should this just say "run brew whatever" if that cleans it up?

@@ -488,6 +488,20 @@ def check_broken_sdks
#{installation_instructions}
EOS
end

def check_pkgconfig_current_symlink
Copy link
Member

Choose a reason for hiding this comment

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

I'd suggest this is added to e.g. fatal_preinstall_checks

@MikeMcQuaid
Copy link
Member

@carlocab would be good to get this in for 3.6.0 if you get the chance 🙇🏻

@carlocab
Copy link
Member Author

How soon did you want to get 3.6.0 out? Will try to get this ready with sufficient time for review before then.

@MikeMcQuaid
Copy link
Member

@carlocab Not that soon! A week or two?

@carlocab
Copy link
Member Author

Ok, will work on this tomorrow. Feel free to nudge if you don't hear anything by Thursday.

@carlocab
Copy link
Member Author

Apologies for the delay here; I was mulling over how specific this solution really is to pkg-config, and it seems we have a bunch of symlink handling elsewhere too (e.g. Linux-preferred GCC, but we want to get rid of those).

I wonder if

  1. there's a more general approach that handles the necessary symlinking
  2. creating symlinks might be how we might want to avoid the reinstall-at-OS-upgrade problem in other formulae too (e.g. a symlink to the correct SDK inside HOMEBREW_PREFIX?)

@MikeMcQuaid
Copy link
Member

2. creating symlinks might be how we might want to avoid the reinstall-at-OS-upgrade problem in other formulae too (e.g. a symlink to the correct SDK inside HOMEBREW_PREFIX?)

TBH I think we should just handle the reinstall-at-OS-upgrade next time brew install/brew upgrade or maybe even brew update is run after an OS upgrade?

@github-actions
Copy link

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@github-actions github-actions bot added the stale No recent activity label Sep 22, 2022
@github-actions github-actions bot closed this Sep 30, 2022
@github-actions github-actions bot added the outdated PR was locked due to age label Oct 31, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 31, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated PR was locked due to age stale No recent activity
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants