forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.2'
Change-Id: I259a402bc896fc2e359cc96b7510453ac9a9a552
This commit is contained in:
Vendored
+10
@@ -45,6 +45,8 @@ Debugging
|
||||
* CDB
|
||||
* Fixed display order of vectors in vectors (QTCREATORBUG-16813)
|
||||
* Fixed display of QList contents (QTCREATORBUG-16750)
|
||||
* QML
|
||||
* Fixed that expansion state was reset when stepping
|
||||
|
||||
QML Profiler
|
||||
|
||||
@@ -69,4 +71,12 @@ Android
|
||||
|
||||
iOS
|
||||
|
||||
* Fixed simulator support with Xcode 8 (QTCREATORBUG-16942)
|
||||
Known issue: Qt Creator is blocked until simulator finishes starting
|
||||
* Fixed that standard paths reported by QStandardPaths were wrong when
|
||||
running on simulator (QTCREATORBUG-13655)
|
||||
* Fixed QML debugging on device (QTCREATORBUG-15812)
|
||||
|
||||
QNX
|
||||
|
||||
* Fixed QML debugging (QTCREATORBUG-17208)
|
||||
|
||||
Vendored
+24
-2
@@ -22,6 +22,8 @@ Welcome
|
||||
|
||||
* Added keyboard shortcuts for opening recent sessions and projects
|
||||
* Improved performance when many sessions are shown
|
||||
* Fixed dropping files on Qt Creator when Welcome screen was visible
|
||||
(QTCREATORBUG-14194)
|
||||
|
||||
Editing
|
||||
|
||||
@@ -42,6 +44,8 @@ All Projects
|
||||
QMake Projects
|
||||
|
||||
* Removed Qt Labs Controls wizard which is superseded by Qt Quick Controls 2
|
||||
* Fixed that run button could spuriously stay disabled
|
||||
(QTCREATORBUG-16172, QTCREATORBUG-15583)
|
||||
* Fixed `Open with Designer` and `Open with Linguist` for mobile and embedded Qt
|
||||
(QTCREATORBUG-16558)
|
||||
* Fixed Add Library wizard when selecting library from absolute path or
|
||||
@@ -65,6 +69,7 @@ C++ Support
|
||||
|
||||
* Added preview of images to tool tip on Qt resource URLs
|
||||
* Added option to skip big files when indexing (QTCREATORBUG-16712)
|
||||
* Fixed random crash in LookupContext (QTCREATORBUG-14911)
|
||||
* Fixed `Move Definition to Class` for functions in template class and
|
||||
template member functions (QTCREATORBUG-14354)
|
||||
* Fixed issues with `Add Declaration`, `Add Definition`, and
|
||||
@@ -75,13 +80,15 @@ C++ Support
|
||||
|
||||
Debugging
|
||||
|
||||
* Added pretty printing of `QRegExp` captures
|
||||
* Added pretty printing of `QStaticStringData`
|
||||
* Added pretty printing of `QRegExp` captures, `QStaticStringData`, and
|
||||
`std::pair`
|
||||
* Improved pretty printing of QV4 types
|
||||
* Made display of maps more compact
|
||||
* Fixed pretty printing of `QFixed`
|
||||
* LLDB
|
||||
* Added support for Qt Creator variables `%{...}` in startup commands
|
||||
* QML
|
||||
* Fixed `Load QML Stack` with Qt 5.7 and later (QTCREATORBUG-17097)
|
||||
|
||||
QML Profiler
|
||||
|
||||
@@ -104,6 +111,11 @@ Qt Quick Designer
|
||||
(QTCREATORBUG-14830)
|
||||
* Fixed issues with pressing escape
|
||||
|
||||
Qt Designer
|
||||
|
||||
* Fixed that resources could not be selected in new form
|
||||
(QTCREATORBUG-15560)
|
||||
|
||||
Diff Viewer
|
||||
|
||||
* Added local diff for modified files in Qt Creator (`Tools` > `Diff` >
|
||||
@@ -132,6 +144,12 @@ Model Editor
|
||||
|
||||
Platform Specific
|
||||
|
||||
Windows
|
||||
|
||||
* Added support for MSVC 2017
|
||||
* Fixed that environment variables containing special characters were not
|
||||
passed correctly to user applications (QTCREATORBUG-17219)
|
||||
|
||||
Android
|
||||
|
||||
* Improved stability of determination if application is running
|
||||
@@ -141,6 +159,10 @@ Android
|
||||
(QTCREATORBUG-16630)
|
||||
* Fixed handling of minimum required API level (QTCREATORBUG-16740)
|
||||
|
||||
iOS
|
||||
|
||||
* Fixed that Qt Creator was blocked until simulator finished starting
|
||||
|
||||
Credits for these changes go to:
|
||||
Aaron Barany
|
||||
Alessandro Portale
|
||||
|
||||
+1
-1
@@ -179,7 +179,7 @@ Component.prototype.createOperations = function()
|
||||
component.addOperation( "InstallIcons", "@TargetDir@/share/icons" );
|
||||
component.addOperation( "CreateDesktopEntry",
|
||||
"QtProject-qtcreator.desktop",
|
||||
"Type=Application\nExec=" + component.qtCreatorBinaryPath + "\nPath=@TargetDir@\nName=Qt Creator\nGenericName=The IDE of choice for Qt development.\nGenericName[de]=Die IDE der Wahl zur Qt Entwicklung\nIcon=QtProject-qtcreator\nTerminal=false\nCategories=Development;IDE;Qt;\nMimeType=text/x-c++src;text/x-c++hdr;text/x-xsrc;application/x-designer;application/vnd.nokia.qt.qmakeprofile;application/vnd.nokia.xml.qt.resource;text/x-qml;text/x-qt.qml;text/x-qt.qbs;"
|
||||
"Type=Application\nExec=" + component.qtCreatorBinaryPath + "\nPath=@TargetDir@\nName=Qt Creator\nGenericName=The IDE of choice for Qt development.\nGenericName[de]=Die IDE der Wahl zur Qt Entwicklung\nIcon=QtProject-qtcreator\nTerminal=false\nCategories=Development;IDE;Qt;\nMimeType=text/x-c++src;text/x-c++hdr;text/x-xsrc;application/x-designer;application/vnd.qt.qmakeprofile;application/vnd.qt.xml.resource;text/x-qml;text/x-qt.qml;text/x-qt.qbs;"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 27 KiB |
@@ -578,6 +578,45 @@
|
||||
|
||||
\endlist
|
||||
|
||||
\section2 Enabling and Disabling Breakpoints
|
||||
|
||||
To temporarily disable a breakpoint without deleting it and losing associated
|
||||
data like conditions and commands:
|
||||
|
||||
\list
|
||||
|
||||
\li Right-click the breakpoint marker in the text editor and select
|
||||
\uicontrol{Disable Breakpoint}.
|
||||
|
||||
\li Select the breakpoint in the \uicontrol Breakpoints view and press
|
||||
\key Space.
|
||||
|
||||
\li Select \uicontrol {Disabled Breakpoint} in the context menu in the
|
||||
\uicontrol Breakpoints view.
|
||||
|
||||
\endlist
|
||||
|
||||
A disabled breakpoint is marked with a hollow read circle in the
|
||||
text editor and the \uicontrol Breakpoint view.
|
||||
|
||||
To re-enable a temporarily disabled breakpoint:
|
||||
|
||||
\list
|
||||
|
||||
\li Right-click the marker of a disabled breakpoint in the text editor and
|
||||
select \uicontrol{Enable Breakpoint}.
|
||||
|
||||
\li Select a disabled breakpoint in the \uicontrol Breakpoints view and press
|
||||
\key Space.
|
||||
|
||||
\li Select \uicontrol {Disabled Breakpoint} in the context menu in the
|
||||
\uicontrol Breakpoints view.
|
||||
|
||||
\endlist
|
||||
|
||||
With the notable exception of data breakpoints, breakpoints retain their
|
||||
enabled or disabled state when the debugged program is restarted.
|
||||
|
||||
\section2 Setting Data Breakpoints
|
||||
|
||||
A \e {data breakpoint} stops the program when data is read or written at the
|
||||
@@ -604,6 +643,11 @@
|
||||
you can select \uicontrol {Add Data Breakpoint at Object's Address} in the
|
||||
context menu to set the data breakpoint.
|
||||
|
||||
Data breakpoints will be disabled when the debugged program exits, as it
|
||||
is unlikely that the used addresses will stay the same at the next program
|
||||
launch. If you really want a data breakpoint to be active again, re-enable
|
||||
it manually.
|
||||
|
||||
\section1 Viewing Call Stack Trace
|
||||
|
||||
When the program being debugged is interrupted, \QC displays the nested
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
\page creator-clang-codemodel.html
|
||||
\nextpage creator-finding-overview.html
|
||||
|
||||
\title Parsing C++ Files
|
||||
\title Parsing C++ Files with the Clang Code Model
|
||||
|
||||
The \e {code model} is the part of an IDE that understands the language you
|
||||
are using to write your application. It is the framework that allows \QC
|
||||
@@ -62,12 +62,13 @@
|
||||
|
||||
\endlist
|
||||
|
||||
An IDE needs a parser for the language and the semantic analyzes.
|
||||
\QC comes with an experimental plugin that provides some of these services
|
||||
for C++ on top of \l{http://clang.llvm.org/}{Clang}.
|
||||
|
||||
\section1 Using Clang Code Model
|
||||
\section1 About the Clang Code Model
|
||||
|
||||
The \l{http://clang.llvm.org/}{Clang} project provides libraries for parsing
|
||||
C and C++ source files. The feedback you get through warning and
|
||||
The Clang project provides libraries for parsing
|
||||
C language family source files. The feedback you get through warning and
|
||||
error markers is the same as a compiler will give you, not an incomplete
|
||||
set or a close approximation, as when using the built-in \QC code model.
|
||||
Clang focuses on detailed information for diagnostics, which is really
|
||||
@@ -84,38 +85,6 @@
|
||||
include several files, processing a single file and all the included files
|
||||
can take a while.
|
||||
|
||||
To make parsing faster, pre-compiled headers are ignored by default. To
|
||||
specify that Clang processes them, select \uicontrol Tools >
|
||||
\uicontrol Options > \uicontrol C++ > \uicontrol {Code Model}, and
|
||||
deselect the \uicontrol {Ignore pre-compiled headers} check box.
|
||||
|
||||
When Clang encounters risky or possibly erroneous constructions, it issues
|
||||
warnings. To request or suppress warnings, select \uicontrol Tools >
|
||||
\uicontrol Options > \uicontrol C++ > \uicontrol {Code Model}. You can
|
||||
either select one of the predefined configurations, or create a copy of a
|
||||
configuration and edit it to fit your needs:
|
||||
|
||||
\list
|
||||
|
||||
\li \uicontrol {Pedantic Warnings} uses the \c -Wpendantic option that
|
||||
requests all the warnings demanded by strict ISO C and ISO C++.
|
||||
|
||||
\li \uicontrol {Warnings for Questionable Constructs} combines the
|
||||
\c -Wall and \c -Wextra options to request all warnings about easily
|
||||
avoidable questionable constructions and some additional warnings.
|
||||
|
||||
\li \uicontrol {Warnings for Almost Everything} uses the \c -Weverything
|
||||
option with negative options to suppress some warnings.
|
||||
|
||||
\endlist
|
||||
|
||||
You can edit the predefined configurations to request specific warnings
|
||||
beginning with \c -W. Each of these warnings also has a negative version
|
||||
that begins with \c -Wno. Keep in mind that some options turn on other
|
||||
options. For more information, see
|
||||
\l{https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html}
|
||||
{Options to Request or Suppress Warnings} or the GCC or Clang manual pages.
|
||||
|
||||
The following services are currently implemented in the experimental Clang
|
||||
code model plugin:
|
||||
|
||||
@@ -123,51 +92,19 @@
|
||||
|
||||
\li Code completion
|
||||
\li Syntactic and semantic highlighting
|
||||
\li Diagnostics
|
||||
|
||||
\endlist
|
||||
|
||||
To use the plugin, you must build it and configure it in \QC.
|
||||
|
||||
\section2 Building Clang Code Model Plugin
|
||||
\section1 Activating Clang Code Model
|
||||
|
||||
\list 1
|
||||
If you build \QC yourself, ensure that the plugin is also built, as
|
||||
described in the \QC
|
||||
\l{https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/README.md}{README file}.
|
||||
|
||||
\li Acquire Clang 3.9.0 or higher in one of the following ways:
|
||||
|
||||
\list
|
||||
|
||||
\li Use the package manager of your system.
|
||||
|
||||
\li Download and install the Clang package from the
|
||||
\l{https://download.qt.io/development_releases/prebuilt/libclang/}
|
||||
{Qt Download Page}.
|
||||
|
||||
\li Build Clang by following
|
||||
\l{http://clang.llvm.org/get_started.html}
|
||||
{Getting Started: Building and Running Clang}.
|
||||
|
||||
Add the following options to the \c cmake call in order to
|
||||
build an optimized version and to specify the installation
|
||||
directory:
|
||||
|
||||
\c -DCMAKE_BUILD_TYPE=Release
|
||||
\c -DCMAKE_INSTALL_PREFIX=/your/install/dir
|
||||
|
||||
After building, install with
|
||||
|
||||
\c {make install}
|
||||
|
||||
\endlist
|
||||
|
||||
\li Set LLVM_INSTALL_DIR to point to the installation directory
|
||||
of LLVM either as part of the build environment or pass it directly
|
||||
to qmake when you build \QC.
|
||||
|
||||
\li Rerun \c qmake and build \QC.
|
||||
|
||||
\endlist
|
||||
|
||||
\section2 Configuring Clang Code Model Plugin
|
||||
To activate the plugin:
|
||||
|
||||
\list 1
|
||||
|
||||
@@ -176,14 +113,52 @@
|
||||
|
||||
\li Restart \QC to be able to use the plugin.
|
||||
|
||||
\li To specify settings for the Clang code model, select
|
||||
\uicontrol Tools > \uicontrol Options > \uicontrol C++ >
|
||||
If you build \QC yourself, add \c ${LLVM_INSTALL_DIR}\bin to the
|
||||
\c PATH variable so the LLVM libraries will be found on startup.
|
||||
|
||||
\endlist
|
||||
|
||||
\section1 Configuring Clang Code Model
|
||||
|
||||
To specify settings for the Clang code model:
|
||||
|
||||
\list 1
|
||||
|
||||
\li Select \uicontrol Tools > \uicontrol Options > \uicontrol C++ >
|
||||
\uicontrol {Code Model}.
|
||||
|
||||
\image qtcreator-clang-code-model-options.png
|
||||
|
||||
\li In the \uicontrol {Configuration to use} list, select the
|
||||
warnings to request.
|
||||
\li In the \uicontrol {Configuration to use} list, configure the
|
||||
diagnostics that Clang should issue.
|
||||
|
||||
You can either select one of the predefined configurations, or
|
||||
create a copy of a configuration and edit it to fit your needs:
|
||||
|
||||
\list
|
||||
|
||||
\li \uicontrol {Pedantic Warnings} uses the \c -Wpendantic
|
||||
option that requests all the warnings demanded by strict
|
||||
ISO C and ISO C++.
|
||||
|
||||
\li \uicontrol {Warnings for Questionable Constructs} combines
|
||||
the \c -Wall and \c -Wextra options to request all warnings
|
||||
about easily avoidable questionable constructions and some
|
||||
additional warnings.
|
||||
|
||||
\li \uicontrol {Warnings for Almost Everything} uses the \c
|
||||
-Weverything option with negative options to suppress some
|
||||
warnings.
|
||||
|
||||
\endlist
|
||||
|
||||
You can edit the predefined configurations to request specific
|
||||
warnings beginning with \c -W. Each of these warnings also has a
|
||||
negative version that begins with \c -Wno. Keep in mind that some
|
||||
options turn on other options. For more information, see
|
||||
\l{https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html}
|
||||
{Options to Request or Suppress Warnings} or the GCC or Clang
|
||||
manual pages.
|
||||
|
||||
\li To have Clang process pre-compiled headers, deselect the
|
||||
\uicontrol {Ignore pre-compiled headers} check box.
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
You can use a diff editor to compare two versions of a file and
|
||||
view the differences side-by-side in the \uicontrol Edit mode.
|
||||
|
||||
\li \l{Parsing C++ Files}
|
||||
\li \l{Parsing C++ Files with the Clang Code Model}
|
||||
|
||||
An experimental Clang code model plugin enables you to replace the
|
||||
built-in \QC code model with the Clang code model. Clang is a C
|
||||
|
||||
@@ -1781,7 +1781,7 @@
|
||||
You can also press \key {Alt+Enter} to open a context menu that contains
|
||||
refactoring actions available in the current cursor position.
|
||||
|
||||
If you use the \l{Parsing C++ Files}{Clang code model} to parse the C++
|
||||
If you use the \l{Parsing C++ Files with the Clang Code Model}{Clang code model} to parse the C++
|
||||
files, the \l{http://clang.llvm.org/diagnostics.html}{Clang fix-it hints}
|
||||
that have been integrated into \QC are also available to you. In addition to
|
||||
the standard ways of activating refactoring actions, you can select the
|
||||
|
||||
@@ -43,9 +43,13 @@
|
||||
\uicontrol {About Plugins} > \uicontrol Utilities > \uicontrol {Auto Test}.
|
||||
Restart \QC to be able to use the plugin.
|
||||
|
||||
\section1 Creating Qt Tests
|
||||
\section1 Creating Tests
|
||||
|
||||
You can use a wizard to create projects that contain Qt tests:
|
||||
You can use a wizard to create projects that contain Qt or Google tests.
|
||||
|
||||
\section2 Creating Qt Tests
|
||||
|
||||
To create a Qt test:
|
||||
|
||||
\list 1
|
||||
\li Select \uicontrol File > \uicontrol {New File or Project} >
|
||||
@@ -58,6 +62,9 @@
|
||||
|
||||
\list 1
|
||||
|
||||
\li In the \uicontrol {Test framework} field, select
|
||||
\uicontrol {Qt Test}.
|
||||
|
||||
\li Select the \uicontrol {GUI Application} check box to create
|
||||
a Qt application.
|
||||
|
||||
@@ -87,6 +94,52 @@
|
||||
function in your test. For more information about creating Qt tests, see
|
||||
\l{Creating a Test}.
|
||||
|
||||
\section2 Creating Google Tests
|
||||
|
||||
To create a Google test:
|
||||
|
||||
\list 1
|
||||
\li Select \uicontrol File > \uicontrol {New File or Project} >
|
||||
\uicontrol {Other Project} > \uicontrol {Auto Test} >
|
||||
\uicontrol Choose to create a project with boilerplate code for a
|
||||
Google test.
|
||||
|
||||
\li In the \uicontrol {Project and Test Information} dialog, specify
|
||||
settings for the project and test:
|
||||
|
||||
\list 1
|
||||
|
||||
\li In the \uicontrol {Test framework} field, select
|
||||
\uicontrol {Google Test}.
|
||||
|
||||
\li In the \uicontrol {Test case name} field, enter a name for
|
||||
the test case.
|
||||
|
||||
\li In the \uicontrol {Test set name} field, enter a name for
|
||||
the test set.
|
||||
|
||||
\li Select the \uicontrol {Enable C++ 11} check box to
|
||||
support C++ 11 features in the test.
|
||||
|
||||
\li In the \uicontrol {Build auto tests} field, select
|
||||
\uicontrol Always to always build the test when building
|
||||
the project or \uicontrol {Debug Only} to only build it
|
||||
during debug builds.
|
||||
|
||||
\li In the \uicontrol {Google test repository} field, select
|
||||
a directory that contains a clone of the googletest
|
||||
repository.
|
||||
|
||||
To use an installed Google C++ Testing framework instead,
|
||||
see \l{Setting Up the Google C++ Testing Framework}.
|
||||
|
||||
\endlist
|
||||
|
||||
\endlist
|
||||
|
||||
\QC creates the test in the \c{tests\auto} directory in the project
|
||||
directory.
|
||||
|
||||
\section1 Setting Up the Google C++ Testing Framework
|
||||
|
||||
To build and run Google tests, you must have the Google C++ Testing
|
||||
|
||||
@@ -265,6 +265,8 @@
|
||||
|
||||
\li Search from the selected directory.
|
||||
|
||||
\li Display the contents of a particular directory in the view.
|
||||
|
||||
\endlist
|
||||
|
||||
\section2 Viewing the Class Hierarchy
|
||||
|
||||
@@ -1,773 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Creator Manual}
|
||||
\previouspage creator-project-wizards-xml.html
|
||||
\page creator-version-control.html
|
||||
\nextpage creator-configuring-projects.html
|
||||
|
||||
\title Using Version Control Systems
|
||||
|
||||
Version control systems supported by \QC are:
|
||||
\table
|
||||
\header
|
||||
\li Version Control System
|
||||
\li Address
|
||||
\li Notes
|
||||
\row
|
||||
\li Bazaar
|
||||
\li \l{http://bazaar.canonical.com/}
|
||||
\li
|
||||
\row
|
||||
\li ClearCase
|
||||
\li \l{http://www-01.ibm.com/software/awdtools/clearcase/}
|
||||
\li
|
||||
\row
|
||||
\li CVS
|
||||
\li \l{http://www.cvshome.org}
|
||||
\li
|
||||
\row
|
||||
\li Git
|
||||
\li \l{http://git-scm.com/}
|
||||
\li Git version 1.8.0, or later
|
||||
|
||||
Gerrit version 2.6, or later
|
||||
\row
|
||||
\li Mercurial
|
||||
\li \l{http://mercurial.selenic.com/}
|
||||
\li
|
||||
\row
|
||||
\li Perforce
|
||||
\li \l{http://www.perforce.com}
|
||||
\li Server version 2006.1 and later
|
||||
\row
|
||||
\li Subversion
|
||||
\li \l{http://subversion.apache.org/}
|
||||
\li Subversion version 1.7.0 and later
|
||||
\endtable
|
||||
|
||||
\section1 Setting Up Version Control Systems
|
||||
|
||||
\QC uses the version control system's command line clients to access your
|
||||
repositories. To allow access, make sure that the command line clients can
|
||||
be located using the \c{PATH} environment variable or specify the path to
|
||||
the command line client executables in \uicontrol{Tools} > \uicontrol{Options} >
|
||||
\uicontrol {Version Control}.
|
||||
|
||||
After you set up the version control system, use the command line to check
|
||||
that everything works (for example, use the status command). If no issues
|
||||
arise, you should be ready to use the system also from \QC.
|
||||
|
||||
\section2 Using msysGit on Windows
|
||||
|
||||
If you configure Git for use with \c {git bash}, only, and use SSH
|
||||
authorization, Git looks for the SSH keys in the directory where the
|
||||
\c HOME environment points to. The variable is always set by \c {git bash}.
|
||||
|
||||
However, the variable is typically not set in a Windows command prompt. When
|
||||
you run Git from a Windows command prompt, it looks for the SSH keys in its
|
||||
installation directory, and therefore, the authorization fails.
|
||||
|
||||
You can set the \c HOME environment variable from \QC. Select \uicontrol {Tools >
|
||||
Options > Version Control > Git}. Select the \uicontrol {Environment Variables}
|
||||
and the \uicontrol {Set "HOME" environment variable} check boxes. \c HOME is set
|
||||
to \c %HOMEDRIVE%%HOMEPATH% when the Git executable is run and authorization
|
||||
works as it would with \c {git bash}.
|
||||
|
||||
\section1 Setting Up General Options
|
||||
|
||||
Select \uicontrol{Tools} > \uicontrol{Options} > \uicontrol{Version Control}
|
||||
> \uicontrol{General}
|
||||
to specify settings for submit messages:
|
||||
|
||||
\list
|
||||
|
||||
\li \uicontrol{Submit message check script} is a script or program that
|
||||
can be used to perform checks on the submit message before
|
||||
submitting. The submit message is passed in as the script's first
|
||||
parameter. If there is an error, the script should output a
|
||||
message on standard error and return a non-zero exit code.
|
||||
|
||||
\li \uicontrol{User/alias configuration file} is a text file that lists
|
||||
author names in mailmap format. For each author, you must specify a
|
||||
real name and email address and optionally an alias and a second
|
||||
email address. For example:
|
||||
|
||||
\code
|
||||
Jon Doe <Jon.Doe@company.com> jdoe <jdoe@somemail.com>
|
||||
Hans Mustermann <Hans.Mustermann@company.com> hm <info@company.com>
|
||||
\endcode
|
||||
|
||||
After you specify a file in this field, you can select authors
|
||||
as values of the submit message fields in the \uicontrol Nicknames dialog.
|
||||
|
||||
\li \uicontrol{User fields configuration file} is a simple text file
|
||||
consisting of lines specifying submit message fields that take
|
||||
authors as values, for example:
|
||||
|
||||
\code
|
||||
Acked-by:
|
||||
Initial-patch-by:
|
||||
Reported-by:
|
||||
Rubber-stamped-by:
|
||||
Signed-off-by:
|
||||
Tested-by:
|
||||
\endcode
|
||||
|
||||
After you specify a file in this field, you can add authors as
|
||||
values of the submit message fields when submitting changes. If
|
||||
you also specified a \uicontrol{User/alias configuration file}, you can
|
||||
select authors in the \uicontrol Nicknames dialog.
|
||||
|
||||
\li \uicontrol{SSH prompt command} specifies an ssh-askpass command that you
|
||||
can use (on Linux) to prompt the user for a password when using SSH.
|
||||
For example, \c ssh-askpass or \c x11-ssh-askpass, depending on the
|
||||
ssh-askpass implementation that you use.
|
||||
|
||||
\li \uicontrol {Patch command} specifies the path to the patch utility that is
|
||||
used to apply changes in the format used to represent the diff
|
||||
output. The \uicontrol Revert command uses the patch utility to revert
|
||||
partial changes.
|
||||
|
||||
\endlist
|
||||
|
||||
\section1 Creating VCS Repositories for New Projects
|
||||
|
||||
\QC allows you to create repositories for version control systems that
|
||||
support local repository creation, such as Git, Mercurial, or Bazaar.
|
||||
When creating a new project by selecting \uicontrol File > \uicontrol{New File or
|
||||
Project}, you can choose a version control system on the final wizard page.
|
||||
|
||||
You can also select \uicontrol Tools and then select \uicontrol {Create Repository}
|
||||
in the submenu for the version control system.
|
||||
|
||||
To import a project that is under version control, choose \uicontrol {File >
|
||||
New File or Project > Project from Version Control} and select the
|
||||
version control system that you use. Follow the instructions of the
|
||||
wizard to import the project.
|
||||
|
||||
\section1 Using Version Control Systems
|
||||
|
||||
The \uicontrol{Tools} menu contains a submenu for each supported version
|
||||
control system.
|
||||
|
||||
The \uicontrol{Version Control} output pane displays the commands that are
|
||||
executed, a timestamp, and the relevant output. Select \uicontrol {Window > Output
|
||||
Panes > Version Control} to open the pane.
|
||||
|
||||
\image qtcreator-vcs-pane.png
|
||||
|
||||
\section2 Adding Files
|
||||
|
||||
When you create a new file or a new project, the wizard displays a page
|
||||
asking whether the files should be added to a version control system.
|
||||
This happens when the parent directory or the project is already
|
||||
under version control and the system supports the concept of adding files,
|
||||
for example, Perforce and Subversion. Alternatively, you can
|
||||
add files later by using the version control tool menus.
|
||||
|
||||
With Git, there is no concept of adding files. Instead, all modified
|
||||
files must be staged for a commit.
|
||||
|
||||
\section2 Viewing Diff Output
|
||||
|
||||
All version control systems provide menu options to \e{diff} the current
|
||||
file or project: to compare it with the latest version stored in the
|
||||
repository and to display the differences. In \QC, a diff is displayed in a
|
||||
read-only editor. If the file is accessible, you can double-click on a
|
||||
selected diff chunk and \QC opens an editor displaying the file, scrolled to
|
||||
the line in question.
|
||||
|
||||
\image qtcreator-vcs-diff.png
|
||||
|
||||
With Git and Subversion, the diff is displayed side-by-side in a \l{Comparing Files}
|
||||
{diff editor} by default. To use the inline diff view instead, select the
|
||||
\uicontrol {Switch to Text Diff Editor} (1) option from the toolbar. In the inline
|
||||
diff view, you can use context menu commands to apply, revert, stage, and
|
||||
unstage hunks, as well as send them to a code pasting service.
|
||||
|
||||
\section3 Using GNU Diffutils with ClearCase
|
||||
|
||||
You can use the GNU Diffutils tool With ClearCase to compare files and
|
||||
activities:
|
||||
|
||||
\list 1
|
||||
|
||||
\li Download \l{http://gnuwin32.sourceforge.net/packages/diffutils.htm}
|
||||
{Diffutils} and extract it to a directory in your PATH.
|
||||
|
||||
\li Select \uicontrol Tools > \uicontrol Options >
|
||||
\uicontrol {Version Control} > \uicontrol ClearCase.
|
||||
|
||||
\li Select the \uicontrol External radio button. The radio button is
|
||||
disabled if \c diff is not found in the PATH.
|
||||
|
||||
\li In the \uicontrol Arguments field, specify arguments for running
|
||||
\c diff.
|
||||
|
||||
\endlist
|
||||
|
||||
\section2 Viewing Versioning History and Change Details
|
||||
|
||||
Display the versioning history of a file by selecting \uicontrol{Log}
|
||||
or \uicontrol{Filelog}. Typically, the log output contains the date, the commit
|
||||
message, and a change or revision identifier. Click on the identifier to
|
||||
display a description of the change including the diff in the
|
||||
\uicontrol {Git Show} view.
|
||||
|
||||
\image qtcreator-vcs-show.png
|
||||
|
||||
Right-clicking on an identifier brings up a context menu that lets you
|
||||
show annotation views of previous versions (see \l{Annotating Files}).
|
||||
With Git you can also choose to cherry-pick or revert a change.
|
||||
|
||||
\section2 Annotating Files
|
||||
|
||||
Annotation views are obtained by selecting \uicontrol{Annotate} or \uicontrol{Blame}.
|
||||
Selecting \uicontrol{Annotate} or \uicontrol{Blame} displays the lines of the file
|
||||
prepended by the change identifier they originate from. Clicking on the
|
||||
change identifier shows a detailed description of the change.
|
||||
|
||||
To show the annotation of a previous version, right-click on the
|
||||
version identifier at the beginning of a line and choose one of the
|
||||
revisions shown at the bottom of the context menu. This allows you to
|
||||
navigate through the history of the file and obtain previous versions of
|
||||
it. It also works for Git and Mercurial using SHA-1.
|
||||
|
||||
The same context menu is available when right-clicking on a version
|
||||
identifier in the file log view of a single file.
|
||||
|
||||
\section2 Committing Changes
|
||||
|
||||
Once you have finished making changes, submit them to the version control
|
||||
system by choosing \uicontrol{Commit} or \uicontrol{Submit}. \QC displays a
|
||||
commit page containing a text editor where you can enter your commit
|
||||
message and a checkable list of modified files to be included.
|
||||
|
||||
\image qtcreator-vcs-commit.png
|
||||
|
||||
When you have finished filling out the commit page information, click on
|
||||
\uicontrol{Commit} to start committing.
|
||||
|
||||
The \uicontrol{Diff Selected Files} button brings up a diff view of the
|
||||
files selected in the file list. Since the commit page is just another
|
||||
editor, you can go back to it by closing the diff view. You can also switch
|
||||
to an open diff view by selecting it in the \uicontrol{Open Documents} pane in the
|
||||
sidebar.
|
||||
|
||||
\section2 Reverting Changes
|
||||
|
||||
All supported version control systems support reverting your project to
|
||||
known states. This functionality is generally called \e reverting.
|
||||
|
||||
The changes discarded depend on the version control system.
|
||||
|
||||
A version control system can replace the \uicontrol Revert menu option with other
|
||||
options.
|
||||
|
||||
\section3 Reverting Changes Using Git
|
||||
|
||||
The Git version control system has an index that is used to stage
|
||||
changes. The index is committed on the next commit. Git allows you to revert
|
||||
back to the state of the last commit as well as to the state staged in the
|
||||
index.
|
||||
|
||||
\list
|
||||
|
||||
\li \uicontrol Git > \uicontrol {Current File} > \uicontrol{Undo Unstaged Changes} reverts
|
||||
all changes and resets the current file to the state of the
|
||||
index.
|
||||
|
||||
\li \uicontrol Git > \uicontrol {Current File} > \uicontrol {Undo Uncommitted Changes}
|
||||
reverts all changes, discarding the
|
||||
index. This returns the current file to the state it was in right
|
||||
after the last commit.
|
||||
|
||||
\li \uicontrol Git > \uicontrol {Local Repository} > \uicontrol Reset opens a dialog
|
||||
where you can select the SHA-1 to reset the working directory to.
|
||||
This is useful after applying patches for review, for example. You
|
||||
can choose between a \uicontrol Soft reset that does not touch the index
|
||||
file nor the working tree at all, a \uicontrol Hard reset that discards
|
||||
all changes to tracked files in working tree, and a \uicontrol Mixed
|
||||
reset that resets HEAD and the index (nothing remains staged)
|
||||
without touching the working directory.
|
||||
|
||||
\endlist
|
||||
|
||||
\section2 Viewing Status
|
||||
|
||||
You can select \uicontrol{Status} to view the status of the project or
|
||||
repository.
|
||||
|
||||
\section2 Updating the Working Tree
|
||||
|
||||
You can select \uicontrol Update to update your working tree with the latest
|
||||
changes from the branch. Some version control systems allow you to choose
|
||||
between updating the current project and updating all projects.
|
||||
|
||||
With Git, you stash your changes and then pull the changes from the
|
||||
repository.
|
||||
|
||||
\section2 Deleting Files
|
||||
|
||||
You can select \uicontrol Delete to delete obsolete files from the repository.
|
||||
|
||||
With Git, you delete the files from the working tree and then stage the
|
||||
deleted files for a commit.
|
||||
|
||||
\section2 Using Additional Bazaar Functions
|
||||
|
||||
Bazaar is a free version control system sponsored by Canonical.
|
||||
|
||||
The \uicontrol Bazaar submenu contains the following additional items:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Menu Item
|
||||
\li Description
|
||||
\row
|
||||
\li \uicontrol Pull
|
||||
\li Turn the branch into a mirror of another branch.
|
||||
\row
|
||||
\li \uicontrol Push
|
||||
\li Update a mirror of the branch.
|
||||
\row
|
||||
\li \uicontrol Uncommit
|
||||
\li Remove the last committed revision.
|
||||
\endtable
|
||||
|
||||
\section3 Uncommitting Revisions
|
||||
|
||||
In Bazaar, committing changes to a branch creates a new revision that holds
|
||||
a snapshot of the state of the working tree. To remove the last committed
|
||||
revision, select \uicontrol Tools > \uicontrol Bazaar > \uicontrol Uncommit.
|
||||
|
||||
In the \uicontrol Uncommit dialog, select options to keep tags that point to
|
||||
removed revisions and to only remove the commits from the local branch when
|
||||
in a checkout.
|
||||
|
||||
To remove all commits up to an entry in the revision log, specify the
|
||||
revision in the \uicontrol Revision field.
|
||||
|
||||
To test the outcome of the \uicontrol Uncommit command without actually removing
|
||||
anything, select \uicontrol {Dry Run}.
|
||||
|
||||
\uicontrol Uncommit leaves the working tree ready for a new commit. The only
|
||||
change it might make is restoring pending merges that were present before
|
||||
the commit.
|
||||
|
||||
\section2 Using Additional ClearCase Functions
|
||||
|
||||
IBM Rational ClearCase is a version control, workspace management, parallel
|
||||
development support, and build automation solution developed by IBM. The
|
||||
ClearCase client plugin is available on Linux and Windows for accessing a
|
||||
ClearCase server.
|
||||
|
||||
The \uicontrol ClearCase submenu contains the following additional items:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Menu Item
|
||||
\li Description
|
||||
\row
|
||||
\li \uicontrol{Check In}
|
||||
\li Create a permanent new version of the current file or all files
|
||||
in the versioned object base (VOB).
|
||||
\row
|
||||
\li \uicontrol{Check In Activity}
|
||||
\li Check in checked-out versions in the change set of the current
|
||||
Unified Change Management (UCM) activity.
|
||||
\row
|
||||
\li \uicontrol{Check Out}
|
||||
\li Create a writable copy of a branch. If you check out files in a
|
||||
UCM view, they are added to the change set of the UCM activity.
|
||||
\row
|
||||
\li \uicontrol{Undo Check Out}
|
||||
\li Cancel the checkout for a file and delete the checked-out
|
||||
version.
|
||||
\row
|
||||
\li \uicontrol{Undo Hijack}
|
||||
\li Resolve hijacked files. If you change the read-only attribute of
|
||||
a file that is loaded into a snapshot view and modify the file
|
||||
without checking it out, you \e hijack the file.
|
||||
\endtable
|
||||
|
||||
\section2 Using Additional CVS Functions
|
||||
|
||||
CVS is an open source version control system.
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol CVS > \uicontrol Edit to open a file for editing.
|
||||
To discard the changes that you made in a file, select \uicontrol Unedit.
|
||||
|
||||
\section2 Using Additional Git Functions
|
||||
|
||||
Git is a fast decentralized version control system. Git is available
|
||||
for Windows, Linux and Mac.
|
||||
|
||||
You can use the \l{http://code.google.com/p/gerrit/}{Gerrit} code review
|
||||
tool for projects that use Git.
|
||||
|
||||
\section3 Working with the Current File
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol Git > \uicontrol {Current File} >
|
||||
\uicontrol {Stage File for
|
||||
Commit} to mark a new or modified file for committing to the repository.
|
||||
|
||||
To undo this function, select \uicontrol {Unstage File from Commit}.
|
||||
|
||||
\section3 Working with the Current Project
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol Git > \uicontrol {Current Project} >
|
||||
\uicontrol {Clean Project}
|
||||
to clean the working directory. All files that are not under version control
|
||||
are displayed in the \uicontrol {Clean Repository} dialog. Ignored files are
|
||||
deselected by default. Select the files to delete and click \uicontrol Delete.
|
||||
|
||||
\section3 Working with Local Repositories
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol Git > \uicontrol {Local Repository} >
|
||||
\uicontrol Clean to clean
|
||||
the repository.
|
||||
|
||||
To apply latest changes to the last commit, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Local Repository} > \uicontrol {Amend Last Commit}. You can also edit the
|
||||
commit message.
|
||||
|
||||
To amend an earlier comment in a series of related commits, select
|
||||
\uicontrol Tools > \uicontrol Git > \uicontrol {Local Repository} >
|
||||
\uicontrol {Fixup Previous Commit}. This operation is done using interactive
|
||||
rebase. In case of conflicts, a merge tool is suggested.
|
||||
|
||||
To change a series of commits in the local repository, select \uicontrol Tools >
|
||||
\uicontrol Git > \uicontrol {Local Repository} > \uicontrol {Interactive Rebase}. You can
|
||||
reorder or discard commits, squash them into a single commit, or edit the
|
||||
commit messages.
|
||||
|
||||
The following sections describe how to manage local and remote branches,
|
||||
apply patches, and use stashes.
|
||||
|
||||
\section4 Working with Branches
|
||||
|
||||
To work with Git branches, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Local Repository} > \uicontrol {Branches}. The checked out branch
|
||||
is shown in bold and underlined in the list of branches. Double-click branch
|
||||
names to edit them.
|
||||
|
||||
\image qtcreator-vcs-gitbranch.png "Branches dialog"
|
||||
|
||||
The following operations are supported:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Menu Item
|
||||
\li Description
|
||||
\row
|
||||
\li \uicontrol{Refresh}
|
||||
\li Refresh the list of branches.
|
||||
\row
|
||||
\li \uicontrol{Add}
|
||||
\li Create new tracking and non-tracking branches.
|
||||
\row
|
||||
\li \uicontrol{Remove}
|
||||
\li Remove a local branch. You cannot delete remote branches.
|
||||
\row
|
||||
\li \uicontrol Rename
|
||||
\li Rename a local branch.
|
||||
\row
|
||||
\li \uicontrol{Checkout}
|
||||
\li Check out the selected branch and make it current. You can stash
|
||||
changes you have made to tracked files.
|
||||
\row
|
||||
\li \uicontrol{Diff}
|
||||
\li Show the differences between the selected and the current
|
||||
branch.
|
||||
\row
|
||||
\li \uicontrol{Log}
|
||||
\li Show the changes in a branch.
|
||||
\row
|
||||
\li \uicontrol Merge
|
||||
\li Join the development histories in two branches together.
|
||||
|
||||
If the commit you are merging can be reached by following the
|
||||
first commit's history, there is no divergent work to merge
|
||||
together. To allow Git to move the branch pointer forward,
|
||||
select \uicontrol {Fast-Forward}. If you do not want to fast-forward
|
||||
the branch, select \uicontrol {No Fast-Forward}.
|
||||
\row
|
||||
\li \uicontrol Rebase
|
||||
\li Copy local commits to the updated upstream head.
|
||||
\row
|
||||
\li \uicontrol Reset
|
||||
\li Hard reset the active branch to the selected branch.
|
||||
\row
|
||||
\li \uicontrol {Cherry Pick}
|
||||
\li Cherry pick the top commit from the selected branch.
|
||||
\row
|
||||
\li \uicontrol Track
|
||||
\li Set the current branch to track the selected one.
|
||||
\endtable
|
||||
|
||||
\section4 Applying Patches
|
||||
|
||||
Patches are rewriting instructions that can be applied to a set of files.
|
||||
To apply a patch file that is open in \QC, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Local Repository} > \uicontrol Patch >
|
||||
\uicontrol {Apply from Editor}.
|
||||
|
||||
To select the patch file to apply from the file system, select
|
||||
\uicontrol {Apply from File}.
|
||||
|
||||
\section4 Using Stashes
|
||||
|
||||
With Git, you can put your current set of changes onto a virtual shelf
|
||||
called a \e stash. Stashes are useful, for example, to put aside a set of
|
||||
changes to work on higher priority tasks or to pull in new chages from
|
||||
another repository.
|
||||
|
||||
To stash all local changes, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Local Repository} > \uicontrol Stash > \uicontrol Stash. The working copy is reset
|
||||
to the state it had after the last commit. To save the current state of your
|
||||
unstaged files and reset the repository to its staged state, select
|
||||
\uicontrol {Stash Unstaged Files}.
|
||||
|
||||
To display a dialog that shows all known stashes with options to restore,
|
||||
display or delete them, select \uicontrol Stashes.
|
||||
|
||||
To save a snapshot of your current work under a name for later reference,
|
||||
select \uicontrol {Take Snapshot}. The working copy is unchanged. For example, if
|
||||
you want to try something and find out later that it does not work, you can
|
||||
discard the changes and return to the state of the snapshot.
|
||||
|
||||
To remove a single stashed state from the stash list and apply it on top of
|
||||
the current working tree state, select \uicontrol {Stash Pop}.
|
||||
|
||||
\section3 Applying Actions to Commits
|
||||
|
||||
To browse a directory or the commit history and to apply actions on the
|
||||
commits, select \uicontrol Tools > \uicontrol Git > \uicontrol {Actions on Commits}. You can
|
||||
checkout, revert, or cherry-pick commits or view them in the diff editor.
|
||||
|
||||
\image creator-git-commit-actions.png "Select a Git Commit dialog"
|
||||
|
||||
\section3 Working with Remote Repositories
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol Git > \uicontrol {Remote Repository} > \uicontrol Pull to
|
||||
pull changes from the remote repository. If there are locally modified
|
||||
files, you are prompted to stash the changes. Select \uicontrol Tools >
|
||||
\uicontrol Options > \uicontrol {Version Control} > \uicontrol Git and then select the
|
||||
\uicontrol {Pull with rebase} check box to perform a rebase operation while
|
||||
pulling.
|
||||
|
||||
\section4 Managing Remote Repositories
|
||||
|
||||
To manage remote repositories available in Git, select \uicontrol Tools > \uicontrol Git
|
||||
> \uicontrol {Remote Repository} > \uicontrol{Manage Remotes}. Double-click the names
|
||||
and URLs of the remote repositories to edit them.
|
||||
|
||||
The following operations are supported:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Menu Item
|
||||
\li Description
|
||||
\row
|
||||
\li \uicontrol{Refresh}
|
||||
\li Refresh the list of remote repositories.
|
||||
\row
|
||||
\li \uicontrol{Add}
|
||||
\li Add a new remote repository.
|
||||
\row
|
||||
\li \uicontrol{Fetch}
|
||||
\li Fetch all the branches and change information from a remote
|
||||
repository.
|
||||
\row
|
||||
\li \uicontrol Push
|
||||
\li Push committed changes to the remote repository.
|
||||
\row
|
||||
\li \uicontrol{Remove}
|
||||
\li Remove a remote repository.
|
||||
|
||||
\endtable
|
||||
|
||||
\section4 Using Git with Subversion
|
||||
|
||||
You can use Git as a client for a Subversion server. To fetch changes from a
|
||||
Subversion repository to a Git repository, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Remote Repository} > \uicontrol Subversion > \uicontrol Fetch.
|
||||
|
||||
To view the Git Subversion log, select \uicontrol Log.
|
||||
|
||||
\section4 Reviewing Code with Gerrit
|
||||
|
||||
If your Git project uses Gerrit for code reviews, you can view your changes
|
||||
in \QC.
|
||||
|
||||
Select \uicontrol Tools > \uicontrol Options > \uicontrol {Version Control}
|
||||
> \uicontrol Gerrit to
|
||||
specify the connection to the Gerrit server.
|
||||
|
||||
\image qtcreator-gerrit-options.png
|
||||
|
||||
To push committed changes to Gerrit, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Remote Repository} > \uicontrol {Push to Gerrit}.
|
||||
|
||||
To view the same information about each change as in the Gerrit
|
||||
web interface, select \uicontrol Tools > \uicontrol Git > \uicontrol {Remote Repository} >
|
||||
\uicontrol Gerrit.
|
||||
|
||||
\image qtcreator-gerrit.png
|
||||
|
||||
To view details of the selected change, select \uicontrol Show.
|
||||
|
||||
To cherry-pick the selected change to the local repository, select
|
||||
\uicontrol {Cherry Pick}. To remove the change after testing it, select \uicontrol Tools >
|
||||
\uicontrol Git > \uicontrol {Local Repository} > \uicontrol Reset. In the
|
||||
\uicontrol {Undo Changes to} dialog, select the
|
||||
state to reset the working directory to, and then select \uicontrol OK.
|
||||
|
||||
To check out the change in a headless state, select \uicontrol Checkout.
|
||||
|
||||
To refresh the list of changes, select \uicontrol Refresh.
|
||||
|
||||
\section3 Working with Git Tools
|
||||
|
||||
To start a graphical interface to Git, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Git Tools} > \uicontrol {Git Gui}.
|
||||
|
||||
\note On \macos, the default Git installation does not contain Git Gui. To
|
||||
use Git Gui, install it separately. To start Git Gui from \QC, select
|
||||
\uicontrol Preferences > \uicontrol {Version Control} > \uicontrol Git, and set the path to
|
||||
the environment that contains Git Gui in the \uicontrol {Prepend to PATH} field.
|
||||
|
||||
To start the commit viewer for Git, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Git Tools} > \uicontrol Gitk. You can also start the tool to view commits in
|
||||
the current document or in the folder that contains the current document.
|
||||
To specify arguments for running Gitk, select \uicontrol Tools > \uicontrol Options >
|
||||
\uicontrol {Version Control} > \uicontrol Git.
|
||||
|
||||
To use some other application for viewing Git history, such as GitX or
|
||||
QGit viewer, select \uicontrol Tools > \uicontrol Options > \uicontrol {Version Control} >
|
||||
\uicontrol Git and specify the path to the application executable in the
|
||||
\uicontrol {Command} field. To start the application, select \uicontrol Tools > \uicontrol Git
|
||||
> \uicontrol {Git Tools} > \uicontrol {Repository Browser}.
|
||||
|
||||
To resolve merge conflicts, select \uicontrol Tools > \uicontrol Git > \uicontrol {Git Tools}
|
||||
> \uicontrol {Merge Tool}.
|
||||
|
||||
\section2 Using Additional Mercurial Functionality
|
||||
|
||||
Mercurial is a free, distributed source control management tool.
|
||||
|
||||
The \uicontrol Mercurial submenu contains the following additional items:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Menu Item
|
||||
\li Description
|
||||
\row
|
||||
\li \uicontrol{Import}
|
||||
\li Apply changes from a patch file.
|
||||
\row
|
||||
\li \uicontrol{Incoming}
|
||||
\li Monitor the status of a remote repository by listing
|
||||
the changes that will be pulled.
|
||||
\row
|
||||
\li \uicontrol{Outgoing}
|
||||
\li Monitor the status of a remote repository by listing
|
||||
the changes that will be pushed.
|
||||
\row
|
||||
\li \uicontrol{Pull}
|
||||
\li Pull changes from the remote repository.
|
||||
\row
|
||||
\li \uicontrol{Push}
|
||||
\li Push changes to the remote repository.
|
||||
\endtable
|
||||
|
||||
\section2 Using Additional Perforce Functions
|
||||
|
||||
Perforce is a fast software configuration management system developed by
|
||||
Perforce Software.
|
||||
|
||||
When you start \QC, it looks for the executable specified
|
||||
in the \uicontrol{P4 command} field in \uicontrol{Tools > Options > Version
|
||||
Control > Perforce}. If the file is not found, the following error
|
||||
message is displayed in the \uicontrol {Version Control} output pane:
|
||||
\uicontrol {Perforce: Unable to determine the repository: "p4.exe"
|
||||
terminated with exit code 1}. If you use Perforce, check that the
|
||||
path to the executable is specified correctly in the \uicontrol{P4 command}
|
||||
field.
|
||||
|
||||
If you do not use Perforce, you can disable the Perforce plugin to
|
||||
get rid of the error message. Choose \uicontrol {Help > About Plugins} and
|
||||
deselect the \uicontrol Load check box for the \uicontrol Perforce plugin in the
|
||||
\uicontrol {Version Control} group.
|
||||
|
||||
In the Perforce options, you can specify workspace details:
|
||||
\uicontrol {P4 user}, \uicontrol {P4 client}, and \uicontrol {P4 port}. To
|
||||
specify the details individually for several projects, use configuration
|
||||
files instead. Create a \c {p4config.txt} configuration file for each
|
||||
project in the top level project directory.
|
||||
|
||||
The \uicontrol Perforce submenu contains the following additional items:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Menu Item
|
||||
\li Description
|
||||
\row
|
||||
\li \uicontrol{Describe}
|
||||
\li View information about changelists and the files in them.
|
||||
\row
|
||||
\li \uicontrol{Edit File}
|
||||
\li Open a file for editing.
|
||||
\row
|
||||
\li \uicontrol{Opened}
|
||||
\li List files that are open for editing.
|
||||
\row
|
||||
\li \uicontrol{Pending Changes}
|
||||
\li Group files for commit.
|
||||
\endtable
|
||||
|
||||
\section2 Using Additional Subversion Functions
|
||||
|
||||
Subversion is an open source version control system.
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol Subversion > \uicontrol Describe to display commit log
|
||||
messages for a revision.
|
||||
|
||||
*/
|
||||
@@ -170,10 +170,10 @@
|
||||
|
||||
Qt unit tests for features or classes
|
||||
|
||||
\li Qt Auto Test
|
||||
\li Auto Test Project
|
||||
|
||||
Projects with boilerplate code for a Qt test. For more
|
||||
information, see \l {Creating Qt Tests}.
|
||||
Projects with boilerplate code for a Qt or Google test. For more
|
||||
information, see \l {Creating Tests}.
|
||||
|
||||
\li Qt Quick UI
|
||||
|
||||
@@ -189,9 +189,9 @@
|
||||
|
||||
Custom \QD widget or widget collection
|
||||
|
||||
\li Empty Qt Project
|
||||
\li Empty qmake Project
|
||||
|
||||
Empty Qt project that is based on qmake but does not use any
|
||||
Empty qmake project that is based on qmake but does not use any
|
||||
default classes
|
||||
|
||||
\li Subdirs Project
|
||||
@@ -358,7 +358,13 @@
|
||||
|
||||
\li Nim (experimental)
|
||||
|
||||
Nim source files with UTF-8 encoding.
|
||||
\list
|
||||
|
||||
\li Nim script files.
|
||||
|
||||
\li Nim source files with UTF-8 encoding.
|
||||
|
||||
\endlist
|
||||
|
||||
\endlist
|
||||
|
||||
|
||||
@@ -76,9 +76,14 @@
|
||||
|
||||
\QC attempts to identify the type and version of the debugger and
|
||||
shows them in the \uicontrol Type and \uicontrol Version fields.
|
||||
In addition, \QC shows the ABI version that will be used on embedded
|
||||
devices in the \uicontrol ABIs field.
|
||||
|
||||
\li In the \uicontrol ABIs field, specify the ABI versions to use on embedded
|
||||
devices.
|
||||
\li In the \uicontrol {Working directory} field, specify the working
|
||||
directory of the application process. If the application is run
|
||||
locally, the working directory defaults to the build directory. If
|
||||
the application is run remotely on a device, the value depends on
|
||||
the shell or the device. Usually, you can leave this field empty.
|
||||
|
||||
\endlist
|
||||
*/
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
To disable a kit for the project, select \uicontrol {Disable Kit for Project}
|
||||
in the context menu.
|
||||
|
||||
To import an existing build for the project, select
|
||||
\uicontrol {Import Existing Build} in the context menu.
|
||||
|
||||
\section1 Specifying Settings
|
||||
|
||||
The \uicontrol Projects mode displays one of the following views:
|
||||
@@ -99,7 +102,7 @@
|
||||
|
||||
\li \l{Specifying Dependencies}{Dependencies}
|
||||
|
||||
\li \l{Parsing C++ Files}{Clang Code Model} (experimental)
|
||||
\li \l{Parsing C++ Files with the Clang Code Model} (experimental)
|
||||
|
||||
\li \l{Using Clang Static Analyzer}{Clang Static Analyzer}
|
||||
|
||||
|
||||
+10
-1
@@ -164,6 +164,15 @@
|
||||
\endlist
|
||||
\endlist
|
||||
\li \l{Using Version Control Systems}
|
||||
\list
|
||||
\li \l{Using Bazaar}
|
||||
\li \l{Using ClearCase}
|
||||
\li \l{Using CVS}
|
||||
\li \l{Using Git}
|
||||
\li \l{Using Mercurial}
|
||||
\li \l{Using Perforce}
|
||||
\li \l{Using Subversion}
|
||||
\endlist
|
||||
\li \l{Configuring Projects}
|
||||
\list
|
||||
\li \l{Adding Kits}
|
||||
@@ -215,7 +224,7 @@
|
||||
\li \l{Pasting and Fetching Code Snippets}
|
||||
\li \l{Using Text Editing Macros}
|
||||
\li \l{Comparing Files}
|
||||
\li \l{Parsing C++ Files}
|
||||
\li \l{Parsing C++ Files with the Clang Code Model}
|
||||
\endlist
|
||||
\li \l{Finding}
|
||||
\list
|
||||
|
||||
@@ -106,8 +106,8 @@
|
||||
\endlist
|
||||
|
||||
To create a graphical button that scales beautifully without using vector
|
||||
graphics, use the \l{BorderImage} type. For more information, see
|
||||
\l{Creating Scalable Buttons and Borders}.
|
||||
graphics, use the \l [QML]{BorderImage}{Border Image} type. For more
|
||||
information, see \l{Creating Scalable Buttons and Borders}.
|
||||
|
||||
*/
|
||||
|
||||
@@ -121,17 +121,17 @@
|
||||
|
||||
\title Creating Scalable Buttons and Borders
|
||||
|
||||
You can use the
|
||||
\l{BorderImage} type to display an image, such as a PNG file, as a border
|
||||
and a background.
|
||||
You can use the \l [QML]{BorderImage}{Border Image} type to display an
|
||||
image, such as a PNG file, as a border and a background.
|
||||
|
||||
Use two border images and suitable graphics to make it look like the
|
||||
button is pushed down when it is clicked. One of the border images
|
||||
is visible by default. You can specify that it is hidden and the other one
|
||||
becomes visible when the mouse is clicked.
|
||||
|
||||
Add a \l MouseArea type that covers the whole area and emits the clicked
|
||||
signal (\c {item.clicked()}) when it detects a mouse click.
|
||||
Add a \l [QML]{MouseArea}{Mouse Area} type that covers the whole area and
|
||||
emits the clicked signal (\c {item.clicked()}) when it detects a mouse
|
||||
click.
|
||||
|
||||
You can add text to the button and set it up as a property. The text can
|
||||
then be initialized from the outside, making the button a reusable UI
|
||||
|
||||
@@ -48,28 +48,28 @@
|
||||
|
||||
\list
|
||||
|
||||
\li \l{BorderImage} uses an image as a border or background.
|
||||
\li \l [QML]{BorderImage}{Border Image} uses an image as a border or background.
|
||||
|
||||
\li \l{Image}
|
||||
\li \l [QML]{Image}
|
||||
adds a bitmap to the scene. You can stretch and tile images.
|
||||
|
||||
\li \l{Item}
|
||||
\li \l [QML]{Item}
|
||||
is the most basic of all visual types in QML. Even though it has no
|
||||
visual appearance, it defines all the properties that are common
|
||||
across visual types, such as the x and y position, width and height,
|
||||
anchoring, and key handling.
|
||||
|
||||
\li \l{Rectangle}
|
||||
\li \l [QML]{Rectangle}
|
||||
adds a rectangle that is painted with a solid fill color and an
|
||||
optional border. You can also use the radius property to create
|
||||
rounded rectangles.
|
||||
|
||||
\li \l{Text} adds formatted read-only text.
|
||||
\li \l [QML]{Text} adds formatted read-only text.
|
||||
|
||||
\li \l{TextEdit}
|
||||
\li \l [QML]{TextEdit}{Text Edit}
|
||||
adds a single line of editable formatted text that can be validated.
|
||||
|
||||
\li \l{TextInput}
|
||||
\li \l [QML]{TextInput}{Text Input}
|
||||
adds a single line of editable plain text that can be validated.
|
||||
|
||||
\omit
|
||||
|
||||
@@ -376,8 +376,8 @@
|
||||
You can double-click objects on the canvas to edit their text, color, or
|
||||
source properties inline.
|
||||
Because you can specify several of these properties for some QML types, such
|
||||
as TextEdit, you can also right-click objects to open the inline editors
|
||||
from a context-menu.
|
||||
as \l [QML]{TextEdit}{Text Edit}, you can also right-click objects to open
|
||||
the inline editors from a context-menu.
|
||||
|
||||
\image qmldesigner-inline-editing.png
|
||||
|
||||
|
||||
@@ -40,8 +40,9 @@
|
||||
|
||||
You can export designs from graphics software, such as Adobe Photoshop and
|
||||
GIMP, to QML files. Each scene is converted into a single QML file with an
|
||||
Image or a Text item for each layer and saved on the development PC.
|
||||
Top-level layer groups are converted into merged QML Image types.
|
||||
\l [QML]{Image} or a \l [QML]{Text} item for each layer and saved on the
|
||||
development PC. Top-level layer groups are converted into merged QML
|
||||
\l [QML]{Image} types.
|
||||
|
||||
\note GIMP does not support grouping, and therefore, each layer is exported
|
||||
as an item in GIMP.
|
||||
@@ -74,8 +75,8 @@
|
||||
|
||||
\li Offset, size, ordering and opacity are preserved.
|
||||
|
||||
\li Text layers are converted to Text items, unless you specify that
|
||||
they be converted to Image items.
|
||||
\li Text layers are converted to \l [QML]{Text} items, unless you
|
||||
specify that they be converted to \l [QML]{Image} items.
|
||||
|
||||
\li Hidden layers can be exported, and their visibility is set to
|
||||
hidden.
|
||||
@@ -93,7 +94,7 @@
|
||||
|
||||
\li To minimize the number of items, minimize the number of layers or
|
||||
use top-level layer groups, because each layer or layer group is
|
||||
exported as a Text or Image item.
|
||||
exported as a \l [QML]{Text} or \l [QML]{Image} item.
|
||||
|
||||
\li To make sure that all related items are exported to the same
|
||||
item, use top-level layer groups.
|
||||
@@ -153,10 +154,10 @@
|
||||
location for the QML file.
|
||||
|
||||
\li Select the \uicontrol {Rasterize text} check box to export text layers as
|
||||
images, not as Text items.
|
||||
images, not as \l [QML]{Text} items.
|
||||
|
||||
\li Select the \uicontrol {Group layers} check box to export each top-level
|
||||
group as a merged QML Image item.
|
||||
group as a merged QML \l [QML]{Image} item.
|
||||
|
||||
\li Select the \uicontrol {Export hidden} check box to export hidden layers
|
||||
and to set their visibility property to hidden.
|
||||
|
||||
@@ -218,15 +218,15 @@
|
||||
|
||||
\list
|
||||
|
||||
\li \l{Column} arranges its child items vertically.
|
||||
\li \l[QML] {Column} arranges its child items vertically.
|
||||
|
||||
\li \l{Row} arranges its child items horizontally.
|
||||
\li \l[QML] {Row} arranges its child items horizontally.
|
||||
|
||||
\li \l{Grid}
|
||||
\li \l[QML] {Grid}
|
||||
arranges its child items so that they are aligned in a grid and
|
||||
are not overlapping.
|
||||
|
||||
\li \l{Flow}
|
||||
\li \l[QML] {Flow}
|
||||
arranges its child items side by side, wrapping as necessary.
|
||||
|
||||
\endlist
|
||||
@@ -376,7 +376,7 @@
|
||||
assists in keyboard focus handling when building reusable QML
|
||||
components.
|
||||
|
||||
\li MouseArea enables simple mouse handling.
|
||||
\li \l [QML]{MouseArea}{Mouse Area} enables simple mouse handling.
|
||||
|
||||
\endlist
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
\section1 Previewing Images
|
||||
|
||||
The Qt Quick Toolbar for images allows you to edit the properties of
|
||||
BorderImage and \l{Image} items.
|
||||
\l [QML]{BorderImage}{Border Image} and \l [QML]{Image} items.
|
||||
You can scale and tile the images, replace them with other images,
|
||||
preview them, and change the image margins.
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
\section1 Editing Rectangles
|
||||
|
||||
The Qt Quick Toolbar for rectangles allows you to edit the properties of
|
||||
\l{Rectangle} items. You can change the fill and border colors and add
|
||||
\l [QML]{Rectangle} items. You can change the fill and border colors and add
|
||||
gradients.
|
||||
|
||||
\image qml-toolbar-rectangle.png "Qt Quick Toolbar for rectangles"
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
\li Other bindings than pure expressions
|
||||
\li Signal handlers
|
||||
\li States in other items than the root item
|
||||
\li Root items that are not derived from \l QQuickItem or \l Item
|
||||
\li Root items that are not derived from \l QQuickItem or \l [QML]{Item}
|
||||
\endlist
|
||||
|
||||
The following types are not supported:
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Creator Manual}
|
||||
\previouspage creator-version-control.html
|
||||
\page creator-vcs-bazaar.html
|
||||
\nextpage creator-vcs-clearcase.html
|
||||
|
||||
\title Using Bazaar
|
||||
|
||||
Bazaar is a free version control system sponsored by Canonical.
|
||||
|
||||
In addition to the standard version control system functions described in
|
||||
\l {Using Common Functions}, you can select \uicontrol Tools >
|
||||
\uicontrol Bazaar > \uicontrol Pull to turn a branch into a mirror of
|
||||
another branch. To update the mirror of the branch, select \uicontrol Push.
|
||||
|
||||
\section1 Uncommitting Revisions
|
||||
|
||||
In Bazaar, committing changes to a branch creates a new revision that holds
|
||||
a snapshot of the state of the working tree. To remove the last committed
|
||||
revision, select \uicontrol Tools > \uicontrol Bazaar > \uicontrol Uncommit.
|
||||
|
||||
In the \uicontrol Uncommit dialog, select options to keep tags that point to
|
||||
removed revisions and to only remove the commits from the local branch when
|
||||
in a checkout.
|
||||
|
||||
To remove all commits up to an entry in the revision log, specify the
|
||||
revision in the \uicontrol Revision field.
|
||||
|
||||
To test the outcome of the \uicontrol Uncommit command without actually
|
||||
removing anything, select \uicontrol {Dry Run}.
|
||||
|
||||
\uicontrol Uncommit leaves the working tree ready for a new commit. The only
|
||||
change it might make is restoring pending merges that were present before
|
||||
the commit.
|
||||
*/
|
||||
@@ -0,0 +1,115 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Creator Manual}
|
||||
\previouspage creator-vcs-bazaar.html
|
||||
\page creator-vcs-clearcase.html
|
||||
\nextpage creator-vcs-cvs.html
|
||||
|
||||
\title Using ClearCase
|
||||
|
||||
IBM Rational ClearCase is a version control, workspace management, parallel
|
||||
development support, and build automation solution developed by IBM. The
|
||||
ClearCase client plugin is available on Linux and Windows for accessing a
|
||||
ClearCase server.
|
||||
|
||||
\section1 Using GNU Diffutils with ClearCase
|
||||
|
||||
You can use the GNU Diffutils tool With ClearCase to compare files and
|
||||
activities:
|
||||
|
||||
\list 1
|
||||
|
||||
\li Download \l{http://gnuwin32.sourceforge.net/packages/diffutils.htm}
|
||||
{Diffutils} and extract it to a directory in your PATH.
|
||||
|
||||
\li Select \uicontrol Tools > \uicontrol Options >
|
||||
\uicontrol {Version Control} > \uicontrol ClearCase.
|
||||
|
||||
\li Select the \uicontrol External radio button. The radio button is
|
||||
disabled if \c diff is not found in the PATH.
|
||||
|
||||
\li In the \uicontrol Arguments field, specify arguments for running
|
||||
\c diff.
|
||||
|
||||
\endlist
|
||||
|
||||
\section1 Checking out and Checking in
|
||||
|
||||
In addition to the standard version control system functions described in
|
||||
\l {Using Common Functions}, you can check out and check in files.
|
||||
|
||||
To create a writable copy of a file, select \uicontrol Tools >
|
||||
\uicontrol ClearCase > \uicontrol {Check Out}. If you check out files in a
|
||||
Unified Change Management (UCM) view, they are added to the change set of
|
||||
a UCM activity. By default, the activities are automatically assigned names.
|
||||
To disable this functionality, select \uicontrol Tools > \uicontrol Options
|
||||
> \uicontrol {Version Control} > \uicontrol ClearCase, and then deselect the
|
||||
\uicontrol {Automatically assign activity names} check box.
|
||||
|
||||
To automatically check out files when you edit them, select \uicontrol Tools
|
||||
> \uicontrol Options > \uicontrol {Version Control} > \uicontrol ClearCase,
|
||||
and then select the \uicontrol {Automatically check out files on edit}
|
||||
check box.
|
||||
|
||||
To cancel the checkout for a file and delete the checked-out version,
|
||||
select \uicontrol Tools > \uicontrol ClearCase >
|
||||
\uicontrol {Undo Check Out}.
|
||||
|
||||
To check in checked-out versions of files in the change set of the current
|
||||
UCM activity, select \uicontrol Tools > \uicontrol ClearCase >
|
||||
\uicontrol {Check In Activity}.
|
||||
|
||||
To create a permanent new version of the current file or all files in the
|
||||
versioned object base (VOB), select \uicontrol Tools >
|
||||
\uicontrol {ClearCase} > \uicontrol {Check In}. To be asked to confirm
|
||||
that you want to check in the files, select \uicontrol Tools >
|
||||
\uicontrol Options > \uicontrol {Version Control} > \uicontrol ClearCase,
|
||||
and then select the \uicontrol {Prompt on check-in} check box.
|
||||
|
||||
By default, you are asked to enter a comment when checking files out or in.
|
||||
To suppress this prompt, select \uicontrol Tools > \uicontrol Options >
|
||||
\uicontrol {Version Control} > \uicontrol ClearCase, and then select the
|
||||
\uicontrol {Do not prompt for comment during checkout or check-in} check
|
||||
box.
|
||||
|
||||
If you change the read-only attribute of a file that is loaded into a
|
||||
snapshot view and modify the file without checking it out, you \e hijack the
|
||||
file. To revert a hijacked file to its checked in version, select
|
||||
\uicontrol Tools > \uicontrol ClearCase > \uicontrol {Undo Hijack}.
|
||||
|
||||
By default, the files in the VOBs are indexed for quick access to their
|
||||
statuses. To disable indexing, select \uicontrol Tools > \uicontrol Options
|
||||
> \uicontrol {Version Control} > \uicontrol ClearCase, and then select the
|
||||
\uicontrol {Disable indexer} check box. To only have some VOBs indexed,
|
||||
specify them in the \uicontrol {Index only VOBs} field.
|
||||
*/
|
||||
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Creator Manual}
|
||||
\previouspage creator-vcs-clearcase.html
|
||||
\page creator-vcs-cvs.html
|
||||
\nextpage creator-vcs-git.html
|
||||
|
||||
\title Using CVS
|
||||
|
||||
CVS is an open source version control system.
|
||||
|
||||
In addition to the standard version control system functions described in
|
||||
\l {Using Common Functions}, you can select \uicontrol Tools >
|
||||
\uicontrol CVS > \uicontrol Edit to open a file for editing.
|
||||
|
||||
To discard the changes that you made in a file, select \uicontrol Unedit.
|
||||
|
||||
To specify the CVS root directory, select \uicontrol Tools >
|
||||
\uicontrol Options > \uicontrol {Version Control} > \uicontrol CVS, and then
|
||||
specify the path to the directory in the \uicontrol {CVS root} field.
|
||||
|
||||
You can specify settings for viewing diff output in the
|
||||
\uicontrol {Diff options} field.
|
||||
|
||||
By default, you are prompted to confirm that you want to submit changes.
|
||||
To suppress the prompt, deselect the \uicontrol {Prompt on submit} check
|
||||
box.
|
||||
|
||||
By default, all files that belong to the commit are annotated. To disable
|
||||
this feature, deselect the \uicontrol {Describe all files matching commit
|
||||
id} check box.
|
||||
*/
|
||||
@@ -0,0 +1,349 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Creator Manual}
|
||||
\previouspage creator-vcs-cvs.html
|
||||
\page creator-vcs-git.html
|
||||
\nextpage creator-vcs-mercurial.html
|
||||
|
||||
\title Using Git
|
||||
|
||||
Git is a fast decentralized version control system. Git is available
|
||||
for Windows, Linux, and \macos.
|
||||
|
||||
You can use the \l{http://code.google.com/p/gerrit/}{Gerrit} code review
|
||||
tool for projects that use Git.
|
||||
|
||||
\section1 Using msysGit on Windows
|
||||
|
||||
If you configure Git for use with \c {git bash}, only, and use SSH
|
||||
authorization, Git looks for the SSH keys in the directory where the
|
||||
\c HOME environment points to. The variable is always set by \c {git bash}.
|
||||
|
||||
However, the variable is typically not set in a Windows command prompt. When
|
||||
you run Git from a Windows command prompt, it looks for the SSH keys in its
|
||||
installation directory, and therefore, the authorization fails.
|
||||
|
||||
You can set the \c HOME environment variable from \QC. Select
|
||||
\uicontrol Tools > \uicontrol Options > \uicontrol {Version Control} >
|
||||
\uicontrol Git, and then select the
|
||||
\uicontrol {Set "HOME" environment variable} check box. \c HOME is
|
||||
set to \c %HOMEDRIVE%%HOMEPATH% when the Git executable is run and
|
||||
authorization works as it would with \c {git bash}.
|
||||
|
||||
\section1 Reverting Changes Using Git
|
||||
|
||||
The Git version control system has an index that is used to stage
|
||||
changes. The index is committed on the next commit. Git allows you to revert
|
||||
back to the state of the last commit as well as to the state staged in the
|
||||
index.
|
||||
|
||||
\list
|
||||
|
||||
\li \uicontrol Git > \uicontrol {Current File} >
|
||||
\uicontrol{Undo Unstaged Changes} reverts all changes and resets the
|
||||
current file to the state of the index.
|
||||
|
||||
\li \uicontrol Git > \uicontrol {Current File} >
|
||||
\uicontrol {Undo Uncommitted Changes} reverts all changes,
|
||||
discarding the index. This returns the current file to the state it
|
||||
was in right after the last commit.
|
||||
|
||||
\li \uicontrol Git > \uicontrol {Local Repository} > \uicontrol Reset
|
||||
opens a dialog where you can select the SHA-1 to reset the working
|
||||
directory to. This is useful after applying patches for review, for
|
||||
example. You can choose between a \uicontrol Soft reset that does
|
||||
not touch the index file nor the working tree at all, a
|
||||
\uicontrol Hard reset that discards all changes to tracked files in
|
||||
working tree, and a \uicontrol Mixed reset that resets HEAD and the
|
||||
index (nothing remains staged) without touching the working
|
||||
directory.
|
||||
|
||||
\endlist
|
||||
|
||||
\section1 Working with the Current File
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol Git > \uicontrol {Current File} >
|
||||
\uicontrol {Stage File for Commit} to mark a new or modified file for
|
||||
committing to the repository.
|
||||
|
||||
To undo this function, select \uicontrol {Unstage File from Commit}.
|
||||
|
||||
\section1 Working with the Current Project
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol Git > \uicontrol {Current Project} >
|
||||
\uicontrol {Clean Project}
|
||||
to clean the working directory. All files that are not under version control
|
||||
are displayed in the \uicontrol {Clean Repository} dialog. Ignored files are
|
||||
deselected by default. Select the files to delete and click
|
||||
\uicontrol Delete.
|
||||
|
||||
\section1 Working with Local Repositories
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol Git > \uicontrol {Local Repository} >
|
||||
\uicontrol Clean to clean the repository.
|
||||
|
||||
To apply latest changes to the last commit, select \uicontrol Tools >
|
||||
\uicontrol Git > \uicontrol {Local Repository} >
|
||||
\uicontrol {Amend Last Commit}. You can also edit the commit message.
|
||||
|
||||
To amend an earlier comment in a series of related commits, select
|
||||
\uicontrol Tools > \uicontrol Git > \uicontrol {Local Repository} >
|
||||
\uicontrol {Fixup Previous Commit}. This operation is done using interactive
|
||||
rebase. In case of conflicts, a merge tool is suggested.
|
||||
|
||||
To change a series of commits in the local repository, select
|
||||
\uicontrol Tools > \uicontrol Git > \uicontrol {Local Repository} >
|
||||
\uicontrol {Interactive Rebase}. You can reorder or discard commits, squash
|
||||
them into a single commit, or edit the commit messages.
|
||||
|
||||
The following sections describe how to manage local and remote branches,
|
||||
apply patches, and use stashes.
|
||||
|
||||
\section2 Working with Branches
|
||||
|
||||
To work with Git branches, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Local Repository} > \uicontrol {Branches}. The checked out
|
||||
branch is shown in bold and underlined in the list of branches. Double-click
|
||||
branch names to edit them.
|
||||
|
||||
\image qtcreator-vcs-gitbranch.png "Branches dialog"
|
||||
|
||||
The following operations are supported:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Menu Item
|
||||
\li Description
|
||||
\row
|
||||
\li \uicontrol{Refresh}
|
||||
\li Refresh the list of branches.
|
||||
\row
|
||||
\li \uicontrol{Add}
|
||||
\li Create new tracking and non-tracking branches.
|
||||
\row
|
||||
\li \uicontrol{Remove}
|
||||
\li Remove a local branch. You cannot delete remote branches.
|
||||
\row
|
||||
\li \uicontrol Rename
|
||||
\li Rename a local branch.
|
||||
\row
|
||||
\li \uicontrol{Checkout}
|
||||
\li Check out the selected branch and make it current. You can stash
|
||||
changes you have made to tracked files.
|
||||
\row
|
||||
\li \uicontrol{Diff}
|
||||
\li Show the differences between the selected and the current
|
||||
branch.
|
||||
\row
|
||||
\li \uicontrol{Log}
|
||||
\li Show the changes in a branch.
|
||||
\row
|
||||
\li \uicontrol Merge
|
||||
\li Join the development histories in two branches together.
|
||||
|
||||
If the commit you are merging can be reached by following the
|
||||
first commit's history, there is no divergent work to merge
|
||||
together. To allow Git to move the branch pointer forward,
|
||||
select \uicontrol {Fast-Forward}. If you do not want to
|
||||
fast-forward the branch, select \uicontrol {No Fast-Forward}.
|
||||
\row
|
||||
\li \uicontrol Rebase
|
||||
\li Copy local commits to the updated upstream head.
|
||||
\row
|
||||
\li \uicontrol Reset
|
||||
\li Hard reset the active branch to the selected branch.
|
||||
\row
|
||||
\li \uicontrol {Cherry Pick}
|
||||
\li Cherry pick the top commit from the selected branch.
|
||||
\row
|
||||
\li \uicontrol Track
|
||||
\li Set the current branch to track the selected one.
|
||||
\endtable
|
||||
|
||||
\section2 Applying Patches
|
||||
|
||||
Patches are rewriting instructions that can be applied to a set of files.
|
||||
To apply a patch file that is open in \QC, select \uicontrol Tools >
|
||||
\uicontrol Git > \uicontrol {Local Repository} > \uicontrol Patch >
|
||||
\uicontrol {Apply from Editor}.
|
||||
|
||||
To select the patch file to apply from the file system, select
|
||||
\uicontrol {Apply from File}.
|
||||
|
||||
\section2 Using Stashes
|
||||
|
||||
With Git, you can put your current set of changes onto a virtual shelf
|
||||
called a \e stash. Stashes are useful, for example, to put aside a set of
|
||||
changes to work on higher priority tasks or to pull in new chages from
|
||||
another repository.
|
||||
|
||||
To stash all local changes, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Local Repository} > \uicontrol Stash > \uicontrol Stash. The
|
||||
working copy is reset to the state it had after the last commit. To save the
|
||||
current state of your unstaged files and reset the repository to its staged
|
||||
state, select \uicontrol {Stash Unstaged Files}.
|
||||
|
||||
To display a dialog that shows all known stashes with options to restore,
|
||||
display or delete them, select \uicontrol Stashes.
|
||||
|
||||
To save a snapshot of your current work under a name for later reference,
|
||||
select \uicontrol {Take Snapshot}. The working copy is unchanged. For
|
||||
example, if you want to try something and find out later that it does not
|
||||
work, you can discard the changes and return to the state of the snapshot.
|
||||
|
||||
To remove a single stashed state from the stash list and apply it on top of
|
||||
the current working tree state, select \uicontrol {Stash Pop}.
|
||||
|
||||
\section1 Applying Actions to Commits
|
||||
|
||||
To browse a directory or the commit history and to apply actions on the
|
||||
commits, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Actions on Commits}. You can checkout, revert, or cherry-pick
|
||||
commits or view them in the diff editor.
|
||||
|
||||
\image creator-git-commit-actions.png "Select a Git Commit dialog"
|
||||
|
||||
\section1 Working with Remote Repositories
|
||||
|
||||
In addition to the standard version control system functions, you can
|
||||
select \uicontrol Tools > \uicontrol Git > \uicontrol {Remote Repository} >
|
||||
\uicontrol Pull topull changes from the remote repository. If there are
|
||||
locally modified files, you are prompted to stash the changes. Select
|
||||
\uicontrol Tools > \uicontrol Options > \uicontrol {Version Control} >
|
||||
\uicontrol Git and then select the \uicontrol {Pull with rebase} check box
|
||||
to perform a rebase operation while pulling.
|
||||
|
||||
\section2 Managing Remote Repositories
|
||||
|
||||
To manage remote repositories available in Git, select \uicontrol Tools >
|
||||
\uicontrol Git > \uicontrol {Remote Repository} >
|
||||
\uicontrol{Manage Remotes}. Double-click the names and URLs of the remote
|
||||
repositories to edit them.
|
||||
|
||||
The following operations are supported:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Menu Item
|
||||
\li Description
|
||||
\row
|
||||
\li \uicontrol{Refresh}
|
||||
\li Refresh the list of remote repositories.
|
||||
\row
|
||||
\li \uicontrol{Add}
|
||||
\li Add a new remote repository.
|
||||
\row
|
||||
\li \uicontrol{Fetch}
|
||||
\li Fetch all the branches and change information from a remote
|
||||
repository.
|
||||
\row
|
||||
\li \uicontrol Push
|
||||
\li Push committed changes to the remote repository.
|
||||
\row
|
||||
\li \uicontrol{Remove}
|
||||
\li Remove a remote repository.
|
||||
|
||||
\endtable
|
||||
|
||||
\section2 Using Git with Subversion
|
||||
|
||||
You can use Git as a client for a Subversion server. To fetch changes from a
|
||||
Subversion repository to a Git repository, select \uicontrol Tools >
|
||||
\uicontrol Git > \uicontrol {Remote Repository} > \uicontrol Subversion >
|
||||
\uicontrol Fetch.
|
||||
|
||||
To view the Git Subversion log, select \uicontrol Log.
|
||||
|
||||
\section2 Reviewing Code with Gerrit
|
||||
|
||||
If your Git project uses Gerrit for code reviews, you can view your changes
|
||||
in \QC.
|
||||
|
||||
Select \uicontrol Tools > \uicontrol Options > \uicontrol {Version Control}
|
||||
> \uicontrol Gerrit to specify the connection to the Gerrit server.
|
||||
|
||||
\image qtcreator-gerrit-options.png
|
||||
|
||||
To push committed changes to Gerrit, select \uicontrol Tools >
|
||||
\uicontrol Git > \uicontrol {Remote Repository} >
|
||||
\uicontrol {Push to Gerrit}.
|
||||
|
||||
To view the same information about each change as in the Gerrit
|
||||
web interface, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Remote Repository} > \uicontrol Gerrit.
|
||||
|
||||
\image qtcreator-gerrit.png
|
||||
|
||||
To view details of the selected change, select \uicontrol Show.
|
||||
|
||||
To cherry-pick the selected change to the local repository, select
|
||||
\uicontrol {Cherry Pick}. To remove the change after testing it, select
|
||||
\uicontrol Tools > \uicontrol Git > \uicontrol {Local Repository} >
|
||||
\uicontrol Reset. In the \uicontrol {Undo Changes to} dialog, select the
|
||||
state to reset the working directory to, and then select \uicontrol OK.
|
||||
|
||||
To check out the change in a headless state, select \uicontrol Checkout.
|
||||
|
||||
To refresh the list of changes, select \uicontrol Refresh.
|
||||
|
||||
\section1 Working with Git Tools
|
||||
|
||||
To start a graphical interface to Git, select \uicontrol Tools >
|
||||
\uicontrol Git > \uicontrol {Git Tools} > \uicontrol {Git Gui}.
|
||||
|
||||
\note On \macos, the default Git installation does not contain Git Gui. To
|
||||
use Git Gui, install it separately. To start Git Gui from \QC, select
|
||||
\uicontrol Preferences > \uicontrol {Version Control} > \uicontrol Git, and
|
||||
set the path to the environment that contains Git Gui in the
|
||||
\uicontrol {Prepend to PATH} field.
|
||||
|
||||
To start the commit viewer for Git, select \uicontrol Tools >
|
||||
\uicontrol Git > \uicontrol {Git Tools} > \uicontrol Gitk. You can also
|
||||
start the tool to view commits in the current document or in the folder that
|
||||
contains the current document. To specify arguments for running Gitk, select
|
||||
\uicontrol Tools > \uicontrol Options > \uicontrol {Version Control} >
|
||||
\uicontrol Git.
|
||||
|
||||
To use some other application for viewing Git history, such as GitX or
|
||||
QGit viewer, select \uicontrol Tools > \uicontrol Options >
|
||||
\uicontrol {Version Control} > \uicontrol Git and specify the path to the
|
||||
application executable in the \uicontrol {Command} field. To start the
|
||||
application, select \uicontrol Tools > \uicontrol Git
|
||||
> \uicontrol {Git Tools} > \uicontrol {Repository Browser}.
|
||||
|
||||
To resolve merge conflicts, select \uicontrol Tools > \uicontrol Git >
|
||||
\uicontrol {Git Tools} > \uicontrol {Merge Tool}.
|
||||
*/
|
||||
@@ -0,0 +1,68 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Creator Manual}
|
||||
\previouspage creator-vcs-git.html
|
||||
\page creator-vcs-mercurial.html
|
||||
\nextpage creator-vcs-perforce.html
|
||||
|
||||
\title Using Mercurial
|
||||
|
||||
Mercurial is a free, distributed source control management tool.
|
||||
|
||||
In addition to the standard version control system functions described in
|
||||
\l {Using Common Functions}, you can select the following functions in the
|
||||
\uicontrol Tools > \uicontrol Mercurial submenu:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Menu Item
|
||||
\li Description
|
||||
\row
|
||||
\li \uicontrol{Import}
|
||||
\li Apply changes from a patch file.
|
||||
\row
|
||||
\li \uicontrol{Incoming}
|
||||
\li Monitor the status of a remote repository by listing
|
||||
the changes that will be pulled.
|
||||
\row
|
||||
\li \uicontrol{Outgoing}
|
||||
\li Monitor the status of a remote repository by listing
|
||||
the changes that will be pushed.
|
||||
\row
|
||||
\li \uicontrol{Pull}
|
||||
\li Pull changes from the remote repository.
|
||||
\row
|
||||
\li \uicontrol{Push}
|
||||
\li Push changes to the remote repository.
|
||||
\endtable
|
||||
*/
|
||||
@@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Creator Manual}
|
||||
\previouspage creator-vcs-mercurial.html
|
||||
\page creator-vcs-perforce.html
|
||||
\nextpage creator-vcs-subversion.html
|
||||
|
||||
\title Using Perforce
|
||||
|
||||
Perforce is a fast software configuration management system developed by
|
||||
Perforce Software.
|
||||
|
||||
\section1 Configuring Perforce
|
||||
|
||||
When you start \QC, it looks for the executable specified
|
||||
in the \uicontrol{P4 command} field in \uicontrol{Tools > Options > Version
|
||||
Control > Perforce}. If the file is not found, the following error
|
||||
message is displayed in the \uicontrol {Version Control} output pane:
|
||||
\uicontrol {Perforce: Unable to determine the repository: "p4.exe"
|
||||
terminated with exit code 1}. If you use Perforce, check that the
|
||||
path to the executable is specified correctly in the \uicontrol{P4 command}
|
||||
field.
|
||||
|
||||
If you do not use Perforce, you can disable the Perforce plugin to
|
||||
get rid of the error message. Choose \uicontrol {Help > About Plugins} and
|
||||
deselect the \uicontrol Load check box for the \uicontrol Perforce plugin in
|
||||
the \uicontrol {Version Control} group.
|
||||
|
||||
In the Perforce options, you can specify workspace details:
|
||||
\uicontrol {P4 user}, \uicontrol {P4 client}, and \uicontrol {P4 port}. To
|
||||
specify the details individually for several projects, use configuration
|
||||
files instead. Create a \c {p4config.txt} configuration file for each
|
||||
project in the top level project directory.
|
||||
|
||||
\section1 Editing Files
|
||||
|
||||
In addition to the standard version control system functions described in
|
||||
\l {Using Common Functions}, you can select \uicontrol Tools >
|
||||
\uicontrol Perforce > \uicontrol {Edit File} to open a file for editing
|
||||
within the client workspace. By default, files are automatically opened for
|
||||
editing. To disable this feature, select \uicontrol Tools >
|
||||
\uicontrol Options > \uicontrol {Version Control} > \uicontrol Perforce,
|
||||
and then deselect the \uicontrol {Automatically open files when editing}
|
||||
check box.
|
||||
|
||||
To list files that are open for editing, select \uicontrol Tools >
|
||||
\uicontrol Perforce > \uicontrol Opened.
|
||||
|
||||
To group files for commit, select \uicontrol Tools > \uicontrol Perforce >
|
||||
\uicontrol {Pending Changes}.
|
||||
|
||||
To view information about changelists and the files in them, select
|
||||
\uicontrol Tools > \uicontrol Perforce > \uicontrol Describe.
|
||||
|
||||
By default, you are prompted to confirm that you want to submit changes.
|
||||
To suppress the prompt, select \uicontrol Tools > \uicontrol Options >
|
||||
\uicontrol {Version Control} > \uicontrol Perforce, and then deselect the
|
||||
\uicontrol {Prompt on submit} check box.
|
||||
*/
|
||||
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Creator Manual}
|
||||
\previouspage creator-vcs-perforce.html
|
||||
\page creator-vcs-subversion.html
|
||||
\nextpage creator-configuring-projects.html
|
||||
|
||||
\title Using Subversion
|
||||
|
||||
Subversion is an open source version control system.
|
||||
|
||||
In addition to the standard version control system functions described in
|
||||
\l {Using Common Functions}, you can select \uicontrol Tools >
|
||||
\uicontrol Subversion > \uicontrol Describe to display commit log messages
|
||||
for a revision.
|
||||
|
||||
By default, you are prompted to confirm that you want to submit changes.
|
||||
To suppress the prompt, select \uicontrol Tools > \uicontrol Options >
|
||||
\uicontrol {Version Control} > \uicontrol Subversion, and then deselect the
|
||||
\uicontrol {Prompt on submit} check box.
|
||||
|
||||
To show whitespace changes in annotation views, deselect the
|
||||
\uicontrol {Ignore whitespace changes in annotation} check box.
|
||||
*/
|
||||
@@ -0,0 +1,301 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Creator Manual}
|
||||
\previouspage creator-project-wizards-xml.html
|
||||
\page creator-version-control.html
|
||||
\nextpage creator-vcs-bazaar.html
|
||||
|
||||
\title Using Version Control Systems
|
||||
|
||||
Version control systems supported by \QC are:
|
||||
\table
|
||||
\header
|
||||
\li Version Control System
|
||||
\li Address
|
||||
\li Notes
|
||||
\row
|
||||
\li \l{Using Bazaar}{Bazaar}
|
||||
\li \l{http://bazaar.canonical.com/}
|
||||
\li
|
||||
\row
|
||||
\li \l{Using ClearCase}{ClearCase}
|
||||
\li \l{http://www-01.ibm.com/software/awdtools/clearcase/}
|
||||
\li
|
||||
\row
|
||||
\li \l{Using CVS}{CVS}
|
||||
\li \l{http://www.nongnu.org/cvs/}
|
||||
\li
|
||||
\row
|
||||
\li \l{Using Git}{Git}
|
||||
\li \l{http://git-scm.com/}
|
||||
\li Git version 1.8.0, or later
|
||||
|
||||
Gerrit version 2.6, or later
|
||||
\row
|
||||
\li \l{Using Mercurial}{Mercurial}
|
||||
\li \l{http://mercurial.selenic.com/}
|
||||
\li
|
||||
\row
|
||||
\li \l{Using Perforce}{Perforce}
|
||||
\li \l{http://www.perforce.com}
|
||||
\li Server version 2006.1 and later
|
||||
\row
|
||||
\li \l{Using Subversion}{Subversion}
|
||||
\li \l{http://subversion.apache.org/}
|
||||
\li Subversion version 1.7.0 and later
|
||||
\endtable
|
||||
|
||||
\section1 Setting Up Version Control Systems
|
||||
|
||||
\QC uses the version control system's command line clients to access your
|
||||
repositories. To allow access, make sure that the command line clients can
|
||||
be located using the \c{PATH} environment variable. Alternatively, specify
|
||||
the path to the command line client executable in the \uicontrol Command
|
||||
field in the version control system specific tab in \uicontrol Tools >
|
||||
\uicontrol Options > \uicontrol {Version Control}.
|
||||
|
||||
If authentication is required to access the repository, enter the user
|
||||
credentials in the \uicontrol Username and \uicontrol Password fields.
|
||||
|
||||
Enter a timeout for version control operations in the \uicontrol Timeout
|
||||
field.
|
||||
|
||||
For some version control systems, you can specify the maximum number of
|
||||
lines the log can contain in the \uicontrol {Log count} field.
|
||||
|
||||
After you set up the version control system, use the command line to check
|
||||
that everything works (for example, use the status command). If no issues
|
||||
arise, you should be ready to use the system also from \QC.
|
||||
|
||||
For more information on using msysGit on Windows, see
|
||||
\l {Using msysGit on Windows}.
|
||||
|
||||
\section1 Setting Up General Options
|
||||
|
||||
Select \uicontrol{Tools} > \uicontrol{Options} > \uicontrol{Version Control}
|
||||
> \uicontrol{General}
|
||||
to specify settings for submit messages:
|
||||
|
||||
\list
|
||||
|
||||
\li \uicontrol{Wrap submit messages at} limits the line length of a
|
||||
submit message to the specified number of characters.
|
||||
|
||||
\li \uicontrol{Submit message check script} is a script or program that
|
||||
can be used to perform checks on the submit message before
|
||||
submitting. The submit message is passed in as the script's first
|
||||
parameter. If there is an error, the script should output a
|
||||
message on standard error and return a non-zero exit code.
|
||||
|
||||
\li \uicontrol{User/alias configuration file} is a text file that lists
|
||||
author names in mailmap format. For each author, you must specify a
|
||||
real name and email address and optionally an alias and a second
|
||||
email address. For example:
|
||||
|
||||
\code
|
||||
Jon Doe <Jon.Doe@company.com> jdoe <jdoe@somemail.com>
|
||||
Hans Mustermann <Hans.Mustermann@company.com> hm <info@company.com>
|
||||
\endcode
|
||||
|
||||
After you specify a file in this field, you can select authors
|
||||
as values of the submit message fields in the \uicontrol Nicknames dialog.
|
||||
|
||||
\li \uicontrol{User fields configuration file} is a simple text file
|
||||
consisting of lines specifying submit message fields that take
|
||||
authors as values, for example:
|
||||
|
||||
\code
|
||||
Acked-by:
|
||||
Initial-patch-by:
|
||||
Reported-by:
|
||||
Rubber-stamped-by:
|
||||
Signed-off-by:
|
||||
Tested-by:
|
||||
\endcode
|
||||
|
||||
After you specify a file in this field, you can add authors as
|
||||
values of the submit message fields when submitting changes. If
|
||||
you also specified a \uicontrol{User/alias configuration file}, you can
|
||||
select authors in the \uicontrol Nicknames dialog.
|
||||
|
||||
\li \uicontrol{SSH prompt command} specifies an ssh-askpass command that you
|
||||
can use (on Linux) to prompt the user for a password when using SSH.
|
||||
For example, \c ssh-askpass or \c x11-ssh-askpass, depending on the
|
||||
ssh-askpass implementation that you use.
|
||||
|
||||
\li \uicontrol {Reset VCS Cache} resets the version control system
|
||||
configuration to a state known to \QC after it has been changed
|
||||
from the command line, for example.
|
||||
|
||||
\endlist
|
||||
|
||||
\section1 Creating VCS Repositories for New Projects
|
||||
|
||||
\QC allows you to create repositories for version control systems that
|
||||
support local repository creation, such as Git, Mercurial, or Bazaar.
|
||||
When creating a new project by selecting \uicontrol File > \uicontrol{New File or
|
||||
Project}, you can choose a version control system on the final wizard page.
|
||||
|
||||
You can also select \uicontrol Tools and then select \uicontrol {Create Repository}
|
||||
in the submenu for the version control system.
|
||||
|
||||
To import a project that is under version control, choose \uicontrol {File >
|
||||
New File or Project > Project from Version Control} and select the
|
||||
version control system that you use. Follow the instructions of the
|
||||
wizard to import the project.
|
||||
|
||||
\section1 Using Common Functions
|
||||
|
||||
The \uicontrol{Tools} menu contains a submenu for each supported version
|
||||
control system. This section describes using the functions that are
|
||||
available for all the supported version control systems. For more
|
||||
information about the additional functions and options available for a
|
||||
particular version control system, see the topic dedicated to it.
|
||||
|
||||
The \uicontrol{Version Control} output pane displays the commands that are
|
||||
executed, a timestamp, and the relevant output. Select \uicontrol {Window > Output
|
||||
Panes > Version Control} to open the pane.
|
||||
|
||||
\image qtcreator-vcs-pane.png
|
||||
|
||||
\section2 Adding Files
|
||||
|
||||
When you create a new file or a new project, the wizard displays a page
|
||||
asking whether the files should be added to a version control system.
|
||||
This happens when the parent directory or the project is already
|
||||
under version control and the system supports the concept of adding files,
|
||||
for example, Perforce and Subversion. Alternatively, you can
|
||||
add files later by using the version control tool menus.
|
||||
|
||||
With Git, there is no concept of adding files. Instead, all modified
|
||||
files must be staged for a commit.
|
||||
|
||||
\section2 Viewing Diff Output
|
||||
|
||||
All version control systems provide menu options to \e{diff} the current
|
||||
file or project: to compare it with the latest version stored in the
|
||||
repository and to display the differences. In \QC, a diff is displayed in a
|
||||
read-only editor. If the file is accessible, you can double-click on a
|
||||
selected diff chunk and \QC opens an editor displaying the file, scrolled to
|
||||
the line in question.
|
||||
|
||||
\image qtcreator-vcs-diff.png
|
||||
|
||||
With Git and Subversion, the diff is displayed side-by-side in a \l{Comparing Files}
|
||||
{diff editor} by default. To use the inline diff view instead, select the
|
||||
\uicontrol {Switch to Text Diff Editor} (1) option from the toolbar. In the inline
|
||||
diff view, you can use context menu commands to apply, revert, stage, and
|
||||
unstage hunks, as well as send them to a code pasting service.
|
||||
|
||||
\section2 Viewing Versioning History and Change Details
|
||||
|
||||
Display the versioning history of a file by selecting \uicontrol{Log}
|
||||
or \uicontrol{Filelog}. Typically, the log output contains the date, the commit
|
||||
message, and a change or revision identifier. Click on the identifier to
|
||||
display a description of the change including the diff in the
|
||||
\uicontrol {Git Show} view.
|
||||
|
||||
\image qtcreator-vcs-show.png
|
||||
|
||||
Right-clicking on an identifier brings up a context menu that lets you
|
||||
show annotation views of previous versions (see \l{Annotating Files}).
|
||||
With Git you can also choose to cherry-pick or revert a change.
|
||||
|
||||
\section2 Annotating Files
|
||||
|
||||
Annotation views are obtained by selecting \uicontrol{Annotate} or \uicontrol{Blame}.
|
||||
Selecting \uicontrol{Annotate} or \uicontrol{Blame} displays the lines of the file
|
||||
prepended by the change identifier they originate from. Clicking on the
|
||||
change identifier shows a detailed description of the change.
|
||||
|
||||
To show the annotation of a previous version, right-click on the
|
||||
version identifier at the beginning of a line and choose one of the
|
||||
revisions shown at the bottom of the context menu. This allows you to
|
||||
navigate through the history of the file and obtain previous versions of
|
||||
it. It also works for Git and Mercurial using SHA-1.
|
||||
|
||||
The same context menu is available when right-clicking on a version
|
||||
identifier in the file log view of a single file.
|
||||
|
||||
\section2 Committing Changes
|
||||
|
||||
Once you have finished making changes, submit them to the version control
|
||||
system by choosing \uicontrol{Commit} or \uicontrol{Submit}. \QC displays a
|
||||
commit page containing a text editor where you can enter your commit
|
||||
message and a checkable list of modified files to be included.
|
||||
|
||||
\image qtcreator-vcs-commit.png
|
||||
|
||||
When you have finished filling out the commit page information, click on
|
||||
\uicontrol{Commit} to start committing.
|
||||
|
||||
The \uicontrol{Diff Selected Files} button brings up a diff view of the
|
||||
files selected in the file list. Since the commit page is just another
|
||||
editor, you can go back to it by closing the diff view. You can also switch
|
||||
to an open diff view by selecting it in the \uicontrol{Open Documents} pane in the
|
||||
sidebar.
|
||||
|
||||
\section2 Reverting Changes
|
||||
|
||||
All supported version control systems support reverting your project to
|
||||
known states. This functionality is generally called \e reverting.
|
||||
|
||||
The changes discarded depend on the version control system.
|
||||
|
||||
A version control system can replace the \uicontrol Revert menu option with other
|
||||
options.
|
||||
|
||||
For more information about reverting changes using Git, see
|
||||
\l {Reverting Changes Using Git}.
|
||||
|
||||
\section2 Viewing Status
|
||||
|
||||
You can select \uicontrol{Status} to view the status of the project or
|
||||
repository.
|
||||
|
||||
\section2 Updating the Working Tree
|
||||
|
||||
You can select \uicontrol Update to update your working tree with the latest
|
||||
changes from the branch. Some version control systems allow you to choose
|
||||
between updating the current project and updating all projects.
|
||||
|
||||
With Git, you stash your changes and then pull the changes from the
|
||||
repository.
|
||||
|
||||
\section2 Deleting Files
|
||||
|
||||
You can select \uicontrol Delete to delete obsolete files from the repository.
|
||||
|
||||
With Git, you delete the files from the working tree and then stage the
|
||||
deleted files for a commit.
|
||||
*/
|
||||
@@ -1,4 +1,5 @@
|
||||
import qbs
|
||||
import qbs.FileInfo
|
||||
|
||||
Product {
|
||||
builtByDefault: false
|
||||
@@ -11,6 +12,7 @@ Product {
|
||||
|
||||
Group {
|
||||
name: "main qdocconf file"
|
||||
prefix: product.sourceDirectory + '/'
|
||||
files: [mainDocConfFile]
|
||||
fileTags: ["qdocconf-main"]
|
||||
}
|
||||
|
||||
@@ -50,12 +50,14 @@ QtcProduct {
|
||||
|
||||
Group {
|
||||
name: "PluginMetaData"
|
||||
prefix: product.sourceDirectory + '/'
|
||||
files: [ product.name + ".json.in" ]
|
||||
fileTags: ["pluginJsonIn"]
|
||||
}
|
||||
|
||||
Group {
|
||||
name: "MimeTypes"
|
||||
prefix: product.sourceDirectory + '/'
|
||||
files: [ "*.mimetypes.xml" ]
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,14 @@ Module {
|
||||
id: clangProbe
|
||||
|
||||
property string llvmConfig
|
||||
property string llvmVersion
|
||||
property string llvmIncludeDir
|
||||
property string llvmLibDir
|
||||
property stringList llvmLibs
|
||||
|
||||
configure: {
|
||||
llvmConfig = ClangFunctions.llvmConfig(qbs, QtcFunctions);
|
||||
llvmVersion = ClangFunctions.version(llvmConfig);
|
||||
llvmIncludeDir = ClangFunctions.includeDir(llvmConfig);
|
||||
llvmLibDir = ClangFunctions.libDir(llvmConfig);
|
||||
llvmLibs = ClangFunctions.libraries(qbs.targetOS);
|
||||
@@ -22,6 +24,7 @@ Module {
|
||||
}
|
||||
|
||||
property string llvmConfig: clangProbe.llvmConfig
|
||||
property string llvmVersion: clangProbe.llvmVersion
|
||||
property string llvmIncludeDir: clangProbe.llvmIncludeDir
|
||||
property string llvmLibDir: clangProbe.llvmLibDir
|
||||
property stringList llvmLibs: clangProbe.llvmLibs
|
||||
|
||||
@@ -88,6 +88,7 @@ class Dumper(DumperBase):
|
||||
val.name = nativeValue.name()
|
||||
val.nativeValue = nativeValue
|
||||
val.type = self.fromNativeType(nativeValue.type())
|
||||
val.isBaseClass = val.name == val.type.name
|
||||
val.lIsInScope = True
|
||||
val.laddress = nativeValue.address()
|
||||
return val
|
||||
@@ -114,14 +115,11 @@ class Dumper(DumperBase):
|
||||
nativeType = FakeVoidType(nativeType.name(), self)
|
||||
|
||||
if code == TypeCodePointer:
|
||||
targetType = self.fromNativeType(nativeType.target().unqualified())
|
||||
return self.createPointerType(targetType)
|
||||
return self.createPointerType(self.fromNativeType(nativeType.target()))
|
||||
|
||||
if code == TypeCodeArray:
|
||||
nativeTargetType = nativeType.target().unqualified()
|
||||
targetType = self.fromNativeType(nativeTargetType)
|
||||
count = nativeType.bitsize() // nativeTargetType.bitsize()
|
||||
return self.createArrayType(targetType, count)
|
||||
targetType = self.fromNativeType(nativeType.target())
|
||||
return self.createArrayType(targetType, nativeType.arrayElements())
|
||||
|
||||
typeId = self.nativeTypeId(nativeType)
|
||||
if self.typeData.get(typeId, None) is None:
|
||||
@@ -243,7 +241,10 @@ class Dumper(DumperBase):
|
||||
self.report('result={%s}' % (result))
|
||||
|
||||
def readRawMemory(self, address, size):
|
||||
return cdbext.readRawMemory(address, size)
|
||||
mem = cdbext.readRawMemory(address, size)
|
||||
if len(mem) != size:
|
||||
raise Exception("Invalid memory request")
|
||||
return mem
|
||||
|
||||
def findStaticMetaObject(self, typeName):
|
||||
ptr = self.findValueByExpression('&' + typeName + '::staticMetaObject')
|
||||
|
||||
@@ -214,41 +214,6 @@ class Children:
|
||||
self.d.put(self.d.childrenSuffix)
|
||||
return True
|
||||
|
||||
class PairedChildrenData:
|
||||
def __init__(self, d, pairType, keyType, valueType):
|
||||
self.pairType = pairType
|
||||
self.keyType = keyType
|
||||
self.valueType = valueType
|
||||
|
||||
class PairedChildren(Children):
|
||||
def __init__(self, d, numChild, useKeyAndValue = False,
|
||||
pairType = None, keyType = None, valueType = None, maxNumChild = None):
|
||||
self.d = d
|
||||
if pairType is not None:
|
||||
try:
|
||||
pairType = pairType.stripTypedefs()
|
||||
except:
|
||||
pass
|
||||
if keyType is None:
|
||||
keyType = pairType[0].unqualified()
|
||||
if valueType is None:
|
||||
valueType = pairType[1]
|
||||
d.pairData = PairedChildrenData(d, pairType, keyType, valueType)
|
||||
d.pairData.kname = 'key' if useKeyAndValue else 'first'
|
||||
d.pairData.vname = 'value' if useKeyAndValue else 'second'
|
||||
|
||||
Children.__init__(self, d, numChild,
|
||||
maxNumChild = maxNumChild,
|
||||
addrBase = None, addrStep = None)
|
||||
|
||||
def __enter__(self):
|
||||
self.savedPairData = self.d.pairData if hasattr(self.d, 'pairData') else None
|
||||
Children.__enter__(self)
|
||||
|
||||
def __exit__(self, exType, exValue, exTraceBack):
|
||||
Children.__exit__(self, exType, exValue, exTraceBack)
|
||||
self.d.pairData = self.savedPairData if self.savedPairData else None
|
||||
|
||||
|
||||
class SubItem:
|
||||
def __init__(self, d, component):
|
||||
@@ -809,18 +774,21 @@ class DumperBase:
|
||||
self.putType('bool')
|
||||
self.putNumChild(0)
|
||||
|
||||
def putPairItem(self, index, pair):
|
||||
(first, second) = pair if isinstance(pair, tuple) else pair.members(False)
|
||||
def putPairItem(self, index, pair, keyName='first', valueName='second'):
|
||||
with SubItem(self, index):
|
||||
with Children(self):
|
||||
key = self.putSubItem(self.pairData.kname, first)
|
||||
value = self.putSubItem(self.pairData.vname, second)
|
||||
if index is not None:
|
||||
self.putField('keyprefix', '[%s] ' % index)
|
||||
self.putField('key', key.value)
|
||||
if key.encoding is not None:
|
||||
self.putField('keyencoded', key.encoding)
|
||||
self.putValue(value.value, value.encoding)
|
||||
self.putPairContents(index, pair, keyName, valueName)
|
||||
|
||||
def putPairContents(self, index, pair, kname, vname):
|
||||
with Children(self):
|
||||
first, second = pair if isinstance(pair, tuple) else pair.members(False)
|
||||
key = self.putSubItem(kname, first)
|
||||
value = self.putSubItem(vname, second)
|
||||
if index is not None:
|
||||
self.putField('keyprefix', '[%s] ' % index)
|
||||
self.putField('key', key.value)
|
||||
if key.encoding is not None:
|
||||
self.putField('keyencoded', key.encoding)
|
||||
self.putValue(value.value, value.encoding)
|
||||
|
||||
def putCallItem(self, name, rettype, value, func, *args):
|
||||
with SubItem(self, name):
|
||||
@@ -3647,6 +3615,8 @@ class DumperBase:
|
||||
if tn in ('QByteArray', 'QString', 'QList', 'QStringList',
|
||||
'QStringDataPtr'):
|
||||
return self.ptrSize()
|
||||
if tn == 'QStandardItemData':
|
||||
return 8 + 2 * self.ptrSize()
|
||||
if tn in ('QImage', 'QObject'):
|
||||
return 2 * self.ptrSize()
|
||||
if tn == 'QVariant':
|
||||
@@ -3655,6 +3625,8 @@ class DumperBase:
|
||||
return 16
|
||||
if typish == 'QPoint':
|
||||
return 8
|
||||
if typish == 'Qt::ItemDataRole':
|
||||
return 4
|
||||
if typish == 'QChar':
|
||||
return 2
|
||||
if typish in ('quint32', 'qint32'):
|
||||
@@ -3755,7 +3727,7 @@ class DumperBase:
|
||||
if self.autoPadNext:
|
||||
self.currentBitsize = 8 * ((self.currentBitsize + 7) >> 3) # Fill up byte.
|
||||
padding = (fieldAlign - (self.currentBitsize >> 3)) % fieldAlign
|
||||
warn('AUTO PADDING AT %s BITS BY %s BYTES' % (self.currentBitsize, padding))
|
||||
#warn('AUTO PADDING AT %s BITS BY %s BYTES' % (self.currentBitsize, padding))
|
||||
field = self.dumper.Field(self.dumper)
|
||||
field.code = None
|
||||
#field.lbitpos = self.currentBitsize
|
||||
|
||||
@@ -1026,6 +1026,9 @@ class Dumper(DumperBase):
|
||||
if symbol:
|
||||
ns = symbol.name[:-len(cand)]
|
||||
except:
|
||||
symbol = None
|
||||
|
||||
if symbol is None:
|
||||
try:
|
||||
# Some GDB 7.11.1 on Arch Linux.
|
||||
cand = 'QArrayData::shared_null[0]'
|
||||
|
||||
@@ -264,28 +264,27 @@ class Dumper(DumperBase):
|
||||
field.lbitsize = nativeFieldType.GetByteSize() * 8
|
||||
isBitfield = False
|
||||
|
||||
if isBitfield:
|
||||
if isBitfield: # Bit fields
|
||||
field.ltype = self.createBitfieldType(self.typeName(nativeFieldType), field.lbitsize)
|
||||
else:
|
||||
yield field
|
||||
|
||||
elif field.name is None: # Anon members
|
||||
fakeMember = fakeValue.GetChildAtIndex(i)
|
||||
#try:
|
||||
fakeMemberAddress = fakeMember.GetLoadAddress()
|
||||
#except:
|
||||
# # Happens in the BoostList dumper for a 'const bool'
|
||||
# # item named 'constant_time_size'. There isn't anything we can do
|
||||
# # in this case.
|
||||
# continue
|
||||
|
||||
offset = fakeMemberAddress - fakeAddress
|
||||
|
||||
field.lbitpos = 8 * offset
|
||||
field.ltype = self.fromNativeType(nativeFieldType)
|
||||
yield field
|
||||
|
||||
if field.name in baseNames:
|
||||
field.isBaseClass = True
|
||||
field.baseIndex = baseNames[field.name]
|
||||
elif field.name in baseNames: # Simple bases
|
||||
member = self.fromNativeValue(fakeValue.GetChildAtIndex(i))
|
||||
member.isBaseClass = True
|
||||
yield member
|
||||
|
||||
yield field
|
||||
else: # Normal named members
|
||||
member = self.fromNativeValue(fakeValue.GetChildAtIndex(i))
|
||||
member.name = nativeField.GetName()
|
||||
yield member
|
||||
|
||||
# Empty bases are not covered above.
|
||||
for i in range(nativeType.GetNumberOfDirectBaseClasses()):
|
||||
@@ -298,8 +297,23 @@ class Dumper(DumperBase):
|
||||
member.type = self.fromNativeType(fieldType)
|
||||
member.name = fieldName
|
||||
member.fields = []
|
||||
member.ldata = bytes()
|
||||
member.lbitsize = fieldType.GetByteSize() * 8
|
||||
if False:
|
||||
# This would be correct if we came here only for
|
||||
# truly empty base classes. Alas, we don't, see below.
|
||||
member.ldata = bytes()
|
||||
member.lbitsize = fieldType.GetByteSize() * 8
|
||||
else:
|
||||
# This is a hack. LLDB 3.8 reports declared but not defined
|
||||
# types as having no fields and(!) size == 1. At least
|
||||
# for the common case of a single base class we can
|
||||
# fake the contents by using the whole derived object's
|
||||
# data as base class data.
|
||||
data = fakeValue.GetData()
|
||||
size = nativeType.GetByteSize()
|
||||
member.lbitsize = size * 8
|
||||
error = lldb.SBError()
|
||||
member.laddress = value.laddress
|
||||
member.ldata = data.ReadRawData(error, 0, size)
|
||||
member.isBaseClass = True
|
||||
member.ltype = self.fromNativeType(fieldType)
|
||||
member.name = fieldName
|
||||
|
||||
@@ -190,6 +190,21 @@ def qdump_X_QModelIndex(d, value):
|
||||
d.putCallItem('parent', '@QModelIndex', value, 'parent')
|
||||
#gdb.execute('call free($mi)')
|
||||
|
||||
def qdump__QStandardItemData(d, value):
|
||||
role, pad, val = value.split('{@Qt::ItemDataRole}@{QVariant}')
|
||||
d.putPairContents(role.value(), (role, val), 'role', 'value')
|
||||
|
||||
def qdump__QStandardItem(d, value):
|
||||
vtable, dptr = value.split('pp')
|
||||
vtable1, model, parent, values, children, rows, cols, item = d.split('pppPPIIp', dptr)
|
||||
d.putValue(' ')
|
||||
d.putNumChild(1)
|
||||
if d.isExpanded():
|
||||
with Children(d):
|
||||
d.putSubItem('[model]', d.createValue(model, '@QStandardItemModel'))
|
||||
d.putSubItem('[values]', d.createVectorItem(values, 'QStandardItemData'))
|
||||
d.putSubItem('[children]', d.createVectorItem(children, '@QStandardItem*'))
|
||||
|
||||
|
||||
def qdump__QDate(d, value):
|
||||
jd = value.pointer()
|
||||
@@ -638,7 +653,7 @@ def qdumpHelper_QHash(d, value, keyType, valueType):
|
||||
d.putItemCount(size)
|
||||
if d.isExpanded():
|
||||
isShort = d.qtVersion() < 0x050000 and keyType.name == 'int'
|
||||
with PairedChildren(d, size, keyType=keyType, valueType=valueType, useKeyAndValue=True):
|
||||
with Children(d, size):
|
||||
node = hashDataFirstNode()
|
||||
for i in d.childRange():
|
||||
if isShort:
|
||||
@@ -647,7 +662,7 @@ def qdumpHelper_QHash(d, value, keyType, valueType):
|
||||
else:
|
||||
typeCode = 'Pi@{%s}@{%s}' % (keyType.name, valueType.name)
|
||||
(pnext, hashval, padding1, key, padding2, val) = d.split(typeCode, node)
|
||||
d.putPairItem(i, (key, val))
|
||||
d.putPairItem(i, (key, val), 'key', 'value')
|
||||
node = hashDataNextNode(node)
|
||||
|
||||
|
||||
@@ -937,10 +952,10 @@ def qdumpHelper_Qt4_QMap(d, value, keyType, valueType):
|
||||
typeCode = '{%s}@{%s}' % (keyType.name, valueType.name)
|
||||
pp, payloadSize, fields = d.describeStruct(typeCode)
|
||||
|
||||
with PairedChildren(d, n, useKeyAndValue=True, keyType=keyType, valueType=valueType):
|
||||
with Children(d, n):
|
||||
for i in d.childRange():
|
||||
key, pad, value = d.split(typeCode, it - payloadSize)
|
||||
d.putPairItem(i, (key, value))
|
||||
d.putPairItem(i, (key, value), 'key', 'value')
|
||||
dummy, it = d.split('Pp', it)
|
||||
|
||||
|
||||
@@ -967,9 +982,9 @@ def qdumpHelper_Qt5_QMap(d, value, keyType, valueType):
|
||||
for res in helper(right):
|
||||
yield res
|
||||
|
||||
with PairedChildren(d, n, keyType=keyType, valueType=valueType, useKeyAndValue=True):
|
||||
with Children(d, n):
|
||||
for (pair, i) in zip(helper(dptr + 8), range(n)):
|
||||
d.putPairItem(i, pair)
|
||||
d.putPairItem(i, pair, 'key', 'value')
|
||||
|
||||
|
||||
def qform__QMap():
|
||||
@@ -1062,7 +1077,11 @@ def qdump__QRegExp(d, value):
|
||||
d.putNumChild(1)
|
||||
if d.isExpanded():
|
||||
with Children(d):
|
||||
d.call('void', value, 'capturedTexts') # Warm up internal cache.
|
||||
try:
|
||||
d.call('void', value, 'capturedTexts') # Warm up internal cache.
|
||||
except:
|
||||
# Might fail (LLDB, Core files, ...), still cache might be warm.
|
||||
pass
|
||||
(patternSyntax, caseSensitive, minimal, pad, t, captures) \
|
||||
= d.split('{int}{int}B@{QString}{QStringList}', privAddress + 2 * d.ptrSize())
|
||||
d.putSubItem('syntax', patternSyntax.cast(d.qtNamespace() + 'QRegExp::PatternSyntax'))
|
||||
@@ -1228,14 +1247,6 @@ def qdump__QGraphicsPolygonItem(d, value):
|
||||
d.putItemCount(size)
|
||||
d.putPlotData(data, size, d.createType('QPointF'))
|
||||
|
||||
def qdump__QStandardItem(d, value):
|
||||
d.putBetterType(d.currentType)
|
||||
try:
|
||||
d.putItem(value['d_ptr'])
|
||||
except:
|
||||
d.putPlainChildren(value)
|
||||
|
||||
|
||||
def qedit__QString(d, value, data):
|
||||
d.call('void', value, 'resize', str(len(data)))
|
||||
(base, size, alloc) = d.stringData(value)
|
||||
|
||||
@@ -56,9 +56,12 @@ def qdump__std____1__complex(d, value):
|
||||
|
||||
|
||||
def qdump__std__deque(d, value):
|
||||
if d.isQnxTarget() or d.isMsvcTarget():
|
||||
if d.isQnxTarget():
|
||||
qdump__std__deque__QNX(d, value)
|
||||
return
|
||||
if d.isMsvcTarget():
|
||||
qdump__std__deque__MSVC(d, value)
|
||||
return
|
||||
|
||||
innerType = value.type[0]
|
||||
innerSize = innerType.size()
|
||||
@@ -141,6 +144,34 @@ def qdump__std__deque__QNX(d, value):
|
||||
d.putSubItem(i, map[block][offset])
|
||||
myoff += 1;
|
||||
|
||||
def qdump__std__deque__MSVC(d, value):
|
||||
innerType = value.type[0]
|
||||
innerSize = innerType.size()
|
||||
if innerSize <= 1:
|
||||
bufsize = 16
|
||||
elif innerSize <= 2:
|
||||
bufsize = 8
|
||||
elif innerSize <= 4:
|
||||
bufsize = 4
|
||||
elif innerSize <= 8:
|
||||
bufsize = 2
|
||||
else:
|
||||
bufsize = 1
|
||||
|
||||
(proxy, map, mapsize, myoff, mysize) = value.split("ppppp")
|
||||
|
||||
d.check(0 <= mapsize and mapsize <= 1000 * 1000 * 1000)
|
||||
d.putItemCount(mysize)
|
||||
if d.isExpanded():
|
||||
with Children(d, mysize, maxNumChild=2000, childType=innerType):
|
||||
for i in d.childRange():
|
||||
if myoff >= bufsize * mapsize:
|
||||
myoff = 0
|
||||
buf = map + ((myoff // bufsize) * d.ptrSize())
|
||||
address = d.extractPointer(buf) + ((myoff % bufsize) * innerSize)
|
||||
d.putSubItem(i, d.createValue(address, innerType))
|
||||
myoff += 1
|
||||
|
||||
def qdump__std____debug__deque(d, value):
|
||||
qdump__std__deque(d, value)
|
||||
|
||||
@@ -238,11 +269,12 @@ def qdump__std__map(d, value):
|
||||
d.putItemCount(size)
|
||||
|
||||
if d.isExpanded():
|
||||
pairType = value.type[3][0]
|
||||
with PairedChildren(d, size, pairType=pairType, maxNumChild=1000):
|
||||
keyType = value.type[0]
|
||||
valueType = value.type[1]
|
||||
with Children(d, size, maxNumChild=1000):
|
||||
node = value["_M_t"]["_M_impl"]["_M_header"]["_M_left"]
|
||||
nodeSize = node.dereference().type.size()
|
||||
typeCode = "@{%s}@{%s}" % (pairType[0].name, pairType[1].name)
|
||||
typeCode = "@{%s}@{%s}" % (keyType.name, valueType.name)
|
||||
for i in d.childRange():
|
||||
(pad1, key, pad2, value) = d.split(typeCode, node.pointer() + nodeSize)
|
||||
d.putPairItem(i, (key, value))
|
||||
@@ -267,8 +299,7 @@ def qdump_std__map__helper(d, size, value):
|
||||
head = value['_Myhead']
|
||||
node = head['_Left']
|
||||
nodeType = head.type
|
||||
pairType = head.type[0]
|
||||
with PairedChildren(d, size, pairType=pairType, maxNumChild=1000):
|
||||
with Children(d, size, maxNumChild=1000):
|
||||
for i in d.childRange():
|
||||
pair = node.cast(nodeType).dereference()['_Myval']
|
||||
d.putPairItem(i, pair)
|
||||
@@ -483,10 +514,8 @@ def qdump__std____1__map(d, value):
|
||||
valueType = value.type[0]
|
||||
node = tree["__begin_node_"]
|
||||
nodeType = node.type
|
||||
pairType = value.type[3][0]
|
||||
with PairedChildren(d, size, pairType=pairType, maxNumChild=1000):
|
||||
with Children(d, size, maxNumChild=1000):
|
||||
node = tree["__begin_node_"]
|
||||
nodeType = node.type
|
||||
for i in d.childRange():
|
||||
# There's possibly also:
|
||||
#pair = node['__value_']['__nc']
|
||||
@@ -690,11 +719,6 @@ def qform__std____debug__unordered_map():
|
||||
return mapForms()
|
||||
|
||||
def qdump__std__unordered_map(d, value):
|
||||
keyType = value.type[0]
|
||||
valueType = value.type[1]
|
||||
allocatorType = value.type[4]
|
||||
pairType = allocatorType[0]
|
||||
ptrSize = d.ptrSize()
|
||||
try:
|
||||
# gcc ~= 4.7
|
||||
size = value["_M_element_count"].integer()
|
||||
@@ -721,11 +745,14 @@ def qdump__std__unordered_map(d, value):
|
||||
|
||||
d.putItemCount(size)
|
||||
if d.isExpanded():
|
||||
keyType = value.type[0]
|
||||
valueType = value.type[1]
|
||||
typeCode = 'p@{%s}@{%s}' % (value.type[0].name, value.type[1].name)
|
||||
p = start.pointer()
|
||||
with PairedChildren(d, size, keyType=keyType, valueType=valueType):
|
||||
with Children(d, size):
|
||||
for i in d.childRange():
|
||||
d.putPairItem(i, d.createValue(p + ptrSize, pairType))
|
||||
p = d.extractPointer(p)
|
||||
p, pad, key, pad, val = d.split(typeCode, p)
|
||||
d.putPairItem(i, (key, val))
|
||||
|
||||
def qdump__std____debug__unordered_map(d, value):
|
||||
qdump__std__unordered_map(d, value)
|
||||
@@ -779,7 +806,7 @@ def qdump__std____1__unordered_map(d, value):
|
||||
return val
|
||||
|
||||
node = value["__table_"]["__p1_"]["__first_"]["__next_"]
|
||||
with PairedChildren(d, size, pairType=valueCCorNot(node["__value_"]).type):
|
||||
with Children(d, size):
|
||||
for i in d.childRange():
|
||||
d.putPairItem(i, valueCCorNot(node["__value_"]))
|
||||
node = node["__next_"]
|
||||
|
||||
@@ -82,13 +82,15 @@
|
||||
#include <QAbstractAnimation>
|
||||
#include <QMutableVectorIterator>
|
||||
#include <QQuickView>
|
||||
|
||||
#include <QSet>
|
||||
#include <designersupportdelegate.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
bool testImportStatements(const QStringList &importStatementList, const QUrl &url, QString *errorMessage = 0) {
|
||||
if (importStatementList.isEmpty())
|
||||
return false;
|
||||
// ToDo: move engine outside of this function, this makes it expensive
|
||||
QQmlEngine engine;
|
||||
QQmlComponent testImportComponent(&engine);
|
||||
@@ -110,6 +112,14 @@ bool testImportStatements(const QStringList &importStatementList, const QUrl &ur
|
||||
|
||||
void sortFilterImports(const QStringList &imports, QStringList *workingImports, QStringList *failedImports, const QUrl &url, QString *errorMessage)
|
||||
{
|
||||
static QSet<QString> visited;
|
||||
QString visitCheckId("imports: %1, workingImports: %2, failedImports: %3");
|
||||
visitCheckId = visitCheckId.arg(imports.join(""), workingImports->join(""), failedImports->join(""));
|
||||
if (visited.contains(visitCheckId))
|
||||
return;
|
||||
else
|
||||
visited.insert(visitCheckId);
|
||||
|
||||
for (const QString &import : imports) {
|
||||
const QStringList alreadyTestedImports = *workingImports + *failedImports;
|
||||
if (!alreadyTestedImports.contains(import)) {
|
||||
@@ -429,6 +439,8 @@ void NodeInstanceServer::setupImports(const QVector<AddImportContainer> &contain
|
||||
{
|
||||
Q_ASSERT(quickView());
|
||||
QSet<QString> importStatementSet;
|
||||
QString qtQuickImport;
|
||||
|
||||
foreach (const AddImportContainer &container, containerVector) {
|
||||
QString importStatement = QString("import ");
|
||||
|
||||
@@ -443,27 +455,36 @@ void NodeInstanceServer::setupImports(const QVector<AddImportContainer> &contain
|
||||
if (!container.alias().isEmpty())
|
||||
importStatement += " as " + container.alias();
|
||||
|
||||
importStatementSet.insert(importStatement);
|
||||
if (importStatement.startsWith(QLatin1String("import QtQuick") + QChar(QChar::Space)))
|
||||
qtQuickImport = importStatement;
|
||||
else
|
||||
importStatementSet.insert(importStatement);
|
||||
}
|
||||
|
||||
delete m_importComponent.data();
|
||||
delete m_importComponentObject.data();
|
||||
QStringList importStatementList(importStatementSet.toList());
|
||||
QStringList workingImportStatementList;
|
||||
const QStringList importStatementList(importStatementSet.toList());
|
||||
const QStringList fullImportStatementList(QStringList(qtQuickImport) + importStatementList);
|
||||
|
||||
// check possible import statements combinations
|
||||
// but first try the current order -> maybe it just works
|
||||
if (testImportStatements(importStatementList, fileUrl())) {
|
||||
workingImportStatementList = importStatementList;
|
||||
if (testImportStatements(fullImportStatementList, fileUrl())) {
|
||||
setupOnlyWorkingImports(fullImportStatementList);
|
||||
} else {
|
||||
QString errorMessage;
|
||||
QStringList failedImportList;
|
||||
sortFilterImports(importStatementList, &workingImportStatementList, &failedImportList, fileUrl(), &errorMessage);
|
||||
|
||||
if (!testImportStatements(QStringList(qtQuickImport), fileUrl(), &errorMessage))
|
||||
qtQuickImport = "import QtQuick 2.0";
|
||||
if (testImportStatements(QStringList(qtQuickImport), fileUrl(), &errorMessage)) {
|
||||
QStringList workingImportStatementList;
|
||||
QStringList failedImportList;
|
||||
sortFilterImports(QStringList(qtQuickImport) + importStatementList, &workingImportStatementList,
|
||||
&failedImportList, fileUrl(), &errorMessage);
|
||||
setupOnlyWorkingImports(workingImportStatementList);
|
||||
}
|
||||
if (!errorMessage.isEmpty())
|
||||
sendDebugOutput(DebugOutputCommand::WarningType, errorMessage);
|
||||
}
|
||||
|
||||
setupOnlyWorkingImports(workingImportStatementList);
|
||||
}
|
||||
|
||||
void NodeInstanceServer::setupOnlyWorkingImports(const QStringList &workingImportStatementList)
|
||||
@@ -477,14 +498,6 @@ void NodeInstanceServer::setupOnlyWorkingImports(const QStringList &workingImpor
|
||||
m_importComponent->setData(componentCode.append("\nItem {}\n"), fileUrl());
|
||||
m_importComponentObject = m_importComponent->create();
|
||||
|
||||
if (!m_importComponentObject) {
|
||||
delete m_importComponent;
|
||||
m_importComponent = new QQmlComponent(engine(), quickView());
|
||||
m_importComponent->setData("import QtQuick 2.0\n\nItem {}\n", fileUrl());
|
||||
sendDebugOutput(DebugOutputCommand::WarningType, tr("No working QtQuick import"));
|
||||
m_importComponentObject = m_importComponent->create();
|
||||
}
|
||||
|
||||
Q_ASSERT(m_importComponent && m_importComponentObject);
|
||||
Q_ASSERT_X(m_importComponent->errors().isEmpty(), __FUNCTION__, m_importComponent->errorString().toLatin1());
|
||||
}
|
||||
|
||||
@@ -51,6 +51,21 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
FileContainer(const Utf8String &filePath,
|
||||
const Utf8String &projectPartId,
|
||||
const Utf8StringVector &fileArguments,
|
||||
const Utf8String &unsavedFileContent = Utf8String(),
|
||||
bool hasUnsavedFileContent = false,
|
||||
quint32 documentRevision = 0)
|
||||
: filePath_(filePath),
|
||||
projectPartId_(projectPartId),
|
||||
fileArguments_(fileArguments),
|
||||
unsavedFileContent_(unsavedFileContent),
|
||||
documentRevision_(documentRevision),
|
||||
hasUnsavedFileContent_(hasUnsavedFileContent)
|
||||
{
|
||||
}
|
||||
|
||||
FileContainer(const Utf8String &filePath,
|
||||
const Utf8String &projectPartId,
|
||||
const Utf8StringVector &fileArguments,
|
||||
|
||||
@@ -367,7 +367,6 @@ static ModuleApiInfo findBestModuleApi(const QList<ModuleApiInfo> &apis, const C
|
||||
/*
|
||||
import Qt 4.6
|
||||
import Qt 4.6 as Xxx
|
||||
(import com.nokia.qt is the same as the ones above)
|
||||
*/
|
||||
Import LinkPrivate::importNonFile(Document::Ptr doc, const ImportInfo &importInfo)
|
||||
{
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "pycdbextmodule.h"
|
||||
|
||||
#include "extensioncontext.h"
|
||||
#include "symbolgroup.h"
|
||||
#include "symbolgroupvalue.h"
|
||||
|
||||
#include "pyfield.h"
|
||||
@@ -61,31 +60,22 @@ static PyObject *cdbext_lookupType(PyObject *, PyObject *args) // -> Type
|
||||
|
||||
static PyObject *cdbext_listOfLocals(PyObject *, PyObject *) // -> [ Value ]
|
||||
{
|
||||
ExtensionCommandContext *extCmdCtx = ExtensionCommandContext::instance();
|
||||
ULONG frame;
|
||||
if (FAILED(extCmdCtx->symbols()->GetCurrentScopeFrameIndex(&frame)))
|
||||
Py_RETURN_NONE;
|
||||
|
||||
std::string errorMessage;
|
||||
LocalsSymbolGroup *sg = ExtensionContext::instance().symbolGroup(
|
||||
extCmdCtx->symbols(), extCmdCtx->threadId(), int(frame), &errorMessage);
|
||||
if (!sg)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
const auto children = sg->root()->children();
|
||||
auto locals = PyList_New(0);
|
||||
for (AbstractSymbolGroupNode *abstractChild : children) {
|
||||
if (SymbolGroupNode* child = abstractChild->asSymbolGroupNode())
|
||||
PyList_Append(locals, createValue(child->index(), sg->debugSymbolGroup()));
|
||||
}
|
||||
|
||||
IDebugSymbolGroup2 *sg;
|
||||
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
|
||||
if (FAILED(symbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_ALL, NULL, &sg)))
|
||||
return locals;
|
||||
ULONG symbolCount;
|
||||
if (FAILED(sg->GetNumberSymbols(&symbolCount)))
|
||||
return locals;
|
||||
for (ULONG index = 0; index < symbolCount; ++index)
|
||||
PyList_Append(locals, createValue(index, sg));
|
||||
return locals;
|
||||
}
|
||||
|
||||
static PyObject *cdbext_pointerSize(PyObject *, PyObject *)
|
||||
{
|
||||
HRESULT isPointer64Bit = ExtensionCommandContext::instance()->control()->IsPointer64Bit();
|
||||
return Py_BuildValue("i", isPointer64Bit == S_OK ? 8 : 4);
|
||||
return Py_BuildValue("i", pointerSize());
|
||||
}
|
||||
|
||||
static PyObject *cdbext_readRawMemory(PyObject *, PyObject *args)
|
||||
@@ -95,6 +85,9 @@ static PyObject *cdbext_readRawMemory(PyObject *, PyObject *args)
|
||||
if (!PyArg_ParseTuple(args, "Kk", &address, &size))
|
||||
Py_RETURN_NONE;
|
||||
|
||||
if (debugPyCdbextModule)
|
||||
DebugPrint() << "Read raw memory: " << size << "bytes from " << std::hex << std::showbase << address;
|
||||
|
||||
char *buffer = new char[size];
|
||||
|
||||
CIDebugDataSpaces *data = ExtensionCommandContext::instance()->dataSpaces();
|
||||
@@ -119,43 +112,16 @@ static PyObject *cdbext_createValue(PyObject *, PyObject *args)
|
||||
<< " type name: " << getTypeName(type->m_module, type->m_typeId);
|
||||
}
|
||||
|
||||
ExtensionCommandContext *extCmdCtx = ExtensionCommandContext::instance();
|
||||
CIDebugSymbols *symbols = extCmdCtx->symbols();
|
||||
|
||||
ULONG frame;
|
||||
if (FAILED(symbols->GetCurrentScopeFrameIndex(&frame)))
|
||||
IDebugSymbolGroup2 *symbol;
|
||||
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
|
||||
if (FAILED(symbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_ALL, NULL, &symbol)))
|
||||
Py_RETURN_NONE;
|
||||
|
||||
std::string errorMessage;
|
||||
LocalsSymbolGroup *lsg = ExtensionContext::instance().symbolGroup(
|
||||
symbols, extCmdCtx->threadId(), int(frame), &errorMessage);
|
||||
if (!lsg)
|
||||
ULONG index = DEBUG_ANY_ID;
|
||||
const std::string name = SymbolGroupValue::pointedToSymbolName(
|
||||
address, getTypeName(type->m_module, type->m_typeId));
|
||||
if (FAILED(symbol->AddSymbol(name.c_str(), &index)))
|
||||
Py_RETURN_NONE;
|
||||
|
||||
CIDebugSymbolGroup *dsg = lsg->debugSymbolGroup();
|
||||
ULONG numberOfSymbols = 0;
|
||||
dsg->GetNumberSymbols(&numberOfSymbols);
|
||||
ULONG index = 0;
|
||||
for (;index < numberOfSymbols; ++index) {
|
||||
ULONG64 offset;
|
||||
dsg->GetSymbolOffset(index, &offset);
|
||||
if (offset == address) {
|
||||
DEBUG_SYMBOL_PARAMETERS params;
|
||||
if (SUCCEEDED(dsg->GetSymbolParameters(index, 1, ¶ms))) {
|
||||
if (params.TypeId == type->m_typeId && params.Module == type->m_module)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= numberOfSymbols) {
|
||||
index = DEBUG_ANY_ID;
|
||||
const std::string name = SymbolGroupValue::pointedToSymbolName(
|
||||
address, getTypeName(type->m_module, type->m_typeId));
|
||||
if (FAILED(dsg->AddSymbol(name.c_str(), &index)))
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
return createValue(index, dsg);
|
||||
return createValue(index, symbol);
|
||||
}
|
||||
|
||||
static PyMethodDef cdbextMethods[] = {
|
||||
@@ -233,3 +199,8 @@ PyObject *pyBool(bool b)
|
||||
else
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
int pointerSize()
|
||||
{
|
||||
return ExtensionCommandContext::instance()->control()->IsPointer64Bit() == S_OK ? 8 : 4;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
void initCdbextPythonModule();
|
||||
|
||||
PyObject *pyBool(bool);
|
||||
int pointerSize();
|
||||
|
||||
constexpr bool debugPyCdbextModule = false;
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#include "stringutils.h"
|
||||
#include "symbolgroupvalue.h"
|
||||
|
||||
constexpr bool debugPyType = false;
|
||||
constexpr bool debuggingEnabled() { return debugPyType || debugPyCdbextModule; }
|
||||
constexpr bool debugPyType = true;
|
||||
constexpr bool debuggingTypeEnabled() { return debugPyType || debugPyCdbextModule; }
|
||||
|
||||
enum TypeCodes {
|
||||
TypeCodeTypedef,
|
||||
@@ -53,39 +53,102 @@ enum TypeCodes {
|
||||
TypeCodeUnresolvable
|
||||
};
|
||||
|
||||
bool isArrayPointerAtPosition(const std::string &typeName, size_t position)
|
||||
{
|
||||
if (typeName.length() < position + 3)
|
||||
return false;
|
||||
return typeName.at(position) == '('
|
||||
&& typeName.at(position + 1) == '*'
|
||||
&& typeName.at(position + 2) == ')';
|
||||
}
|
||||
|
||||
bool isPointerType(const std::string &typeName)
|
||||
{
|
||||
if (typeName.empty())
|
||||
return false;
|
||||
if (endsWith(typeName, '*'))
|
||||
return true;
|
||||
|
||||
// check for types like "int (*)[3]" which is a pointer to an integer array with 3 elements
|
||||
const auto arrayPosition = typeName.find_first_of('[');
|
||||
return arrayPosition != std::string::npos
|
||||
&& arrayPosition >= 3 && isArrayPointerAtPosition(typeName, arrayPosition - 3);
|
||||
}
|
||||
|
||||
bool isArrayType(const std::string &typeName)
|
||||
{
|
||||
if (!endsWith(typeName, ']'))
|
||||
return false;
|
||||
// check for types like "int ( *)[3]" which is a pointer to an integer array with 3 elements
|
||||
const auto arrayPosition = typeName.find_first_of('[');
|
||||
return arrayPosition == std::string::npos
|
||||
|| arrayPosition < 3 || !isArrayPointerAtPosition(typeName, arrayPosition - 3);
|
||||
}
|
||||
|
||||
std::string &stripPointerType(std::string &typeName)
|
||||
{
|
||||
if (endsWith(typeName, '*')) {
|
||||
typeName.pop_back();
|
||||
} else {
|
||||
const auto arrayPosition = typeName.find_first_of('[');
|
||||
if (arrayPosition != std::string::npos
|
||||
&& arrayPosition >= 3 && isArrayPointerAtPosition(typeName, arrayPosition - 3)) {
|
||||
typeName.erase(arrayPosition - 3, 3);
|
||||
}
|
||||
}
|
||||
trimBack(typeName);
|
||||
return typeName;
|
||||
}
|
||||
|
||||
ULONG extractArrrayCount(const std::string &typeName, size_t openArrayPos = 0)
|
||||
{
|
||||
if (openArrayPos == 0)
|
||||
openArrayPos = typeName.find_last_of('[');
|
||||
const auto closeArrayPos = typeName.find_last_of(']');
|
||||
if (openArrayPos == std::string::npos || closeArrayPos == std::string::npos)
|
||||
return 0;
|
||||
const std::string arrayCountString = typeName.substr(openArrayPos + 1,
|
||||
closeArrayPos - openArrayPos - 1);
|
||||
try {
|
||||
return std::stoul(arrayCountString);
|
||||
}
|
||||
catch (const std::invalid_argument &) {} // fall through
|
||||
catch (const std::out_of_range &) {} // fall through
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *lookupArrayType(const std::string &typeName)
|
||||
{
|
||||
size_t openArrayPos = typeName.find_last_of('[');
|
||||
if (ULONG arrayCount = extractArrrayCount(typeName, openArrayPos))
|
||||
return createArrayType(arrayCount, (Type*)lookupType(typeName.substr(0, openArrayPos)));
|
||||
return createUnresolvedType(typeName);
|
||||
}
|
||||
|
||||
PyObject *lookupType(const std::string &typeNameIn)
|
||||
{
|
||||
if (debuggingEnabled())
|
||||
if (debuggingTypeEnabled())
|
||||
DebugPrint() << "lookup type '" << typeNameIn << "'";
|
||||
std::string typeName = typeNameIn;
|
||||
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
|
||||
trimBack(typeName);
|
||||
trimFront(typeName);
|
||||
|
||||
if (isPointerType(typeName))
|
||||
return createPointerType((Type*)lookupType(stripPointerType(typeName)));
|
||||
if (SymbolGroupValue::isArrayType(typeName))
|
||||
return lookupArrayType(typeName);
|
||||
|
||||
if (typeName.find("enum ") == 0)
|
||||
typeName.erase(0, 5);
|
||||
trimBack(typeName);
|
||||
if (typeName == "__int64" || typeName == "unsigned __int64")
|
||||
typeName.erase(typeName.find("__"), 2);
|
||||
std::string fullTypeName = typeName;
|
||||
// GetSymbolTypeId doesn't support pointer types so we need to strip off the '*' first
|
||||
while (endsWith(typeName, '*')) {
|
||||
typeName.pop_back();
|
||||
trimBack(typeName);
|
||||
}
|
||||
|
||||
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
|
||||
ULONG64 module;
|
||||
ULONG typeId;
|
||||
if (FAILED(symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module)))
|
||||
return createUnresolvedType(typeNameIn);
|
||||
if (typeName != fullTypeName) {
|
||||
if (module == 0) { // found some builtin type like char so we take the first module available to look up the pointer type
|
||||
ULONG loaded, unloaded;
|
||||
if (FAILED(symbols->GetNumberModules(&loaded, &unloaded)))
|
||||
return createUnresolvedType(typeNameIn);
|
||||
if ((loaded + unloaded == 0) || FAILED(symbols->GetModuleByIndex(0, &module)))
|
||||
return createUnresolvedType(typeNameIn);
|
||||
}
|
||||
if (FAILED(symbols->GetTypeId(module, fullTypeName.c_str(), &typeId)))
|
||||
return createUnresolvedType(typeNameIn);
|
||||
}
|
||||
return createType(module, typeId);
|
||||
return createUnresolvedType(typeName);
|
||||
return createType(module, typeId, typeName);
|
||||
}
|
||||
|
||||
char *getTypeName(ULONG64 module, ULONG typeId)
|
||||
@@ -95,13 +158,13 @@ char *getTypeName(ULONG64 module, ULONG typeId)
|
||||
ULONG size = 0;
|
||||
symbols->GetTypeName(module, typeId, NULL, 0, &size);
|
||||
if (size > 0) {
|
||||
typeName = new char[size];
|
||||
typeName = (char *)malloc(size);
|
||||
if (SUCCEEDED(symbols->GetTypeName(module, typeId, typeName, size, &size)))
|
||||
return typeName;
|
||||
else
|
||||
delete[] typeName;
|
||||
free(typeName);
|
||||
}
|
||||
typeName = new char[1];
|
||||
typeName = (char *)malloc(1);
|
||||
typeName[0] = 0;
|
||||
|
||||
return typeName;
|
||||
@@ -109,8 +172,19 @@ char *getTypeName(ULONG64 module, ULONG typeId)
|
||||
|
||||
const char *getTypeName(Type *type)
|
||||
{
|
||||
if (type->m_name == 0)
|
||||
type->m_name = getTypeName(type->m_module, type->m_typeId);
|
||||
if (type->m_name == nullptr) {
|
||||
if (type->m_targetType) {
|
||||
std::ostringstream str;
|
||||
str << getTypeName(type->m_targetType);
|
||||
if (type->m_arraySize)
|
||||
str << '[' << type->m_arraySize << ']';
|
||||
else
|
||||
str << '*';
|
||||
type->m_name = strdup(str.str().c_str());
|
||||
} else {
|
||||
type->m_name = getTypeName(type->m_module, type->m_typeId);
|
||||
}
|
||||
}
|
||||
return type->m_name;
|
||||
}
|
||||
|
||||
@@ -119,17 +193,26 @@ PyObject *type_Name(Type *self)
|
||||
return Py_BuildValue("s", getTypeName(self));
|
||||
}
|
||||
|
||||
ULONG typeBitSize(Type *type)
|
||||
{
|
||||
if (!type->m_resolved)
|
||||
return 0;
|
||||
if (type->m_targetType && type->m_arraySize != 0)
|
||||
return type->m_arraySize * typeBitSize(type->m_targetType);
|
||||
if ((type->m_targetType && type->m_arraySize == 0) || isPointerType(getTypeName(type)))
|
||||
return pointerSize() * 8;
|
||||
|
||||
ULONG size = 0;
|
||||
ExtensionCommandContext::instance()->symbols()->GetTypeSize(
|
||||
type->m_module, type->m_typeId, &size);
|
||||
if (size == 0)
|
||||
return 0;
|
||||
return size * 8;
|
||||
}
|
||||
|
||||
PyObject *type_bitSize(Type *self)
|
||||
{
|
||||
ULONG size;
|
||||
auto extcmd = ExtensionCommandContext::instance();
|
||||
if (!self->m_resolved)
|
||||
size = 0;
|
||||
else if (endsWith(getTypeName(self), '*'))
|
||||
size = SUCCEEDED(ExtensionCommandContext::instance()->control()->IsPointer64Bit()) ? 8 : 4;
|
||||
else if (FAILED(extcmd->symbols()->GetTypeSize(self->m_module, self->m_typeId, &size)))
|
||||
Py_RETURN_NONE;
|
||||
return Py_BuildValue("k", size * 8);
|
||||
return Py_BuildValue("k", typeBitSize(self));
|
||||
}
|
||||
|
||||
bool isType(const std::string &typeName, const std::vector<std::string> &types)
|
||||
@@ -148,16 +231,18 @@ PyObject *type_Code(Type *self)
|
||||
TypeCodes code = TypeCodeStruct;
|
||||
if (!self->m_resolved) {
|
||||
code = TypeCodeUnresolvable;
|
||||
} else if (self->m_targetType) {
|
||||
code = self->m_arraySize == 0 ? TypeCodePointer : TypeCodeArray;
|
||||
} else {
|
||||
const char *typeNameCstr = getTypeName(self);
|
||||
if (typeNameCstr == 0)
|
||||
Py_RETURN_NONE;
|
||||
const std::string typeName(typeNameCstr);
|
||||
if (SymbolGroupValue::isArrayType(typeName))
|
||||
if (isArrayType(typeName))
|
||||
code = TypeCodeArray;
|
||||
else if (typeName.find("<function>") != std::string::npos)
|
||||
code = TypeCodeFunction;
|
||||
else if (endsWith(typeName, "*"))
|
||||
else if (isPointerType(typeName))
|
||||
code = TypeCodePointer;
|
||||
else if (isType(typeName, integralTypes))
|
||||
code = TypeCodeIntegral;
|
||||
@@ -176,13 +261,19 @@ PyObject *type_Unqualified(Type *self)
|
||||
|
||||
PyObject *type_Target(Type *self)
|
||||
{
|
||||
std::string typeName(getTypeName(self));
|
||||
if (endsWith(typeName, "*")) {
|
||||
typeName.pop_back();
|
||||
return lookupType(typeName);
|
||||
if (self->m_targetType) {
|
||||
auto target = reinterpret_cast<PyObject *>(self->m_targetType);
|
||||
Py_IncRef(target);
|
||||
return target;
|
||||
}
|
||||
std::string typeName(getTypeName(self));
|
||||
if (isPointerType(typeName))
|
||||
return lookupType(stripPointerType(typeName));
|
||||
if (SymbolGroupValue::isArrayType(typeName)) {
|
||||
typeName.pop_back();
|
||||
while (!endsWith(typeName, '[') && !typeName.empty())
|
||||
typeName.pop_back();
|
||||
if (typeName.empty())
|
||||
Py_RETURN_NONE;
|
||||
typeName.pop_back();
|
||||
return lookupType(typeName);
|
||||
}
|
||||
@@ -201,6 +292,8 @@ PyObject *type_Fields(Type *self)
|
||||
{
|
||||
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
|
||||
auto fields = PyList_New(0);
|
||||
if (self->m_targetType)
|
||||
return fields;
|
||||
for (ULONG fieldIndex = 0;; ++fieldIndex) {
|
||||
ULONG fieldNameSize = 0;
|
||||
symbols->GetFieldName(self->m_module, self->m_typeId, fieldIndex, NULL, 0, &fieldNameSize);
|
||||
@@ -227,6 +320,8 @@ PyObject *type_Fields(Type *self)
|
||||
|
||||
PyObject *type_Module(Type *self)
|
||||
{
|
||||
if (self->m_targetType)
|
||||
return type_Module(self->m_targetType);
|
||||
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
|
||||
ULONG size;
|
||||
symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, DEBUG_ANY_ID, self->m_module, NULL, 0, &size);
|
||||
@@ -241,6 +336,13 @@ PyObject *type_Module(Type *self)
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *type_ArrayElements(Type *self)
|
||||
{
|
||||
if (self->m_arraySize)
|
||||
return Py_BuildValue("k", self->m_arraySize);
|
||||
return Py_BuildValue("k", extractArrrayCount(getTypeName(self)));
|
||||
}
|
||||
|
||||
std::vector<std::string> innerTypesOf(const std::string &t)
|
||||
{
|
||||
std::vector<std::string> rc;
|
||||
@@ -249,6 +351,13 @@ std::vector<std::string> innerTypesOf(const std::string &t)
|
||||
if (pos == std::string::npos)
|
||||
return rc;
|
||||
|
||||
// exclude special values like "<Value unavailable error>"
|
||||
if (pos == 0)
|
||||
return rc;
|
||||
// exclude untyped member in the form of class::<untyped>
|
||||
if (pos >= 2 && t.at(pos - 1) == ':' && t.at(pos - 2) == ':')
|
||||
return rc;
|
||||
|
||||
rc.reserve(5);
|
||||
const std::string::size_type size = t.size();
|
||||
// Record all elements of level 1 to work correctly for
|
||||
@@ -312,11 +421,11 @@ PyObject *type_TemplateArgument(Type *self, PyObject *args)
|
||||
PyObject *type_TemplateArguments(Type *self)
|
||||
{
|
||||
std::vector<std::string> innerTypes = innerTypesOf(getTypeName(self));
|
||||
if (debuggingEnabled())
|
||||
if (debuggingTypeEnabled())
|
||||
DebugPrint() << "template arguments of: " << getTypeName(self);
|
||||
auto templateArguments = PyList_New(0);
|
||||
for (const std::string &innerType : innerTypes) {
|
||||
if (debuggingEnabled())
|
||||
if (debuggingTypeEnabled())
|
||||
DebugPrint() << " template argument: " << innerType;
|
||||
PyObject* childValue;
|
||||
try {
|
||||
@@ -345,16 +454,29 @@ PyObject *type_New(PyTypeObject *type, PyObject *, PyObject *)
|
||||
|
||||
void type_Dealloc(Type *self)
|
||||
{
|
||||
delete[] self->m_name;
|
||||
free(self->m_name);
|
||||
}
|
||||
|
||||
PyObject *createType(ULONG64 module, ULONG typeId, char* name)
|
||||
PyObject *createType(ULONG64 module, ULONG typeId, const std::string &name)
|
||||
{
|
||||
std::string typeName = SymbolGroupValue::stripClassPrefixes(name);
|
||||
if (typeName.compare(0, 6, "union ") == 0)
|
||||
typeName.erase(0, 6);
|
||||
|
||||
if (!typeName.empty()) {
|
||||
if (isPointerType(typeName))
|
||||
return createPointerType((Type*)lookupType(stripPointerType(typeName)));
|
||||
if (isArrayType(typeName))
|
||||
return lookupArrayType(typeName);
|
||||
}
|
||||
|
||||
Type *type = PyObject_New(Type, type_pytype());
|
||||
type->m_module = module;
|
||||
type->m_typeId = typeId;
|
||||
type->m_name = name;
|
||||
type->m_arraySize = 0;
|
||||
type->m_targetType = nullptr;
|
||||
type->m_resolved = true;
|
||||
type->m_name = typeName.empty() ? nullptr : strdup(typeName.c_str());
|
||||
return reinterpret_cast<PyObject *>(type);
|
||||
}
|
||||
|
||||
@@ -363,11 +485,30 @@ PyObject *createUnresolvedType(const std::string &name)
|
||||
Type *type = PyObject_New(Type, type_pytype());
|
||||
type->m_module = 0;
|
||||
type->m_typeId = 0;
|
||||
type->m_arraySize = 0;
|
||||
type->m_targetType = nullptr;
|
||||
type->m_name = strdup(name.c_str());
|
||||
type->m_resolved = false;
|
||||
return reinterpret_cast<PyObject *>(type);
|
||||
}
|
||||
|
||||
PyObject *createArrayType(ULONG arraySize, Type *targetType)
|
||||
{
|
||||
Type *type = PyObject_New(Type, type_pytype());
|
||||
type->m_module = 0;
|
||||
type->m_typeId = 0;
|
||||
type->m_arraySize = arraySize;
|
||||
type->m_targetType = targetType;
|
||||
type->m_name = nullptr;
|
||||
type->m_resolved = true;
|
||||
return reinterpret_cast<PyObject *>(type);
|
||||
}
|
||||
|
||||
PyObject *createPointerType(Type *targetType)
|
||||
{
|
||||
return createArrayType(0, targetType);
|
||||
}
|
||||
|
||||
static PyMethodDef typeMethods[] = {
|
||||
{"name", PyCFunction(type_Name), METH_NOARGS,
|
||||
"Return the type name"},
|
||||
@@ -385,6 +526,8 @@ static PyMethodDef typeMethods[] = {
|
||||
"List of fields (member and base classes) of this type"},
|
||||
{"module", PyCFunction(type_Module), METH_NOARGS,
|
||||
"Returns name for the module containing this type"},
|
||||
{"arrayElements", PyCFunction(type_ArrayElements), METH_NOARGS,
|
||||
"Returns the number of elements in an array or 0 for non array types"},
|
||||
|
||||
{"templateArgument", PyCFunction(type_TemplateArgument), METH_VARARGS,
|
||||
"Returns template argument at position"},
|
||||
|
||||
@@ -37,6 +37,8 @@ struct Type
|
||||
PyObject_HEAD
|
||||
ULONG m_typeId;
|
||||
ULONG64 m_module;
|
||||
ULONG m_arraySize;
|
||||
Type *m_targetType;
|
||||
bool m_resolved;
|
||||
char *m_name; // owned
|
||||
};
|
||||
@@ -45,5 +47,11 @@ PyTypeObject *type_pytype();
|
||||
char *getTypeName(ULONG64 module, ULONG typeId);
|
||||
|
||||
PyObject *lookupType(const std::string &typeName);
|
||||
PyObject *createType(ULONG64 module, ULONG typeId, char *name = nullptr);
|
||||
|
||||
PyObject *createType(ULONG64 module, ULONG typeId, const std::string &name = std::string());
|
||||
PyObject *createUnresolvedType(const std::string &name);
|
||||
PyObject *createArrayType(ULONG arraySize, Type *targetType);
|
||||
PyObject *createPointerType(Type *targetType);
|
||||
|
||||
bool isPointerType(const std::string &typeName);
|
||||
std::string &stripPointerType(std::string &typeName);
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
#include "pytype.h"
|
||||
#include "pyfield.h"
|
||||
#include "stringutils.h"
|
||||
#include "symbolgroupvalue.h"
|
||||
|
||||
constexpr bool debugPyValue = false;
|
||||
constexpr bool debuggingValueEnabled() { return debugPyValue || debugPyCdbextModule; }
|
||||
|
||||
std::string getSymbolName(CIDebugSymbolGroup *sg, ULONG index)
|
||||
{
|
||||
@@ -42,25 +46,56 @@ std::string getSymbolName(CIDebugSymbolGroup *sg, ULONG index)
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string getSymbolName(Value *value)
|
||||
{
|
||||
return getSymbolName(value->m_symbolGroup, value->m_index);
|
||||
}
|
||||
|
||||
PyObject *value_Name(Value *self)
|
||||
{
|
||||
if (!self->m_symbolGroup)
|
||||
Py_RETURN_NONE;
|
||||
const std::string &symbolName = getSymbolName(self->m_symbolGroup, self->m_index);
|
||||
const std::string &symbolName = getSymbolName(self);
|
||||
if (symbolName.empty())
|
||||
Py_RETURN_NONE;
|
||||
return Py_BuildValue("s", symbolName.c_str());
|
||||
}
|
||||
|
||||
char *getTypeName(Value *value)
|
||||
{
|
||||
char *typeName = nullptr;
|
||||
ULONG size = 0;
|
||||
value->m_symbolGroup->GetSymbolTypeName(value->m_index, NULL, 0, &size);
|
||||
if (size > 0) {
|
||||
typeName = new char[size+3];
|
||||
if (SUCCEEDED(value->m_symbolGroup->GetSymbolTypeName(value->m_index, typeName, size, NULL)))
|
||||
return typeName;
|
||||
delete[] typeName;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyObject *value_Type(Value *self)
|
||||
{
|
||||
if (!self->m_symbolGroup)
|
||||
Py_RETURN_NONE;
|
||||
DEBUG_SYMBOL_PARAMETERS params;
|
||||
const HRESULT hr = self->m_symbolGroup->GetSymbolParameters(self->m_index, 1, ¶ms);
|
||||
if (FAILED(hr))
|
||||
if (FAILED(self->m_symbolGroup->GetSymbolParameters(self->m_index, 1, ¶ms)))
|
||||
Py_RETURN_NONE;
|
||||
return createType(params.Module, params.TypeId);
|
||||
char *typeName = getTypeName(self);
|
||||
auto ret = createType(params.Module, params.TypeId, typeName ? typeName : std::string());
|
||||
delete[] typeName;
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *value_Bitsize(Value *self)
|
||||
{
|
||||
if (!self->m_symbolGroup)
|
||||
Py_RETURN_NONE;
|
||||
ULONG size;
|
||||
if (FAILED(self->m_symbolGroup->GetSymbolSize(self->m_index, &size)))
|
||||
Py_RETURN_NONE;
|
||||
return Py_BuildValue("k", size * 8);
|
||||
}
|
||||
|
||||
char *valueData(Value *self, PULONG received)
|
||||
@@ -105,7 +140,11 @@ ULONG64 valueAddress(Value *value)
|
||||
PyObject *value_Address(Value *self)
|
||||
{
|
||||
const ULONG64 address = valueAddress(self);
|
||||
return address == 0 ? NULL : Py_BuildValue("K", address);
|
||||
if (debuggingValueEnabled())
|
||||
DebugPrint() << "Address of " << getSymbolName(self) << ": 0x" << std::hex << address;
|
||||
if (address == 0)
|
||||
Py_RETURN_NONE;
|
||||
return Py_BuildValue("K", address);
|
||||
}
|
||||
|
||||
bool expandValue(Value *v)
|
||||
@@ -121,6 +160,8 @@ bool expandValue(Value *v)
|
||||
ULONG numberOfChildren(Value *v)
|
||||
{
|
||||
DEBUG_SYMBOL_PARAMETERS params;
|
||||
if (!expandValue(v))
|
||||
return 0;
|
||||
HRESULT hr = v->m_symbolGroup->GetSymbolParameters(v->m_index, 1, ¶ms);
|
||||
return SUCCEEDED(hr) ? params.SubElements : 0;
|
||||
}
|
||||
@@ -129,24 +170,26 @@ PyObject *value_Dereference(Value *self)
|
||||
{
|
||||
if (!self->m_symbolGroup)
|
||||
Py_RETURN_NONE;
|
||||
DEBUG_SYMBOL_PARAMETERS params;
|
||||
const HRESULT hr = self->m_symbolGroup->GetSymbolParameters(self->m_index, 1, ¶ms);
|
||||
if (FAILED(hr))
|
||||
Py_RETURN_NONE;
|
||||
|
||||
char *name = getTypeName(params.Module, params.TypeId);
|
||||
char *typeName = getTypeName(self);
|
||||
std::string typeNameStr(typeName);
|
||||
const bool isPointer = isPointerType(typeNameStr);
|
||||
const bool isArray = !isPointer && endsWith(typeNameStr, "]");
|
||||
delete[] typeName;
|
||||
|
||||
PyObject *ret = reinterpret_cast<PyObject*>(self);
|
||||
if (endsWith(std::string(name), "*")) {
|
||||
if (numberOfChildren(self) > 0 && expandValue(self)) {
|
||||
ULONG symbolCount = 0;
|
||||
self->m_symbolGroup->GetNumberSymbols(&symbolCount);
|
||||
if (symbolCount > self->m_index + 1)
|
||||
ret = createValue(self->m_index + 1, self->m_symbolGroup);
|
||||
}
|
||||
if (isPointer || isArray) {
|
||||
std::string valueName = getSymbolName(self);
|
||||
if (isPointer)
|
||||
valueName.insert(0, 1, '*');
|
||||
else
|
||||
valueName.append("[0]");
|
||||
ULONG index = DEBUG_ANY_ID;
|
||||
if (SUCCEEDED(self->m_symbolGroup->AddSymbol(valueName.c_str(), &index)))
|
||||
return createValue(index, self->m_symbolGroup);
|
||||
}
|
||||
|
||||
delete[] name;
|
||||
PyObject *ret = reinterpret_cast<PyObject*>(self);
|
||||
Py_XINCREF(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -259,6 +302,11 @@ PyObject *value_ChildFromIndex(Value *self, PyObject *args)
|
||||
if (childCount <= index || !expandValue(self))
|
||||
Py_RETURN_NONE;
|
||||
|
||||
if (debuggingValueEnabled()) {
|
||||
DebugPrint() << "child " << index + 1
|
||||
<< " from " << getSymbolName(self)
|
||||
<< " is " << getSymbolName(self->m_symbolGroup, self->m_index + index + 1);
|
||||
}
|
||||
return createValue(self->m_index + index + 1, self->m_symbolGroup);
|
||||
}
|
||||
|
||||
@@ -281,6 +329,12 @@ void initValue(Value *value)
|
||||
|
||||
PyObject *createValue(ULONG index, CIDebugSymbolGroup *symbolGroup)
|
||||
{
|
||||
ULONG count;
|
||||
if (FAILED(symbolGroup->GetNumberSymbols(&count)))
|
||||
Py_RETURN_NONE;
|
||||
if (index >= count) // don't add values for indices out of bounds
|
||||
Py_RETURN_NONE;
|
||||
|
||||
Value *value = PyObject_New(Value, value_pytype());
|
||||
if (value != NULL) {
|
||||
value->m_index = index;
|
||||
@@ -294,6 +348,8 @@ static PyMethodDef valueMethods[] = {
|
||||
"Name of this thing or None"},
|
||||
{"type", PyCFunction(value_Type), METH_NOARGS,
|
||||
"Type of this value"},
|
||||
{"bitsize", PyCFunction(value_Bitsize), METH_NOARGS,
|
||||
"Return the size of the value in bits"},
|
||||
{"asBytes", PyCFunction(value_AsBytes), METH_NOARGS,
|
||||
"Memory contents of this object, or None"},
|
||||
{"address", PyCFunction(value_Address), METH_NOARGS,
|
||||
|
||||
@@ -284,7 +284,7 @@ bool MimeDatabasePrivate::inherits(const QString &mime, const QString &parent)
|
||||
\code
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/vnd.nokia.qt.qmakeprofile">
|
||||
<mime-type type="application/vnd.qt.qmakeprofile">
|
||||
<comment xml:lang="en">Qt qmake Profile</comment>
|
||||
<glob pattern="*.pro" weight="50"/>
|
||||
</mime-type>
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
#include <utils/runextensions.h>
|
||||
#include <utils/synchronousprocess.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QTime>
|
||||
@@ -49,6 +51,8 @@
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::placeholders;
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
/*
|
||||
@@ -120,6 +124,65 @@ namespace Internal {
|
||||
|
||||
const int MIN_SOCKET_HANDSHAKE_PORT = 20001;
|
||||
const int MAX_SOCKET_HANDSHAKE_PORT = 20999;
|
||||
static const QString pidScript = QStringLiteral("for p in /proc/[0-9]*; "
|
||||
"do cat <$p/cmdline && echo :${p##*/}; done");
|
||||
static const QString pidPollingScript = QStringLiteral("while true; do sleep 1; kill -0 %1; done");
|
||||
static int APP_START_TIMEOUT = 45000;
|
||||
|
||||
static bool isTimedOut(const chrono::high_resolution_clock::time_point &start,
|
||||
int msecs = APP_START_TIMEOUT)
|
||||
{
|
||||
bool timedOut = false;
|
||||
auto end = chrono::high_resolution_clock::now();
|
||||
if (chrono::duration_cast<chrono::milliseconds>(end-start).count() > msecs)
|
||||
timedOut = true;
|
||||
return timedOut;
|
||||
}
|
||||
|
||||
static qint64 extractPID(const QByteArray &output, const QString &packageName)
|
||||
{
|
||||
qint64 pid = -1;
|
||||
foreach (auto tuple, output.split('\n')) {
|
||||
tuple = tuple.simplified();
|
||||
if (!tuple.isEmpty()) {
|
||||
auto parts = tuple.split(':');
|
||||
QString commandName = QString::fromLocal8Bit(parts.first());
|
||||
if (parts.length() == 2 && commandName == packageName) {
|
||||
pid = parts.last().toLongLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
void findProcessPID(QFutureInterface<qint64> &fi, const QString &adbPath,
|
||||
QStringList selector, const QString &packageName)
|
||||
{
|
||||
if (packageName.isEmpty())
|
||||
return;
|
||||
|
||||
qint64 processPID = -1;
|
||||
chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
|
||||
do {
|
||||
QThread::msleep(200);
|
||||
const QByteArray out = Utils::SynchronousProcess()
|
||||
.runBlocking(adbPath, selector << QStringLiteral("shell") << pidScript)
|
||||
.allRawOutput();
|
||||
processPID = extractPID(out, packageName);
|
||||
} while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled());
|
||||
|
||||
if (!fi.isCanceled())
|
||||
fi.reportResult(processPID);
|
||||
}
|
||||
|
||||
static void deleter(QProcess *p)
|
||||
{
|
||||
p->kill();
|
||||
p->waitForFinished();
|
||||
// Might get deleted from its own signal handler.
|
||||
p->deleteLater();
|
||||
}
|
||||
|
||||
class AndroidRunnerWorker : public QObject
|
||||
{
|
||||
@@ -133,6 +196,7 @@ class AndroidRunnerWorker : public QObject
|
||||
public:
|
||||
AndroidRunnerWorker(AndroidRunConfiguration *runConfig, Core::Id runMode,
|
||||
const QString &packageName, const QStringList &selector);
|
||||
~AndroidRunnerWorker();
|
||||
|
||||
void init();
|
||||
|
||||
@@ -151,8 +215,7 @@ signals:
|
||||
void remoteErrorOutput(const QString &output);
|
||||
|
||||
private:
|
||||
void extractPID();
|
||||
void checkPID();
|
||||
void onProcessIdChanged(qint64 pid);
|
||||
void logcatReadStandardError();
|
||||
void logcatReadStandardOutput();
|
||||
void adbKill(qint64 pid);
|
||||
@@ -164,16 +227,14 @@ private:
|
||||
bool runAdb(const QStringList &args, QString *exitMessage = nullptr, int timeoutS = 10);
|
||||
|
||||
// Create the processes and timer in the worker thread, for correct thread affinity
|
||||
QScopedPointer<QProcess> m_adbLogcatProcess;
|
||||
QScopedPointer<QProcess> m_psProc;
|
||||
std::unique_ptr<QProcess, decltype(&deleter)> m_adbLogcatProcess;
|
||||
std::unique_ptr<QProcess, decltype(&deleter)> m_psIsAlive;
|
||||
QScopedPointer<QTcpSocket> m_socket;
|
||||
|
||||
bool m_wasStarted = false;
|
||||
int m_tries = 0;
|
||||
QByteArray m_stdoutBuffer;
|
||||
QByteArray m_stderrBuffer;
|
||||
QByteArray m_psProcBuffer;
|
||||
|
||||
QFuture<qint64> m_pidFinder;
|
||||
qint64 m_processPID = -1;
|
||||
bool m_useCppDebugger = false;
|
||||
QmlDebug::QmlDebugServicesPreset m_qmlDebugServices;
|
||||
@@ -196,7 +257,10 @@ private:
|
||||
|
||||
AndroidRunnerWorker::AndroidRunnerWorker(AndroidRunConfiguration *runConfig, Core::Id runMode,
|
||||
const QString &packageName, const QStringList &selector)
|
||||
: m_selector(selector), m_packageName(packageName)
|
||||
: m_adbLogcatProcess(nullptr, deleter)
|
||||
, m_psIsAlive(nullptr, deleter)
|
||||
, m_selector(selector)
|
||||
, m_packageName(packageName)
|
||||
{
|
||||
Debugger::DebuggerRunConfigurationAspect *aspect
|
||||
= runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
|
||||
@@ -257,14 +321,17 @@ AndroidRunnerWorker::AndroidRunnerWorker(AndroidRunConfiguration *runConfig, Cor
|
||||
}
|
||||
}
|
||||
|
||||
AndroidRunnerWorker::~AndroidRunnerWorker()
|
||||
{
|
||||
if (!m_pidFinder.isFinished())
|
||||
m_pidFinder.cancel();
|
||||
}
|
||||
|
||||
// This is run from the worker thread.
|
||||
void AndroidRunnerWorker::init()
|
||||
{
|
||||
QTC_ASSERT(m_adbLogcatProcess.isNull(), /**/);
|
||||
QTC_ASSERT(m_psProc.isNull(), /**/);
|
||||
|
||||
QTC_ASSERT(!m_adbLogcatProcess, /**/);
|
||||
m_adbLogcatProcess.reset(new QProcess);
|
||||
m_psProc.reset(new QProcess);
|
||||
|
||||
// Detect busybox, as we need to pass -w to ps to get wide output.
|
||||
Utils::SynchronousProcess psProc;
|
||||
@@ -274,11 +341,10 @@ void AndroidRunnerWorker::init()
|
||||
const QString which = response.allOutput();
|
||||
m_isBusyBox = which.startsWith("busybox");
|
||||
|
||||
connect(m_adbLogcatProcess.data(), &QProcess::readyReadStandardOutput,
|
||||
connect(m_adbLogcatProcess.get(), &QProcess::readyReadStandardOutput,
|
||||
this, &AndroidRunnerWorker::logcatReadStandardOutput);
|
||||
connect(m_adbLogcatProcess.data(), &QProcess::readyReadStandardError,
|
||||
connect(m_adbLogcatProcess.get(), &QProcess::readyReadStandardError,
|
||||
this, &AndroidRunnerWorker::logcatReadStandardError);
|
||||
connect(m_psProc.data(), &QIODevice::readyRead, this, &AndroidRunnerWorker::checkPID);
|
||||
|
||||
m_logCatRegExp = QRegExp(QLatin1String("[0-9\\-]*" // date
|
||||
"\\s+"
|
||||
@@ -296,108 +362,29 @@ void AndroidRunnerWorker::init()
|
||||
));
|
||||
}
|
||||
|
||||
static int extractPidFromChunk(const QByteArray &chunk, int from)
|
||||
{
|
||||
int pos1 = chunk.indexOf(' ', from);
|
||||
if (pos1 == -1)
|
||||
return -1;
|
||||
while (chunk[pos1] == ' ')
|
||||
++pos1;
|
||||
int pos3 = chunk.indexOf(' ', pos1);
|
||||
int pid = chunk.mid(pos1, pos3 - pos1).toInt();
|
||||
return pid;
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::extractPID()
|
||||
{
|
||||
const int to = m_psProcBuffer.lastIndexOf('\n');
|
||||
if (to <= 0) {
|
||||
m_processPID = -1;
|
||||
} else {
|
||||
const int from = m_psProcBuffer.lastIndexOf('\n', to - 1);
|
||||
m_processPID = extractPidFromChunk(m_psProcBuffer, from == -1 ? 0 : from);
|
||||
m_psProcBuffer = m_psProcBuffer.mid(to);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::checkPID()
|
||||
{
|
||||
// Don't write to m_psProc from a different thread
|
||||
QTC_ASSERT(QThread::currentThread() == thread(), return);
|
||||
|
||||
m_psProcBuffer.append(m_psProc->readAllStandardOutput());
|
||||
extractPID();
|
||||
|
||||
if (m_processPID == -1) {
|
||||
if (m_wasStarted) {
|
||||
m_wasStarted = false;
|
||||
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
|
||||
.arg(m_packageName));
|
||||
return; // Don't restart the timer
|
||||
} else {
|
||||
if (++m_tries > 3)
|
||||
emit remoteProcessFinished(QLatin1String("\n\n") + tr("Unable to start \"%1\".")
|
||||
.arg(m_packageName));
|
||||
}
|
||||
} else if (!m_wasStarted){
|
||||
if (m_useCppDebugger) {
|
||||
// This will be funneled to the engine to actually start and attach
|
||||
// gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
|
||||
QByteArray serverChannel = ':' + QByteArray::number(m_localGdbServerPort.number());
|
||||
emit remoteServerRunning(serverChannel, m_processPID);
|
||||
} else if (m_qmlDebugServices == QmlDebug::QmlDebuggerServices) {
|
||||
// This will be funneled to the engine to actually start and attach
|
||||
// gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
|
||||
QByteArray serverChannel = QByteArray::number(m_qmlPort.number());
|
||||
emit remoteServerRunning(serverChannel, m_processPID);
|
||||
} else if (m_qmlDebugServices == QmlDebug::QmlProfilerServices) {
|
||||
emit remoteProcessStarted(Utils::Port(), m_qmlPort);
|
||||
} else {
|
||||
// Start without debugging.
|
||||
emit remoteProcessStarted(Utils::Port(), Utils::Port());
|
||||
}
|
||||
m_wasStarted = true;
|
||||
logcatReadStandardOutput();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::forceStop()
|
||||
{
|
||||
runAdb(selector() << "shell" << "am" << "force-stop" << m_packageName, nullptr, 30);
|
||||
|
||||
// try killing it via kill -9
|
||||
const QByteArray out = Utils::SynchronousProcess()
|
||||
.runBlocking(m_adb,
|
||||
selector() << "shell" << QLatin1String(m_isBusyBox ? "ps -w" : "ps"))
|
||||
.runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScript)
|
||||
.allRawOutput();
|
||||
|
||||
int from = 0;
|
||||
while (1) {
|
||||
const int to = out.indexOf('\n', from);
|
||||
if (to == -1)
|
||||
break;
|
||||
QString line = QString::fromUtf8(out.data() + from, to - from - 1);
|
||||
if (line.endsWith(m_packageName) || line.endsWith(m_gdbserverPath)) {
|
||||
int pid = extractPidFromChunk(out, from);
|
||||
adbKill(pid);
|
||||
}
|
||||
from = to + 1;
|
||||
qint64 pid = extractPID(out.simplified(), m_packageName);
|
||||
if (pid != -1) {
|
||||
adbKill(pid);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::asyncStart(const QString &intentName,
|
||||
const QVector<QStringList> &adbCommands)
|
||||
{
|
||||
m_tries = 0;
|
||||
m_wasStarted = false;
|
||||
forceStop();
|
||||
|
||||
// Its assumed that the device or avd serial returned by selector() is online.
|
||||
m_adbLogcatProcess->start(m_adb, selector() << "logcat");
|
||||
m_psProc->start(m_adb, selector() << "shell"
|
||||
<< QString("while true; do sleep 1; %1 | (grep '%2' || echo -1); done")
|
||||
.arg(QLatin1String(m_isBusyBox ? "ps -w" : "ps"), m_packageName));
|
||||
|
||||
forceStop();
|
||||
QString errorMessage;
|
||||
|
||||
if (m_useCppDebugger)
|
||||
@@ -529,6 +516,9 @@ void AndroidRunnerWorker::asyncStart(const QString &intentName,
|
||||
}
|
||||
|
||||
}
|
||||
m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPID, m_adb, selector(),
|
||||
m_packageName),
|
||||
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
|
||||
}
|
||||
|
||||
bool AndroidRunnerWorker::adbShellAmNeedsQuotes()
|
||||
@@ -584,21 +574,19 @@ void AndroidRunnerWorker::handleRemoteDebuggerRunning()
|
||||
|
||||
void AndroidRunnerWorker::asyncStop(const QVector<QStringList> &adbCommands)
|
||||
{
|
||||
m_adbLogcatProcess->kill();
|
||||
m_psProc->kill();
|
||||
if (!m_pidFinder.isFinished())
|
||||
m_pidFinder.cancel();
|
||||
|
||||
m_adbLogcatProcess.reset();
|
||||
m_psIsAlive.reset();
|
||||
|
||||
m_tries = 0;
|
||||
if (m_processPID != -1) {
|
||||
forceStop();
|
||||
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" terminated.")
|
||||
.arg(m_packageName));
|
||||
}
|
||||
foreach (const QStringList &entry, adbCommands)
|
||||
runAdb(selector() << entry);
|
||||
|
||||
m_adbLogcatProcess->waitForFinished();
|
||||
m_psProc->waitForFinished();
|
||||
m_psProcBuffer.clear();
|
||||
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" terminated.").arg(m_packageName));
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::setAdbParameters(const QString &packageName, const QStringList &selector)
|
||||
@@ -650,6 +638,44 @@ void AndroidRunnerWorker::logcatProcess(const QByteArray &text, QByteArray &buff
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
{
|
||||
// Don't write to m_psProc from a different thread
|
||||
QTC_ASSERT(QThread::currentThread() == thread(), return);
|
||||
m_processPID = pid;
|
||||
if (m_processPID == -1) {
|
||||
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
|
||||
.arg(m_packageName));
|
||||
m_psIsAlive.reset();
|
||||
} else {
|
||||
if (m_useCppDebugger) {
|
||||
// This will be funneled to the engine to actually start and attach
|
||||
// gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
|
||||
QByteArray serverChannel = ':' + QByteArray::number(m_localGdbServerPort.number());
|
||||
emit remoteServerRunning(serverChannel, m_processPID);
|
||||
} else if (m_qmlDebugServices == QmlDebug::QmlDebuggerServices) {
|
||||
// This will be funneled to the engine to actually start and attach
|
||||
// gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
|
||||
QByteArray serverChannel = QByteArray::number(m_qmlPort.number());
|
||||
emit remoteServerRunning(serverChannel, m_processPID);
|
||||
} else if (m_qmlDebugServices == QmlDebug::QmlProfilerServices) {
|
||||
emit remoteProcessStarted(Utils::Port(), m_qmlPort);
|
||||
} else {
|
||||
// Start without debugging.
|
||||
emit remoteProcessStarted(Utils::Port(), Utils::Port());
|
||||
}
|
||||
logcatReadStandardOutput();
|
||||
QTC_ASSERT(!m_psIsAlive, /**/);
|
||||
m_psIsAlive.reset(new QProcess);
|
||||
connect(m_psIsAlive.get(), &QIODevice::readyRead, [this](){
|
||||
if (!m_psIsAlive->readAllStandardOutput().simplified().isEmpty())
|
||||
onProcessIdChanged(-1);
|
||||
});
|
||||
m_psIsAlive->start(m_adb, selector() << QStringLiteral("shell")
|
||||
<< pidPollingScript.arg(m_processPID));
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::logcatReadStandardError()
|
||||
{
|
||||
if (m_processPID != -1)
|
||||
|
||||
@@ -83,18 +83,32 @@ using namespace ClangCodeModel::Internal;
|
||||
using namespace ClangBackEnd;
|
||||
using namespace TextEditor;
|
||||
|
||||
namespace {
|
||||
|
||||
QString backendProcessPath()
|
||||
static QString backendProcessPath()
|
||||
{
|
||||
return Core::ICore::libexecPath()
|
||||
+ QStringLiteral("/clangbackend")
|
||||
+ QStringLiteral(QTC_HOST_EXE_SUFFIX);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
static bool printAliveMessageHelper()
|
||||
{
|
||||
const bool print = qEnvironmentVariableIntValue("QTC_CLANG_FORCE_VERBOSE_ALIVE");
|
||||
if (!print) {
|
||||
qCDebug(log) << "Hint: AliveMessage will not be printed. "
|
||||
"Force it by setting QTC_CLANG_FORCE_VERBOSE_ALIVE=1.";
|
||||
}
|
||||
|
||||
return print;
|
||||
}
|
||||
|
||||
static bool printAliveMessage()
|
||||
{
|
||||
static bool print = log().isDebugEnabled() ? printAliveMessageHelper() : false;
|
||||
return print;
|
||||
}
|
||||
|
||||
IpcReceiver::IpcReceiver()
|
||||
: m_printAliveMessage(printAliveMessage())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -143,7 +157,8 @@ bool IpcReceiver::isExpectingCodeCompletedMessage() const
|
||||
|
||||
void IpcReceiver::alive()
|
||||
{
|
||||
qCDebug(log) << "<<< AliveMessage";
|
||||
if (m_printAliveMessage)
|
||||
qCDebug(log) << "<<< AliveMessage";
|
||||
QTC_ASSERT(m_aliveHandler, return);
|
||||
m_aliveHandler();
|
||||
}
|
||||
@@ -505,8 +520,11 @@ void IpcCommunicator::registerCurrentCodeModelUiHeaders()
|
||||
using namespace CppTools;
|
||||
|
||||
const auto editorSupports = CppModelManager::instance()->abstractEditorSupports();
|
||||
foreach (const AbstractEditorSupport *es, editorSupports)
|
||||
updateUnsavedFile(es->fileName(), es->contents(), es->revision());
|
||||
foreach (const AbstractEditorSupport *es, editorSupports) {
|
||||
const QString mappedPath
|
||||
= ModelManagerSupportClang::instance()->dummyUiHeaderOnDiskPath(es->fileName());
|
||||
updateUnsavedFile(mappedPath, es->contents(), es->revision());
|
||||
}
|
||||
}
|
||||
|
||||
void IpcCommunicator::registerProjectsParts(const QList<CppTools::ProjectPart::Ptr> projectParts)
|
||||
@@ -517,43 +535,21 @@ void IpcCommunicator::registerProjectsParts(const QList<CppTools::ProjectPart::P
|
||||
|
||||
void IpcCommunicator::updateTranslationUnitFromCppEditorDocument(const QString &filePath)
|
||||
{
|
||||
const auto document = CppTools::CppModelManager::instance()->cppEditorDocument(filePath);
|
||||
const CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
|
||||
|
||||
updateTranslationUnit(filePath, document->contents(), document->revision());
|
||||
}
|
||||
|
||||
void IpcCommunicator::updateUnsavedFileFromCppEditorDocument(const QString &filePath)
|
||||
{
|
||||
const auto document = CppTools::CppModelManager::instance()->cppEditorDocument(filePath);
|
||||
const CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
|
||||
|
||||
updateUnsavedFile(filePath, document->contents(), document->revision());
|
||||
}
|
||||
|
||||
namespace {
|
||||
CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath)
|
||||
{
|
||||
return CppTools::CppModelManager::instance()->cppEditorDocument(filePath);
|
||||
}
|
||||
|
||||
bool documentHasChanged(const QString &filePath,
|
||||
uint revision)
|
||||
{
|
||||
auto *document = cppDocument(filePath);
|
||||
|
||||
if (document)
|
||||
return document->sendTracker().shouldSendRevision(revision);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setLastSentDocumentRevision(const QString &filePath,
|
||||
uint revision)
|
||||
{
|
||||
auto *document = cppDocument(filePath);
|
||||
|
||||
if (document)
|
||||
document->sendTracker().setLastSentRevision(int(revision));
|
||||
}
|
||||
}
|
||||
|
||||
void IpcCommunicator::updateTranslationUnit(const QString &filePath,
|
||||
@@ -581,6 +577,20 @@ void IpcCommunicator::updateUnsavedFile(const QString &filePath, const QByteArra
|
||||
documentRevision}});
|
||||
}
|
||||
|
||||
static bool documentHasChanged(const QString &filePath, uint revision)
|
||||
{
|
||||
if (CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath))
|
||||
return document->sendTracker().shouldSendRevision(revision);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void setLastSentDocumentRevision(const QString &filePath, uint revision)
|
||||
{
|
||||
if (CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath))
|
||||
document->sendTracker().setLastSentRevision(int(revision));
|
||||
}
|
||||
|
||||
void IpcCommunicator::updateTranslationUnitWithRevisionCheck(const FileContainer &fileContainer)
|
||||
{
|
||||
if (documentHasChanged(fileContainer.filePath(), fileContainer.documentRevision())) {
|
||||
@@ -610,9 +620,7 @@ void IpcCommunicator::updateTranslationUnitWithRevisionCheck(Core::IDocument *do
|
||||
|
||||
void IpcCommunicator::updateChangeContentStartPosition(const QString &filePath, int position)
|
||||
{
|
||||
auto *document = cppDocument(filePath);
|
||||
|
||||
if (document)
|
||||
if (CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath))
|
||||
document->sendTracker().applyContentChange(position);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ private:
|
||||
private:
|
||||
AliveHandler m_aliveHandler;
|
||||
QHash<quint64, ClangCompletionAssistProcessor *> m_assistProcessorsTable;
|
||||
const bool m_printAliveMessage = false;
|
||||
};
|
||||
|
||||
class IpcSenderInterface
|
||||
|
||||
@@ -30,6 +30,7 @@ SOURCES += \
|
||||
clangprojectsettings.cpp \
|
||||
clangprojectsettingswidget.cpp \
|
||||
clangtextmark.cpp \
|
||||
clanguiheaderondiskmanager.cpp \
|
||||
clangutils.cpp
|
||||
|
||||
HEADERS += \
|
||||
@@ -61,6 +62,7 @@ HEADERS += \
|
||||
clangprojectsettings.h \
|
||||
clangprojectsettingswidget.h \
|
||||
clangtextmark.h \
|
||||
clanguiheaderondiskmanager.h \
|
||||
clangutils.h
|
||||
|
||||
FORMS += clangprojectsettingswidget.ui
|
||||
|
||||
@@ -87,6 +87,8 @@ QtcPlugin {
|
||||
"clangprojectsettingswidget.ui",
|
||||
"clangtextmark.cpp",
|
||||
"clangtextmark.h",
|
||||
"clanguiheaderondiskmanager.cpp",
|
||||
"clanguiheaderondiskmanager.h",
|
||||
"clangutils.cpp",
|
||||
"clangutils.h",
|
||||
]
|
||||
|
||||
@@ -519,15 +519,10 @@ void ClangCompletionAssistProcessor::sendFileContent(const QByteArray &customFil
|
||||
uint(m_interface->textDocument()->revision())}});
|
||||
}
|
||||
namespace {
|
||||
CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath)
|
||||
{
|
||||
return CppTools::CppModelManager::instance()->cppEditorDocument(filePath);
|
||||
}
|
||||
|
||||
bool shouldSendDocumentForCompletion(const QString &filePath,
|
||||
int completionPosition)
|
||||
{
|
||||
auto *document = cppDocument(filePath);
|
||||
CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
|
||||
|
||||
if (document) {
|
||||
auto &sendTracker = document->sendTracker();
|
||||
@@ -541,7 +536,7 @@ bool shouldSendDocumentForCompletion(const QString &filePath,
|
||||
bool shouldSendCodeCompletion(const QString &filePath,
|
||||
int completionPosition)
|
||||
{
|
||||
auto *document = cppDocument(filePath);
|
||||
CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
|
||||
|
||||
if (document) {
|
||||
auto &sendTracker = document->sendTracker();
|
||||
@@ -553,7 +548,7 @@ bool shouldSendCodeCompletion(const QString &filePath,
|
||||
|
||||
void setLastDocumentRevision(const QString &filePath)
|
||||
{
|
||||
auto *document = cppDocument(filePath);
|
||||
CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
|
||||
|
||||
if (document)
|
||||
document->sendTracker().setLastSentRevision(int(document->revision()));
|
||||
@@ -562,7 +557,7 @@ void setLastDocumentRevision(const QString &filePath)
|
||||
void setLastCompletionPosition(const QString &filePath,
|
||||
int completionPosition)
|
||||
{
|
||||
auto *document = cppDocument(filePath);
|
||||
CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
|
||||
|
||||
if (document)
|
||||
document->sendTracker().setLastCompletionPosition(completionPosition);
|
||||
|
||||
@@ -346,7 +346,12 @@ void ClangDiagnosticManager::addClangTextMarks(
|
||||
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics)
|
||||
{
|
||||
for (const ClangBackEnd::DiagnosticContainer &diagnostic : diagnostics) {
|
||||
auto textMark = new ClangTextMark(filePath(), diagnostic);
|
||||
const auto onMarkRemoved = [this](const ClangTextMark *mark) {
|
||||
const auto it = std::remove(m_clangTextMarks.begin(), m_clangTextMarks.end(), mark);
|
||||
m_clangTextMarks.erase(it, m_clangTextMarks.end());
|
||||
delete mark;
|
||||
};
|
||||
auto textMark = new ClangTextMark(filePath(), diagnostic, onMarkRemoved);
|
||||
m_clangTextMarks.push_back(textMark);
|
||||
m_textDocument->addMark(textMark);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <cpptools/cpptoolsbridge.h>
|
||||
#include <cpptools/cpptoolsreuse.h>
|
||||
#include <cpptools/cppworkingcopy.h>
|
||||
#include <cpptools/editordocumenthandle.h>
|
||||
|
||||
#include <texteditor/convenience.h>
|
||||
#include <texteditor/fontsettings.h>
|
||||
@@ -325,6 +326,10 @@ void ClangEditorDocumentProcessor::registerTranslationUnitForEditor(CppTools::Pr
|
||||
m_ipcCommunicator.unregisterTranslationUnitsForEditor({fileContainerWithArguments()});
|
||||
m_ipcCommunicator.registerTranslationUnitsForEditor({fileContainerWithArguments(projectPart)});
|
||||
}
|
||||
} else if (revision() != 1) {
|
||||
// E.g. a refactoring action opened the document and modified it immediately.
|
||||
m_ipcCommunicator.registerTranslationUnitsForEditor({{fileContainerWithArgumentsAndDocumentContent(projectPart)}});
|
||||
ClangCodeModel::Utils::setLastSentDocumentRevision(filePath(), revision());
|
||||
} else {
|
||||
m_ipcCommunicator.registerTranslationUnitsForEditor({{fileContainerWithArguments(projectPart)}});
|
||||
}
|
||||
@@ -438,6 +443,20 @@ ClangEditorDocumentProcessor::fileContainerWithArguments(CppTools::ProjectPart *
|
||||
return {filePath(), projectPartId, Utf8StringVector(theFileArguments), revision()};
|
||||
}
|
||||
|
||||
ClangBackEnd::FileContainer
|
||||
ClangEditorDocumentProcessor::fileContainerWithArgumentsAndDocumentContent(
|
||||
CppTools::ProjectPart *projectPart) const
|
||||
{
|
||||
const QStringList theFileArguments = fileArguments(filePath(), projectPart);
|
||||
|
||||
return ClangBackEnd::FileContainer(filePath(),
|
||||
projectPart->id(),
|
||||
Utf8StringVector(theFileArguments),
|
||||
textDocument()->toPlainText(),
|
||||
true,
|
||||
revision());
|
||||
}
|
||||
|
||||
ClangBackEnd::FileContainer
|
||||
ClangEditorDocumentProcessor::fileContainerWithDocumentContent(const QString &projectpartId) const
|
||||
{
|
||||
|
||||
@@ -100,6 +100,8 @@ private:
|
||||
HeaderErrorDiagnosticWidgetCreator creatorForHeaderErrorDiagnosticWidget(
|
||||
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic);
|
||||
ClangBackEnd::FileContainer fileContainerWithArguments(CppTools::ProjectPart *projectPart) const;
|
||||
ClangBackEnd::FileContainer fileContainerWithArgumentsAndDocumentContent(
|
||||
CppTools::ProjectPart *projectPart) const;
|
||||
ClangBackEnd::FileContainer fileContainerWithDocumentContent(const QString &projectpartId) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
using namespace ClangCodeModel;
|
||||
using namespace ClangCodeModel::Internal;
|
||||
|
||||
static ModelManagerSupportClang *m_instance_forTestsOnly = 0;
|
||||
static ModelManagerSupportClang *m_instance = 0;
|
||||
|
||||
static CppTools::CppModelManager *cppModelManager()
|
||||
{
|
||||
@@ -60,8 +60,8 @@ static CppTools::CppModelManager *cppModelManager()
|
||||
ModelManagerSupportClang::ModelManagerSupportClang()
|
||||
: m_completionAssistProvider(m_ipcCommunicator)
|
||||
{
|
||||
QTC_CHECK(!m_instance_forTestsOnly);
|
||||
m_instance_forTestsOnly = this;
|
||||
QTC_CHECK(!m_instance);
|
||||
m_instance = this;
|
||||
|
||||
Core::EditorManager *editorManager = Core::EditorManager::instance();
|
||||
connect(editorManager, &Core::EditorManager::editorOpened,
|
||||
@@ -88,7 +88,7 @@ ModelManagerSupportClang::ModelManagerSupportClang()
|
||||
|
||||
ModelManagerSupportClang::~ModelManagerSupportClang()
|
||||
{
|
||||
m_instance_forTestsOnly = 0;
|
||||
m_instance = 0;
|
||||
}
|
||||
|
||||
CppTools::CppCompletionAssistProvider *ModelManagerSupportClang::completionAssistProvider()
|
||||
@@ -244,15 +244,19 @@ void ModelManagerSupportClang::onAbstractEditorSupportContentsUpdated(const QStr
|
||||
const QByteArray &content)
|
||||
{
|
||||
QTC_ASSERT(!filePath.isEmpty(), return);
|
||||
m_ipcCommunicator.updateUnsavedFile(filePath, content, 0);
|
||||
|
||||
const QString mappedPath = m_uiHeaderOnDiskManager.createIfNeeded(filePath);
|
||||
m_ipcCommunicator.updateUnsavedFile(mappedPath, content, 0);
|
||||
}
|
||||
|
||||
void ModelManagerSupportClang::onAbstractEditorSupportRemoved(const QString &filePath)
|
||||
{
|
||||
QTC_ASSERT(!filePath.isEmpty(), return);
|
||||
|
||||
if (!cppModelManager()->cppEditorDocument(filePath)) {
|
||||
const QString mappedPath = m_uiHeaderOnDiskManager.remove(filePath);
|
||||
const QString projectPartId = Utils::projectPartIdForFile(filePath);
|
||||
m_ipcCommunicator.unregisterUnsavedFilesForEditor({{filePath, projectPartId}});
|
||||
m_ipcCommunicator.unregisterUnsavedFilesForEditor({{mappedPath, projectPartId}});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,18 +351,26 @@ void ModelManagerSupportClang::unregisterTranslationUnitsWithProjectParts(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef QT_TESTLIB_LIB
|
||||
ModelManagerSupportClang *ModelManagerSupportClang::instance_forTestsOnly()
|
||||
ModelManagerSupportClang *ModelManagerSupportClang::instance()
|
||||
{
|
||||
return m_instance_forTestsOnly;
|
||||
return m_instance;
|
||||
}
|
||||
#endif
|
||||
|
||||
IpcCommunicator &ModelManagerSupportClang::ipcCommunicator()
|
||||
{
|
||||
return m_ipcCommunicator;
|
||||
}
|
||||
|
||||
QString ModelManagerSupportClang::dummyUiHeaderOnDiskPath(const QString &filePath) const
|
||||
{
|
||||
return m_uiHeaderOnDiskManager.mapPath(filePath);
|
||||
}
|
||||
|
||||
QString ModelManagerSupportClang::dummyUiHeaderOnDiskDirPath() const
|
||||
{
|
||||
return m_uiHeaderOnDiskManager.directoryPath();
|
||||
}
|
||||
|
||||
QString ModelManagerSupportProviderClang::id() const
|
||||
{
|
||||
return QLatin1String(Constants::CLANG_MODELMANAGERSUPPORT_ID);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "clangcompletionassistprovider.h"
|
||||
#include "clanguiheaderondiskmanager.h"
|
||||
|
||||
#include <cpptools/cppmodelmanagersupport.h>
|
||||
|
||||
@@ -58,10 +59,10 @@ public:
|
||||
TextEditor::TextDocument *baseTextDocument) override;
|
||||
|
||||
IpcCommunicator &ipcCommunicator();
|
||||
QString dummyUiHeaderOnDiskDirPath() const;
|
||||
QString dummyUiHeaderOnDiskPath(const QString &filePath) const;
|
||||
|
||||
#ifdef QT_TESTLIB_LIB
|
||||
static ModelManagerSupportClang *instance_forTestsOnly();
|
||||
#endif
|
||||
static ModelManagerSupportClang *instance();
|
||||
|
||||
private:
|
||||
void onEditorOpened(Core::IEditor *editor);
|
||||
@@ -96,6 +97,7 @@ private:
|
||||
void connectToWidgetsMarkContextMenuRequested(QWidget *editorWidget);
|
||||
|
||||
private:
|
||||
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
|
||||
IpcCommunicator m_ipcCommunicator;
|
||||
ClangCompletionAssistProvider m_completionAssistProvider;
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "clangdiagnostictooltipwidget.h"
|
||||
|
||||
#include <utils/icon.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/theme/theme.h>
|
||||
|
||||
#include <QLayout>
|
||||
@@ -60,9 +61,14 @@ Core::Id cartegoryForSeverity(ClangBackEnd::DiagnosticSeverity severity)
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
ClangTextMark::ClangTextMark(const QString &fileName, const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||
: TextEditor::TextMark(fileName, int(diagnostic.location().line()), cartegoryForSeverity(diagnostic.severity())),
|
||||
m_diagnostic(diagnostic)
|
||||
ClangTextMark::ClangTextMark(const QString &fileName,
|
||||
const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||
const RemovedFromEditorHandler &removedHandler)
|
||||
: TextEditor::TextMark(fileName,
|
||||
int(diagnostic.location().line()),
|
||||
cartegoryForSeverity(diagnostic.severity()))
|
||||
, m_diagnostic(diagnostic)
|
||||
, m_removedFromEditorHandler(removedHandler)
|
||||
{
|
||||
setPriority(TextEditor::TextMark::HighPriority);
|
||||
setIcon(diagnostic.severity());
|
||||
@@ -93,5 +99,11 @@ bool ClangTextMark::addToolTipContent(QLayout *target)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClangTextMark::removedFromEditor()
|
||||
{
|
||||
QTC_ASSERT(m_removedFromEditorHandler, return);
|
||||
m_removedFromEditorHandler(this);
|
||||
}
|
||||
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
|
||||
@@ -30,18 +30,28 @@
|
||||
|
||||
#include <texteditor/textmark.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
|
||||
class ClangTextMark : public TextEditor::TextMark
|
||||
{
|
||||
public:
|
||||
ClangTextMark(const QString &fileName, const ClangBackEnd::DiagnosticContainer &diagnostic);
|
||||
using RemovedFromEditorHandler = std::function<void(ClangTextMark *)>;
|
||||
|
||||
ClangTextMark(const QString &fileName,
|
||||
const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||
const RemovedFromEditorHandler &removedHandler);
|
||||
|
||||
private:
|
||||
bool addToolTipContent(QLayout *target);
|
||||
void setIcon(ClangBackEnd::DiagnosticSeverity severity);
|
||||
|
||||
bool addToolTipContent(QLayout *target) override;
|
||||
void removedFromEditor() override;
|
||||
|
||||
private:
|
||||
ClangBackEnd::DiagnosticContainer m_diagnostic;
|
||||
RemovedFromEditorHandler m_removedFromEditorHandler;
|
||||
};
|
||||
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clanguiheaderondiskmanager.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
UiHeaderOnDiskManager::UiHeaderOnDiskManager()
|
||||
: m_temporaryDir(QDir::tempPath() + QStringLiteral("/qtc-clang-uiheader-XXXXXX"))
|
||||
{
|
||||
QTC_CHECK(m_temporaryDir.isValid());
|
||||
}
|
||||
|
||||
QString UiHeaderOnDiskManager::createIfNeeded(const QString &filePath)
|
||||
{
|
||||
const QString mappedPath = mapPath(filePath);
|
||||
if (!QFileInfo::exists(mappedPath)) {
|
||||
const bool fileCreated = QFile(mappedPath).open(QFile::WriteOnly); // touch file
|
||||
QTC_CHECK(fileCreated);
|
||||
}
|
||||
|
||||
return mappedPath;
|
||||
}
|
||||
|
||||
QString UiHeaderOnDiskManager::remove(const QString &filePath)
|
||||
{
|
||||
const QString mappedPath = mapPath(filePath);
|
||||
if (QFileInfo::exists(mappedPath)) {
|
||||
const bool fileRemoved = QFile::remove(mappedPath);
|
||||
QTC_CHECK(fileRemoved);
|
||||
}
|
||||
|
||||
return mappedPath;
|
||||
}
|
||||
|
||||
QString UiHeaderOnDiskManager::directoryPath() const
|
||||
{
|
||||
return m_temporaryDir.path();
|
||||
}
|
||||
|
||||
QString UiHeaderOnDiskManager::mapPath(const QString &filePath) const
|
||||
{
|
||||
return directoryPath() + '/' + QFileInfo(filePath).fileName();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
@@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTemporaryDir>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
// TODO: Remove once libclang supports unsaved files that do not exist.
|
||||
class UiHeaderOnDiskManager
|
||||
{
|
||||
public:
|
||||
UiHeaderOnDiskManager();
|
||||
|
||||
QString createIfNeeded(const QString &filePath);
|
||||
QString remove(const QString &filePath);
|
||||
|
||||
QString mapPath(const QString &filePath) const;
|
||||
QString directoryPath() const;
|
||||
|
||||
private:
|
||||
QTemporaryDir m_temporaryDir;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
@@ -26,12 +26,14 @@
|
||||
#include "clangutils.h"
|
||||
|
||||
#include "clangeditordocumentprocessor.h"
|
||||
#include "clangmodelmanagersupport.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/idocument.h>
|
||||
#include <cpptools/baseeditordocumentparser.h>
|
||||
#include <cpptools/compileroptionsbuilder.h>
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/editordocumenthandle.h>
|
||||
#include <cpptools/projectpart.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -103,6 +105,7 @@ public:
|
||||
optionsBuilder.addPredefinedMacrosAndHeaderPathsOptions();
|
||||
optionsBuilder.addWrappedQtHeadersIncludePath();
|
||||
optionsBuilder.addHeaderPathOptions();
|
||||
optionsBuilder.addDummyUiHeaderOnDiskIncludePath();
|
||||
optionsBuilder.addProjectConfigFileInclude();
|
||||
|
||||
optionsBuilder.addMsvcCompatibilityVersion();
|
||||
@@ -145,7 +148,7 @@ private:
|
||||
void addPredefinedMacrosAndHeaderPathsOptionsForNonMsvc()
|
||||
{
|
||||
static const QString resourceDir = getResourceDir();
|
||||
if (!resourceDir.isEmpty()) {
|
||||
if (QTC_GUARD(!resourceDir.isEmpty())) {
|
||||
add(QLatin1String("-nostdlibinc"));
|
||||
add(QLatin1String("-I") + QDir::toNativeSeparators(resourceDir));
|
||||
add(QLatin1String("-undef"));
|
||||
@@ -172,6 +175,13 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void addDummyUiHeaderOnDiskIncludePath()
|
||||
{
|
||||
const QString path = ModelManagerSupportClang::instance()->dummyUiHeaderOnDiskDirPath();
|
||||
if (!path.isEmpty())
|
||||
add(includeDirOption() + QDir::toNativeSeparators(path));
|
||||
}
|
||||
|
||||
void addExtraOptions()
|
||||
{
|
||||
add(QLatin1String("-fmessage-length=0"));
|
||||
@@ -222,5 +232,16 @@ QString projectPartIdForFile(const QString &filePath)
|
||||
return QString();
|
||||
}
|
||||
|
||||
CppEditorDocumentHandle *cppDocument(const QString &filePath)
|
||||
{
|
||||
return CppTools::CppModelManager::instance()->cppEditorDocument(filePath);
|
||||
}
|
||||
|
||||
void setLastSentDocumentRevision(const QString &filePath, uint revision)
|
||||
{
|
||||
if (CppEditorDocumentHandle *document = cppDocument(filePath))
|
||||
document->sendTracker().setLastSentRevision(int(revision));
|
||||
}
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace Clang
|
||||
|
||||
@@ -27,9 +27,16 @@
|
||||
|
||||
#include <cpptools/projectpart.h>
|
||||
|
||||
namespace CppTools {
|
||||
class CppEditorDocumentHandle;
|
||||
}
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Utils {
|
||||
|
||||
CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath);
|
||||
void setLastSentDocumentRevision(const QString &filePath, uint revision);
|
||||
|
||||
QStringList createClangOptions(const CppTools::ProjectPart::Ptr &pPart,
|
||||
CppTools::ProjectFile::Kind fileKind);
|
||||
QStringList createClangOptions(const CppTools::ProjectPart::Ptr &pPart,
|
||||
|
||||
@@ -250,13 +250,13 @@ class ChangeIpcSender
|
||||
public:
|
||||
ChangeIpcSender(IpcSenderInterface *ipcSender)
|
||||
{
|
||||
auto &ipc = ModelManagerSupportClang::instance_forTestsOnly()->ipcCommunicator();
|
||||
auto &ipc = ModelManagerSupportClang::instance()->ipcCommunicator();
|
||||
m_previousSender = ipc.setIpcSender(ipcSender);
|
||||
}
|
||||
|
||||
~ChangeIpcSender()
|
||||
{
|
||||
auto &ipc = ModelManagerSupportClang::instance_forTestsOnly()->ipcCommunicator();
|
||||
auto &ipc = ModelManagerSupportClang::instance()->ipcCommunicator();
|
||||
ipc.setIpcSender(m_previousSender);
|
||||
}
|
||||
|
||||
@@ -1210,7 +1210,7 @@ void ClangCodeCompletionTest::testUpdateBackendAfterRestart()
|
||||
spy.senderLog.clear();
|
||||
|
||||
// Kill backend process...
|
||||
auto &ipcCommunicator = ModelManagerSupportClang::instance_forTestsOnly()->ipcCommunicator();
|
||||
auto &ipcCommunicator = ModelManagerSupportClang::instance()->ipcCommunicator();
|
||||
ipcCommunicator.killBackendProcess();
|
||||
QSignalSpy waitForReinitializedBackend(&ipcCommunicator,
|
||||
SIGNAL(backendReinitialized()));
|
||||
|
||||
@@ -411,7 +411,8 @@ void CMakeTool::fetchVersionFromVersionOutput() const
|
||||
return;
|
||||
|
||||
QRegularExpression versionLine("^cmake version ((\\d+).(\\d+).(\\d+).*)$");
|
||||
for (const QString &line : response.stdOut().split('\n')) {
|
||||
const QString responseText = response.stdOut();
|
||||
for (const QStringRef &line : responseText.splitRef(QLatin1Char('\n'))) {
|
||||
QRegularExpressionMatch match = versionLine.match(line);
|
||||
if (!match.hasMatch())
|
||||
continue;
|
||||
|
||||
@@ -702,14 +702,16 @@ QString DocumentManager::getSaveFileName(const QString &title, const QString &pa
|
||||
const int index = regExp.lastIndexIn(*selectedFilter);
|
||||
if (index != -1) {
|
||||
bool suffixOk = false;
|
||||
const QStringList &suffixes = regExp.cap(1).remove(QLatin1Char('*')).split(QLatin1Char(' '));
|
||||
foreach (const QString &suffix, suffixes)
|
||||
QString caption = regExp.cap(1);
|
||||
caption.remove(QLatin1Char('*'));
|
||||
const QVector<QStringRef> suffixes = caption.splitRef(QLatin1Char(' '));
|
||||
foreach (const QStringRef &suffix, suffixes)
|
||||
if (fileName.endsWith(suffix)) {
|
||||
suffixOk = true;
|
||||
break;
|
||||
}
|
||||
if (!suffixOk && !suffixes.isEmpty())
|
||||
fileName.append(suffixes.at(0));
|
||||
fileName.append(suffixes.at(0).toString());
|
||||
}
|
||||
}
|
||||
if (QFile::exists(fileName)) {
|
||||
|
||||
@@ -2793,6 +2793,16 @@ IEditor *EditorManager::openEditorWithContents(Id editorId,
|
||||
return edt;
|
||||
}
|
||||
|
||||
bool EditorManager::skipOpeningBigTextFile(const QString &filePath)
|
||||
{
|
||||
return EditorManagerPrivate::skipOpeningBigTextFile(filePath);
|
||||
}
|
||||
|
||||
void EditorManager::clearUniqueId(IDocument *document)
|
||||
{
|
||||
document->setProperty(scratchBufferKey, QVariant());
|
||||
}
|
||||
|
||||
bool EditorManager::saveDocument(IDocument *document)
|
||||
{
|
||||
return EditorManagerPrivate::saveDocument(document);
|
||||
|
||||
@@ -118,6 +118,8 @@ public:
|
||||
const QByteArray &contents = QByteArray(),
|
||||
const QString &uniqueId = QString(),
|
||||
OpenEditorFlags flags = NoFlags);
|
||||
static bool skipOpeningBigTextFile(const QString &filePath);
|
||||
static void clearUniqueId(IDocument *document);
|
||||
|
||||
static bool openExternalEditor(const QString &fileName, Id editorId);
|
||||
static void addCloseEditorListener(const std::function<bool(IEditor *)> &listener);
|
||||
|
||||
@@ -144,6 +144,7 @@ EditorToolBar::EditorToolBar(QWidget *parent) :
|
||||
d->m_editorList->setProperty("notelideasterisk", true);
|
||||
d->m_editorList->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
d->m_editorList->setMinimumContentsLength(20);
|
||||
d->m_editorList->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
|
||||
d->m_editorList->setModel(DocumentModel::model());
|
||||
d->m_editorList->setMaxVisibleItems(40);
|
||||
d->m_editorList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
@@ -1098,8 +1098,11 @@ void MainWindow::aboutQtCreator()
|
||||
m_versionDialog = new VersionDialog(this);
|
||||
connect(m_versionDialog, &QDialog::finished,
|
||||
this, &MainWindow::destroyVersionDialog);
|
||||
ICore::registerWindow(m_versionDialog, Context("Core.VersionDialog"));
|
||||
m_versionDialog->show();
|
||||
} else {
|
||||
ICore::raiseWindow(m_versionDialog);
|
||||
}
|
||||
m_versionDialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::destroyVersionDialog()
|
||||
|
||||
@@ -76,7 +76,10 @@ GeneratedCodeModelSupport::GeneratedCodeModelSupport(CppModelManager *modelmanag
|
||||
QLoggingCategory log("qtc.cpptools.generatedcodemodelsupport");
|
||||
qCDebug(log) << "ctor GeneratedCodeModelSupport for" << m_generator->source()
|
||||
<< generatedFile;
|
||||
init();
|
||||
|
||||
connect(m_generator, &ProjectExplorer::ExtraCompiler::contentsChanged,
|
||||
this, &GeneratedCodeModelSupport::onContentsChanged, Qt::QueuedConnection);
|
||||
onContentsChanged(generatedFile);
|
||||
}
|
||||
|
||||
GeneratedCodeModelSupport::~GeneratedCodeModelSupport()
|
||||
@@ -95,12 +98,6 @@ void GeneratedCodeModelSupport::onContentsChanged(const Utils::FileName &file)
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratedCodeModelSupport::init() const
|
||||
{
|
||||
connect(m_generator, &ProjectExplorer::ExtraCompiler::contentsChanged,
|
||||
this, &GeneratedCodeModelSupport::onContentsChanged, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
QByteArray GeneratedCodeModelSupport::contents() const
|
||||
{
|
||||
return m_generator->content(m_generatedFileName);
|
||||
|
||||
@@ -59,7 +59,6 @@ public:
|
||||
|
||||
private:
|
||||
void onContentsChanged(const Utils::FileName &file);
|
||||
void init() const;
|
||||
Utils::FileName m_generatedFileName;
|
||||
ProjectExplorer::ExtraCompiler *m_generator;
|
||||
};
|
||||
|
||||
@@ -137,6 +137,7 @@ DEBUGGER_EXPORT void enableMainWindow(bool on);
|
||||
DEBUGGER_EXPORT QWidget *mainWindow();
|
||||
|
||||
DEBUGGER_EXPORT void selectPerspective(const QByteArray &perspectiveId);
|
||||
DEBUGGER_EXPORT QByteArray currentPerspective();
|
||||
|
||||
// Convenience functions.
|
||||
DEBUGGER_EXPORT void showStatusMessage(const QString &message, int timeoutMS = 10000);
|
||||
|
||||
@@ -228,8 +228,8 @@ bool BreakpointParameters::isCppBreakpoint() const
|
||||
if (qmlExtensionString.isEmpty())
|
||||
qmlExtensionString = ".qml;.js";
|
||||
|
||||
auto qmlFileExtensions = qmlExtensionString.split(";", QString::SkipEmptyParts);
|
||||
foreach (QString extension, qmlFileExtensions) {
|
||||
auto qmlFileExtensions = qmlExtensionString.splitRef(QLatin1Char(';'), QString::SkipEmptyParts);
|
||||
foreach (QStringRef extension, qmlFileExtensions) {
|
||||
if (fileName.endsWith(extension, Qt::CaseInsensitive))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2071,7 +2071,7 @@ void CdbEngine::ensureUsing32BitStackInWow64(const DebuggerResponse &response, c
|
||||
{
|
||||
// Parsing the header of the stack output to check which bitness
|
||||
// the cdb is currently using.
|
||||
foreach (const QString &line, response.data.data().split('\n')) {
|
||||
foreach (const QStringRef &line, response.data.data().splitRef(QLatin1Char('\n'))) {
|
||||
if (!line.startsWith("Child"))
|
||||
continue;
|
||||
if (line.startsWith("ChildEBP")) {
|
||||
@@ -2909,7 +2909,8 @@ void CdbEngine::setupScripting(const DebuggerResponse &response)
|
||||
return;
|
||||
}
|
||||
const QString &verOutput = data.data();
|
||||
const QStringList pythonVersion = verOutput.split(' ').first().split('.');
|
||||
const QString firstToken = verOutput.split(QLatin1Char(' ')).constFirst();
|
||||
const QVector<QStringRef> pythonVersion =firstToken.splitRef(QLatin1Char('.'));
|
||||
|
||||
bool ok = false;
|
||||
if (pythonVersion.size() == 3) {
|
||||
|
||||
@@ -301,6 +301,7 @@ void DebuggerMainWindow::loadPerspectiveHelper(const QByteArray &perspectiveId,
|
||||
|
||||
QTC_ASSERT(m_perspectiveForPerspectiveId.contains(m_currentPerspectiveId), return);
|
||||
const Perspective *perspective = m_perspectiveForPerspectiveId.value(m_currentPerspectiveId);
|
||||
perspective->aboutToActivate();
|
||||
for (const Perspective::Operation &operation : perspective->operations()) {
|
||||
QDockWidget *dock = m_dockForDockId.value(operation.dockId);
|
||||
if (!dock) {
|
||||
@@ -405,6 +406,17 @@ void Perspective::setName(const QString &name)
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
void Perspective::setAboutToActivateCallback(const Perspective::Callback &cb)
|
||||
{
|
||||
m_aboutToActivateCallback = cb;
|
||||
}
|
||||
|
||||
void Perspective::aboutToActivate() const
|
||||
{
|
||||
if (m_aboutToActivateCallback)
|
||||
m_aboutToActivateCallback();
|
||||
}
|
||||
|
||||
QList<QWidget *> ToolbarDescription::widgets() const
|
||||
{
|
||||
return m_widgets;
|
||||
|
||||
@@ -82,6 +82,10 @@ public:
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
using Callback = std::function<void()>;
|
||||
void setAboutToActivateCallback(const Callback &cb);
|
||||
void aboutToActivate() const;
|
||||
|
||||
private:
|
||||
Perspective(const Perspective &) = delete;
|
||||
void operator=(const Perspective &) = delete;
|
||||
@@ -90,6 +94,7 @@ private:
|
||||
QVector<QByteArray> m_docks;
|
||||
QVector<Operation> m_operations;
|
||||
QPointer<QWidget> m_centralWidget;
|
||||
Callback m_aboutToActivateCallback;
|
||||
};
|
||||
|
||||
class DEBUGGER_EXPORT ToolbarDescription
|
||||
|
||||
@@ -3610,6 +3610,11 @@ void selectPerspective(const QByteArray &perspectiveId)
|
||||
dd->m_mainWindow->restorePerspective(perspectiveId);
|
||||
}
|
||||
|
||||
QByteArray currentPerspective()
|
||||
{
|
||||
return dd->m_mainWindow->currentPerspective();
|
||||
}
|
||||
|
||||
QWidget *mainWindow()
|
||||
{
|
||||
return dd->m_mainWindow;
|
||||
|
||||
@@ -822,9 +822,9 @@ QString DebuggerCommand::argsToString() const
|
||||
|
||||
DebuggerEncoding::DebuggerEncoding(const QString &data)
|
||||
{
|
||||
const QStringList l = data.split(':');
|
||||
const QVector<QStringRef> l = data.splitRef(QLatin1Char(':'));
|
||||
|
||||
const QString &t = l.at(0);
|
||||
const QStringRef &t = l.at(0);
|
||||
if (t == "latin1") {
|
||||
type = HexEncodedLatin1;
|
||||
size = 1;
|
||||
|
||||
@@ -3515,14 +3515,14 @@ void GdbEngine::handleRegisterListing(const DebuggerResponse &response)
|
||||
m_registers.clear();
|
||||
QStringList lines = response.consoleStreamOutput.split('\n');
|
||||
for (int i = 1; i < lines.size(); ++i) {
|
||||
QStringList parts = QString(lines.at(i)).split(' ', QString::SkipEmptyParts);
|
||||
const QVector<QStringRef> parts = lines.at(i).splitRef(' ', QString::SkipEmptyParts);
|
||||
if (parts.size() < 7)
|
||||
continue;
|
||||
int gdbRegisterNumber = parts.at(1).toInt();
|
||||
Register reg;
|
||||
reg.name = parts.at(0);
|
||||
reg.name = parts.at(0).toString();
|
||||
reg.size = parts.at(4).toInt();
|
||||
reg.reportedType = parts.at(5);
|
||||
reg.reportedType = parts.at(5).toString();
|
||||
m_registers[gdbRegisterNumber] = reg;
|
||||
}
|
||||
}
|
||||
@@ -3895,7 +3895,7 @@ static SourcePathMap mergeStartParametersSourcePathMap(const DebuggerRunParamete
|
||||
void GdbEngine::startGdb(const QStringList &args)
|
||||
{
|
||||
const QString tests = QString::fromLocal8Bit(qgetenv("QTC_DEBUGGER_TESTS"));
|
||||
foreach (const QString &test, tests.split(','))
|
||||
foreach (const QStringRef &test, tests.splitRef(QLatin1Char(',')))
|
||||
m_testCases.insert(test.toInt());
|
||||
foreach (int test, m_testCases)
|
||||
showMessage("ENABLING TEST CASE: " + QString::number(test));
|
||||
|
||||
@@ -983,6 +983,9 @@ void LldbEngine::reloadRegisters()
|
||||
if (!Internal::isRegistersWindowVisible())
|
||||
return;
|
||||
|
||||
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
||||
return;
|
||||
|
||||
DebuggerCommand cmd("fetchRegisters");
|
||||
cmd.callback = [this](const DebuggerResponse &response) {
|
||||
RegisterHandler *handler = registerHandler();
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
#include <QTableWidget>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
#include <QToolTip>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -352,6 +353,27 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class TextEdit : public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool event(QEvent *ev) override
|
||||
{
|
||||
if (ev->type() == QEvent::ToolTip) {
|
||||
auto hev = static_cast<QHelpEvent *>(ev);
|
||||
QTextCursor cursor = cursorForPosition(hev->pos());
|
||||
int nextPos = cursor.position();
|
||||
if (document() && nextPos + 1 < document()->characterCount())
|
||||
++nextPos;
|
||||
cursor.setPosition(nextPos, QTextCursor::KeepAnchor);
|
||||
QString msg = QString("Position: %1 Character: %2")
|
||||
.arg(cursor.anchor()).arg(cursor.selectedText());
|
||||
QToolTip::showText(hev->globalPos(), msg, this);
|
||||
}
|
||||
return QTextEdit::event(ev);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -1603,9 +1625,10 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev)
|
||||
canRemoveWatches && !m_handler->watchedExpressions().isEmpty(),
|
||||
[this] { clearWatches(); });
|
||||
|
||||
addAction(menu, tr("Select Widget to Add into Expression Evaluator"),
|
||||
canHandleWatches && canInsertWatches && m_engine->hasCapability(WatchWidgetsCapability),
|
||||
[this, ev] { ev.view()->grabMouse(Qt::CrossCursor); m_grabbing = true; });
|
||||
// FIXME:
|
||||
// addAction(menu, tr("Select Widget to Add into Expression Evaluator"),
|
||||
// canHandleWatches && canInsertWatches && m_engine->hasCapability(WatchWidgetsCapability),
|
||||
// [this, ev] { ev.view()->grabMouse(Qt::CrossCursor); m_grabbing = true; });
|
||||
|
||||
menu->addSeparator();
|
||||
menu->addMenu(createFormatMenu(item));
|
||||
@@ -2211,7 +2234,7 @@ void WatchModel::showEditValue(const WatchItem *item)
|
||||
str = QString::fromUtf16((ushort *)ba.constData(), ba.size() / 2);
|
||||
else if (format == DisplayUtf16String)
|
||||
str = QString::fromUcs4((uint *)ba.constData(), ba.size() / 4);
|
||||
m_separatedView->prepareObject<QTextEdit>(item)->setPlainText(str);
|
||||
m_separatedView->prepareObject<TextEdit>(item)->setPlainText(str);
|
||||
} else if (format == DisplayPlotData) {
|
||||
// Plots
|
||||
std::vector<double> data;
|
||||
@@ -2508,7 +2531,7 @@ void WatchHandler::addDumpers(const GdbMi &dumpers)
|
||||
DisplayFormats formats;
|
||||
formats.append(RawFormat);
|
||||
QString reportedFormats = dumper["formats"].data();
|
||||
foreach (const QString &format, reportedFormats.split(',')) {
|
||||
foreach (const QStringRef &format, reportedFormats.splitRef(',')) {
|
||||
if (int f = format.toInt())
|
||||
formats.append(DisplayFormat(f));
|
||||
}
|
||||
@@ -2637,3 +2660,5 @@ static QVariant createItemDelegate()
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
||||
#include "watchhandler.moc"
|
||||
|
||||
@@ -250,17 +250,16 @@ DiffEditor::DiffEditor()
|
||||
this, &DiffEditor::setCurrentDiffFileIndex);
|
||||
m_toolBar->addWidget(m_entriesComboBox);
|
||||
|
||||
m_contextLabel = new QLabel(m_toolBar);
|
||||
|
||||
m_contextLabel->setText(tr("Context lines:"));
|
||||
m_contextLabel->setContentsMargins(6, 0, 6, 0);
|
||||
m_toolBar->addWidget(m_contextLabel);
|
||||
QLabel *contextLabel = new QLabel(m_toolBar);
|
||||
contextLabel->setText(tr("Context lines:"));
|
||||
contextLabel->setContentsMargins(6, 0, 6, 0);
|
||||
m_contextLabelAction = m_toolBar->addWidget(contextLabel);
|
||||
|
||||
m_contextSpinBox = new QSpinBox(m_toolBar);
|
||||
m_contextSpinBox->setRange(1, 100);
|
||||
m_contextSpinBox->setFrame(false);
|
||||
m_contextSpinBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); // Mac Qt5
|
||||
m_toolBar->addWidget(m_contextSpinBox);
|
||||
m_contextSpinBoxAction = m_toolBar->addWidget(m_contextSpinBox);
|
||||
|
||||
m_whitespaceButtonAction = m_toolBar->addAction(tr("Ignore Whitespace"));
|
||||
m_whitespaceButtonAction->setCheckable(true);
|
||||
@@ -544,8 +543,8 @@ void DiffEditor::documentStateChanged()
|
||||
const bool contextVisible = !m_document->isContextLineCountForced();
|
||||
|
||||
m_whitespaceButtonAction->setVisible(canReload);
|
||||
m_contextLabel->setVisible(canReload && contextVisible);
|
||||
m_contextSpinBox->setVisible(canReload && contextVisible);
|
||||
m_contextLabelAction->setVisible(canReload && contextVisible);
|
||||
m_contextSpinBoxAction->setVisible(canReload && contextVisible);
|
||||
m_reloadAction->setVisible(canReload);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QSpinBox;
|
||||
class QToolBar;
|
||||
class QToolButton;
|
||||
@@ -95,11 +94,12 @@ private:
|
||||
QToolBar *m_toolBar;
|
||||
QComboBox *m_entriesComboBox;
|
||||
QSpinBox *m_contextSpinBox;
|
||||
QAction *m_contextSpinBoxAction = nullptr;
|
||||
QAction *m_toggleSyncAction;
|
||||
QAction *m_whitespaceButtonAction;
|
||||
QAction *m_toggleDescriptionAction;
|
||||
QAction *m_reloadAction;
|
||||
QLabel *m_contextLabel;
|
||||
QAction *m_contextLabelAction = nullptr;
|
||||
QAction *m_viewSwitcherAction;
|
||||
QPair<QString, QString> m_currentFileChunk;
|
||||
int m_currentViewIndex;
|
||||
|
||||
@@ -215,6 +215,7 @@ bool DiffEditorDocument::save(QString *errorString, const QString &fileName, boo
|
||||
|
||||
setController(0);
|
||||
setDescription(QString());
|
||||
Core::EditorManager::clearUniqueId(this);
|
||||
|
||||
const QFileInfo fi(fileName);
|
||||
setTemporary(false);
|
||||
|
||||
@@ -555,13 +555,16 @@ void DiffEditorPlugin::diffExternalFiles()
|
||||
QString());
|
||||
if (fileName1.isNull())
|
||||
return;
|
||||
if (EditorManager::skipOpeningBigTextFile(fileName1))
|
||||
return;
|
||||
|
||||
const QString fileName2 = QFileDialog::getOpenFileName(ICore::dialogParent(),
|
||||
tr("Select Second File for Diff"),
|
||||
QString());
|
||||
if (fileName2.isNull())
|
||||
return;
|
||||
|
||||
if (EditorManager::skipOpeningBigTextFile(fileName2))
|
||||
return;
|
||||
|
||||
const QString documentId = QLatin1String("Diff ") + fileName1 + QLatin1String(", ") + fileName2;
|
||||
const QString title = tr("Diff \"%1\", \"%2\"").arg(fileName1, fileName2);
|
||||
|
||||
@@ -353,6 +353,9 @@ QString DiffUtils::makePatchLine(const QChar &startLineCharacter,
|
||||
QString DiffUtils::makePatch(const ChunkData &chunkData,
|
||||
bool lastChunk)
|
||||
{
|
||||
if (chunkData.contextChunk)
|
||||
return QString();
|
||||
|
||||
QString diffText;
|
||||
int leftLineCount = 0;
|
||||
int rightLineCount = 0;
|
||||
|
||||
@@ -148,7 +148,7 @@ void UnifiedView::setSync(bool sync)
|
||||
SideBySideView::SideBySideView() : m_widget(0)
|
||||
{
|
||||
setId(SIDE_BY_SIDE_VIEW_ID);
|
||||
setIcon(Icons::UNIFIED_DIFF.icon());
|
||||
setIcon(Icons::SIDEBYSIDE_DIFF.icon());
|
||||
setToolTip(QCoreApplication::translate("DiffEditor::SideBySideView",
|
||||
"Switch to Side By Side Diff Editor"));
|
||||
setSupportsSync(true);
|
||||
|
||||
@@ -727,13 +727,16 @@ void GitClient::requestReload(const QString &documentId, const QString &source,
|
||||
|
||||
IDocument *document = DiffEditorController::findOrCreateDocument(documentId, title);
|
||||
QTC_ASSERT(document, return);
|
||||
DiffEditorController *controller = factory(document);
|
||||
QTC_ASSERT(controller, return);
|
||||
DiffEditorController *controller = DiffEditorController::controller(document);
|
||||
if (!controller) {
|
||||
controller = factory(document);
|
||||
QTC_ASSERT(controller, return);
|
||||
|
||||
connect(controller, &DiffEditorController::chunkActionsRequested,
|
||||
this, &GitClient::slotChunkActionsRequested, Qt::DirectConnection);
|
||||
connect(controller, &DiffEditorController::requestInformationForCommit,
|
||||
this, &GitClient::branchesForCommit);
|
||||
connect(controller, &DiffEditorController::chunkActionsRequested,
|
||||
this, &GitClient::slotChunkActionsRequested, Qt::DirectConnection);
|
||||
connect(controller, &DiffEditorController::requestInformationForCommit,
|
||||
this, &GitClient::branchesForCommit);
|
||||
}
|
||||
|
||||
VcsBasePlugin::setSource(document, sourceCopy);
|
||||
EditorManager::activateEditorForDocument(document);
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace {
|
||||
Q_LOGGING_CATEGORY(kitSetupLog, "qtc.ios.kitSetup")
|
||||
}
|
||||
|
||||
using ToolChainPair = std::pair<ClangToolChain *, ClangToolChain *>;
|
||||
namespace Ios {
|
||||
namespace Internal {
|
||||
|
||||
@@ -89,7 +90,7 @@ static bool handledPlatform(const Platform &platform)
|
||||
return deviceId(platform).isValid()
|
||||
&& (platform.platformKind & Platform::BasePlatform) != 0
|
||||
&& (platform.platformKind & Platform::Cxx11Support) == 0
|
||||
&& platform.compilerPath.toString().contains(QLatin1String("clang"));
|
||||
&& platform.type == Platform::CLang;
|
||||
}
|
||||
|
||||
static QList<Platform> handledPlatforms()
|
||||
@@ -116,23 +117,31 @@ static QList<ClangToolChain *> autoDetectedIosToolChains()
|
||||
});
|
||||
}
|
||||
|
||||
static ClangToolChain *findToolChainForPlatform(const Platform &platform, const QList<ClangToolChain *> &toolChains)
|
||||
static ToolChainPair findToolChainForPlatform(const Platform &platform, const QList<ClangToolChain *> &toolChains)
|
||||
{
|
||||
return Utils::findOrDefault(toolChains, [&platform](ClangToolChain *toolChain) {
|
||||
return platform.compilerPath == toolChain->compilerCommand()
|
||||
&& platform.backendFlags == toolChain->platformCodeGenFlags()
|
||||
&& platform.backendFlags == toolChain->platformLinkerFlags();
|
||||
});
|
||||
ToolChainPair platformToolChains;
|
||||
auto toolchainMatch = [](ClangToolChain *toolChain, const Utils::FileName &compilerPath, const QStringList &flags) {
|
||||
return compilerPath == toolChain->compilerCommand()
|
||||
&& flags == toolChain->platformCodeGenFlags()
|
||||
&& flags == toolChain->platformLinkerFlags();
|
||||
};
|
||||
platformToolChains.first = Utils::findOrDefault(toolChains, std::bind(toolchainMatch, std::placeholders::_1,
|
||||
platform.cCompilerPath,
|
||||
platform.backendFlags));
|
||||
platformToolChains.second = Utils::findOrDefault(toolChains, std::bind(toolchainMatch, std::placeholders::_1,
|
||||
platform.cxxCompilerPath,
|
||||
platform.backendFlags));
|
||||
return platformToolChains;
|
||||
}
|
||||
|
||||
static QHash<Platform, ClangToolChain *> findToolChains(const QList<Platform> &platforms)
|
||||
static QHash<Platform, ToolChainPair> findToolChains(const QList<Platform> &platforms)
|
||||
{
|
||||
QHash<Platform, ClangToolChain *> platformToolChainHash;
|
||||
QHash<Platform, ToolChainPair> platformToolChainHash;
|
||||
const QList<ClangToolChain *> toolChains = autoDetectedIosToolChains();
|
||||
foreach (const Platform &platform, platforms) {
|
||||
ClangToolChain *toolChain = findToolChainForPlatform(platform, toolChains);
|
||||
if (toolChain)
|
||||
platformToolChainHash.insert(platform, toolChain);
|
||||
ToolChainPair platformToolchains = findToolChainForPlatform(platform, toolChains);
|
||||
if (platformToolchains.first || platformToolchains.second)
|
||||
platformToolChainHash.insert(platform, platformToolchains);
|
||||
}
|
||||
return platformToolChainHash;
|
||||
}
|
||||
@@ -173,11 +182,12 @@ static void printKits(const QSet<Kit *> &kits)
|
||||
qCDebug(kitSetupLog) << " -" << kit->displayName();
|
||||
}
|
||||
|
||||
static void setupKit(Kit *kit, Core::Id pDeviceType, ClangToolChain *pToolchain,
|
||||
static void setupKit(Kit *kit, Core::Id pDeviceType, const ToolChainPair& toolChains,
|
||||
const QVariant &debuggerId, const Utils::FileName &sdkPath, BaseQtVersion *qtVersion)
|
||||
{
|
||||
DeviceTypeKitInformation::setDeviceTypeId(kit, pDeviceType);
|
||||
ToolChainKitInformation::setToolChain(kit, pToolchain);
|
||||
ToolChainKitInformation::setToolChain(kit, ToolChain::Language::C, toolChains.first);
|
||||
ToolChainKitInformation::setToolChain(kit, ToolChain::Language::Cxx, toolChains.second);
|
||||
QtKitInformation::setQtVersion(kit, qtVersion);
|
||||
// only replace debugger with the default one if we find an unusable one here
|
||||
// (since the user could have changed it)
|
||||
@@ -206,7 +216,7 @@ void IosConfigurations::updateAutomaticKitList()
|
||||
qCDebug(kitSetupLog) << "Developer path:" << developerPath();
|
||||
|
||||
// platform name -> tool chain
|
||||
const QHash<Platform, ClangToolChain *> platformToolChainHash = findToolChains(platforms);
|
||||
const QHash<Platform, ToolChainPair> platformToolChainHash = findToolChains(platforms);
|
||||
|
||||
const QHash<Abi::Architecture, QSet<BaseQtVersion *> > qtVersionsForArch = iosQtVersions();
|
||||
qCDebug(kitSetupLog) << "iOS Qt versions:";
|
||||
@@ -222,30 +232,32 @@ void IosConfigurations::updateAutomaticKitList()
|
||||
// match existing kits and create missing kits
|
||||
foreach (const Platform &platform, platforms) {
|
||||
qCDebug(kitSetupLog) << "Guaranteeing kits for " << platform.name ;
|
||||
ClangToolChain *pToolchain = platformToolChainHash.value(platform);
|
||||
if (!pToolchain) {
|
||||
const ToolChainPair &platformToolchains = platformToolChainHash.value(platform);
|
||||
if (!platformToolchains.first && !platformToolchains.second) {
|
||||
qCDebug(kitSetupLog) << " - No tool chain found";
|
||||
continue;
|
||||
}
|
||||
Core::Id pDeviceType = deviceId(platform);
|
||||
QTC_ASSERT(pDeviceType.isValid(), continue);
|
||||
Abi::Architecture arch = pToolchain->targetAbi().architecture();
|
||||
Abi::Architecture arch = platformToolchains.second ? platformToolchains.second->targetAbi().architecture() :
|
||||
platformToolchains.first->targetAbi().architecture();
|
||||
|
||||
QSet<BaseQtVersion *> qtVersions = qtVersionsForArch.value(arch);
|
||||
foreach (BaseQtVersion *qtVersion, qtVersions) {
|
||||
qCDebug(kitSetupLog) << " - Qt version:" << qtVersion->displayName();
|
||||
Kit *kit = Utils::findOrDefault(existingKits, [&pDeviceType, &pToolchain, &qtVersion](const Kit *kit) {
|
||||
Kit *kit = Utils::findOrDefault(existingKits, [&pDeviceType, &platformToolchains, &qtVersion](const Kit *kit) {
|
||||
// we do not compare the sdk (thus automatically upgrading it in place if a
|
||||
// new Xcode is used). Change?
|
||||
return DeviceTypeKitInformation::deviceTypeId(kit) == pDeviceType
|
||||
&& ToolChainKitInformation::toolChain(kit, ToolChain::Language::Cxx) == pToolchain
|
||||
&& ToolChainKitInformation::toolChain(kit, ToolChain::Language::Cxx) == platformToolchains.second
|
||||
&& ToolChainKitInformation::toolChain(kit, ToolChain::Language::C) == platformToolchains.first
|
||||
&& QtKitInformation::qtVersion(kit) == qtVersion;
|
||||
});
|
||||
QTC_ASSERT(!resultingKits.contains(kit), continue);
|
||||
if (kit) {
|
||||
qCDebug(kitSetupLog) << " - Kit matches:" << kit->displayName();
|
||||
kit->blockNotification();
|
||||
setupKit(kit, pDeviceType, pToolchain, debuggerId, platform.sdkPath, qtVersion);
|
||||
setupKit(kit, pDeviceType, platformToolchains, debuggerId, platform.sdkPath, qtVersion);
|
||||
kit->unblockNotification();
|
||||
} else {
|
||||
qCDebug(kitSetupLog) << " - Setting up new kit";
|
||||
@@ -254,7 +266,7 @@ void IosConfigurations::updateAutomaticKitList()
|
||||
kit->setAutoDetected(true);
|
||||
const QString baseDisplayName = tr("%1 %2").arg(platform.name, qtVersion->unexpandedDisplayName());
|
||||
kit->setUnexpandedDisplayName(baseDisplayName);
|
||||
setupKit(kit, pDeviceType, pToolchain, debuggerId, platform.sdkPath, qtVersion);
|
||||
setupKit(kit, pDeviceType, platformToolchains, debuggerId, platform.sdkPath, qtVersion);
|
||||
kit->unblockNotification();
|
||||
KitManager::registerKit(kit);
|
||||
}
|
||||
@@ -350,14 +362,18 @@ void IosConfigurations::setDeveloperPath(const FileName &devPath)
|
||||
}
|
||||
}
|
||||
|
||||
static ClangToolChain *createToolChain(const Platform &platform)
|
||||
static ClangToolChain *createToolChain(const Platform &platform, ToolChain::Language l)
|
||||
{
|
||||
if (l == ToolChain::Language::None)
|
||||
return nullptr;
|
||||
|
||||
ClangToolChain *toolChain = new ClangToolChain(ToolChain::AutoDetection);
|
||||
toolChain->setLanguage(ToolChain::Language::Cxx);
|
||||
toolChain->setDisplayName(platform.name);
|
||||
toolChain->setLanguage(l);
|
||||
toolChain->setDisplayName(l == ToolChain::Language::Cxx ? platform.name + "++" : platform.name);
|
||||
toolChain->setPlatformCodeGenFlags(platform.backendFlags);
|
||||
toolChain->setPlatformLinkerFlags(platform.backendFlags);
|
||||
toolChain->resetToolChain(platform.compilerPath);
|
||||
toolChain->resetToolChain(l == ToolChain::Language::Cxx ?
|
||||
platform.cxxCompilerPath : platform.cCompilerPath);
|
||||
return toolChain;
|
||||
}
|
||||
|
||||
@@ -373,12 +389,17 @@ QList<ToolChain *> IosToolChainFactory::autoDetect(const QList<ToolChain *> &exi
|
||||
QList<ClangToolChain *> toolChains;
|
||||
toolChains.reserve(platforms.size());
|
||||
foreach (const Platform &platform, platforms) {
|
||||
ClangToolChain *toolChain = findToolChainForPlatform(platform, existingClangToolChains);
|
||||
if (!toolChain) {
|
||||
toolChain = createToolChain(platform);
|
||||
existingClangToolChains.append(toolChain);
|
||||
}
|
||||
toolChains.append(toolChain);
|
||||
ToolChainPair platformToolchains = findToolChainForPlatform(platform, existingClangToolChains);
|
||||
auto createOrAdd = [&](ClangToolChain* toolChain, ToolChain::Language l) {
|
||||
if (!toolChain) {
|
||||
toolChain = createToolChain(platform, l);
|
||||
existingClangToolChains.append(toolChain);
|
||||
}
|
||||
toolChains.append(toolChain);
|
||||
};
|
||||
|
||||
createOrAdd(platformToolchains.first, ToolChain::Language::C);
|
||||
createOrAdd(platformToolchains.second, ToolChain::Language::Cxx);
|
||||
}
|
||||
return Utils::transform(toolChains, [](ClangToolChain *tc) -> ToolChain * { return tc; });
|
||||
}
|
||||
|
||||
@@ -116,17 +116,26 @@ void IosProbe::setupDefaultToolchains(const QString &devPath, const QString &xco
|
||||
qCDebug(probeLog) << QString::fromLatin1("Setting up platform \"%1\".").arg(xcodeName);
|
||||
QString indent = QLatin1String(" ");
|
||||
|
||||
auto getClangInfo = [devPath, indent](const QString &compiler) {
|
||||
QFileInfo compilerInfo(devPath
|
||||
+ QLatin1String("/Toolchains/XcodeDefault.xctoolchain/usr/bin/")
|
||||
+ compiler);
|
||||
if (!compilerInfo.exists())
|
||||
qCWarning(probeLog) << indent << QString::fromLatin1("Default toolchain %1 not found.")
|
||||
.arg(compilerInfo.canonicalFilePath());
|
||||
return compilerInfo;
|
||||
};
|
||||
|
||||
// detect clang (default toolchain)
|
||||
QFileInfo clangFileInfo(devPath
|
||||
+ QLatin1String("/Toolchains/XcodeDefault.xctoolchain/usr/bin")
|
||||
+ QLatin1String("/clang++"));
|
||||
bool hasClang = clangFileInfo.exists();
|
||||
if (!hasClang)
|
||||
qCWarning(probeLog) << indent << QString::fromLatin1("Default toolchain %1 not found.")
|
||||
.arg(clangFileInfo.canonicalFilePath());
|
||||
const QFileInfo clangCppInfo = getClangInfo("clang++");
|
||||
const bool hasClangCpp = clangCppInfo.exists();
|
||||
|
||||
const QFileInfo clangCInfo = getClangInfo("clang");
|
||||
const bool hasClangC = clangCInfo.exists();
|
||||
|
||||
// Platforms
|
||||
QDir platformsDir(devPath + QLatin1String("/Platforms"));
|
||||
QFileInfoList platforms = platformsDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
const QDir platformsDir(devPath + QLatin1String("/Platforms"));
|
||||
const QFileInfoList platforms = platformsDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
foreach (const QFileInfo &fInfo, platforms) {
|
||||
if (fInfo.isDir() && fInfo.suffix() == QLatin1String("platform")) {
|
||||
qCDebug(probeLog) << indent << QString::fromLatin1("Setting up %1").arg(fInfo.fileName());
|
||||
@@ -159,14 +168,20 @@ void IosProbe::setupDefaultToolchains(const QString &devPath, const QString &xco
|
||||
defaultProp[i.key()] = i.value();
|
||||
}
|
||||
|
||||
QString clangFullName = name + QLatin1String("-clang") + xcodeName;
|
||||
QString clang11FullName = name + QLatin1String("-clang11") + xcodeName;
|
||||
const QString clangFullName = name + QLatin1String("-clang") + xcodeName;
|
||||
const QString clang11FullName = name + QLatin1String("-clang11") + xcodeName;
|
||||
// detect gcc
|
||||
QFileInfo gccFileInfo(fInfo.absoluteFilePath() + QLatin1String("/Developer/usr/bin/g++"));
|
||||
QString gccFullName = name + QLatin1String("-gcc") + xcodeName;
|
||||
if (!gccFileInfo.exists())
|
||||
gccFileInfo = QFileInfo(devPath + QLatin1String("/usr/bin/g++"));
|
||||
bool hasGcc = gccFileInfo.exists();
|
||||
QFileInfo gccCppInfo(fInfo.absoluteFilePath() + QLatin1String("/Developer/usr/bin/g++"));
|
||||
if (!gccCppInfo.exists())
|
||||
gccCppInfo = QFileInfo(devPath + QLatin1String("/usr/bin/g++"));
|
||||
const bool hasGccCppCompiler = gccCppInfo.exists();
|
||||
|
||||
QFileInfo gccCInfo(fInfo.absoluteFilePath() + QLatin1String("/Developer/usr/bin/gcc"));
|
||||
if (!gccCInfo.exists())
|
||||
gccCInfo = QFileInfo(devPath + QLatin1String("/usr/bin/gcc"));
|
||||
const bool hasGccCCompiler = gccCInfo.exists();
|
||||
|
||||
const QString gccFullName = name + QLatin1String("-gcc") + xcodeName;
|
||||
|
||||
QStringList extraFlags;
|
||||
if (defaultProp.contains(QLatin1String("NATIVE_ARCH"))) {
|
||||
@@ -178,45 +193,58 @@ void IosProbe::setupDefaultToolchains(const QString &devPath, const QString &xco
|
||||
// don't generate a toolchain for 64 bit (to fix when we support that)
|
||||
extraFlags << QLatin1String("-arch") << QLatin1String("i386");
|
||||
}
|
||||
if (hasClang) {
|
||||
Platform clangProfile;
|
||||
clangProfile.developerPath = Utils::FileName::fromString(devPath);
|
||||
clangProfile.platformKind = 0;
|
||||
clangProfile.name = clangFullName;
|
||||
clangProfile.platformPath = Utils::FileName(fInfo);
|
||||
clangProfile.compilerPath = Utils::FileName(clangFileInfo);
|
||||
|
||||
auto getArch = [extraFlags](const QFileInfo &compiler) {
|
||||
QStringList flags = extraFlags;
|
||||
flags << QLatin1String("-dumpmachine");
|
||||
QString compilerTriplet = qsystem(clangFileInfo.canonicalFilePath(), flags)
|
||||
.simplified();
|
||||
QStringList compilerTripletl = compilerTriplet.split(QLatin1Char('-'));
|
||||
clangProfile.architecture = compilerTripletl.value(0);
|
||||
const QStringList compilerTriplet = qsystem(compiler.canonicalFilePath(), flags)
|
||||
.simplified().split(QLatin1Char('-'));
|
||||
return compilerTriplet.value(0);
|
||||
};
|
||||
|
||||
if (hasClangCpp || hasClangC) {
|
||||
Platform clangProfile;
|
||||
clangProfile.type = Platform::CLang;
|
||||
clangProfile.developerPath = Utils::FileName::fromString(devPath);
|
||||
clangProfile.platformKind = 0;
|
||||
clangProfile.platformPath = Utils::FileName(fInfo);
|
||||
clangProfile.architecture = getArch(hasClangCpp ? clangCppInfo : clangCInfo);
|
||||
clangProfile.backendFlags = extraFlags;
|
||||
qCDebug(probeLog) << indent << QString::fromLatin1("* adding profile %1").arg(clangProfile.name);
|
||||
m_platforms[clangProfile.name] = clangProfile;
|
||||
clangProfile.platformKind |= Platform::Cxx11Support;
|
||||
clangProfile.backendFlags.append(QLatin1String("-std=c++11"));
|
||||
clangProfile.backendFlags.append(QLatin1String("-stdlib=libc++"));
|
||||
clangProfile.name = clang11FullName;
|
||||
m_platforms[clangProfile.name] = clangProfile;
|
||||
clangProfile.name = clangFullName;
|
||||
if (hasClangC) {
|
||||
clangProfile.cCompilerPath = Utils::FileName(clangCInfo);
|
||||
m_platforms[clangFullName] = clangProfile;
|
||||
}
|
||||
if (hasClangCpp) {
|
||||
clangProfile.cxxCompilerPath = Utils::FileName(clangCppInfo);
|
||||
m_platforms[clangFullName] = clangProfile;
|
||||
clangProfile.platformKind |= Platform::Cxx11Support;
|
||||
clangProfile.backendFlags.append(QLatin1String("-std=c++11"));
|
||||
clangProfile.backendFlags.append(QLatin1String("-stdlib=libc++"));
|
||||
clangProfile.name = clang11FullName;
|
||||
m_platforms[clang11FullName] = clangProfile;
|
||||
}
|
||||
}
|
||||
if (hasGcc) {
|
||||
|
||||
if (hasGccCppCompiler || hasGccCCompiler) {
|
||||
Platform gccProfile;
|
||||
gccProfile.type = Platform::GCC;
|
||||
gccProfile.developerPath = Utils::FileName::fromString(devPath);
|
||||
gccProfile.name = gccFullName;
|
||||
gccProfile.platformKind = 0;
|
||||
// use the arm-apple-darwin10-llvm-* variant and avoid the extraFlags if available???
|
||||
gccProfile.platformPath = Utils::FileName(fInfo);
|
||||
gccProfile.compilerPath = Utils::FileName(gccFileInfo);
|
||||
QStringList flags = extraFlags;
|
||||
flags << QLatin1String("-dumpmachine");
|
||||
QString compilerTriplet = qsystem(gccFileInfo.canonicalFilePath(), flags)
|
||||
.simplified();
|
||||
QStringList compilerTripletl = compilerTriplet.split(QLatin1Char('-'));
|
||||
gccProfile.architecture = compilerTripletl.value(0);
|
||||
gccProfile.architecture = getArch(hasGccCppCompiler ? gccCppInfo : gccCInfo);
|
||||
gccProfile.backendFlags = extraFlags;
|
||||
qCDebug(probeLog) << indent << QString::fromLatin1("* adding profile %1").arg(gccProfile.name);
|
||||
m_platforms[gccProfile.name] = gccProfile;
|
||||
if (hasGccCppCompiler) {
|
||||
gccProfile.cxxCompilerPath = Utils::FileName(gccCppInfo);
|
||||
}
|
||||
if (hasGccCCompiler) {
|
||||
gccProfile.cCompilerPath = Utils::FileName(gccCInfo);
|
||||
}
|
||||
m_platforms[gccFullName] = gccProfile;
|
||||
}
|
||||
|
||||
// set SDKs/sysroot
|
||||
@@ -262,15 +290,18 @@ void IosProbe::setupDefaultToolchains(const QString &devPath, const QString &xco
|
||||
if (sysRoot.isEmpty() && !sdkName.isEmpty())
|
||||
qCDebug(probeLog) << indent << QString::fromLatin1("Failed to find sysroot %1").arg(sdkName);
|
||||
}
|
||||
if (hasClang && !sysRoot.isEmpty()) {
|
||||
m_platforms[clangFullName].platformKind |= Platform::BasePlatform;
|
||||
m_platforms[clangFullName].sdkPath = Utils::FileName::fromString(sysRoot);
|
||||
m_platforms[clang11FullName].platformKind |= Platform::BasePlatform;
|
||||
m_platforms[clang11FullName].sdkPath = Utils::FileName::fromString(sysRoot);
|
||||
}
|
||||
if (hasGcc && !sysRoot.isEmpty()) {
|
||||
m_platforms[gccFullName].platformKind |= Platform::BasePlatform;
|
||||
m_platforms[gccFullName].sdkPath = Utils::FileName::fromString(sysRoot);
|
||||
|
||||
if (!sysRoot.isEmpty()) {
|
||||
auto itr = m_platforms.begin();
|
||||
while (itr != m_platforms.end()) {
|
||||
if (itr.key() == clangFullName ||
|
||||
itr.key() == clang11FullName ||
|
||||
itr.key() == gccFullName) {
|
||||
itr.value().platformKind |= Platform::BasePlatform;
|
||||
itr.value().sdkPath = Utils::FileName::fromString(sysRoot);
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
indent = QLatin1String(" ");
|
||||
@@ -293,7 +324,8 @@ QDebug operator<<(QDebug debug, const Platform &platform)
|
||||
{
|
||||
QDebugStateSaver saver(debug); Q_UNUSED(saver)
|
||||
debug.nospace() << "(name=" << platform.name
|
||||
<< ", compiler=" << platform.compilerPath.toString()
|
||||
<< ", C++ compiler=" << platform.cxxCompilerPath.toString()
|
||||
<< ", C compiler=" << platform.cCompilerPath.toString()
|
||||
<< ", flags=" << platform.backendFlags
|
||||
<< ")";
|
||||
return debug;
|
||||
|
||||
@@ -40,13 +40,20 @@ public:
|
||||
Cxx11Support = 1 << 1
|
||||
};
|
||||
|
||||
enum CompilerType {
|
||||
CLang,
|
||||
GCC
|
||||
};
|
||||
|
||||
quint32 platformKind;
|
||||
CompilerType type;
|
||||
QString name;
|
||||
Utils::FileName developerPath;
|
||||
Utils::FileName platformPath;
|
||||
Utils::FileName sdkPath;
|
||||
Utils::FileName defaultToolchainPath;
|
||||
Utils::FileName compilerPath;
|
||||
Utils::FileName cxxCompilerPath;
|
||||
Utils::FileName cCompilerPath;
|
||||
QString architecture;
|
||||
QStringList backendFlags;
|
||||
|
||||
|
||||
@@ -166,6 +166,9 @@ static QList<Abi> parseCoffHeader(const QByteArray &data)
|
||||
case 14:
|
||||
flavor = Abi::WindowsMsvc2015Flavor;
|
||||
break;
|
||||
case 15:
|
||||
flavor = Abi::WindowsMsvc2017Flavor;
|
||||
break;
|
||||
default: // Keep unknown flavor
|
||||
if (minorLinker != 0)
|
||||
flavor = Abi::WindowsMSysFlavor; // MSVC seems to avoid using minor numbers
|
||||
@@ -349,7 +352,7 @@ Abi::Abi(const QString &abiString) :
|
||||
m_architecture(UnknownArchitecture), m_os(UnknownOS),
|
||||
m_osFlavor(UnknownFlavor), m_binaryFormat(UnknownFormat), m_wordWidth(0)
|
||||
{
|
||||
QStringList abiParts = abiString.split(QLatin1Char('-'));
|
||||
const QVector<QStringRef> abiParts = abiString.splitRef(QLatin1Char('-'));
|
||||
if (abiParts.count() >= 1) {
|
||||
if (abiParts.at(0) == QLatin1String("unknown"))
|
||||
m_architecture = UnknownArchitecture;
|
||||
@@ -422,6 +425,8 @@ Abi::Abi(const QString &abiString) :
|
||||
m_osFlavor = WindowsMsvc2013Flavor;
|
||||
else if (abiParts.at(2) == QLatin1String("msvc2015") && m_os == WindowsOS)
|
||||
m_osFlavor = WindowsMsvc2015Flavor;
|
||||
else if (abiParts.at(2) == QLatin1String("msvc2017") && m_os == WindowsOS)
|
||||
m_osFlavor = WindowsMsvc2017Flavor;
|
||||
else if (abiParts.at(2) == QLatin1String("msys") && m_os == WindowsOS)
|
||||
m_osFlavor = WindowsMSysFlavor;
|
||||
else if (abiParts.at(2) == QLatin1String("ce") && m_os == WindowsOS)
|
||||
@@ -448,12 +453,14 @@ Abi::Abi(const QString &abiString) :
|
||||
}
|
||||
|
||||
if (abiParts.count() >= 5) {
|
||||
const QString &bits = abiParts.at(4);
|
||||
const QStringRef &bits = abiParts.at(4);
|
||||
if (!bits.endsWith(QLatin1String("bit")))
|
||||
return;
|
||||
|
||||
bool ok = false;
|
||||
int bitCount = bits.leftRef(bits.count() - 3).toInt(&ok);
|
||||
const QStringRef number =
|
||||
bits.string()->midRef(bits.position(), bits.count() - 3);
|
||||
const int bitCount = number.toInt(&ok);
|
||||
if (!ok)
|
||||
return;
|
||||
if (bitCount != 8 && bitCount != 16 && bitCount != 32 && bitCount != 64)
|
||||
@@ -468,7 +475,7 @@ Abi Abi::abiFromTargetTriplet(const QString &triple)
|
||||
if (machine.isEmpty())
|
||||
return Abi();
|
||||
|
||||
QStringList parts = machine.split(QRegExp(QLatin1String("[ /-]")));
|
||||
const QVector<QStringRef> parts = machine.splitRef(QRegExp(QLatin1String("[ /-]")));
|
||||
|
||||
Abi::Architecture arch = Abi::UnknownArchitecture;
|
||||
Abi::OS os = Abi::UnknownOS;
|
||||
@@ -477,7 +484,7 @@ Abi Abi::abiFromTargetTriplet(const QString &triple)
|
||||
unsigned char width = 0;
|
||||
int unknownCount = 0;
|
||||
|
||||
foreach (const QString &p, parts) {
|
||||
for (const QStringRef &p : parts) {
|
||||
if (p == QLatin1String("unknown") || p == QLatin1String("pc") || p == QLatin1String("none")
|
||||
|| p == QLatin1String("gnu") || p == QLatin1String("uclibc")
|
||||
|| p == QLatin1String("86_64") || p == QLatin1String("redhat")
|
||||
@@ -695,6 +702,8 @@ QString Abi::toString(const OSFlavor &of)
|
||||
return QLatin1String("msvc2013");
|
||||
case Abi::WindowsMsvc2015Flavor:
|
||||
return QLatin1String("msvc2015");
|
||||
case Abi::WindowsMsvc2017Flavor:
|
||||
return QLatin1String("msvc2017");
|
||||
case Abi::WindowsMSysFlavor:
|
||||
return QLatin1String("msys");
|
||||
case Abi::WindowsCEFlavor:
|
||||
@@ -746,6 +755,7 @@ QList<Abi::OSFlavor> Abi::flavorsForOs(const Abi::OS &o)
|
||||
case WindowsOS:
|
||||
return result << WindowsMsvc2005Flavor << WindowsMsvc2008Flavor << WindowsMsvc2010Flavor
|
||||
<< WindowsMsvc2012Flavor << WindowsMsvc2013Flavor << WindowsMsvc2015Flavor
|
||||
<< WindowsMsvc2017Flavor
|
||||
<< WindowsMSysFlavor << WindowsCEFlavor << UnknownFlavor;
|
||||
case VxWorks:
|
||||
return result << VxWorksFlavor << UnknownFlavor;
|
||||
@@ -766,7 +776,9 @@ Abi Abi::hostAbi()
|
||||
|
||||
#if defined (Q_OS_WIN)
|
||||
os = WindowsOS;
|
||||
#if _MSC_VER == 1900
|
||||
#if _MSC_VER >= 1910
|
||||
subos = WindowsMsvc2017Flavor;
|
||||
#elif _MSC_VER == 1900
|
||||
subos = WindowsMsvc2015Flavor;
|
||||
#elif _MSC_VER == 1800
|
||||
subos = WindowsMsvc2013Flavor;
|
||||
|
||||
@@ -85,6 +85,7 @@ public:
|
||||
WindowsMsvc2012Flavor,
|
||||
WindowsMsvc2013Flavor,
|
||||
WindowsMsvc2015Flavor,
|
||||
WindowsMsvc2017Flavor,
|
||||
WindowsMSysFlavor,
|
||||
WindowsCEFlavor,
|
||||
|
||||
|
||||
@@ -101,7 +101,8 @@ ToolChain::CompilerFlags AbstractMsvcToolChain::compilerFlags(const QStringList
|
||||
case Abi::WindowsMsvc2012Flavor: flags |= StandardCxx11;
|
||||
break;
|
||||
case Abi::WindowsMsvc2013Flavor:
|
||||
case Abi::WindowsMsvc2015Flavor: flags |= StandardCxx14;
|
||||
case Abi::WindowsMsvc2015Flavor:
|
||||
case Abi::WindowsMsvc2017Flavor: flags |= StandardCxx14;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QSettings>
|
||||
#include <QVector>
|
||||
#include <QVersionNumber>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QFormLayout>
|
||||
@@ -56,28 +58,39 @@ namespace Internal {
|
||||
// Helpers:
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
struct MsvcPlatform {
|
||||
MsvcToolChain::Platform platform;
|
||||
const char *name;
|
||||
const char *prefix; // VS up until 14.0 (MSVC2015)
|
||||
const char *bat;
|
||||
};
|
||||
|
||||
const MsvcPlatform platforms[] =
|
||||
{
|
||||
{ MsvcToolChain::x86, "x86", "/bin", "vcvars32.bat" },
|
||||
{ MsvcToolChain::amd64, "amd64", "/bin/amd64", "vcvars64.bat" },
|
||||
{ MsvcToolChain::x86_amd64, "x86_amd64", "/bin/x86_amd64", "vcvarsx86_amd64.bat" },
|
||||
{ MsvcToolChain::ia64, "ia64", "/bin/ia64", "vcvars64.bat" },
|
||||
{ MsvcToolChain::x86_ia64, "x86_ia64", "/bin/x86_ia64", "vcvarsx86_ia64.bat" },
|
||||
{ MsvcToolChain::arm, "arm", "/bin/arm", "vcvarsarm.bat" },
|
||||
{ MsvcToolChain::x86_arm, "x86_arm", "/bin/x86_arm", "vcvarsx86_arm.bat" },
|
||||
{ MsvcToolChain::amd64_arm, "amd64_arm", "/bin/amd64_arm", "vcvarsamd64_arm.bat" },
|
||||
{ MsvcToolChain::amd64_x86, "amd64_x86", "/bin/amd64_x86", "vcvarsamd64_x86.bat" }
|
||||
};
|
||||
|
||||
static const MsvcPlatform *platformEntry(MsvcToolChain::Platform t)
|
||||
{
|
||||
for (const MsvcPlatform &p : platforms) {
|
||||
if (p.platform == t)
|
||||
return &p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static QString platformName(MsvcToolChain::Platform t)
|
||||
{
|
||||
switch (t) {
|
||||
case MsvcToolChain::x86:
|
||||
return QLatin1String("x86");
|
||||
case MsvcToolChain::amd64_x86:
|
||||
return QLatin1String("amd64_x86");
|
||||
case MsvcToolChain::amd64:
|
||||
return QLatin1String("amd64");
|
||||
case MsvcToolChain::x86_amd64:
|
||||
return QLatin1String("x86_amd64");
|
||||
case MsvcToolChain::ia64:
|
||||
return QLatin1String("ia64");
|
||||
case MsvcToolChain::x86_ia64:
|
||||
return QLatin1String("x86_ia64");
|
||||
case MsvcToolChain::arm:
|
||||
return QLatin1String("arm");
|
||||
case MsvcToolChain::x86_arm:
|
||||
return QLatin1String("x86_arm");
|
||||
case MsvcToolChain::amd64_arm:
|
||||
return QLatin1String("amd64_arm");
|
||||
}
|
||||
if (const MsvcPlatform *p = platformEntry(t))
|
||||
return QLatin1String(p->name);
|
||||
return QString();
|
||||
}
|
||||
|
||||
@@ -101,6 +114,78 @@ static bool hostSupportsPlatform(MsvcToolChain::Platform platform)
|
||||
}
|
||||
}
|
||||
|
||||
static QString fixRegistryPath(const QString &path)
|
||||
{
|
||||
QString result = QDir::fromNativeSeparators(path);
|
||||
if (result.endsWith(QLatin1Char('/')))
|
||||
result.chop(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct VisualStudioInstallation
|
||||
{
|
||||
QString vsName;
|
||||
QVersionNumber version;
|
||||
QString path; // Main installation path
|
||||
QString vcVarsPath; // Path under which the various vc..bat are to be found
|
||||
QString vcVarsAll;
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug d, const VisualStudioInstallation &i)
|
||||
{
|
||||
QDebugStateSaver saver(d);
|
||||
d.noquote();
|
||||
d.nospace();
|
||||
d << "VisualStudioInstallation(\"" << i.vsName << "\", v=" << i.version
|
||||
<< ", path=\"" << QDir::toNativeSeparators(i.path)
|
||||
<< "\", vcVarsPath=\"" << QDir::toNativeSeparators(i.vcVarsPath)
|
||||
<< "\", vcVarsAll=\"" << QDir::toNativeSeparators(i.vcVarsAll) << "\")";
|
||||
return d;
|
||||
}
|
||||
|
||||
static QVector<VisualStudioInstallation> detectVisualStudio()
|
||||
{
|
||||
QVector<VisualStudioInstallation> result;
|
||||
#ifdef Q_OS_WIN64
|
||||
const QString keyRoot = QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\");
|
||||
#else
|
||||
const QString keyRoot = QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\");
|
||||
#endif
|
||||
QSettings vsRegistry(keyRoot + QStringLiteral("VS7"), QSettings::NativeFormat);
|
||||
QScopedPointer<QSettings> vcRegistry;
|
||||
const QString vcvarsall = QStringLiteral("/vcvarsall.bat");
|
||||
foreach (const QString &vsName, vsRegistry.allKeys()) {
|
||||
const QVersionNumber version = QVersionNumber::fromString(vsName);
|
||||
if (!version.isNull()) {
|
||||
VisualStudioInstallation installation;
|
||||
installation.vsName = vsName;
|
||||
installation.version = version;
|
||||
if (version.majorVersion() > 14) {
|
||||
// Starting with 15 (MSVC2017): There are no more VC entries,
|
||||
// build path from VS installation
|
||||
installation.path = fixRegistryPath(vsRegistry.value(vsName).toString());
|
||||
installation.vcVarsPath = installation.path + QStringLiteral("/VC/Auxiliary/Build");
|
||||
installation.vcVarsAll = installation.vcVarsPath + vcvarsall;
|
||||
} else {
|
||||
// Up to 14 (MSVC2015): Look up via matching VC entry
|
||||
if (vcRegistry.isNull())
|
||||
vcRegistry.reset(new QSettings(keyRoot + QStringLiteral("VC7"), QSettings::NativeFormat));
|
||||
installation.path = fixRegistryPath(vcRegistry->value(vsName).toString());
|
||||
installation.vcVarsPath = installation.path;
|
||||
installation.vcVarsAll = installation.vcVarsPath + vcvarsall;
|
||||
}
|
||||
if (QFileInfo(installation.vcVarsAll).isFile()) {
|
||||
result.append(installation);
|
||||
} else {
|
||||
qWarning().noquote() << "Unable to find MSVC setup script "
|
||||
<< QDir::toNativeSeparators(installation.vcVarsPath) << " in version "
|
||||
<< version;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Abi findAbiOfMsvc(MsvcToolChain::Type type, MsvcToolChain::Platform platform, const QString &version)
|
||||
{
|
||||
Abi::Architecture arch = Abi::X86Architecture;
|
||||
@@ -135,7 +220,9 @@ static Abi findAbiOfMsvc(MsvcToolChain::Type type, MsvcToolChain::Platform platf
|
||||
else if (version == QLatin1String("v7.0A") || version == QLatin1String("v7.1"))
|
||||
msvcVersionString = QLatin1String("10.0");
|
||||
}
|
||||
if (msvcVersionString.startsWith(QLatin1String("14.")))
|
||||
if (msvcVersionString.startsWith(QLatin1String("15.")))
|
||||
flavor = Abi::WindowsMsvc2017Flavor;
|
||||
else if (msvcVersionString.startsWith(QLatin1String("14.")))
|
||||
flavor = Abi::WindowsMsvc2015Flavor;
|
||||
else if (msvcVersionString.startsWith(QLatin1String("12.")))
|
||||
flavor = Abi::WindowsMsvc2013Flavor;
|
||||
@@ -384,6 +471,9 @@ Utils::FileNameList MsvcToolChain::suggestedMkspecList() const
|
||||
<< Utils::FileName::fromLatin1("winrt-arm-msvc2015")
|
||||
<< Utils::FileName::fromLatin1("winrt-x86-msvc2015")
|
||||
<< Utils::FileName::fromLatin1("winrt-x64-msvc2015");
|
||||
case Abi::WindowsMsvc2017Flavor:
|
||||
return Utils::FileNameList()
|
||||
<< Utils::FileName::fromLatin1("win32-msvc2017");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -576,45 +666,19 @@ QSet<ToolChain::Language> MsvcToolChainFactory::supportedLanguages() const
|
||||
return { ToolChain::Language::C, ToolChain::Language::Cxx };
|
||||
}
|
||||
|
||||
bool MsvcToolChainFactory::checkForVisualStudioInstallation(const QString &vsName)
|
||||
QString MsvcToolChainFactory::vcVarsBatFor(const QString &basePath, MsvcToolChain::Platform platform,
|
||||
const QVersionNumber &v)
|
||||
{
|
||||
const QSettings vsRegistry(
|
||||
#ifdef Q_OS_WIN64
|
||||
QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VS7"),
|
||||
#else
|
||||
QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7"),
|
||||
#endif
|
||||
QSettings::NativeFormat);
|
||||
|
||||
return vsRegistry.contains(vsName);
|
||||
}
|
||||
|
||||
QString MsvcToolChainFactory::vcVarsBatFor(const QString &basePath, MsvcToolChain::Platform platform)
|
||||
{
|
||||
const QString toolchainName = platformName(platform);
|
||||
|
||||
if (toolchainName.startsWith(QLatin1Char('/'))) // windows sdk case, all use SetEnv.cmd
|
||||
return basePath + QLatin1String("/SetEnv.cmd");
|
||||
if (toolchainName == QLatin1String("x86"))
|
||||
return basePath + QLatin1String("/bin/vcvars32.bat");
|
||||
if (toolchainName == QLatin1String("amd64_arm"))
|
||||
return basePath + QLatin1String("/bin/amd64_arm/vcvarsamd64_arm.bat");
|
||||
if (toolchainName == QLatin1String("x86_amd64"))
|
||||
return basePath + QLatin1String("/bin/x86_amd64/vcvarsx86_amd64.bat");
|
||||
if (toolchainName == QLatin1String("amd64"))
|
||||
return basePath + QLatin1String("/bin/amd64/vcvars64.bat");
|
||||
if (toolchainName == QLatin1String("x86_arm"))
|
||||
return basePath + QLatin1String("/bin/x86_arm/vcvarsx86_arm.bat");
|
||||
if (toolchainName == QLatin1String("arm"))
|
||||
return basePath + QLatin1String("/bin/arm/vcvarsarm.bat");
|
||||
if (toolchainName == QLatin1String("ia64"))
|
||||
return basePath + QLatin1String("/bin/ia64/vcvars64.bat");
|
||||
if (toolchainName == QLatin1String("x86_ia64"))
|
||||
return basePath + QLatin1String("/bin/x86_ia64/vcvarsx86_ia64.bat");
|
||||
if (toolchainName == QLatin1String("amd64_x86"))
|
||||
return basePath + QLatin1String("/bin/amd64_x86/vcvarsamd64_x86.bat");
|
||||
|
||||
return QString();
|
||||
QString result;
|
||||
if (const MsvcPlatform *p = platformEntry(platform)) {
|
||||
result += basePath;
|
||||
// Starting with 15.0 (MSVC2017), the .bat are in one folder.
|
||||
if (v.majorVersion() <= 14)
|
||||
result += QLatin1String(p->prefix);
|
||||
result += QLatin1Char('/');
|
||||
result += QLatin1String(p->bat);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static QList<ToolChain *> findOrCreateToolChain(
|
||||
@@ -773,50 +837,29 @@ QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &al
|
||||
}
|
||||
|
||||
// 2) Installed MSVCs
|
||||
const QSettings vsRegistry(
|
||||
#ifdef Q_OS_WIN64
|
||||
QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7"),
|
||||
#else
|
||||
QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7"),
|
||||
#endif
|
||||
QSettings::NativeFormat);
|
||||
foreach (const QString &vsName, vsRegistry.allKeys()) {
|
||||
// Scan for version major.minor
|
||||
const int dotPos = vsName.indexOf(QLatin1Char('.'));
|
||||
if (dotPos == -1)
|
||||
continue;
|
||||
if (!checkForVisualStudioInstallation(vsName))
|
||||
continue;
|
||||
// prioritized list.
|
||||
// x86_arm was put before amd64_arm as a workaround for auto detected windows phone
|
||||
// toolchains. As soon as windows phone builds support x64 cross builds, this change
|
||||
// can be reverted.
|
||||
const MsvcToolChain::Platform platforms[] = {
|
||||
MsvcToolChain::x86, MsvcToolChain::amd64_x86,
|
||||
MsvcToolChain::amd64, MsvcToolChain::x86_amd64,
|
||||
MsvcToolChain::arm, MsvcToolChain::x86_arm, MsvcToolChain::amd64_arm,
|
||||
MsvcToolChain::ia64, MsvcToolChain::x86_ia64
|
||||
};
|
||||
|
||||
QString path = QDir::fromNativeSeparators(vsRegistry.value(vsName).toString());
|
||||
if (path.endsWith(QLatin1Char('/')))
|
||||
path.chop(1);
|
||||
const int version = vsName.leftRef(dotPos).toInt();
|
||||
const QString vcvarsAllbat = path + QLatin1String("/vcvarsall.bat");
|
||||
if (QFileInfo(vcvarsAllbat).isFile()) {
|
||||
// prioritized list.
|
||||
// x86_arm was put before amd64_arm as a workaround for auto detected windows phone
|
||||
// toolchains. As soon as windows phone builds support x64 cross builds, this change
|
||||
// can be reverted.
|
||||
const QVector<MsvcToolChain::Platform> platforms = {
|
||||
MsvcToolChain::x86, MsvcToolChain::amd64_x86,
|
||||
MsvcToolChain::amd64, MsvcToolChain::x86_amd64,
|
||||
MsvcToolChain::arm, MsvcToolChain::x86_arm, MsvcToolChain::amd64_arm,
|
||||
MsvcToolChain::ia64, MsvcToolChain::x86_ia64
|
||||
};
|
||||
foreach (const MsvcToolChain::Platform &platform, platforms) {
|
||||
const bool toolchainInstalled = QFileInfo(vcVarsBatFor(path, platform)).isFile();
|
||||
if (hostSupportsPlatform(platform) && toolchainInstalled) {
|
||||
results.append(findOrCreateToolChain(
|
||||
alreadyKnown,
|
||||
generateDisplayName(vsName, MsvcToolChain::VS, platform),
|
||||
findAbiOfMsvc(MsvcToolChain::VS, platform, vsName),
|
||||
vcvarsAllbat, platformName(platform),
|
||||
ToolChain::AutoDetection));
|
||||
}
|
||||
foreach (const VisualStudioInstallation &i, detectVisualStudio()) {
|
||||
for (MsvcToolChain::Platform platform : platforms) {
|
||||
const bool toolchainInstalled =
|
||||
QFileInfo(vcVarsBatFor(i.vcVarsPath, platform, i.version)).isFile();
|
||||
if (hostSupportsPlatform(platform) && toolchainInstalled) {
|
||||
results.append(findOrCreateToolChain(
|
||||
alreadyKnown,
|
||||
generateDisplayName(i.vsName, MsvcToolChain::VS, platform),
|
||||
findAbiOfMsvc(MsvcToolChain::VS, platform, i.vsName),
|
||||
i.vcVarsAll, platformName(platform),
|
||||
ToolChain::AutoDetection));
|
||||
}
|
||||
} else {
|
||||
qWarning("Unable to find MSVC setup script %s in version %d", qPrintable(vcvarsAllbat), version);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "toolchainconfigwidget.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QLabel)
|
||||
QT_FORWARD_DECLARE_CLASS(QVersionNumber)
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
@@ -133,9 +134,8 @@ public:
|
||||
ToolChain *restore(const QVariantMap &data) override;
|
||||
|
||||
ToolChainConfigWidget *configurationWidget(ToolChain *);
|
||||
static QString vcVarsBatFor(const QString &basePath, MsvcToolChain::Platform platform);
|
||||
private:
|
||||
static bool checkForVisualStudioInstallation(const QString &vsName);
|
||||
static QString vcVarsBatFor(const QString &basePath, MsvcToolChain::Platform platform,
|
||||
const QVersionNumber &v);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QRegularExpression>
|
||||
#include <QSettings>
|
||||
|
||||
namespace QbsProjectManager {
|
||||
@@ -158,6 +159,20 @@ QVariantMap DefaultPropertyProvider::properties(const ProjectExplorer::Kit *k,
|
||||
return data;
|
||||
}
|
||||
|
||||
static void filterCompilerLinkerFlags(const ProjectExplorer::Abi &targetAbi, QStringList &flags)
|
||||
{
|
||||
for (int i = 0; i < flags.size(); ) {
|
||||
if (targetAbi.architecture() != ProjectExplorer::Abi::UnknownArchitecture
|
||||
&& flags[i] == QStringLiteral("-arch")
|
||||
&& i + 1 < flags.size()) {
|
||||
flags.removeAt(i);
|
||||
flags.removeAt(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplorer::Kit *k,
|
||||
const QVariantMap &defaultData) const
|
||||
{
|
||||
@@ -208,26 +223,6 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor
|
||||
data.insert(QLatin1String(QBS_TARGETOS), targetOS);
|
||||
|
||||
QStringList toolchain = toolchainList(mainTc);
|
||||
if (!toolchain.isEmpty())
|
||||
data.insert(QLatin1String(QBS_TOOLCHAIN), toolchain);
|
||||
|
||||
if (targetAbi.os() == ProjectExplorer::Abi::DarwinOS) {
|
||||
// Set Xcode SDK name and version - required by Qbs if a sysroot is present
|
||||
// Ideally this would be done in a better way...
|
||||
const QRegExp sdkNameRe(QLatin1String("(macosx|iphoneos|iphonesimulator)([0-9]+\\.[0-9]+)"));
|
||||
const QRegExp sdkVersionRe(QLatin1String("([0-9]+\\.[0-9]+)"));
|
||||
QDir sysrootdir(sysroot);
|
||||
const QSettings sdkSettings(sysrootdir.absoluteFilePath(QLatin1String("SDKSettings.plist")), QSettings::NativeFormat);
|
||||
const QString sdkName(sdkSettings.value(QLatin1String("CanonicalName")).toString());
|
||||
const QString sdkVersion(sdkSettings.value(QLatin1String("Version")).toString());
|
||||
if (sdkNameRe.exactMatch(sdkName) && sdkVersionRe.exactMatch(sdkVersion)) {
|
||||
for (int i = 3; i > 0; --i)
|
||||
sysrootdir.cdUp();
|
||||
data.insert(QLatin1String(CPP_PLATFORMPATH), sysrootdir.absolutePath());
|
||||
data.insert(QLatin1String(CPP_XCODESDKNAME), sdkName);
|
||||
data.insert(QLatin1String(CPP_XCODESDKVERSION), sdkVersion);
|
||||
}
|
||||
}
|
||||
|
||||
Utils::FileName cCompilerPath;
|
||||
if (tcC)
|
||||
@@ -276,10 +271,51 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor
|
||||
data.insert(QLatin1String(CPP_TOOLCHAINPATH), mainFileInfo.absolutePath());
|
||||
|
||||
if (ProjectExplorer::GccToolChain *gcc = dynamic_cast<ProjectExplorer::GccToolChain *>(mainTc)) {
|
||||
data.insert(QLatin1String(CPP_PLATFORMCOMMONCOMPILERFLAGS), gcc->platformCodeGenFlags());
|
||||
data.insert(QLatin1String(CPP_PLATFORMLINKERFLAGS), gcc->platformLinkerFlags());
|
||||
QStringList compilerFlags = gcc->platformCodeGenFlags();
|
||||
filterCompilerLinkerFlags(targetAbi, compilerFlags);
|
||||
data.insert(QLatin1String(CPP_PLATFORMCOMMONCOMPILERFLAGS), compilerFlags);
|
||||
|
||||
QStringList linkerFlags = gcc->platformLinkerFlags();
|
||||
filterCompilerLinkerFlags(targetAbi, linkerFlags);
|
||||
data.insert(QLatin1String(CPP_PLATFORMLINKERFLAGS), linkerFlags);
|
||||
}
|
||||
|
||||
if (targetAbi.os() == ProjectExplorer::Abi::DarwinOS) {
|
||||
// Reverse engineer the Xcode developer path from the compiler path
|
||||
const QRegularExpression compilerRe(
|
||||
QStringLiteral("^(?<developerpath>.*)/Toolchains/(?:.+)\\.xctoolchain/usr/bin$"));
|
||||
const QRegularExpressionMatch compilerReMatch = compilerRe.match(cxxFileInfo.absolutePath());
|
||||
if (compilerReMatch.hasMatch()) {
|
||||
const QString developerPath = compilerReMatch.captured(QStringLiteral("developerpath"));
|
||||
data.insert(QLatin1String(XCODE_DEVELOPERPATH), developerPath);
|
||||
toolchain.insert(0, QStringLiteral("xcode"));
|
||||
|
||||
// If the sysroot is part of this developer path, set the canonical SDK name
|
||||
const QDir sysrootdir(QDir::cleanPath(sysroot));
|
||||
const QString sysrootAbs = sysrootdir.absolutePath();
|
||||
const QSettings sdkSettings(
|
||||
sysrootdir.absoluteFilePath(QStringLiteral("SDKSettings.plist")),
|
||||
QSettings::NativeFormat);
|
||||
const QString version(
|
||||
sdkSettings.value(QStringLiteral("Version")).toString());
|
||||
QString canonicalName(
|
||||
sdkSettings.value(QStringLiteral("CanonicalName")).toString());
|
||||
canonicalName.chop(version.size());
|
||||
if (!canonicalName.isEmpty() && !version.isEmpty()
|
||||
&& sysrootAbs.startsWith(developerPath)) {
|
||||
if (sysrootAbs.toLower().endsWith(QStringLiteral("/%1.sdk")
|
||||
.arg(canonicalName + version)))
|
||||
data.insert(QLatin1String(XCODE_SDK), QString(canonicalName + version));
|
||||
if (sysrootAbs.toLower().endsWith(QStringLiteral("/%1.sdk")
|
||||
.arg(canonicalName)))
|
||||
data.insert(QLatin1String(XCODE_SDK), canonicalName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!toolchain.isEmpty())
|
||||
data.insert(QLatin1String(QBS_TOOLCHAIN), toolchain);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user