Start to fusl toolchain
R=viettrungluu@chromium.org
Review URL: https://codereview.chromium.org/1649133002 .
diff --git a/build/toolchain/fusl/BUILD.gn b/build/toolchain/fusl/BUILD.gn
new file mode 100644
index 0000000..e6bb779
--- /dev/null
+++ b/build/toolchain/fusl/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/toolchain/gcc_toolchain.gni")
+
+gcc_toolchain("fusl_x64") {
+ prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
+ root_build_dir)
+
+ cc = "$prefix/clang"
+ cxx = "$prefix/clang++"
+
+ readelf = "readelf"
+ nm = "nm"
+ ar = "ar"
+ ld = cc
+
+ toolchain_cpu = "x64"
+ toolchain_os = "linux"
+ is_clang = true
+
+ use_goma = false
+ use_ccache = false
+}
diff --git a/fusl/BUILD.gn b/fusl/BUILD.gn
index a352bcb..268f30f 100644
--- a/fusl/BUILD.gn
+++ b/fusl/BUILD.gn
@@ -2,6 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+# Define the sysroot directory.
+sysroot = "$root_out_dir/sysroot"
+
config("fusl_config") {
cflags = [
# Flags from musl
@@ -39,6 +42,8 @@
]
}
+# See the discussion below about what these files are, and their
+# relationship to other C runtime files.
source_set("crt") {
cflags = []
@@ -1467,10 +1472,12 @@
deps += [ ":libc_${current_cpu}" ]
}
-# Build a sysroot.
-sysroot = "${target_out_dir}/sysroot/"
-sysroot_lib_dir = "${sysroot}/usr/lib"
-sysroot_include_dir = "${sysroot}/usr/include"
+# For simplicity, musl places all its symbols in libc. To support
+# linking against e.g. libm, either implicitly or with an explicit -lm
+# flag, we build empty libraries.
+static_library("libm") {
+ complete_static_lib = true
+}
template("copy_objects") {
assert(defined(invoker.input_dir), "input_dir must be defined")
@@ -1504,6 +1511,9 @@
}
}
+sysroot_lib_dir = "${sysroot}/usr/lib"
+sysroot_include_dir = "${sysroot}/usr/include"
+
copy_objects("copy_crt_objects") {
sources = [
"Scrt1.o",
@@ -1548,34 +1558,126 @@
]
}
-copy("copy_libc") {
+copy("copy_libs") {
deps = [
":libc",
+ ":libm",
]
sources = [
"${target_out_dir}/libc.a",
+ "${target_out_dir}/libm.a",
]
outputs = [
- "${sysroot_lib_dir}/libc.a",
+ "${sysroot_lib_dir}/{{source_name_part}}.a",
]
}
-group("sysroot") {
+group("copy_sysroot") {
deps = [
":copy_crt_objects",
":copy_include",
":copy_include_bits",
- ":copy_libc",
+ ":copy_libs",
]
if (current_cpu == "x64") {
deps += [ ":copy_crt_x64_objects" ]
}
}
+# The crtXXX.o files that are copied elsewhere in this file define
+# _start, and the machinery to implement calling into the init and
+# fini sections. These things are libc dependent and hence part of
+# libc.
+#
+# Unlike the other crtXXX.o files, crtbegin and crtend, are provided
+# by the toolchain, not the libc. So we steal them from the host.
+#
+# crtbegin and crtend know how to call constructors and destructors.
+#
+# libgcc provides runtime support, and so also comes from the
+# compiler. Things in here are stack unwinding, arithmetic not
+# supported on the target architecture, and so on.
+#
+# The best document I am aware of describing the different variants of
+# these files (and crtXXX.o above) is
+# https://dev.gentoo.org/~vapier/crt.txt
+#
+# S and _s mean shared or PIE
+# T and _eh mean static
+action("finish_sysroot") {
+ script = "tools/populate_crt.py"
+
+ clang = "//third_party/llvm-build/Release+Asserts/bin/clang"
+ target = "$sysroot/usr/lib"
+
+ files = [
+ "crtbegin.o",
+ "crtbeginS.o",
+ "crtbeginT.o",
+ "crtend.o",
+ "crtendS.o",
+
+ "libgcc.a",
+ "libgcc_eh.a",
+ "libgcc_s.so",
+ ]
+
+ args = [
+ rebase_path(clang),
+ rebase_path(target),
+ ]
+ args += files
+
+ outputs = [
+ "$target/crtbegin.o",
+ "$target/crtbeginSo.o",
+ "$target/crtbeginT.o",
+ "$target/crtend.o",
+ "$target/crtendS.o",
+
+ "$target/libgcc.a",
+ "$target/libgcc_eh.a",
+ "$target/libgcc_s.so",
+ ]
+
+ deps = [
+ ":copy_sysroot",
+ ]
+}
+
+config("sysroot_config") {
+ rebased_sysroot = rebase_path(sysroot)
+
+ cflags = [
+ "--sysroot=$rebased_sysroot",
+ "-fPIC",
+ "-static",
+ ]
+
+ ldflags = [
+ "--sysroot=$rebased_sysroot",
+ "-static",
+ ]
+}
+
+executable("empty_main") {
+ configs = []
+ configs += [ ":sysroot_config" ]
+
+ sources = [
+ "test/empty_main.c",
+ ]
+
+ deps = [
+ ":finish_sysroot",
+ ]
+}
+
group("fusl") {
deps = [
- ":crt",
- ":libc",
- ":sysroot",
+ ":crt(//build/toolchain/fusl:fusl_$current_cpu)",
+ ":empty_main(//build/toolchain/fusl:fusl_$current_cpu)",
+ ":finish_sysroot(//build/toolchain/fusl:fusl_$current_cpu)",
+ ":libc(//build/toolchain/fusl:fusl_$current_cpu)",
]
}
diff --git a/fusl/test/empty_main.c b/fusl/test/empty_main.c
new file mode 100644
index 0000000..42d078b
--- /dev/null
+++ b/fusl/test/empty_main.c
@@ -0,0 +1,7 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main(int argc, char** argv) {
+ return 0;
+}
diff --git a/fusl/tools/populate_crt.py b/fusl/tools/populate_crt.py
new file mode 100644
index 0000000..733e5c8
--- /dev/null
+++ b/fusl/tools/populate_crt.py
@@ -0,0 +1,73 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os.path
+import shutil
+import subprocess
+import sys
+
+
+"""Populate the compiler-provided portions of the fusl sysroot.
+
+In particular, crtbegin, ocrtend.o,libgcc.a, and so on must be copied
+from the host sysroot to our sysroot.
+"""
+
+def parse_clang_dirs(clang):
+ """Parse the output of |clang -print-search-dirs|.
+
+ This is used to find library search paths. One line of the output
+ is formatted something like:
+
+ libraries: =/usr/lib/gcc/4.8:/lib:/usr/lib
+
+ This functions strips the 'libraries: =' prefix and splits on the
+ colon, returning the list:
+
+ [ '/usr/lib/gcc/4.8', '/lib', '/usr/lib' ]
+ """
+
+ clang_search_dirs = subprocess.check_output([clang, '-print-search-dirs'])
+
+ library_line = None
+ library_line_prefix = 'libraries: ='
+ for line in clang_search_dirs.split('\n'):
+ if line.startswith(library_line_prefix):
+ prefix_length = len(library_line_prefix)
+ library_line = line[prefix_length:]
+ break
+ assert(library_line)
+ return library_line.split(':')
+
+
+def try_populate(artifact, library_paths, target):
+ """Returns whether we found the artifact and copied it."""
+
+ for library_path in library_paths:
+ source = os.path.join(library_path, artifact)
+ if not os.path.isfile(source):
+ continue
+ shutil.copy(source, target)
+ return True
+
+ return False
+
+
+def main():
+ clang = sys.argv[1]
+ target = sys.argv[2]
+ artifacts = sys.argv[3:]
+ assert(len(artifacts))
+
+ library_paths = parse_clang_dirs(clang)
+
+ for artifact in artifacts:
+ if not try_populate(artifact, library_paths, target):
+ print('Unable to locate %s in any of the following paths: %s' %
+ (artifact, library_paths))
+ exit(1)
+
+
+if __name__ == '__main__':
+ main()