Skip to content

incompatible_remove_legacy_whole_archive: Remove --legacy_whole_archive while setting default to false #7362

@hlopko

Description

@hlopko

Flag: --incompatible_remove_legacy_whole_archive
Available since: 0.25
Will be flipped: 0.26, unless we hear from Bazel users it's not enough. Bazel 1.0 is the latest flipping possibility, but we will gladly postpone the flip until then, if Bazel users need more time. Please speak up.

Motivation

The docs of this flag say:

--[no]legacy_whole_archive default: "true"
When on, use --whole-archive for cc_binary rules that have linkshared=1 and either linkstatic=1 or '-static' in linkopts. This is for backwards compatibility only. A better alternative is to use alwayslink=1 where required.

What this means is that all library archives (and library object groups, as defined by --start-lib/--end-lib) are added to the link command wrapped in -whole-archive, -no-whole-archive, which instructs the linker to always include the entire library. Even with dead code elimination, this can be pernicious if the library defines some global initializer, as that will cause all of the code dependencies of those initializers to be kept.

History

--(legacy_)whole-archive was introduced on 2004-04-19, with the commit description saying:

I think --whole-archive was just the
magical incantation that got swigdeps.so working.
...
You're right though that the real question is what would break if we
removed this, and I don't really have a good idea.

Problem

"Legacy" whole-archive behavior is a poor default, but it is difficult to change.

--[no]legacy_whole_archive is a whole build option. It is impossible to "tag" individual shared, statically linked, dynamic libraries which can be built without "whole-archive" semantics.

Care must be taken to flip the default--libraries which export symbols must be tagged as alwayslink=1 unless some other mechanism exists in the dylib to preserve the symbols which are being exported.

It is a difficult thing to test: unexported symbols are only noticed at runtime, which means that 100% test coverage would have to exist for a depot-wide mass cleanup.

Migration

--legacy_whole_archive will be superseded by --incompatible_remove_legacy_whole_archive. --incompatible_remove_legacy_whole_archive, when true, removes both the old flag, and the behavior enabled by features (explained below).

Bazel now has a mechanism to configure individual cc_binary targets which can be built without --legacy_whole_archive. This mechanism still honors the --incompatible_remove_legacy_whole_archive. This mechanism is based on feature named "legacy_whole_archive". When added to the features attribute of cc_binary, Bazel will keep the legacy whole archive behavior, but only for the cc_binary, not for the whole build.

This is the migration plan we will follow at Google:

  1. Add --features=legacy_whole_archive to the global .bazelrc.
  2. Users can start adding features = "-legacy_whole_archive" (note, minus here) to targets that are safe to build without the legacy behavior.
  3. Add a presubmit check telling users they should add features = [ "-legacy_whole_archive" ].
  4. Have a presubmit check comparing the binary size with and without the feature, to motivate users to migrate.
  5. Once everything is migrated, remove legacy_whole_archive from global .bazelrc.
  6. Celebrate
  7. Remove -legacy_whole_archive features from targets.

Metadata

Metadata

Assignees

Labels

P1I'll work on this now. (Assignee required)incompatible-changeIncompatible/breaking changeteam-Rules-CPPIssues for C++ rules

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions