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

The OSX libtool wrapper increases incremental build times #11846

Closed
michaeleisel opened this issue Jul 27, 2020 · 16 comments
Closed

The OSX libtool wrapper increases incremental build times #11846

michaeleisel opened this issue Jul 27, 2020 · 16 comments
Labels
category: rules > ObjC / iOS / J2ObjC P3 We're not considering working on this, but happy to review a PR. (No assignee) team-Rules-CPP Issues for C++ rules

Comments

@michaeleisel
Copy link
Contributor

tools/objc/libtool.sh increases the incremental build time for a single-target app with 700 implementation files by ~3 seconds. It appears that /usr/bin/libtool takes only a fraction of a second, but the work being done beforehand with symlinks and hashing takes longer. This work is to prevent giving libtool object files with the same basename. A few things:

  • libtool seems to just throw a warning, rather than error out. Is there really a problem here?
  • If so, which parts of this can we get rid of? E.g., reproducible hashing, symlinks for all files rather than just the duplicates, etc.
@michaeleisel
Copy link
Contributor Author

@c-parsons can you provide some context on this?

@keith
Copy link
Member

keith commented Jul 27, 2020

I would definitely be curious to know what the bug mentioned here is (or was):

# Libtool artifact symlinking. Apple's libtool has a bug when there are two
# input files with the same basename. We thus create symlinks that are named
# with a hash suffix for each input, and pass them to libtool.
# See b/28186497.

@kastiglione
Copy link
Contributor

kastiglione commented Jul 27, 2020

Basenames are enforced to be unique per module by swiftc.

% swiftc input.swift foo/input.swift 
<unknown>:0: error: filename "input.swift" used twice: 'input.swift' and 'foo/input.swift'
<unknown>:0: note: filenames are used to distinguish private declarations with the same name

In which case, this behavior seems to be pure overhead for swift_library archives.

@oquenchil oquenchil added category: rules > ObjC / iOS / J2ObjC team-Rules-CPP Issues for C++ rules P3 We're not considering working on this, but happy to review a PR. (No assignee) labels Jul 28, 2020
@c-parsons
Copy link
Contributor

This change was from several years ago, so take my recollection with a grain of salt.
If I recall correctly, these libtool warnings for same-basename files was problematic for Xcode integration when compiling objective C sources. Given your findings on build performance, we should maybe revisit this.

@michaeleisel
Copy link
Contributor Author

So we could either:

  • detect if everything is unique, in which case take a fast path
  • only for those that are not unique do this work
  • try to optimize the specific operations being done

I don't like working in bash, so if I'm implementing it, I'm inclined towards the first option, especially because it couldn't have been working for people in Xcode anyways if they had duplicate basenames. But I'm curious what people would like.

@allevato
Copy link
Member

cc @trybka who may have some thoughts on improvements to this script.

@michaeleisel
Copy link
Contributor Author

Another alternative that @keith brought up is to provide some ability to just disable this whole thing and run /usr/bin/libtool directly

@michaeleisel
Copy link
Contributor Author

@trybka ping. i'm happy to rewrite the current rule in c++, as i believe that will solve the performance issues here, if you're fine with that as well

@trybka
Copy link
Contributor

trybka commented Aug 14, 2020

The warning isn't spurious: It picks one and omits the other, which is ... problematic.

If you use xcodebuild, then it'll name outputs foo.o, foo0.o, etc. which does avoid the problem.

In Bazel, we had to resort to this ... workaround.

The current functionality (hashing/symlinking) is actually in Python: tools/objc/make_hashed_objlist.py
I have no objection to rewriting it in C++, and I think any of the optimizations you mentioned (detect unique and skip, only rename non-unique, make individual operations faster) are all fine with me.

@michaeleisel
Copy link
Contributor Author

@trybka do we need the hash to be deterministic? bit more work in c++ if we have to add in md5 support

@michaeleisel
Copy link
Contributor Author

@trybka PR opened: #11958

@trybka
Copy link
Contributor

trybka commented Aug 17, 2020

I do believe it needs to be deterministic, otherwise it will invalidate caches.

If archives can be generated which contain bit-for-bit identical object files, but the names differ, that is a problem.

That "different" archive will be detected by Bazel to be a new input, and will cause re-linking to potentially occur, invalidating caches.

bazel-io pushed a commit that referenced this issue Aug 24, 2020
If there are no duplicate .o basenames, then libtool can be invoked directly without symlinking. From #11846

Closes #11958.

PiperOrigin-RevId: 328185225
michaeleisel added a commit to michaeleisel/bazel that referenced this issue Sep 1, 2020
If there are no duplicate .o basenames, then libtool can be invoked directly without symlinking. From bazelbuild#11846

Closes bazelbuild#11958.

PiperOrigin-RevId: 328185225
michaeleisel added a commit to michaeleisel/bazel that referenced this issue Sep 3, 2020
If there are no duplicate .o basenames, then libtool can be invoked directly without symlinking. From bazelbuild#11846

Closes bazelbuild#11958.

PiperOrigin-RevId: 328185225
@michaeleisel
Copy link
Contributor Author

this is now done, released in 3.5 (with a fix for a regression it introduced in 3.6 rc4). @trybka let's close?

@keith
Copy link
Member

keith commented Oct 3, 2020

I don't think it made 3.5? 3.6 is the first release with both I think?

@michaeleisel
Copy link
Contributor Author

ah is that right? (we've been on a fork with both anyways). in any case, this seems resolved

@trybka
Copy link
Contributor

trybka commented Oct 3, 2020

I don't think I have any specific bits to close these?

@oquenchil probably does.

copybara-service bot pushed a commit to tensorflow/tensorflow that referenced this issue Jan 11, 2021
…ctor

With the bazel version update from 3.1.0 to 3.7.2, the object file hash values
are no longer added when their names are unique within an objc_library. See:
* bazelbuild/bazel#11846
* bazelbuild/bazel#11958

However, object name collision can still happen when there is a source code with
the same basename in a transitive dependency tree. Normally there is no problem
with this, but this had an unfortunate interaction with the symbol hiding script
we use for building the iOS static framework. That is, when an archive file (.a)
contains more than one object file with the same name, the 'ar -x' command
executed as part of the symbol hiding script would overwrite the conflicting
object file, causing the overwritten object file to be not included in the final
static framework.

This was causing a link error at CocoaPods lint step, as it had some missing
function definitions. This is now fixed by using a custom extraction script
written in Python, which gracefully handles the object file name collision.

This also fixes a previously existed race condition when the symbol hiding
script is run in parallel for multiple static framework targets, by using
separate temporary directories while extracting the object files.

Verified that this fix works with CocoaPods lint.

PiperOrigin-RevId: 351118550
Change-Id: Iec26e4720c21f271822785032d5fb6f4717eebca
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category: rules > ObjC / iOS / J2ObjC P3 We're not considering working on this, but happy to review a PR. (No assignee) team-Rules-CPP Issues for C++ rules
Projects
None yet
Development

No branches or pull requests

7 participants