From e8e1d878ba228409f23491766deb9a7c8c10deb7 Mon Sep 17 00:00:00 2001 From: agrieve Date: Mon, 10 Aug 2015 14:17:56 -0700 Subject: [PATCH] GN: Use lib.unstripped rather than lib.stripped. Add a toolchain.gni toolchain.gni introduces: root_shlib_dir, shlib_prefix, and shlib_extension The original goal of this change was to put shlibs under lib/ for Linux / Android, since that's where GYP puts them. However, the lack of support for loadable_module (or more specifically - per target output directory) in GN makes this infeasible at the moment. This change also mitigates a subtle bug where on Android the unstripped .so is used mistakenly instead of the lib.stripped/ version. It also fixes shlib's link_output being set to the unstripped .so rather than the stripped .so (on Android). BUG=509771 Review URL: https://codereview.chromium.org/1236503002 Cr-Original-Commit-Position: refs/heads/master@{#342697} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: c3cd5e6fe977af4a3c8b20ccb332896b2c888354 --- android/BUILD.gn | 2 +- config/android/config.gni | 4 --- config/android/rules.gni | 17 ++++++------ config/gcc/BUILD.gn | 12 ++++++--- toolchain/android/BUILD.gn | 24 +---------------- toolchain/gcc_toolchain.gni | 53 +++++++++++++++++++++++++++---------- toolchain/toolchain.gni | 40 ++++++++++++++++++++++++++++ toolchain/win/BUILD.gn | 3 +-- 8 files changed, 100 insertions(+), 55 deletions(-) create mode 100644 toolchain/toolchain.gni diff --git a/android/BUILD.gn b/android/BUILD.gn index d90ad70ab..5e97d1a47 100644 --- a/android/BUILD.gn +++ b/android/BUILD.gn @@ -30,7 +30,7 @@ action("cpplib_stripped") { _strip_bin = "${android_tool_prefix}strip" _soname = "libc++_shared.so" _input_so = "${android_libcpp_root}/libs/${android_app_abi}/${_soname}" - _output_so = "${root_out_dir}/lib.stripped/${_soname}" + _output_so = "${root_shlib_dir}/${_soname}" script = "//build/gn_run_binary.py" inputs = [ diff --git a/config/android/config.gni b/config/android/config.gni index b0c7e482d..8fb5960b4 100644 --- a/config/android/config.gni +++ b/config/android/config.gni @@ -167,12 +167,8 @@ if (is_android) { android_libcpp_root = "$android_ndk_root/sources/cxx-stl/llvm-libc++" if (is_component_build) { android_libcpp_library = "c++_shared" - # By appending .cr, we prevent name collisions with libraries already - # loaded by the Android zygote. - android_product_extension = ".cr.so" } else { android_libcpp_library = "c++_static" - android_product_extension = ".so" } # ABI ------------------------------------------------------------------------ diff --git a/config/android/rules.gni b/config/android/rules.gni index 960c61bd7..f627e4369 100644 --- a/config/android/rules.gni +++ b/config/android/rules.gni @@ -5,6 +5,7 @@ import("//base/android/linker/config.gni") import("//build/config/android/config.gni") import("//build/config/android/internal_rules.gni") +import("//build/toolchain/toolchain.gni") import("//third_party/android_platform/config.gni") import("//tools/grit/grit_rule.gni") @@ -1438,7 +1439,7 @@ template("android_apk") { } if (is_component_build) { - _native_libs += [ "$root_out_dir/lib.stripped/libc++_shared.so" ] + _native_libs += [ "$root_shlib_dir/libc++_shared.so" ] _chromium_linker_dep += [ "//build/android:cpplib_stripped" ] } @@ -1447,12 +1448,13 @@ template("android_apk") { process_file_template(invoker.native_libs, "{{source_name_part}}") _native_libs += process_file_template( _first_ext_removed, - "$root_build_dir/lib.stripped/{{source_name_part}}$android_product_extension") + "$root_shlib_dir/{{source_name_part}}$shlib_extension") _native_libs_dir = base_path + "/libs" if (_use_chromium_linker) { - _native_libs += [ "$root_build_dir/lib.stripped/libchromium_android_linker$android_product_extension" ] + _native_libs += + [ "$root_shlib_dir/libchromium_android_linker$shlib_extension" ] } _enable_relocation_packing = false @@ -1663,7 +1665,7 @@ template("android_apk") { skip_packing_list = [ "gdbserver", - "libchromium_android_linker$android_product_extension", + "libchromium_android_linker$shlib_extension", ] enable_packing_arg = 0 @@ -1947,7 +1949,7 @@ template("unittest_apk") { if (defined(invoker.unittests_binary)) { unittests_binary = invoker.unittests_binary } else { - unittests_binary = "lib${test_suite_name}${android_product_extension}" + unittests_binary = "lib${test_suite_name}${shlib_extension}" } if (defined(invoker.apk_name)) { @@ -2081,7 +2083,7 @@ template("android_aidl") { # Example # create_native_executable_dist("foo_dist") { # dist_dir = "$root_build_dir/foo_dist" -# binary = "$root_build_dir/exe.stripped/foo" +# binary = "$root_build_dir/foo" # deps = [ ":the_thing_that_makes_foo" ] # } template("create_native_executable_dist") { @@ -2100,7 +2102,6 @@ template("create_native_executable_dist") { find_deps_target_name = "${template_name}__find_library_dependencies" copy_target_name = "${template_name}__copy_libraries_and_exe" - stripped_libraries_dir = "$root_build_dir/lib.stripped" action(find_deps_target_name) { visibility = [ ":$copy_target_name" ] @@ -2120,7 +2121,7 @@ template("create_native_executable_dist") { rebase_path(depfile, root_build_dir), "--input-libraries=$rebased_binaries", "--libraries-dir", - rebase_path(stripped_libraries_dir, root_build_dir), + rebase_path(root_shlib_dir, root_build_dir), "--output", rebase_path(libraries_list, root_build_dir), "--readelf", diff --git a/config/gcc/BUILD.gn b/config/gcc/BUILD.gn index edfb92c76..b6ab1d4b9 100644 --- a/config/gcc/BUILD.gn +++ b/config/gcc/BUILD.gn @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/toolchain/toolchain.gni") + # This config causes functions not to be automatically exported from shared # libraries. By default, all symbols are exported but this means there are # lots of exports that slow everything down. In general we explicitly mark @@ -26,11 +28,15 @@ config("executable_ldconfig") { "-Wl,-z,nocopyreloc", ] } else { - # Android doesn't support rpath. + # Note: Android doesn't support rpath. + rpath_link = "" + if (shlib_subdir != ".") { + rpath_link = "${shlib_subdir}/" + } ldflags = [ # Want to pass "\$". GN will re-escape as required for ninja. - "-Wl,-rpath=\$ORIGIN/", - "-Wl,-rpath-link=", + "-Wl,-rpath=\$ORIGIN/${rpath_link}", + "-Wl,-rpath-link=${rpath_link}", # Newer binutils don't set DT_RPATH unless you disable "new" dtags # and the new DT_RUNPATH doesn't work without --no-as-needed flag. diff --git a/toolchain/android/BUILD.gn b/toolchain/android/BUILD.gn index 867fa4897..ed7c407ce 100644 --- a/toolchain/android/BUILD.gn +++ b/toolchain/android/BUILD.gn @@ -64,32 +64,10 @@ template("android_gcc_toolchain") { ld = cxx readelf = compiler_prefix + tool_prefix + "readelf" nm = compiler_prefix + tool_prefix + "nm" + strip = "${tool_prefix}strip" toolchain_os = "android" toolchain_cpu = invoker.toolchain_cpu - - # We make the assumption that the gcc_toolchain will produce a soname with - # the following definition. - soname = "{{target_output_name}}{{output_extension}}" - - stripped_soname = "lib.stripped/${soname}" - temp_stripped_soname = "${stripped_soname}.tmp" - - android_strip = "${tool_prefix}strip" - - strip_command = - "$android_strip --strip-unneeded -o $temp_stripped_soname $soname" - replace_command = "if ! cmp -s $temp_stripped_soname $stripped_soname; then mv $temp_stripped_soname $stripped_soname; fi" - postsolink = "$strip_command && $replace_command" - solink_outputs = [ stripped_soname ] - default_output_extension = android_product_extension - - # We make the assumption that the gcc_toolchain will produce an exe with - # the following definition. - exe = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" - stripped_exe = "exe.stripped/$exe" - postlink = "$android_strip --strip-unneeded -o $stripped_exe $exe" - link_outputs = [ stripped_exe ] } } diff --git a/toolchain/gcc_toolchain.gni b/toolchain/gcc_toolchain.gni index 29b913759..14a66e40f 100644 --- a/toolchain/gcc_toolchain.gni +++ b/toolchain/gcc_toolchain.gni @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/toolchain/toolchain.gni") + # This value will be inherited in the toolchain below. concurrent_links = exec_script("get_concurrent_links.py", [], "value") @@ -34,6 +36,11 @@ concurrent_links = exec_script("get_concurrent_links.py", [], "value") # - deps # Just forwarded to the toolchain definition. # - is_clang +# Whether to use clang instead of gcc. +# - strip +# Location of the strip executable. When specified, strip will be run on +# all shared libraries and executables as they are built. The pre-stripped +# artifacts will be put in lib.stripped/ and exe.stripped/. template("gcc_toolchain") { toolchain(target_name) { assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value") @@ -138,24 +145,34 @@ template("gcc_toolchain") { tool("solink") { soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". sofile = "{{root_out_dir}}/$soname" # Possibly including toolchain dir. + if (shlib_subdir != ".") { + sofile = "{{root_out_dir}}/$shlib_subdir/$soname" + } rspfile = sofile + ".rsp" + unstripped_sofile = sofile + if (defined(invoker.strip)) { + unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname" + } + # These variables are not built into GN but are helpers that implement # (1) linking to produce a .so, (2) extracting the symbols from that file # to a temporary file, (3) if the temporary file has differences from the # existing .TOC file, overwrite it, otherwise, don't change it. tocfile = sofile + ".TOC" temporary_tocname = sofile + ".tmp" - link_command = - "$ld -shared {{ldflags}} -o $sofile -Wl,-soname=$soname @$rspfile" + + link_command = "$ld -shared {{ldflags}} -o $unstripped_sofile -Wl,-soname=$soname @$rspfile" assert(defined(readelf), "to solink you must have a readelf") assert(defined(nm), "to solink you must have an nm") - toc_command = "{ $readelf -d $sofile | grep SONAME ; $nm -gD -f p $sofile | cut -f1-2 -d' '; } > $temporary_tocname" + toc_command = "{ $readelf -d $unstripped_sofile | grep SONAME ; $nm -gD -f p $unstripped_sofile | cut -f1-2 -d' '; } > $temporary_tocname" replace_command = "if ! cmp -s $temporary_tocname $tocfile; then mv $temporary_tocname $tocfile; fi" command = "$link_command && $toc_command && $replace_command" - if (defined(invoker.postsolink)) { - command += " && " + invoker.postsolink + if (defined(invoker.strip)) { + strip_command = + "${invoker.strip} --strip-unneeded -o $sofile $unstripped_sofile" + command += " && " + strip_command } rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" @@ -164,7 +181,7 @@ template("gcc_toolchain") { # Use this for {{output_extension}} expansions unless a target manually # overrides it (in which case {{output_extension}} will be what the target # specifies). - default_output_extension = ".so" + default_output_extension = shlib_extension if (defined(invoker.default_output_extension)) { default_output_extension = invoker.default_output_extension } @@ -182,27 +199,35 @@ template("gcc_toolchain") { sofile, tocfile, ] - if (defined(invoker.solink_outputs)) { - outputs += invoker.solink_outputs + if (sofile != unstripped_sofile) { + outputs += [ unstripped_sofile ] } link_output = sofile depend_output = tocfile } tool("link") { - outfile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" + exename = "{{target_output_name}}{{output_extension}}" + outfile = "{{root_out_dir}}/$exename" rspfile = "$outfile.rsp" - command = "$ld {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix" - if (defined(invoker.postlink)) { - command += " && " + invoker.postlink + unstripped_outfile = outfile + if (defined(invoker.strip)) { + unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$exename" + } + + command = "$ld {{ldflags}} -o $unstripped_outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix" + if (defined(invoker.strip)) { + strip_command = + "${invoker.strip} --strip-unneeded -o $outfile $unstripped_outfile" + command += " && " + strip_command } description = "LINK $outfile" rspfile_content = "{{inputs}}" outputs = [ outfile, ] - if (defined(invoker.link_outputs)) { - outputs += invoker.link_outputs + if (outfile != unstripped_outfile) { + outputs += [ unstripped_outfile ] } } diff --git a/toolchain/toolchain.gni b/toolchain/toolchain.gni new file mode 100644 index 000000000..5bd7d9c71 --- /dev/null +++ b/toolchain/toolchain.gni @@ -0,0 +1,40 @@ +# Copyright 2015 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. + +# Toolchain-related configuration that may be needed outside the context of the +# toolchain() rules themselves. + +# Subdirectory within root_out_dir for shared library files. +# TODO(agrieve): GYP sets this to "lib" for Linux & Android, but this won't work +# in GN until support for loadable_module() is added. +# See: https://codereview.chromium.org/1236503002/ +shlib_subdir = "." + +# Root out dir for shared library files. +root_shlib_dir = root_out_dir +if (shlib_subdir != ".") { + root_shlib_dir += "/$shlib_subdir" +} + +# Extension for shared library files (including leading dot). +if (is_mac || is_ios) { + shlib_extension = ".dylib" +} else if (is_android && is_component_build) { + # By appending .cr, we prevent name collisions with libraries already + # loaded by the Android zygote. + shlib_extension = ".cr.so" +} else if (is_posix) { + shlib_extension = ".so" +} else if (is_win) { + shlib_extension = ".dll" +} else { + assert(false, "Platform not supported") +} + +# Prefix for shared library files. +if (is_posix) { + shlib_prefix = "lib" +} else { + shlib_prefix = "" +} diff --git a/toolchain/win/BUILD.gn b/toolchain/win/BUILD.gn index 6c3e06b1b..a0542678e 100644 --- a/toolchain/win/BUILD.gn +++ b/toolchain/win/BUILD.gn @@ -147,8 +147,7 @@ template("msvc_toolchain") { tool("solink") { dllname = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" # e.g. foo.dll - libname = - "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.lib" # e.g. foo.dll.lib + libname = "${dllname}.lib" # e.g. foo.dll.lib rspfile = "${dllname}.rsp" link_command = "$python_path gyp-win-tool link-wrapper $env False link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:${dllname}.pdb @$rspfile"