mistydemeo / tigerbrew

Experimental fork of homebrew for PPC Macs on Tiger
Other
542 stars 130 forks source link

"@loader_path/..." dylib ID not understood by ld or ld64 #1147

Closed gsteemso closed 6 months ago

gsteemso commented 6 months ago

In the file "keg_relocate.rb", there is a function "fix_install_names". Its purpose is to change the library pathnames within freshly-installed Mach-O files so that they point to the installed location rather than the built location, so that any libraries thus referenced will in fact be found when needed.

Unfortunately, it changes a specific subset of the replacement pathnames to begin with "@loader_path", a flavour of shorthand that neither Tiger's ld, nor Leopard's ld, nor Tigerbrew's ld64 has any idea what to do with. I first encountered the problem in various things that attempted to link to icu4c, and in fact had to resort to manually editing the referenced names of that package's libraries before anything related to that package would work. Not realizing at the time that Tigerbrew had committed this offense /on purpose/, I resorted to coding up a post-installation block to do the rewriting for me, and order was seemingly restored.

Now that I have discovered exactly where this gibberish is originating, I want to submit a patch to get rid of it. However, I am a little unclear on the reasoning behind the specific pathnames chosen in the "fixed_name" routine for each type of Mach-O file it handles, and I would appreciate some insight so that the patch is done correctly the first time.

Advice please.

sevan commented 6 months ago
  # If file is a dylib or bundle itself, look for the dylib named by
  # bad_name relative to the lib directory, so that we can skip the more
  # expensive recursive search if possible.
  def fixed_name(file, bad_name)
    if bad_name.start_with? PREFIX_PLACEHOLDER
      bad_name.sub(PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s)
    elsif bad_name.start_with? CELLAR_PLACEHOLDER
      bad_name.sub(CELLAR_PLACEHOLDER, HOMEBREW_CELLAR.to_s)
    elsif (file.dylib? || file.mach_o_bundle?) && (file.parent + bad_name).exist?
      "@loader_path/#{bad_name}"
    elsif file.mach_o_executable? && (lib + bad_name).exist?
      "#{lib}/#{bad_name}"
    elsif (abs_name = find_dylib(Pathname.new(bad_name).basename)) && abs_name.exist?
      abs_name.to_s
    else
      opoo "Could not fix #{bad_name} in #{file}"
      bad_name
    end
  end

I don't believe I've hit the issue you're describing but I've also steered clear of icu4c so far. Seems to apply to bundles & libraries only. You're not going to get a new ld into place nor a newer dyld which supports loader_path so need to see what the issue is with the cases you've hit.

gsteemso commented 6 months ago

The issue is that something will try to link to the icu4c libraries and ld will immediately choke on the part that says "@loader_path", causing the other software to crash. As you point out, we aren't going to be getting a different linker, so the only solution is to stop Tigerbrew from writing "@loader_path". That part is straightforward. What i'm unclear on is what path should be used instead, as the original code selects amongst several possibilities. I think if you want to always get the libraries of the same vintage within a given project, you want the Cellar-prefix path, whereas if you want the libraries from a different package, you'd want the opt-prefix path because otherwise things would break every time you upgraded the other package, maybe?

sevan commented 6 months ago

Not sure, I will try and poke at icu4c at some later time & report back. I'd say unless you're a 100% certain about an issue and you've tested a change across the board, I would steer clear of the framework internals and making changes to the how system operates.

gsteemso commented 6 months ago

I did everything I could think of to find some aspect of "@loader_path" that worked, and couldn't. It was to some degree cemented for me when another package - I forget which - came up with the same problem. However, the logic that embeds "@loader_path" does not always trigger - sometimes a real path gets used instead - and some other change I made caused that other package to go back to being built without the problem. It was really convincing when a different change I made caused ICU4C to be built with normal paths, and functioning properly (I was working on a different problem and the "@loader_path"s came back as I progressed, but for a short interval I didn't need to manually rewrite the damned paths; I think it was after that I came up with the post-install block to automate getting rid of them).

In short: Yes, the "@loader_path" logic is bad and needs to go. I challenge you to scour your whole hard drive for a single library that is using it and can be successfully loaded! I'm going to do that very thing after dinner.

gsteemso commented 6 months ago

I did as I said and scoured my hard drive... and to my great surprise, found thousands of working examples. Apparently "@loader_path" IS understood by stock ld, even on 10.4. I stand corrected.

In light of this information, obviously I have had to recant my earlier-stated position, heh. I apologize for my near-histrionics.

After some thought, I have a possible idea what may have actually gone wrong with libicu4c. I'll get back to you if it works. First I'll have to erase that post-installation block for removing "@loader_path" instances...it's bizarre that it worked, mind you.

groan Back to the drafting board.

gsteemso commented 6 months ago

As a strange footnote to my investigation above... I found a few hundred files that had paths beginning "@loader_path/../[relative path]", but only five files in iTunes that had "@loader_path/[library name]" (i.e., with the linked libraries being in the same directory – and none at all with the linked libraries in a subdirectory. This changes nothing, of course, but it's a rather odd data point.

Given that I was dead wrong about this, I'm marking it "closed".