-
Notifications
You must be signed in to change notification settings - Fork 715
feat: fat static libraries with all transitive dependencies #4271
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
Conversation
|
awaiting-review |
|
Mathlib CI status (docs):
|
|
|
||
| /-- The path to the static fat library in the package's `libDir`. -/ | ||
| @[inline] def staticFatLibFile (self : LeanLib) : FilePath := | ||
| self.pkg.nativeLibDir / nameToStaticLib s!"{self.config.libName}Fat" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| self.pkg.nativeLibDir / nameToStaticLib s!"{self.config.libName}Fat" | |
| self.pkg.nativeLibDir / self.staticLibFileName.addExtension "fat" |
I would be inclined to give this extension .a.fat like the export and noexport variants. When Is there a reason you avoided that approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tydeu I didn't want to hamper the default behaviour of ld searching for -lfoo as libfoo.a, so I preferred to keep the .a as the rightmost extension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bollu My thought process is that I wouldn't expect a user to be shipping all 3 different variants of the static library but instead just distribute the appropriate one as libfoo.a. Internally, in Lake, the full name can be easily used without concern.
One problem with having a suffix just for this version of the library is that it can conflict with a library name ending in a normal library ending with the same suffix. For example, a Lean library named BigFat's normal static library would conflict with the Lean library Big's fat static library. As this would be a very confusing issue for a user to debug, it would probably be best to ensure all static libraries have non-overlapping suffixes (or none) to avoid this.
| let mods ← self.rootModules.concatMapM fun mod => do | ||
| return (← mod.transImports.fetch).push mod | ||
| let oJobs ← mods.concatMapM fun mod => | ||
| mod.nativeFacets (shouldExport := true) |>.mapM fun facet => fetch <| mod.facet facet.name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the fat library really have exported symbols? Exported symbols are generally only for dynamic libraries. Statically linking a library will cause symbol resolution regardless of export.
| mod.nativeFacets (shouldExport := true) |>.mapM fun facet => fetch <| mod.facet facet.name | |
| mod.nativeFacets (shouldExport := false) |>.mapM fun facet => fetch <| mod.facet facet.name |
If the exported symbols are expected to be needed, then it may be necessary to have export / noexport variants of the fat library just like the standard static library. With exported symbols, it is easy for a fat library to surpass Windows symbol limits.
tydeu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have finally reviewed this PR. My apologies for taking so long! 🙏
There are some elements that need discussion and potential rework -- see the line-by-line comments for details. However, overall, I think you are on the right track, and I would be happy to see this PR merged!
|
I think it is a bit misleading to call this a "fat library", and suggest using the term "statically linked" instead. "fat binaries" are the usual term for binaries which simultaneously contain code from multiple architectures (e.g. x86 and ARM), with some header information so that they can be correctly run in multiple environments. The technique is fairly rarely used; a notable recent application of the technique is in Apple binaries during the ARM transition period. See also Fat binary. |
Statically linked is too general for this. The standard static library Lake produces is also statically linked (as would be any static library). Furthermore, it is perfectly normal for a static library to not contain symbols from other (public) libraries, so it would weird to use the general term for the currently name "fat" version. Maybe we could call this a "standalone" static library instead of a "fat" one? |
Co-authored-by: Mac Malone <[email protected]>
Co-authored-by: Mac Malone <[email protected]>
Adapted from this zulip thread titled 'reverse FFI: building a "fat" static library'
The motivation is to enable more reverse-FFI use-cases. End users should be able to build a single static library that can be linked against. This library should include all (transitive) dependencies of the Lean library. This enables easy static linking.
My personal use-case is to link a lean+mathlib+batteries library against a rust project. This is accomplished by building a static library as proposed, and linking against this in the
build.rsbuild script.The larger part of the PR is to add an example that showcases how to use it in a new example in a library with a dependency, which has been adapted from the already existing example of
reverse-ffi. We add a new test that checks that reverse FFI does indeed include transitive dependencies by grepping for the_initialize_function of the dependency.