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

Ignore unparseable static libraries #235

Merged
merged 5 commits into from
Jan 17, 2025

Conversation

HexDecimal
Copy link
Collaborator

@HexDecimal HexDecimal commented Jan 3, 2025

Pull Request Checklist

  • Read and follow the CONTRIBUTING.md guide
  • Mentioned relevant issues
  • Append public facing changes to Changelog.md
  • Ensure new features are covered by tests
  • Ensure fixes are verified by tests

This branch was an attempt to remove macholib and write a better otool parser but I underestimated how difficult the output of otool was. I wasn't able to resolve cases where it'd decide to not return the architecture info in its output because it decided it was the current systems architecture. In the end I decided it was more reliable to suppress the error from macholib instead of trying to remove the library.

This suppresses ValueError: Unknown Mach-O header which fixes #229, fixes #227. I don't have a fat static binary to test this such as an archive (.a) compiled for both arm64 and x86_64.

While working on this I noticed the -m flag on otool and enabled it because delocate is always working with the whole file at once. This flag is documented as:

-m The object file names are not assumed to be in the archive(member) syntax, which allows file names containing parenthesis.

I also looked at the previous install dependencies, machomacomangler and bindepend, and removed them because there was no code using them. These looked like previous attempts at cross-platform handling of MacOS binary files.

Copy link

codecov bot commented Jan 3, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.84%. Comparing base (e90c30c) to head (d247830).
Report is 6 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #235      +/-   ##
==========================================
- Coverage   97.06%   96.84%   -0.22%     
==========================================
  Files          16       16              
  Lines        1361     1365       +4     
==========================================
+ Hits         1321     1322       +1     
- Misses         40       43       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@HexDecimal
Copy link
Collaborator Author

Something to add to make_libs.sh to generate a fat arm64/x86_64 archive .a file would be nice for this. Any suggestions?

Copy link
Owner

@matthew-brett matthew-brett left a comment

Choose a reason for hiding this comment

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

This one looks fine to me. For my own benefit, the changes here are:

  • Checking for, ignoring a known error frommacholib when parsing static libraries.
  • Using the -m flag to otool, therefore allowing parentheses in input file names.
  • Elevating some deprecation warnings to errors.

The only question I had was - is ignoring the static libraries the right thing? I guess it is, in that they cannot by definition be necessary for execution.

@HexDecimal
Copy link
Collaborator Author

Elevating some deprecation warnings to errors.

I don't think I've promoted any deprecation warnings to errors. Any deleted warning code was moved to a @deprecated decorator. This allows type linters to detect calls to deprecated functions.

The only question I had was - is ignoring the static libraries the right thing? I guess it is, in that they cannot by definition be necessary for execution.

This still checks static libraries. It's just that macholib does not support fat static libraries at the moment, so only single architecture static libraries will be analyzed. A version of macholib which does support them will automatically work as it won't throw an error anymore.

@HexDecimal
Copy link
Collaborator Author

HexDecimal commented Jan 13, 2025

There isn't a perfect solution to static libraries. Whether the static library is possibly loaded as part of the package logic or is solely used to create but not run other tools depends on the specific package.

It should be a simple change if we want to skip over static libraries during this minimum version analyses. It can even be toggled with a flag to delocate. Maybe count static libs by default but allow using a flag to ignore them.

@matthew-brett
Copy link
Owner

I don't think I've promoted any deprecation warnings to errors. Any deleted warning code was moved to a @deprecated decorator. This allows type linters to detect calls to deprecated functions.

Ah - yes - sorry - thanks for the clarification.

@matthew-brett
Copy link
Owner

It should be a simple change if we want to skip over static libraries during this minimum version analyses. It can even be toggled with a flag to delocate. Maybe count static libs by default but allow using a flag to ignore them.

That sounds good - do you think the function should error when it can't detect minimum version from static libs - as it does now - unless the ignore flag is set?

@HexDecimal
Copy link
Collaborator Author

That sounds good - do you think the function should error when it can't detect minimum version from static libs - as it does now - unless the ignore flag is set?

I don't have a preference on that, but the error is that macholib is unable to parse the file in the first place, so a failed parse doesn't mean the file was actually a fat static lib and not some other file type.

There's not much that can be done other than to fix the issue upstream: ronaldoussoren/macholib#49

Decorator warnings are more modern and work better for linters and IDE's
Documentation shows that this is needed to disable special handling of
file names which would prevent the loading of paths with parentheses.
Added tests for this. Verified the test will fail without the new flag.
machomacomangler and bindepend are not currently being used
Macholib raises ValueError when failing to parse files which can be used
to detect if the file is a Mach-O object.
It is also raised on Mach-O objects it doesn't know how to handle.

Checking for this error means `_is_macho_file` is redundant.

Add min version tests for various file types.
These tests clarify that static libraries don't have min version info.
@HexDecimal
Copy link
Collaborator Author

I added tests to verify ignoring static library info but it turns out these new tests demonstrate that static libraries do not have the LC_BUILD_VERSION or LC_VERSION_MIN_MACOSX commands in the first place. This means they don't have the minimum version info that's being checked for and there's no reason to ignore them specifically. My previous inference on static libraries having these attributes was accidental misinformation on my part. Dylib, shared objects, and object files have minimum version information.

Keeping this in mind, there's no difference between a static library and any non-library file as far as _get_macos_min_version is concerned. I no longer feel a need to test using a real fat static archive file. A test showing that current static libraries return no minimum version information is good enough, I think.

I've added # pragma: no cover to the unexpected exception line since there's no practical way to cover it.

@matthew-brett
Copy link
Owner

Ok - thanks for persisting. Is this one ready to go in now? You have an outstanding "Ensure new features are covered by tests" checkbox - did you mean (above) that you don't think you can practically do that?

@HexDecimal
Copy link
Collaborator Author

Ok - thanks for persisting. Is this one ready to go in now? You have an outstanding "Ensure new features are covered by tests" checkbox - did you mean (above) that you don't think you can practically do that?

I was considering the -m flag a feature that I wasn't testing for. I could probably figure out a way to write one more test for it, for completeness.

@HexDecimal HexDecimal marked this pull request as draft January 17, 2025 16:51
@HexDecimal HexDecimal marked this pull request as ready for review January 17, 2025 18:02
@HexDecimal
Copy link
Collaborator Author

Turns out I did have tests for -m, but I've ended up adding more. I've also verified just now that these tests do fail if the -m flag is removed.

Also verified that removing `-m` causes these tests to fail
@HexDecimal
Copy link
Collaborator Author

I also attempted to cover the _line0_says_object branches, but I couldn't figure out which files which would fail _line0_says_object while also passing _is_macho_file. I'm unsure what _line0_says_object is checking for.

Copy link
Owner

@matthew-brett matthew-brett left a comment

Choose a reason for hiding this comment

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

Looks good, thanks.

@HexDecimal HexDecimal merged commit 5a21ee0 into matthew-brett:main Jan 17, 2025
14 of 15 checks passed
@HexDecimal HexDecimal deleted the fix-static-libs branch January 17, 2025 18:46
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.

Fat binaries of static libraries are not supported in the wheel delocate-merge fails to merge numpy
2 participants