Merge remote-tracking branch 'origin/4.2'

Change-Id: I259a402bc896fc2e359cc96b7510453ac9a9a552
This commit is contained in:
Orgad Shaneh
2016-11-28 15:27:51 +02:00
128 changed files with 3030 additions and 1713 deletions
+10
View File
@@ -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)
+24 -2
View File
@@ -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
@@ -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

+44
View File
@@ -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
+54 -79
View File
@@ -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
+1 -1
View File
@@ -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
+55 -2
View File
@@ -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
+2
View File
@@ -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
-773
View File
@@ -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
View File
@@ -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
+7 -7
View File
@@ -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
+7 -7
View File
@@ -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
+2 -2
View File
@@ -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
+8 -7
View File
@@ -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.
+5 -5
View File
@@ -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
+2 -2
View File
@@ -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"
+1 -1
View File
@@ -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:
+66
View File
@@ -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.
*/
+115
View File
@@ -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.
*/
+62
View File
@@ -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.
*/
+349
View File
@@ -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}.
*/
+68
View File
@@ -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
*/
+89
View File
@@ -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.
*/
+54
View File
@@ -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.
*/
+301
View File
@@ -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.
*/
+2
View File
@@ -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"]
}
+2
View File
@@ -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" ]
}
+3
View File
@@ -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
+8 -7
View File
@@ -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')
+19 -47
View File
@@ -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
+3
View File
@@ -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]'
+30 -16
View File
@@ -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
+26 -15
View File
@@ -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)
+45 -18
View File
@@ -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());
}
+15
View File
@@ -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,
-1
View File
@@ -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 -55
View File
@@ -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, &params))) {
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;
+193 -50
View File
@@ -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"},
+9 -1
View File
@@ -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);
+75 -19
View File
@@ -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, &params);
if (FAILED(hr))
if (FAILED(self->m_symbolGroup->GetSymbolParameters(self->m_index, 1, &params)))
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, &params);
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, &params);
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,
+1 -1
View File
@@ -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>
+133 -107
View File
@@ -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;
};
+15 -3
View File
@@ -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
+12 -2
View File
@@ -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
+22 -1
View File
@@ -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
+7
View File
@@ -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;
+5 -3
View File
@@ -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);
+1
View File
@@ -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);
+4 -1
View File
@@ -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);
+2 -2
View File
@@ -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;
}
+3 -2
View File
@@ -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
+5
View File
@@ -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;
+2 -2
View File
@@ -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;
+4 -4
View File
@@ -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));
+3
View File
@@ -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();
+30 -5
View File
@@ -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"
+7 -8
View File
@@ -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);
}
+2 -2
View File
@@ -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);
+4 -1
View File
@@ -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);
+3
View File
@@ -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;
+1 -1
View File
@@ -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);
+9 -6
View File
@@ -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);
+53 -32
View File
@@ -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; });
}
+84 -52
View File
@@ -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;
+8 -1
View File
@@ -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;
+18 -6
View File
@@ -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;
+1
View File
@@ -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;
+144 -101
View File
@@ -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);
}
}
+3 -3
View File
@@ -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