Index: llvm/trunk/utils/gn/build/symlink_or_copy.gni =================================================================== --- llvm/trunk/utils/gn/build/symlink_or_copy.gni +++ llvm/trunk/utils/gn/build/symlink_or_copy.gni @@ -0,0 +1,24 @@ +# Creates a symlink (or, on Windows, copies). +# Args: +# source: Path to link to. +# output: Where to create the symlink. +template("symlink_or_copy") { + action(target_name) { + forward_variables_from(invoker, [ "deps" ]) + + # Make a stamp file the output to work around + # https://github.com/ninja-build/ninja/issues/1186 + stamp = + "$target_gen_dir/" + get_path_info(invoker.output, "file") + ".stamp" + outputs = [ + stamp, + ] + script = "//llvm/utils/gn/build/symlink_or_copy.py" + args = [ + "--stamp", + rebase_path(stamp, root_out_dir), + invoker.source, + rebase_path(invoker.output, root_out_dir), + ] + } +} Index: llvm/trunk/utils/gn/build/symlink_or_copy.py =================================================================== --- llvm/trunk/utils/gn/build/symlink_or_copy.py +++ llvm/trunk/utils/gn/build/symlink_or_copy.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +"""Symlinks, or on Windows copies, an existing file to a second location. + +Overwrites the target location if it exists. +Updates the mtime on a stamp file when done.""" + +import argparse +import errno +import os +import sys + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--stamp', required=True, + help='name of a file whose mtime is updated on run') + parser.add_argument('source') + parser.add_argument('output') + args = parser.parse_args() + + # FIXME: This should not check the host platform but the target platform + # (which needs to be passed in as an arg), for cross builds. + if sys.platform != 'win32': + try: + os.symlink(args.source, args.output) + except OSError as e: + if e.errno == errno.EEXIST: + os.remove(args.output) + os.symlink(args.source, args.output) + else: + raise + else: + import shutil + output = args.output + ".exe" + source = args.source + ".exe" + shutil.copyfile(os.path.join(os.path.dirname(output), source), output) + + open(args.stamp, 'w') # Update mtime on stamp file. + + +if __name__ == '__main__': + sys.exit(main()) Index: llvm/trunk/utils/gn/secondary/BUILD.gn =================================================================== --- llvm/trunk/utils/gn/secondary/BUILD.gn +++ llvm/trunk/utils/gn/secondary/BUILD.gn @@ -1,11 +1,40 @@ group("default") { deps = [ - "//lld/tools/lld", + ":lld", "//llvm/tools/llc", "//llvm/tools/llvm-undname", ] } +# Symlink handling. +# On POSIX, symlinks to the target can be created before the target exist, +# and the target can depend on the symlink targets, so that building the +# target ensures the symlinks exist. +# However, symlinks didn't exist on Windows until recently, so there the +# binary needs to be copied -- which requires it to exist. So the symlink step +# needs to run after the target that creates the binary. +# In the cmake build, this is done via a "postbuild" on the target, which just +# tacks on "&& copy out.exe out2.exe" to the link command. +# GN doesn't have a way to express postbuild commands. It could probably be +# emulated by having the link command in the toolchain be a wrapper script that +# reads a ".symlinks" file next to the target, and have an action write that +# and make the target depend on that, but then every single link has to use the +# wrapper (unless we do further acrobatics to use a different toolchain for +# targets that need symlinks) even though most links don't need symlinks. +# Instead, have a top-level target for each target that needs symlinks, and +# make that depend on the symlinks. Then the symlinks can depend on the +# executable. This has the effect that `ninja lld` builds lld and then creates +# symlinks (via this target), while `ninja bin/lld` only builds lld and doesn't +# update symlinks (in particular, on Windows it doesn't copy the new lld to its +# new locations); also `ninja lld-link` will build lld and copy it (on Windows) +# to lld-link, but it won't copy it to ld.lld. +# That seems simpler, more explicit, and good enough. +group("lld") { + deps = [ + "//lld/tools/lld:symlinks", + ] +} + # A pool called "console" in the root BUILD.gn is magic and represents ninja's # built-in console pool. (Requires a GN with `gn --version` >= 552353.) pool("console") { Index: llvm/trunk/utils/gn/secondary/lld/tools/lld/BUILD.gn =================================================================== --- llvm/trunk/utils/gn/secondary/lld/tools/lld/BUILD.gn +++ llvm/trunk/utils/gn/secondary/lld/tools/lld/BUILD.gn @@ -1,4 +1,28 @@ -# FIXME: Set up symlinks pointing to lld. +import("//llvm/utils/gn/build/symlink_or_copy.gni") + +symlinks = [ + "lld-link", + "ld.lld", + "ld64.lld", + "wasm-ld", +] +foreach(target, symlinks) { + symlink_or_copy(target) { + deps = [ + ":lld", + ] + source = "lld" + output = "$root_out_dir/bin/$target" + } +} + +# //:lld depends on this symlink target, see comment in //BUILD.gn. +group("symlinks") { + deps = [] + foreach(target, symlinks) { + deps += [ ":$target" ] + } +} executable("lld") { configs += [ "//llvm/utils/gn/build:lld_code" ]