Browse Source

ci: generate debug symbols on Linux (#18676)

Julien Isorce 5 years ago
parent
commit
92ff39c168

+ 11 - 2
.circleci/config.yml

@@ -349,9 +349,18 @@ step-maybe-electron-dist-strip: &step-maybe-electron-dist-strip
   run:
     name: Strip electron binaries
     command: |
-      if [ "$STRIP_BINARIES" == "true" ] && [ "`uname`" != "Darwin" ]; then
+      if [ "$STRIP_BINARIES" == "true" ] && [ "`uname`" == "Linux" ]; then
+        if [ x"$TARGET_ARCH" == x ]; then
+          target_cpu=x64
+        elif [ "$TARGET_ARCH" == "ia32" ]; then
+          target_cpu=x86
+        else
+          target_cpu="$TARGET_ARCH"
+        fi
         cd src
-        electron/script/strip-binaries.py --target-cpu="$TARGET_ARCH"
+        electron/script/copy-debug-symbols.py --target-cpu="$target_cpu" --out-dir=out/Default/debug --compress
+        electron/script/strip-binaries.py --target-cpu="$target_cpu"
+        electron/script/add-debug-link.py --target-cpu="$target_cpu" --debug-dir=out/Default/debug
       fi
 
 step-electron-dist-build: &step-electron-dist-build

+ 66 - 0
script/add-debug-link.py

@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+from __future__ import print_function
+import argparse
+import os
+import sys
+
+from lib.config import LINUX_BINARIES, PLATFORM
+from lib.util import execute, get_objcopy_path, get_out_dir
+
+def add_debug_link_into_binaries(directory, target_cpu, debug_dir):
+  for binary in LINUX_BINARIES:
+    binary_path = os.path.join(directory, binary)
+    if os.path.isfile(binary_path):
+      add_debug_link_into_binary(binary_path, target_cpu, debug_dir)
+
+def add_debug_link_into_binary(binary_path, target_cpu, debug_dir):
+  try:
+    objcopy = get_objcopy_path(target_cpu)
+  except:
+    if PLATFORM == 'linux' and (target_cpu == 'x86' or target_cpu == 'arm' or
+       target_cpu == 'arm64'):
+      # Skip because no objcopy binary on the given target.
+      return
+    raise
+  debug_name = get_debug_name(binary_path)
+  # Make sure the path to the binary is not relative because of cwd param.
+  real_binary_path = os.path.realpath(binary_path)
+  cmd = [objcopy, '--add-gnu-debuglink=' + debug_name, real_binary_path]
+  execute(cmd, cwd=debug_dir)
+
+def get_debug_name(binary_path):
+  return os.path.basename(binary_path) + '.debug'
+
+def main():
+  args = parse_args()
+  if args.file:
+    add_debug_link_into_binary(args.file, args.target_cpu, args.debug_dir)
+  else:
+    add_debug_link_into_binaries(args.directory, args.target_cpu,
+                                 args.debug_dir)
+
+def parse_args():
+  parser = argparse.ArgumentParser(description='Add debug link to binaries')
+  parser.add_argument('-d', '--directory',
+                      help='Path to the dir that contains files to add links',
+                      default=get_out_dir(),
+                      required=False)
+  parser.add_argument('-f', '--file',
+                      help='Path to a specific file to add debug link',
+                      required=False)
+  parser.add_argument('-s', '--debug-dir',
+                      help='Path to the dir that contain the debugs',
+                      default=None,
+                      required=True)
+  parser.add_argument('-v', '--verbose',
+                      action='store_true',
+                      help='Prints the output of the subprocesses')
+  parser.add_argument('--target-cpu',
+                      default='',
+                      required=False,
+                      help='Target cpu of binaries to add debug link')
+
+  return parser.parse_args()
+
+if __name__ == '__main__':
+  sys.exit(main())

+ 75 - 0
script/copy-debug-symbols.py

@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+from __future__ import print_function
+import argparse
+import os
+import sys
+
+from lib.config import LINUX_BINARIES, PLATFORM
+from lib.util import execute, get_objcopy_path, get_out_dir, safe_mkdir
+
+# It has to be done before stripping the binaries.
+def copy_debug_from_binaries(directory, out_dir, target_cpu, compress):
+  for binary in LINUX_BINARIES:
+    binary_path = os.path.join(directory, binary)
+    if os.path.isfile(binary_path):
+      copy_debug_from_binary(binary_path, out_dir, target_cpu, compress)
+
+def copy_debug_from_binary(binary_path, out_dir, target_cpu, compress):
+  try:
+    objcopy = get_objcopy_path(target_cpu)
+  except:
+    if PLATFORM == 'linux' and (target_cpu == 'x86' or target_cpu == 'arm' or
+       target_cpu == 'arm64'):
+      # Skip because no objcopy binary on the given target.
+      return
+    raise
+  debug_name = get_debug_name(binary_path)
+  cmd = [objcopy, '--only-keep-debug']
+  if compress:
+    cmd.extend(['--compress-debug-sections'])
+  cmd.extend([binary_path, os.path.join(out_dir, debug_name)])
+  execute(cmd)
+  return debug_name
+
+def get_debug_name(binary_path):
+  return os.path.basename(binary_path) + '.debug'
+
+def main():
+  args = parse_args()
+  safe_mkdir(args.out_dir)
+  if args.file:
+    copy_debug_from_binary(args.file, args.out_dir, args.target_cpu,
+                           args.compress)
+  else:
+    copy_debug_from_binaries(args.directory, args.out_dir, args.target_cpu,
+                             args.compress)
+
+def parse_args():
+  parser = argparse.ArgumentParser(description='Copy debug from binaries')
+  parser.add_argument('-d', '--directory',
+                      help='Path to the dir that contains files to copy',
+                      default=get_out_dir(),
+                      required=False)
+  parser.add_argument('-f', '--file',
+                      help='Path to a specific file to copy debug symbols',
+                      required=False)
+  parser.add_argument('-o', '--out-dir',
+                      help='Path to the dir that will contain the debugs',
+                      default=None,
+                      required=True)
+  parser.add_argument('-v', '--verbose',
+                      action='store_true',
+                      help='Prints the output of the subprocesses')
+  parser.add_argument('--target-cpu',
+                      default='',
+                      required=False,
+                      help='Target cpu of binaries to copy debug symbols')
+  parser.add_argument('--compress',
+                      action='store_true',
+                      required=False,
+                      help='Compress the debug symbols')
+
+  return parser.parse_args()
+
+if __name__ == '__main__':
+  sys.exit(main())

+ 12 - 0
script/lib/config.py

@@ -26,6 +26,18 @@ PLATFORM = {
   'win32': 'win32',
 }[sys.platform]
 
+LINUX_BINARIES = [
+  'electron',
+  'chrome-sandbox',
+  'crashpad_handler',
+  'libffmpeg.so',
+  'libGLESv2.so',
+  'libEGL.so',
+  'swiftshader/libGLESv2.so',
+  'swiftshader/libEGL.so',
+  'libvk_swiftshader.so'
+]
+
 verbose_mode = False
 
 

+ 13 - 1
script/lib/util.py

@@ -123,7 +123,8 @@ def make_zip(zip_file_path, files, dirs):
     files += dirs
     execute(['zip', '-r', '-y', zip_file_path] + files)
   else:
-    zip_file = zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_DEFLATED)
+    zip_file = zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_DEFLATED,
+                               allowZip64=True)
     for filename in files:
       zip_file.write(filename, filename)
     for dirname in dirs:
@@ -266,3 +267,14 @@ def get_buildtools_executable(name):
   if sys.platform == 'win32':
     path += '.exe'
   return path
+
+def get_objcopy_path(target_cpu):
+  if PLATFORM != 'linux':
+    raise Exception(
+      "get_objcopy_path: unexpected platform '{0}'".format(PLATFORM))
+
+  if target_cpu != 'x64':
+      raise Exception(
+      "get_objcopy_path: unexpected target cpu '{0}'".format(target_cpu))
+  return os.path.join(SRC_DIR, 'third_party', 'binutils', 'Linux_x64',
+                        'Release', 'bin', 'objcopy')

+ 1 - 0
script/release/release.js

@@ -114,6 +114,7 @@ function assetsForVersion (version, validatingRelease) {
     `electron-${version}-linux-armv7l.zip`,
     `electron-${version}-linux-ia32-symbols.zip`,
     `electron-${version}-linux-ia32.zip`,
+    `electron-${version}-linux-x64-debug.zip`,
     `electron-${version}-linux-x64-symbols.zip`,
     `electron-${version}-linux-x64.zip`,
     `electron-${version}-mas-x64-dsym.zip`,

+ 5 - 0
script/release/uploaders/upload.py

@@ -35,6 +35,7 @@ DIST_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION)
 SYMBOLS_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION, 'symbols')
 DSYM_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION, 'dsym')
 PDB_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION, 'pdb')
+DEBUG_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION, 'debug')
 
 
 def main():
@@ -83,6 +84,10 @@ def main():
     pdb_zip = os.path.join(OUT_DIR, PDB_NAME)
     shutil.copy2(os.path.join(OUT_DIR, 'pdb.zip'), pdb_zip)
     upload_electron(release, pdb_zip, args)
+  elif PLATFORM == 'linux':
+    debug_zip = os.path.join(OUT_DIR, DEBUG_NAME)
+    shutil.copy2(os.path.join(OUT_DIR, 'debug.zip'), debug_zip)
+    upload_electron(release, debug_zip, args)
 
   # Upload free version of ffmpeg.
   ffmpeg = get_zip_name('ffmpeg', ELECTRON_VERSION)

+ 2 - 14
script/strip-binaries.py

@@ -4,22 +4,11 @@ import argparse
 import os
 import sys
 
+from lib.config import LINUX_BINARIES
 from lib.util import execute, get_out_dir
 
-LINUX_BINARIES_TO_STRIP = [
-  'electron',
-  'chrome-sandbox',
-  'crashpad_handler',
-  'libffmpeg.so',
-  'libGLESv2.so',
-  'libEGL.so',
-  'swiftshader/libGLESv2.so',
-  'swiftshader/libEGL.so',
-  'libvk_swiftshader.so'
-]
-
 def strip_binaries(directory, target_cpu):
-  for binary in LINUX_BINARIES_TO_STRIP:
+  for binary in LINUX_BINARIES:
     binary_path = os.path.join(directory, binary)
     if os.path.isfile(binary_path):
       strip_binary(binary_path, target_cpu)
@@ -37,7 +26,6 @@ def strip_binary(binary_path, target_cpu):
 
 def main():
   args = parse_args()
-  print(args)
   if args.file:
     strip_binary(args.file, args.target_cpu)
   else:

+ 7 - 0
script/zip-symbols.py

@@ -43,6 +43,13 @@ def main():
       pdb_zip_file = os.path.join(args.build_dir, pdb_name)
       print('Making pdb zip: ' + pdb_zip_file)
       make_zip(pdb_zip_file, pdbs + licenses, [])
+  elif PLATFORM == 'linux':
+    debug_name = 'debug.zip'
+    with scoped_cwd(args.build_dir):
+      dirs = ['debug']
+      debug_zip_file = os.path.join(args.build_dir, debug_name)
+      print('Making debug zip: ' + debug_zip_file)
+      make_zip(debug_zip_file, licenses, dirs)
 
 def parse_args():
   parser = argparse.ArgumentParser(description='Zip symbols')