Fix edge cases of legacy crosstool migrator

https://github.com/bazelbuild/bazel/issues/5883

RELNOTES: None.
PiperOrigin-RevId: 227688115
diff --git a/tools/migration/legacy_fields_migration_lib.py b/tools/migration/legacy_fields_migration_lib.py
index ac0ae8d..70d24c5 100644
--- a/tools/migration/legacy_fields_migration_lib.py
+++ b/tools/migration/legacy_fields_migration_lib.py
@@ -29,6 +29,10 @@
     "c++-link-nodeps-dynamic-library"
 ]
 
+DYNAMIC_LIBRARY_LINK_ACTIONS = [
+    "c++-link-dynamic-library", "c++-link-nodeps-dynamic-library"
+]
+
 # Map converting from LinkingMode to corresponding feature name
 LINKING_MODE_TO_FEATURE_NAME = {
     "FULLY_STATIC": "fully_static_link",
@@ -42,24 +46,88 @@
   """Migrates parsed crosstool (inplace) to not use legacy fields."""
   crosstool.ClearField("default_toolchain")
   for toolchain in crosstool.toolchain:
-    # clear noop fields first
-    toolchain.ClearField("debian_extra_requires")
-    toolchain.ClearField("gcc_plugin_compiler_flag")
-    toolchain.ClearField("ar_flag")
-    toolchain.ClearField("ar_thin_archives_flag")
-    toolchain.ClearField("gcc_plugin_header_directory")
-    toolchain.ClearField("mao_plugin_header_directory")
-    toolchain.ClearField("supports_normalizing_ar")
-    toolchain.ClearField("supports_thin_archives")
-    toolchain.ClearField("supports_incremental_linker")
-    toolchain.ClearField("supports_dsym")
-    toolchain.ClearField("default_python_top")
-    toolchain.ClearField("default_python_version")
-    toolchain.ClearField("python_preload_swigdeps")
-
     _ = [_migrate_expand_if_all_available(f) for f in toolchain.feature]
     _ = [_migrate_expand_if_all_available(ac) for ac in toolchain.action_config]
 
+    if (toolchain.dynamic_library_linker_flag or
+        _contains_dynamic_flags(toolchain)) and not _contains_feature(
+            toolchain, "supports_dynamic_linker"):
+      feature = toolchain.feature.add()
+      feature.name = "supports_dynamic_linker"
+      feature.enabled = True
+
+    if toolchain.supports_start_end_lib and not _contains_feature(
+        toolchain, "supports_start_end_lib"):
+      feature = toolchain.feature.add()
+      feature.name = "supports_start_end_lib"
+      feature.enabled = True
+
+    if toolchain.supports_interface_shared_objects and not _contains_feature(
+        toolchain, "supports_interface_shared_libraries"):
+      feature = toolchain.feature.add()
+      feature.name = "supports_interface_shared_libraries"
+      feature.enabled = True
+
+    if toolchain.supports_embedded_runtimes and not _contains_feature(
+        toolchain, "static_link_cpp_runtimes"):
+      feature = toolchain.feature.add()
+      feature.name = "static_link_cpp_runtimes"
+      feature.enabled = True
+
+    if toolchain.needsPic and not _contains_feature(toolchain, "supports_pic"):
+      feature = toolchain.feature.add()
+      feature.name = "supports_pic"
+      feature.enabled = True
+
+    if toolchain.supports_fission and not _contains_feature(
+        toolchain, "per_object_debug_info"):
+      # feature {
+      #   name: "per_object_debug_info"
+      #   flag_set {
+      #     action: "assemble"
+      #     action: "preprocess-assemble"
+      #     action: "c-compile"
+      #     action: "c++-compile"
+      #     action: "c++-module-codegen"
+      #     action: "lto-backend"
+      #     flag_group {
+      #       expand_if_all_available: 'per_object_debug_info_file'",
+      #       flag: "-gsplit-dwarf"
+      #     }
+      #   }
+      # }
+      feature = toolchain.feature.add()
+      feature.name = "per_object_debug_info"
+      flag_set = feature.flag_set.add()
+      flag_set.action[:] = [
+          "c-compile", "c++-compile", "c++-module-codegen", "assemble",
+          "preprocess-assemble", "lto-backend"
+      ]
+      flag_group = flag_set.flag_group.add()
+      flag_group.expand_if_all_available[:] = ["per_object_debug_info_file"]
+      flag_group.flag[:] = ["-gsplit-dwarf"]
+
+    if toolchain.objcopy_embed_flag and not _contains_feature(
+        toolchain, "objcopy_embed_flags"):
+      feature = toolchain.feature.add()
+      feature.name = "objcopy_embed_flags"
+      feature.enabled = True
+      flag_set = feature.flag_set.add()
+      flag_set.action[:] = ["objcopy_embed_data"]
+      flag_group = flag_set.flag_group.add()
+      flag_group.flag[:] = toolchain.objcopy_embed_flag
+
+    if toolchain.ld_embed_flag and not _contains_feature(
+        toolchain, "ld_embed_flags"):
+      feature = toolchain.feature.add()
+      feature.name = "ld_embed_flags"
+      feature.enabled = True
+      flag_set = feature.flag_set.add()
+      flag_set.action[:] = ["ld_embed_data"]
+      flag_group = flag_set.flag_group.add()
+      flag_group.flag[:] = toolchain.ld_embed_flag
+
+
     # Create default_link_flags feature for linker_flag
     flag_sets = _extract_legacy_link_flag_sets_for(toolchain)
     if flag_sets:
@@ -78,8 +146,6 @@
       feature.name = "default_compile_flags"
       _add_flag_sets(feature, flag_sets)
 
-    toolchain.ClearField("compilation_mode_flags")
-
     # Unfiltered cxx flags have to have their own special feature.
     # "unfiltered_compile_flags" is a well-known (by Bazel) feature name that is
     # excluded from nocopts filtering.
@@ -97,8 +163,38 @@
         feature.enabled = True
 
       _add_flag_sets(
-          feature, [[None, ALL_COMPILE_ACTIONS, toolchain.unfiltered_cxx_flag]])
-      toolchain.ClearField("unfiltered_cxx_flag")
+          feature,
+          [[None, ALL_COMPILE_ACTIONS, toolchain.unfiltered_cxx_flag, []]])
+
+    # clear fields
+    toolchain.ClearField("debian_extra_requires")
+    toolchain.ClearField("gcc_plugin_compiler_flag")
+    toolchain.ClearField("ar_flag")
+    toolchain.ClearField("ar_thin_archives_flag")
+    toolchain.ClearField("gcc_plugin_header_directory")
+    toolchain.ClearField("mao_plugin_header_directory")
+    toolchain.ClearField("supports_normalizing_ar")
+    toolchain.ClearField("supports_thin_archives")
+    toolchain.ClearField("supports_incremental_linker")
+    toolchain.ClearField("supports_dsym")
+    toolchain.ClearField("supports_gold_linker")
+    toolchain.ClearField("default_python_top")
+    toolchain.ClearField("default_python_version")
+    toolchain.ClearField("python_preload_swigdeps")
+    toolchain.ClearField("needsPic")
+    toolchain.ClearField("compilation_mode_flags")
+    toolchain.ClearField("linking_mode_flags")
+    toolchain.ClearField("unfiltered_cxx_flag")
+    toolchain.ClearField("ld_embed_flag")
+    toolchain.ClearField("objcopy_embed_flag")
+    toolchain.ClearField("supports_start_end_lib")
+    toolchain.ClearField("supports_interface_shared_objects")
+    toolchain.ClearField("supports_fission")
+    toolchain.ClearField("compiler_flag")
+    toolchain.ClearField("cxx_flag")
+    toolchain.ClearField("linker_flag")
+    toolchain.ClearField("static_runtimes_filegroup")
+    toolchain.ClearField("dynamic_runtimes_filegroup")
 
 
 def _add_flag_sets(feature, flag_sets):
@@ -107,11 +203,13 @@
     with_feature = flag_set[0]
     actions = flag_set[1]
     flags = flag_set[2]
+    expand_if_all_available = flag_set[3]
     flag_set = feature.flag_set.add()
     if with_feature is not None:
       flag_set.with_feature.add().feature[:] = [with_feature]
     flag_set.action[:] = actions
     flag_group = flag_set.flag_group.add()
+    flag_group.expand_if_all_available[:] = expand_if_all_available
     flag_group.flag[:] = flags
   return feature
 
@@ -120,11 +218,9 @@
   """Get flag sets for default_compile_flags feature."""
   result = []
   if toolchain.compiler_flag:
-    result.append([None, ALL_COMPILE_ACTIONS, toolchain.compiler_flag])
-    toolchain.ClearField("compiler_flag")
+    result.append([None, ALL_COMPILE_ACTIONS, toolchain.compiler_flag, []])
   if toolchain.cxx_flag:
-    result.append([None, ALL_CXX_COMPILE_ACTIONS, toolchain.cxx_flag])
-    toolchain.ClearField("cxx_flag")
+    result.append([None, ALL_CXX_COMPILE_ACTIONS, toolchain.cxx_flag, []])
 
   # Migrate compiler_flag/cxx_flag from compilation_mode_flags
   for cmf in toolchain.compilation_mode_flags:
@@ -139,10 +235,10 @@
       feature.name = mode
 
     if cmf.compiler_flag:
-      result.append([mode, ALL_COMPILE_ACTIONS, cmf.compiler_flag])
+      result.append([mode, ALL_COMPILE_ACTIONS, cmf.compiler_flag, []])
 
     if cmf.cxx_flag:
-      result.append([mode, ALL_CXX_COMPILE_ACTIONS, cmf.cxx_flag])
+      result.append([mode, ALL_CXX_COMPILE_ACTIONS, cmf.cxx_flag, []])
 
   return result
 
@@ -153,8 +249,7 @@
 
   # Migrate linker_flag
   if toolchain.linker_flag:
-    result.append([None, ALL_LINK_ACTIONS, toolchain.linker_flag])
-  toolchain.ClearField("linker_flag")
+    result.append([None, ALL_LINK_ACTIONS, toolchain.linker_flag, []])
 
   # Migrate linker_flags from compilation_mode_flags
   for cmf in toolchain.compilation_mode_flags:
@@ -168,7 +263,7 @@
       feature.name = mode
 
     if cmf.linker_flag:
-      result.append([mode, ALL_LINK_ACTIONS, cmf.linker_flag])
+      result.append([mode, ALL_LINK_ACTIONS, cmf.linker_flag, []])
 
   # Migrate linker_flags from linking_mode_flags
   for lmf in toolchain.linking_mode_flags:
@@ -178,15 +273,23 @@
     if _contains_feature(toolchain, mode):
       continue
 
-    # dynamic_linking_mode is also a marker feature it has a meaning
-    # even when empty
-    if lmf.linker_flag or mode == "dynamic_linking_mode":
+    if lmf.linker_flag:
       feature = toolchain.feature.add()
       feature.name = mode
 
     if lmf.linker_flag:
-      result.append([mode, ALL_LINK_ACTIONS, lmf.linker_flag])
-  toolchain.ClearField("linking_mode_flags")
+      result.append([mode, ALL_LINK_ACTIONS, lmf.linker_flag, []])
+
+  if toolchain.dynamic_library_linker_flag:
+    result.append([
+        None, DYNAMIC_LIBRARY_LINK_ACTIONS,
+        toolchain.dynamic_library_linker_flag, []
+    ])
+
+  if toolchain.test_only_linker_flag:
+    result.append([
+        None, ALL_LINK_ACTIONS, toolchain.test_only_linker_flag, ["is_cc_test"]
+    ])
 
   return result
 
@@ -215,3 +318,11 @@
             flag_set.expand_if_all_available[:])
         flag_group.expand_if_all_available[:] = new_vars
       flag_set.ClearField("expand_if_all_available")
+
+
+def _contains_dynamic_flags(toolchain):
+  for lmf in toolchain.linking_mode_flags:
+    mode = crosstool_config_pb2.LinkingMode.Name(lmf.mode)
+    if mode == "DYNAMIC":
+      return True
+  return False
diff --git a/tools/migration/legacy_fields_migration_lib_test.py b/tools/migration/legacy_fields_migration_lib_test.py
index c0165ce..41a467a 100644
--- a/tools/migration/legacy_fields_migration_lib_test.py
+++ b/tools/migration/legacy_fields_migration_lib_test.py
@@ -4,6 +4,7 @@
 from tools.migration.legacy_fields_migration_lib import ALL_COMPILE_ACTIONS
 from tools.migration.legacy_fields_migration_lib import ALL_CXX_COMPILE_ACTIONS
 from tools.migration.legacy_fields_migration_lib import ALL_LINK_ACTIONS
+from tools.migration.legacy_fields_migration_lib import DYNAMIC_LIBRARY_LINK_ACTIONS
 from tools.migration.legacy_fields_migration_lib import migrate_legacy_fields
 
 
@@ -30,7 +31,7 @@
 
 class LegacyFieldsMigrationLibTest(unittest.TestCase):
 
-  def test_deletes_unused_fields(self):
+  def test_deletes_fields(self):
     crosstool = make_crosstool("""
           debian_extra_requires: 'debian-1'
           gcc_plugin_compiler_flag: 'gcc_plugin_compiler_flag-1'
@@ -45,6 +46,13 @@
           supports_thin_archives: false
           supports_incremental_linker: false
           supports_dsym: false
+          supports_gold_linker: false
+          needsPic: false
+          supports_start_end_lib: false
+          supports_interface_shared_objects: false
+          supports_fission: false
+          static_runtimes_filegroup: 'yolo'
+          dynamic_runtimes_filegroup: 'yolo'
       """)
     output = migrate_to_string(crosstool)
     self.assertNotIn("debian_extra_requires", output)
@@ -60,6 +68,13 @@
     self.assertNotIn("default_python_top", output)
     self.assertNotIn("default_python_version", output)
     self.assertNotIn("python_preload_swigdeps", output)
+    self.assertNotIn("supports_gold_linker", output)
+    self.assertNotIn("needsPic", output)
+    self.assertNotIn("supports_start_end_lib", output)
+    self.assertNotIn("supports_interface_shared_objects", output)
+    self.assertNotIn("supports_fission", output)
+    self.assertNotIn("static_runtimes_filegroup", output)
+    self.assertNotIn("dynamic_runtimes_filegroup", output)
 
   def test_deletes_default_toolchains(self):
     crosstool = make_crosstool("")
@@ -121,6 +136,19 @@
     self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
                      ["linker-flag-1"])
 
+  def test_migrate_dynamic_library_linker_flags(self):
+    crosstool = make_crosstool("""
+        dynamic_library_linker_flag: 'linker-flag-1'
+    """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(len(output.linker_flag), 0)
+    self.assertEqual(output.feature[0].name, "default_link_flags")
+    self.assertEqual(output.feature[0].flag_set[0].action,
+                     DYNAMIC_LIBRARY_LINK_ACTIONS)
+    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
+                     ["linker-flag-1"])
+
   def test_compilation_mode_flags(self):
     crosstool = make_crosstool("""
         compiler_flag: "compile-flag-1"
@@ -230,16 +258,78 @@
     self.assertNotIn("coverage-flag-3", output)
     self.assertNotIn("COVERAGE", output)
 
-  def test_dynamic_linking_mode_is_added_even_when_empty(self):
+  def test_supports_dynamic_linker_when_dynamic_library_linker_flag_is_used(
+      self):
+    crosstool = make_crosstool("""
+        dynamic_library_linker_flag: "foo"
+    """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "default_link_flags")
+    self.assertEqual(output.feature[1].name, "supports_dynamic_linker")
+    self.assertEqual(output.feature[1].enabled, True)
+
+  def test_supports_dynamic_linker_is_added_when_DYNAMIC_present(self):
     crosstool = make_crosstool("""
     linking_mode_flags {
       mode: DYNAMIC
     }
     """)
-    output = migrate_to_string(crosstool)
-    self.assertNotIn("linking_mode_flags", output)
-    self.assertNotIn("DYNAMIC", output)
-    self.assertIn("name: \"dynamic_linking_mode\"", output)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "supports_dynamic_linker")
+    self.assertEqual(output.feature[0].enabled, True)
+
+  def test_supports_dynamic_linker_is_not_added_when_present(self):
+    crosstool = make_crosstool("""
+    feature { name: "supports_dynamic_linker" enabled: false }
+    """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "supports_dynamic_linker")
+    self.assertEqual(output.feature[0].enabled, False)
+
+  def test_all_linker_flag_ordering(self):
+    crosstool = make_crosstool("""
+    linker_flag: 'linker-flag-1'
+    compilation_mode_flags {
+        mode: OPT
+        linker_flag: 'cmf-flag-2'
+    }
+    linking_mode_flags {
+      mode: MOSTLY_STATIC
+      linker_flag: 'lmf-flag-3'
+    }
+    dynamic_library_linker_flag: 'dl-flag-4'
+    test_only_linker_flag: 'to-flag-5'
+    """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "default_link_flags")
+    self.assertEqual(output.feature[0].enabled, True)
+    self.assertEqual(output.feature[0].flag_set[0].action[:], ALL_LINK_ACTIONS)
+    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:],
+                     ["linker-flag-1"])
+    self.assertEqual(output.feature[0].flag_set[1].action[:], ALL_LINK_ACTIONS)
+    self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0],
+                     "opt")
+    self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag[:],
+                     ["cmf-flag-2"])
+    self.assertEqual(output.feature[0].flag_set[2].action[:], ALL_LINK_ACTIONS)
+    self.assertEqual(output.feature[0].flag_set[2].with_feature[0].feature[0],
+                     "static_linking_mode")
+    self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag[:],
+                     ["lmf-flag-3"])
+    self.assertEqual(output.feature[0].flag_set[3].action[:],
+                     DYNAMIC_LIBRARY_LINK_ACTIONS)
+    self.assertEqual(output.feature[0].flag_set[3].flag_group[0].flag[:],
+                     ["dl-flag-4"])
+    self.assertEqual(output.feature[0].flag_set[4].action[:], ALL_LINK_ACTIONS)
+    self.assertEqual(output.feature[0].flag_set[4].flag_group[0].flag[:],
+                     ["to-flag-5"])
+    self.assertEqual(
+        output.feature[0].flag_set[4].flag_group[0].expand_if_all_available[:],
+        ["is_cc_test"])
 
   def test_linking_mode_features_are_not_added_when_present(self):
     crosstool = make_crosstool("""
@@ -360,6 +450,176 @@
     self.assertEqual(output.feature[1].name, "default_compile_flags")
     self.assertEqual(len(output.feature[1].flag_set), 0)
 
+  def test_supports_start_end_lib_migrated(self):
+    crosstool = make_crosstool("supports_start_end_lib: true")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "supports_start_end_lib")
+    self.assertEqual(output.feature[0].enabled, True)
+
+  def test_supports_start_end_lib_not_migrated_on_false(self):
+    crosstool = make_crosstool("supports_start_end_lib: false")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(len(output.feature), 0)
+
+  def test_supports_start_end_lib_not_migrated_when_already_present(self):
+    crosstool = make_crosstool("""
+            supports_start_end_lib: true
+            feature { name: "supports_start_end_lib" enabled: false }
+        """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "supports_start_end_lib")
+    self.assertEqual(output.feature[0].enabled, False)
+
+  def test_supports_interface_shared_libraries_migrated(self):
+    crosstool = make_crosstool("supports_interface_shared_objects: true")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name,
+                     "supports_interface_shared_libraries")
+    self.assertEqual(output.feature[0].enabled, True)
+
+  def test_supports_interface_shared_libraries_not_migrated_on_false(self):
+    crosstool = make_crosstool("supports_interface_shared_objects: false")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(len(output.feature), 0)
+
+  def test_supports_interface_shared_libraries_not_migrated_when_present(self):
+    crosstool = make_crosstool("""
+            supports_interface_shared_objects: true
+            feature {
+              name: "supports_interface_shared_libraries"
+              enabled: false }
+        """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name,
+                     "supports_interface_shared_libraries")
+    self.assertEqual(output.feature[0].enabled, False)
+
+  def test_supports_embedded_runtimes_migrated(self):
+    crosstool = make_crosstool("supports_embedded_runtimes: true")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "static_link_cpp_runtimes")
+    self.assertEqual(output.feature[0].enabled, True)
+
+  def test_supports_embedded_runtimes_not_migrated_on_false(self):
+    crosstool = make_crosstool("supports_embedded_runtimes: false")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(len(output.feature), 0)
+
+  def test_supports_embedded_runtimes_not_migrated_when_already_present(self):
+    crosstool = make_crosstool("""
+            supports_embedded_runtimes: true
+            feature { name: "static_link_cpp_runtimes" enabled: false }
+        """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "static_link_cpp_runtimes")
+    self.assertEqual(output.feature[0].enabled, False)
+
+  def test_needs_pic_migrated(self):
+    crosstool = make_crosstool("needsPic: true")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "supports_pic")
+    self.assertEqual(output.feature[0].enabled, True)
+
+  def test_needs_pic_not_migrated_on_false(self):
+    crosstool = make_crosstool("needsPic: false")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(len(output.feature), 0)
+
+  def test_needs_pic_not_migrated_when_already_present(self):
+    crosstool = make_crosstool("""
+            needsPic: true
+            feature { name: "supports_pic" enabled: false }
+        """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "supports_pic")
+    self.assertEqual(output.feature[0].enabled, False)
+
+  def test_supports_fission_migrated(self):
+    crosstool = make_crosstool("supports_fission: true")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "per_object_debug_info")
+    self.assertEqual(output.feature[0].enabled, False)
+
+  def test_supports_fission_not_migrated_on_false(self):
+    crosstool = make_crosstool("supports_fission: false")
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(len(output.feature), 0)
+
+  def test_supports_fission_not_migrated_when_already_present(self):
+    crosstool = make_crosstool("""
+            supports_fission: true
+            feature { name: "per_object_debug_info" enabled: false }
+        """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "per_object_debug_info")
+    self.assertEqual(output.feature[0].enabled, False)
+
+  def test_migrating_objcopy_embed_flag(self):
+    crosstool = make_crosstool("""
+            objcopy_embed_flag: "a"
+            objcopy_embed_flag: "b"
+        """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "objcopy_embed_flags")
+    self.assertEqual(output.feature[0].enabled, True)
+    self.assertEqual(output.feature[0].flag_set[0].action[:],
+                     ["objcopy_embed_data"])
+    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:],
+                     ["a", "b"])
+    self.assertEqual(len(output.objcopy_embed_flag), 0)
+
+  def test_not_migrating_objcopy_embed_flag_when_feature_present(self):
+    crosstool = make_crosstool("""
+            objcopy_embed_flag: "a"
+            objcopy_embed_flag: "b"
+            feature { name: "objcopy_embed_flags" }
+        """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "objcopy_embed_flags")
+    self.assertEqual(output.feature[0].enabled, False)
+
+  def test_migrating_ld_embed_flag(self):
+    crosstool = make_crosstool("""
+            ld_embed_flag: "a"
+            ld_embed_flag: "b"
+        """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "ld_embed_flags")
+    self.assertEqual(output.feature[0].enabled, True)
+    self.assertEqual(output.feature[0].flag_set[0].action[:], ["ld_embed_data"])
+    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:],
+                     ["a", "b"])
+    self.assertEqual(len(output.ld_embed_flag), 0)
+
+  def test_not_migrating_objcopy_embed_flag_when_feature_present(self):
+    crosstool = make_crosstool("""
+            objcopy_embed_flag: "a"
+            objcopy_embed_flag: "b"
+            feature { name: "objcopy_embed_flags" }
+        """)
+    migrate_legacy_fields(crosstool)
+    output = crosstool.toolchain[0]
+    self.assertEqual(output.feature[0].name, "objcopy_embed_flags")
+    self.assertEqual(output.feature[0].enabled, False)
+
   def test_migrate_expand_if_all_available_from_flag_sets(self):
     crosstool = make_crosstool("""
         action_config {
diff --git a/tools/migration/legacy_fields_migrator.py b/tools/migration/legacy_fields_migrator.py
index 10ebacd..806d09d 100644
--- a/tools/migration/legacy_fields_migrator.py
+++ b/tools/migration/legacy_fields_migrator.py
@@ -19,6 +19,7 @@
 from google.protobuf import text_format
 from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2
 from tools.migration.legacy_fields_migration_lib import migrate_legacy_fields
+import os
 
 flags.DEFINE_string("input", None, "Input CROSSTOOL file to be migrated")
 flags.DEFINE_string("output", None,
@@ -36,18 +37,29 @@
   if not output_filename:
     raise app.UsageError("ERROR output unspecified")
 
-  f = open(input_filename, "r")
+  f = open(to_absolute_path(input_filename), "r")
   input_text = f.read()
   text_format.Merge(input_text, crosstool)
   f.close()
 
   output_text = migrate_legacy_fields(crosstool)
 
-  f = open(output_filename, "w")
+  f = open(to_absolute_path(output_filename), "w")
   output_text = text_format.MessageToString(crosstool)
   f.write(output_text)
   f.close()
 
 
+def to_absolute_path(path):
+  path = os.path.expanduser(path)
+  if os.path.isabs(path):
+    return path
+  else:
+    if os.environ["BUILD_WORKING_DIRECTORY"]:
+      return os.path.join(os.environ["BUILD_WORKING_DIRECTORY"], path)
+    else:
+      return path
+
+
 if __name__ == "__main__":
   app.run(main)