macOS: Add LLDB debug script when building with separate debug info (dSYM)

The script will look for the most recent Qt Creator version on the system,
and pick up the LLDB summary providers from there, allowing pretty-printing
of Qt types inside LLDB/Xcode.

LLDB will detect the file when loading the dSYM, and inform the user that
the file can be loaded to enable the formatters. The script can be loaded
automatically by adding the following setting in ~/.lldbinit:

    settings set target.load-script-from-symbol-file true

Which comes as a slight security risk, as other libraries might have
scripts of their own. The alternative is to load the script directly
from ~/.lldbinit:

    command script import "<path to debug script in dSYM>"

With an optional target.load-script-from-symbol-file set to false, to
silence the warning when loading the dSYM bundle.

Change-Id: I01ba51dab725a8d0a58f1ad1749742443b639cc5
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Tor Arne Vestbø 2017-05-15 18:04:26 +02:00
parent ddcbe23f20
commit 1b73c202ce
3 changed files with 112 additions and 0 deletions

View File

@ -56,6 +56,13 @@ have_target:!static:if(darwin|!isEmpty(QMAKE_OBJCOPY)) {
debug_info_plist.input = $$QMAKESPEC/Info.plist.dSYM.in
debug_info_plist.output = $${debug_info_target}.$$debug_info_suffix/Contents/Info.plist
QMAKE_SUBSTITUTES += debug_info_plist
!isEmpty(QMAKE_DSYM_DEBUG_SCRIPT) {
debug_script.input = $$QMAKE_DSYM_DEBUG_SCRIPT
debug_script.output = $${debug_info_target}.$$debug_info_suffix/Contents/Resources/Python/$${TARGET}.py
debug_script.CONFIG = verbatim
QMAKE_SUBSTITUTES += debug_script
}
}
contains(INSTALLS, target):isEmpty(target.files):isEmpty(target.commands):isEmpty(target.extra) {
@ -64,6 +71,11 @@ have_target:!static:if(darwin|!isEmpty(QMAKE_OBJCOPY)) {
debug_info_plist_target.files = $${debug_info_target}.$$debug_info_suffix/Contents/Info.plist
debug_info_plist_target.path += $${target.path}/$${debug_info_target_rel}.$$debug_info_suffix/Contents
INSTALLS += debug_info_plist_target
debug_script_target.CONFIG += no_check_exist
debug_script_target.files = $${debug_info_target}.$$debug_info_suffix/Contents/Resources/Python/$${TARGET}.py
debug_script_target.path += $${target.path}/$${debug_info_target_rel}.$$debug_info_suffix/Contents/Resources/Python
INSTALLS += debug_script_target
}
debug_info_target.CONFIG += no_check_exist

View File

@ -146,3 +146,5 @@ ctest_qt5_module_files.files += $$ctest_macros_file.output $$cmake_extras_mkspec
ctest_qt5_module_files.path = $$[QT_INSTALL_LIBS]/cmake/Qt5Core
INSTALLS += ctest_qt5_module_files cmake_qt5_umbrella_module_files
QMAKE_DSYM_DEBUG_SCRIPT = $$PWD/debug_script.py

View File

@ -0,0 +1,98 @@
#############################################################################
##
## Copyright (C) 2017 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of the QtCore module of the Qt Toolkit.
##
## $QT_BEGIN_LICENSE:GPL-EXCEPT$
## Commercial License Usage
## Licensees holding valid commercial Qt licenses may use this file in
## accordance with the commercial license agreement provided with the
## Software or, alternatively, in accordance with the terms contained in
## a written agreement between you and The Qt Company. For licensing terms
## and conditions see https://www.qt.io/terms-conditions. For further
## information use the contact form at https://www.qt.io/contact-us.
##
## GNU General Public License Usage
## Alternatively, this file may be used under the terms of the GNU
## General Public License version 3 as published by the Free Software
## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
## included in the packaging of this file. Please review the following
## information to ensure the GNU General Public License requirements will
## be met: https://www.gnu.org/licenses/gpl-3.0.html.
##
## $QT_END_LICENSE$
##
#############################################################################
import os
import sys
import imp
from distutils.version import LooseVersion
MODULE_NAME = 'qt'
def import_bridge(path, debugger, session_dict, reload_module = False):
if not reload_module and MODULE_NAME in sys.modules:
del sys.modules[MODULE_NAME]
bridge = imp.load_source(MODULE_NAME, path)
if not hasattr(bridge, '__lldb_init_module'):
return None
# Make available for the current LLDB session, so that LLDB
# can find the functions when initializing the module.
session_dict[MODULE_NAME] = bridge
# Initialize the module now that it's available globally
bridge.__lldb_init_module(debugger, session_dict)
if not debugger.GetCategory('Qt'):
# Summary provider failed for some reason
del session_dict[MODULE_NAME]
return None
return bridge
def report_success(bridge):
print "Using Qt summary providers from Creator %s in '%s'" \
% (bridge.CREATOR_VERSION, bridge.CREATOR_PATH)
def __lldb_init_module(debugger, session_dict):
# Check if the module has already been imported globally. This ensures
# that the Qt Creator application search is only performed once per
# LLDB process invocation, while still reloading for each session.
if MODULE_NAME in sys.modules:
module = sys.modules[MODULE_NAME]
# Reload module for this sessions
bridge = import_bridge(module.__file__, debugger, session_dict,
reload_module = True)
if bridge:
report_success(bridge)
return
versions = {}
for install in os.popen(
'mdfind kMDItemCFBundleIdentifier=org.qt-project.qtcreator'
'| while read p;'
'do echo $p=$(mdls "$p" -name kMDItemVersion -raw);'
'done'):
install = install.strip()
(p, v) = install.split('=')
versions[v] = p
for version in sorted(versions, key=LooseVersion, reverse=True):
path = versions[version]
bridge_path = path + '/Contents/Resources/debugger/lldbbridge.py'
bridge = import_bridge(bridge_path, debugger, session_dict)
if bridge:
bridge.CREATOR_VERSION = version
bridge.CREATOR_PATH = path
report_success(bridge)
return
print "Could not find Qt Creator installation, no Qt summary providers installed"