[zircon] [gn] Produce legacy .pkg files for library()

Bug: BLD-325
Bug: BLD-353
Test: gn gen && ninja, manual inspection of .pkg files
Change-Id: If5f9390c69d136b5f1898fa392bea2af0e215365
diff --git a/zircon/BUILD.gn b/zircon/BUILD.gn
index 6957906..60cf43e 100644
--- a/zircon/BUILD.gn
+++ b/zircon/BUILD.gn
@@ -122,11 +122,21 @@
       ]
     }
 
+    environment_redirect("all-ulib-$cpu") {
+      testonly = true
+      cpu = cpu
+      environment_label = "$zx/public/gn/toolchain:user"
+      deps = [
+        "$zx/system/ulib",
+      ]
+    }
+
     legacy_pkg("manifest-$cpu") {
       testonly = true
       data_keys = [ "legacy_pkg_manifest" ]
       deps = [
         ":legacy-$cpu",
+        ":all-ulib-$cpu",
         ":tools",
 
         # Separately listed because they're reached by dependencies only on x64.
diff --git a/zircon/public/gn/BUILDCONFIG.gn b/zircon/public/gn/BUILDCONFIG.gn
index 4368098..d4fb91f 100644
--- a/zircon/public/gn/BUILDCONFIG.gn
+++ b/zircon/public/gn/BUILDCONFIG.gn
@@ -309,20 +309,21 @@
     static = !kernel
   }
   if (defined(invoker.sdk)) {
-    # TODO(BLD-353): This will be used later for the legacy build
-    # integration and/or SDK generated, which isn't implemented yet.  The
-    # parameters are supported (and ignored) now so that library()
-    # invocations can be written now with complete information and not all
-    # need the sdk bits filled in later.
-    not_needed(invoker,
-               [
-                 "sdk",
-                 "sdk_headers",
-               ])
+    # TODO(BLD-353): This is currently used for the legacy build integration.
+    # Eventually it will instead drive the proper SDK production directly, but
+    # it's likely the details will change when that happens.  For now it's not
+    # meant to be very clean, just to do what works in the legacy build.
+    sdk = invoker.sdk
+    sdk_headers = invoker.sdk_headers
+  } else {
+    sdk = false
+    sdk_headers = []
   }
   _library_params = [
     "kernel",
     "host",
+    "sdk",
+    "sdk_headers",
     "shared",
     "static",
   ]
@@ -359,6 +360,16 @@
           public_deps = []
         }
         public_deps += [ ":${_library_name}.headers" ]
+
+        # TODO(BLD-353): temporary hack
+        if (sdk != false && !static && !shared &&
+            toolchain.tags + [ "gcc" ] - [ "gcc" ] == []) {
+          if (!defined(data_deps)) {
+            data_deps = []
+          }
+          data_deps +=
+              [ ":$_library_name-$current_cpu.pkg(${toolchain.label})" ]
+        }
       }
     }
   } else if (is_host) {
@@ -496,6 +507,20 @@
           ":${_library_name}.static",
         ]
       }
+
+      # TODO(BLD-353): temporary hack
+      if (sdk != false && toolchain.environment == "user" &&
+          toolchain.tags + [ "gcc" ] - [ "gcc" ] == []) {
+        if (sdk == "shared") {
+          data_deps = [
+            ":$_library_name-$current_cpu.pkg(${toolchain.shlib})",
+          ]
+        } else {
+          data_deps = [
+            ":$_library_name-$current_cpu.pkg(${toolchain.label})",
+          ]
+        }
+      }
     }
   }
 
@@ -592,6 +617,159 @@
       }
     }
   }
+
+  # TODO(BLD-353): temporary hacks
+  if (sdk != false &&
+      (toolchain.environment == "user" || (!shared && !static))) {
+    if (sdk == "static") {
+      assert(static,
+             "$target_name must have static=true to have sdk=\"static\"")
+    } else if (sdk == "shared") {
+      assert(shared || !defined(toolchain.shlib),
+             "$target_name must have shared=true to have sdk=\"shared\"")
+    } else {
+      assert(sdk == "source",
+             "$target_name sdk=\"$sdk\" not static, shared, or source")
+    }
+    if (toolchain.tags + [ "gcc" ] - [ "gcc" ] != [] ||
+        (defined(toolchain.shlib) &&
+         ((sdk == "shared" && current_toolchain != toolchain.shlib) ||
+          (sdk != "shared" && current_toolchain == toolchain.shlib)))) {
+      sdk = false
+    }
+    if (sdk != false) {
+      import("$zx/public/gn/legacy_pkg.gni")
+      legacy_pkg("$target_name-$current_cpu.pkg") {
+        contents = [
+          "[package]",
+          "name=$_library_name",
+          "type=lib",
+        ]
+        if (sdk == "source") {
+          contents += [
+            "arch=src",
+            "[src]",
+          ]
+          foreach(file, invoker.sources) {
+            contents += [ rebase_path(file, ".") + "=SOURCE/" +
+                          rebase_path(file, "//") ]
+          }
+        } else {
+          contents += [
+            "arch=$zircon_cpu",
+            "[lib]",
+          ]
+          if (sdk == "static") {
+            if (defined(invoker.output_prefix_override) &&
+                invoker.output_prefix_override) {
+              contents += [ "lib/${_library_name}.a=BUILD/" +
+                            rebase_path("$target_out_dir/${_library_name}.a",
+                                        root_build_dir) ]
+            } else {
+              contents += [ "lib/lib${_library_name}.a=BUILD/" +
+                            rebase_path("$target_out_dir/lib${_library_name}.a",
+                                        root_build_dir) ]
+            }
+          } else {
+            soname = "lib${_library_name}.so"
+            contents += [
+              "debug/$soname=BUILD/" +
+                  rebase_path("$target_out_dir/$soname.debug", root_build_dir),
+              "lib/$soname=BUILD/" +
+                  rebase_path("$target_out_dir/$soname.debug", root_build_dir),
+            ]
+            if (defined(invoker.install_path)) {
+              install_path = invoker.install_path
+            } else {
+              install_path = "lib/${toolchain.libprefix}lib${_library_name}.so"
+            }
+            if (install_path != false) {
+              contents +=
+                  [ "dist/$install_path=BUILD/" +
+                    rebase_path("$target_out_dir/$soname", root_build_dir) ]
+            }
+          }
+        }
+        contents += [ "[includes]" ]
+        foreach(file, invoker.sdk_headers) {
+          contents += [ rebase_path(file, ".") + "=SOURCE/" +
+                        rebase_path(file, "//", "include") ]
+        }
+        sdk_deps = []
+        if (defined(invoker.public_deps)) {
+          sdk_deps += invoker.public_deps
+        }
+        if (sdk != "shared" && defined(invoker.deps)) {
+          sdk_deps += invoker.deps
+        }
+        if (sdk_deps != []) {
+          banjo_deps = []
+          fidl_deps = []
+          lib_deps = []
+          foreach(label, sdk_deps) {
+            if (get_path_info(get_label_info(label, "dir"), "dir") ==
+                "$zx/system/banjo") {
+              banjo_deps += [ get_label_info(label, "name") ]
+            } else if (get_label_info(label, "name") == "c.headers" ||
+                       (get_label_info(label, "name") == "c" &&
+                        get_path_info(get_label_info(label, "dir"), "dir") ==
+                        "$zx/system/fidl")) {
+              assert(get_path_info(get_label_info(label, "dir"), "dir") ==
+                     "$zx/system/fidl")
+              fidl_deps +=
+                  [ get_path_info(get_label_info(label, "dir"), "name") ]
+            } else if (get_label_info(label, "name") !=
+                       "generated-public-headers" &&
+                       (get_label_info(label, "dir") != "$zx/system/ulib/fbl" ||
+                        get_label_info(":$target_name", "dir") !=
+                        "$zx/system/ulib/trace-engine")) {
+              if (get_path_info(get_label_info(label, "name"), "extension") ==
+                  "headers") {
+                lib_deps +=
+                    [ get_path_info(get_label_info(label, "name"), "name") ]
+              } else if (get_label_info(label, "name") == "headers") {
+                lib_deps +=
+                    [ get_path_info(get_label_info(label, "dir"), "name") ]
+              } else if (get_path_info(get_label_info(label, "name"), "name") !=
+                         "common" && get_label_info(label, "name") != "static") {
+                lib_deps += [ get_label_info(label, "name") ]
+              }
+            }
+          }
+          if (lib_deps != []) {
+            # Uniquify.
+            unique_lib_deps = []
+            foreach(dep, lib_deps) {
+              unique_lib_deps += [ dep ]
+              unique_lib_deps -= [ dep ]
+              unique_lib_deps += [ dep ]
+            }
+            contents += [ "[deps]" ] + unique_lib_deps
+          }
+          if (banjo_deps != []) {
+            # Uniquify.
+            unique_banjo_deps = []
+            foreach(dep, banjo_deps) {
+              unique_banjo_deps += [ dep ]
+              unique_banjo_deps -= [ dep ]
+              unique_banjo_deps += [ dep ]
+            }
+            contents += [ "[banjo-deps]" ] + unique_banjo_deps
+          }
+          if (fidl_deps != []) {
+            # Uniquify.
+            unique_fidl_deps = []
+            foreach(dep, fidl_deps) {
+              unique_fidl_deps += [ dep ]
+              unique_fidl_deps -= [ dep ]
+              unique_fidl_deps += [ dep ]
+            }
+            contents += [ "[fidl-deps]" ] + unique_fidl_deps
+          }
+        }
+      }
+    }
+  }
 }
 
 ###
diff --git a/zircon/system/ulib/c/BUILD.gn b/zircon/system/ulib/c/BUILD.gn
index 7f120a4..1b283bd 100644
--- a/zircon/system/ulib/c/BUILD.gn
+++ b/zircon/system/ulib/c/BUILD.gn
@@ -2,9 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("$zx/public/gn/legacy_pkg.gni")  # TODO(BLD-353): temporary hack
+
 library("c") {
-  sdk = "shared"
-  sdk_headers = []  # TODO
   shared = true
   static = false
 
@@ -23,6 +23,11 @@
 
   # Suppress the ${toolchain.implicit_deps} that points back to here.
   no_implicit_deps = true
+
+  if (toolchain.environment == "user" && current_toolchain == toolchain.shlib &&
+      toolchain.tags + [ "gcc" ] - [ "gcc" ] == []) {
+    deps += [ ":c-$current_cpu.pkg" ]
+  }
 }
 
 group("crt1") {
@@ -30,3 +35,341 @@
     "$zx/third_party/ulib/musl:crt1",
   ]
 }
+
+# TODO(BLD-353): The generic kludgery can't handle the weirdness here.
+# So emit the pkg file directly.
+if (toolchain.environment == "user" && current_toolchain == toolchain.shlib &&
+    toolchain.tags + [ "gcc" ] - [ "gcc" ] == []) {
+  legacy_pkg("c-$current_cpu.pkg") {
+    contents = [
+      "[package]",
+      "name=c",
+      "type=lib",
+      "arch=$zircon_cpu",
+    ]
+
+    contents += [ "[includes]" ]
+    musl_headers = [
+      "alloca.h",
+      "ar.h",
+      "arpa/ftp.h",
+      "arpa/inet.h",
+      "arpa/nameser.h",
+      "arpa/nameser_compat.h",
+      "arpa/telnet.h",
+      "arpa/tftp.h",
+      "assert.h",
+      "bits/aarch64/endian.h",
+      "bits/aarch64/fenv.h",
+      "bits/aarch64/float.h",
+      "bits/aarch64/io.h",
+      "bits/aarch64/ioctl.h",
+      "bits/aarch64/ipc.h",
+      "bits/aarch64/reg.h",
+      "bits/aarch64/setjmp.h",
+      "bits/aarch64/signal.h",
+      "bits/aarch64/stat.h",
+      "bits/alltypes.h",
+      "bits/endian.h",
+      "bits/errno.h",
+      "bits/fcntl.h",
+      "bits/fenv.h",
+      "bits/float.h",
+      "bits/io.h",
+      "bits/ioctl.h",
+      "bits/ipc.h",
+      "bits/limits.h",
+      "bits/msg.h",
+      "bits/null.h",
+      "bits/poll.h",
+      "bits/posix.h",
+      "bits/reg.h",
+      "bits/resource.h",
+      "bits/sem.h",
+      "bits/setjmp.h",
+      "bits/shm.h",
+      "bits/signal.h",
+      "bits/socket.h",
+      "bits/stat.h",
+      "bits/statfs.h",
+      "bits/termios.h",
+      "bits/x86_64/endian.h",
+      "bits/x86_64/fenv.h",
+      "bits/x86_64/float.h",
+      "bits/x86_64/io.h",
+      "bits/x86_64/ioctl.h",
+      "bits/x86_64/ipc.h",
+      "bits/x86_64/reg.h",
+      "bits/x86_64/setjmp.h",
+      "bits/x86_64/signal.h",
+      "bits/x86_64/stat.h",
+      "byteswap.h",
+      "complex.h",
+      "cpio.h",
+      "crypt.h",
+      "ctype.h",
+      "dirent.h",
+      "dlfcn.h",
+      "elf.h",
+      "endian.h",
+      "err.h",
+      "errno.h",
+      "fcntl.h",
+      "features.h",
+      "fenv.h",
+      "float.h",
+      "fmtmsg.h",
+      "fnmatch.h",
+      "ftw.h",
+      "getopt.h",
+      "glob.h",
+      "grp.h",
+      "iconv.h",
+      "ifaddrs.h",
+      "inttypes.h",
+      "iso646.h",
+      "langinfo.h",
+      "libgen.h",
+      "limits.h",
+      "link.h",
+      "locale.h",
+      "malloc.h",
+      "math.h",
+      "memory.h",
+      "monetary.h",
+      "net/ethernet.h",
+      "net/if.h",
+      "net/if_arp.h",
+      "net/route.h",
+      "netdb.h",
+      "netinet/ether.h",
+      "netinet/icmp6.h",
+      "netinet/if_ether.h",
+      "netinet/igmp.h",
+      "netinet/in.h",
+      "netinet/in_systm.h",
+      "netinet/ip.h",
+      "netinet/ip6.h",
+      "netinet/ip_icmp.h",
+      "netinet/tcp.h",
+      "netinet/udp.h",
+      "netpacket/packet.h",
+      "nl_types.h",
+      "paths.h",
+      "poll.h",
+      "pthread.h",
+      "pty.h",
+      "pwd.h",
+      "regex.h",
+      "resolv.h",
+      "sched.h",
+      "search.h",
+      "semaphore.h",
+      "setjmp.h",
+      "signal.h",
+      "spawn.h",
+      "stdio.h",
+      "stdlib.h",
+      "stdnoreturn.h",
+      "string.h",
+      "strings.h",
+      "stropts.h",
+      "sys/acct.h",
+      "sys/auxv.h",
+      "sys/dir.h",
+      "sys/errno.h",
+      "sys/eventfd.h",
+      "sys/fcntl.h",
+      "sys/file.h",
+      "sys/fsuid.h",
+      "sys/io.h",
+      "sys/ioctl.h",
+      "sys/ipc.h",
+      "sys/klog.h",
+      "sys/mman.h",
+      "sys/mount.h",
+      "sys/msg.h",
+      "sys/mtio.h",
+      "sys/param.h",
+      "sys/personality.h",
+      "sys/poll.h",
+      "sys/quota.h",
+      "sys/random.h",
+      "sys/reboot.h",
+      "sys/reg.h",
+      "sys/select.h",
+      "sys/sem.h",
+      "sys/shm.h",
+      "sys/signal.h",
+      "sys/signalfd.h",
+      "sys/socket.h",
+      "sys/stat.h",
+      "sys/statfs.h",
+      "sys/statvfs.h",
+      "sys/stropts.h",
+      "sys/swap.h",
+      "sys/syslog.h",
+      "sys/termios.h",
+      "sys/time.h",
+      "sys/timeb.h",
+      "sys/timerfd.h",
+      "sys/times.h",
+      "sys/timex.h",
+      "sys/ttydefaults.h",
+      "sys/types.h",
+      "sys/ucontext.h",
+      "sys/uio.h",
+      "sys/un.h",
+      "sys/utsname.h",
+      "sys/vfs.h",
+      "sys/wait.h",
+      "sysexits.h",
+      "syslog.h",
+      "tar.h",
+      "termios.h",
+      "threads.h",
+      "time.h",
+      "uchar.h",
+      "ucontext.h",
+      "unistd.h",
+      "utime.h",
+      "values.h",
+      "wait.h",
+      "wchar.h",
+      "wctype.h",
+      "wordexp.h",
+      "zircon/dlfcn.h",
+      "zircon/sanitizer.h",
+      "zircon/threads.h",
+    ]
+    foreach(file, musl_headers) {
+      contents += [ "$file=SOURCE/third_party/ulib/musl/include/$file" ]
+    }
+
+    public_headers = [
+      "zircon/assert.h",
+      "zircon/boot/bootdata.h",
+      "zircon/boot/driver-config.h",
+      "zircon/boot/e820.h",
+      "zircon/boot/image.h",
+      "zircon/boot/multiboot.h",
+      "zircon/boot/netboot.h",
+      "zircon/boot/sysconfig.h",
+      "zircon/compiler.h",
+      "zircon/device/audio-codec.h",
+      "zircon/device/audio.h",
+      "zircon/device/block.h",
+      "zircon/device/bt-hci.h",
+      "zircon/device/clk.h",
+      "zircon/device/device.h",
+      "zircon/device/display-controller.h",
+      "zircon/device/ethertap.h",
+      "zircon/device/ethernet.h",
+      "zircon/device/intel-hda.h",
+      "zircon/device/ioctl-wrapper.h",
+      "zircon/device/ioctl.h",
+      "zircon/device/ktrace.h",
+      "zircon/device/media-codec.h",
+      "zircon/device/midi.h",
+      "zircon/device/nand.h",
+      "zircon/device/pty.h",
+      "zircon/device/qmi-transport.h",
+      "zircon/device/serial.h",
+      "zircon/device/thermal.h",
+      "zircon/device/usb-peripheral-test.h",
+      "zircon/device/usb-peripheral.h",
+      "zircon/device/vfs.h",
+      "zircon/driver/binding.h",
+      "zircon/errors.h",
+      "zircon/features.h",
+      "zircon/fidl.h",
+      "zircon/hw/gpt.h",
+      "zircon/hw/i2c.h",
+      "zircon/hw/pci.h",
+      "zircon/hw/usb.h",
+      "zircon/hw/usb/audio.h",
+      "zircon/hw/usb/cdc.h",
+      "zircon/hw/usb/dfu.h",
+      "zircon/hw/usb/hid.h",
+      "zircon/hw/usb/hub.h",
+      "zircon/hw/usb/ums.h",
+      "zircon/hw/usb/video.h",
+      "zircon/limits.h",
+      "zircon/listnode.h",
+      "zircon/pixelformat.h",
+      "zircon/process.h",
+      "zircon/processargs.h",
+      "zircon/rights.h",
+      "zircon/syscalls.abigen",
+      "zircon/syscalls.h",
+      "zircon/syscalls/debug.h",
+      "zircon/syscalls/exception.h",
+      "zircon/syscalls/hypervisor.h",
+      "zircon/syscalls/iommu.h",
+      "zircon/syscalls/log.h",
+      "zircon/syscalls/object.h",
+      "zircon/syscalls/pci.h",
+      "zircon/syscalls/policy.h",
+      "zircon/syscalls/port.h",
+      "zircon/syscalls/profile.h",
+      "zircon/syscalls/resource.h",
+      "zircon/syscalls/smc.h",
+      "zircon/syscalls/system.h",
+      "zircon/syscalls/types.h",
+      "zircon/time.h",
+      "zircon/tls.h",
+      "zircon/types.h",
+    ]
+    foreach(file, public_headers) {
+      contents += [ "$file=SOURCE/system/public/$file" ]
+    }
+
+    vdso_headers = [
+      "zircon/syscalls/definitions.h",
+      "zircon/syscalls/definitions.rs",
+    ]
+    foreach(file, vdso_headers) {
+      contents += [ "$file=BUILD/" +
+                    rebase_path("$root_gen_dir/$file", root_build_dir) ]
+    }
+    contents +=
+        [ "zircon/status.h=SOURCE/system/ulib/zircon/include/zircon/status.h" ]
+
+    contents += [ "[lib]" ]
+
+    debug_libs = [
+      "$target_out_dir/libc.so",
+      get_label_info("$zx/system/ulib/zircon", "target_out_dir") +
+          "/libzircon.so",
+    ]
+    foreach(lib, debug_libs) {
+      contents += [
+        "debug/" + get_path_info(lib, "file") + "=BUILD/" +
+            rebase_path("$lib.debug", root_build_dir),
+        "lib/" + get_path_info(lib, "file") + "=BUILD/" +
+            rebase_path("$lib.debug", root_build_dir),
+      ]
+    }
+
+    dummy_libs = [
+      "libdl.so",
+      "libm.so",
+      "libpthread.so",
+      "librt.so",
+    ]
+    foreach(lib, dummy_libs) {
+      contents += [ "lib/$lib=SOURCE/third_party/ulib/musl/lib.ld" ]
+    }
+
+    contents += [
+      "lib/Scrt1.o=BUILD/" + rebase_path(
+              get_label_info(
+                      "$zx/third_party/ulib/musl:crt1(${toolchain.label})",
+                      "target_out_dir") +
+                  "/arch/${toolchain.cpu}/crt1.Scrt1.S.o",
+              root_build_dir),
+      "dist/lib/ld.so.1=BUILD/" +
+          rebase_path("$target_out_dir/libc.so", root_build_dir),
+    ]
+  }
+}
diff --git a/zircon/system/ulib/fbl/BUILD.gn b/zircon/system/ulib/fbl/BUILD.gn
index cde0ae5..c53903c 100644
--- a/zircon/system/ulib/fbl/BUILD.gn
+++ b/zircon/system/ulib/fbl/BUILD.gn
@@ -65,4 +65,13 @@
     # Avoid circularity.
     configs -= [ "$zx/kernel/vm:headers.config" ]
   }
+
+  if (is_fuchsia && !is_kernel) {
+    # TODO(BLD-353): It doesn't really depend on the vDSO, but this is the
+    # way to get the legacy build to use -Isystem/public for host library
+    # builds (go figure).
+    deps = [
+      "$zx/system/ulib/zircon",
+    ]
+  }
 }
diff --git a/zircon/system/ulib/libzbi/BUILD.gn b/zircon/system/ulib/libzbi/BUILD.gn
index c2691e8..50f3252a3 100644
--- a/zircon/system/ulib/libzbi/BUILD.gn
+++ b/zircon/system/ulib/libzbi/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 library("libzbi") {
+  output_prefix_override = true
   sdk = "static"
   sdk_headers = [
     "libzbi/zbi-cpp.h",
diff --git a/zircon/system/ulib/zircon/BUILD.gn b/zircon/system/ulib/zircon/BUILD.gn
index 286cdbb..3c0d2ca 100644
--- a/zircon/system/ulib/zircon/BUILD.gn
+++ b/zircon/system/ulib/zircon/BUILD.gn
@@ -34,8 +34,7 @@
   }
 
   library("zircon") {
-    sdk = "shared"
-    sdk_headers = [ "zircon/status.h" ]  # TODO(BLD-353)
+    # TODO(BLD-353): Legacy export for this is handled in $zx/system/ulib/c.
     shared = true
     static = false