Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.

Creating a new module or tool for Qt: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
(→‎The sync.profile script: Use wiki formatting better)
(→‎The sync.profile script: Switch to DL-form and remove headers that mostly just echoed the DTs.)
Line 163: Line 163:
It may contain the following Perl hashes, and arrays.
It may contain the following Perl hashes, and arrays.


=== modules ===
;<kbd>%modules</kbd>: contains a module's master include name, and the path for the sources, based on <kbd>$basedir</kbd>, which points to the module's base path. For example:
 
* <kbd>%modules</kbd> - contains a module's master include name, and the path for the sources, based on <kbd>$basedir</kbd>, which points to the modules base path. For example:
<code>%modules = ( # path to module name map
<code>%modules = ( # path to module name map
  "QtScript" => "$basedir/src/script",
  "QtScript" => "$basedir/src/script",
Line 171: Line 169:
);</code>
);</code>


=== moduleheaders ===
;<kbd>%moduleheaders</kbd>: restricts the module headers to only those found in these relative paths.
: ''Not really used (used by <kbd>-separate-module</kbd> command line option), use above variable for individual modules.''


* <kbd>%moduleheaders</kbd> - restricts the module headers to only those found in these relative paths.
;<kbd>%classnames</kbd>: contains a header file, and its C++ filename equivalent. (To be used if the file do not really have a C++ class with that name.)  For example:
''Not really used (used by <kbd>-separate-module</kbd> command line option), use above variable for individual modules.
* <kbd>%classnames</kbd>- contains a header file, and its C++ filename equivalent. (To be used if the file do not really have a C++ class with that name.)  For example:
<code>%classnames = (
<code>%classnames = (
  "qglobal.h" => "QtGlobal",
  "qglobal.h" => "QtGlobal",
Line 182: Line 179:
);</code>
);</code>


=== classnames ===
:* Under <kbd>%classnames</kbd>, there is one line like "qtmoduleversion.h" => "QtModuleVersion"
 
:: Here the qtmoduleversion.h was generated by syncqt, just to get a new name based on above rules.
* Under <kbd>%classnames</kbd>, there is one line like "qtmoduleversion.h" => "QtModuleVersion"
:: For this qtmoduleversion.h, it was based on the info from the module .pri file.
: Here the qtmoduleversion.h was generated by syncqt, just to get a new name based on above rules.
:* For example:
: For this qtmoduleversion.h, it was based on the info from the module .pri file.
:: for QtDeclarative module in qtdeclarative repo,
* For example:
:: based on <kbd>QT.declarative.MAJOR_VERSION</kbd>, <kbd>QT.declarative.MINOR_VERSION</kbd> and <kbd>QT.declarative.PATCH_VERSION</kbd> in modules/qt_declarative.pri file
: for QtDeclarative module in qtdeclarative repo,
:: it will generate a src/declarative/qtdeclarativeversion.h
: based on <kbd>QT.declarative.MAJOR_VERSION</kbd>, <kbd>QT.declarative.MINOR_VERSION</kbd> and <kbd>QT.declarative.PATCH_VERSION</kbd> in modules/qt_declarative.pri file
:: Please remember to add this file in qtdeclarative repo .gitignore file.
: it will generate a src/declarative/qtdeclarativeversion.h
: Please remember to add this file in qtdeclarative repo .gitignore file.
 
=== mastercontent ===


* <kbd>%mastercontent</kbd> - contains extra content for a library's master include. For example:
;<kbd>%mastercontent</kbd>: contains extra content for a library's master include. For example:
<code>%mastercontent = (
<code>%mastercontent = (
  "core" => "#include <QtCore/QtCore>",
  "core" => "#include <QtCore/QtCore>",
Line 202: Line 195:
);</code>
);</code>


There are a few things going on here that should be explained further.
: There are a few things going on here that should be explained further. To avoid talking about abstracts, let's use qtsensors as a concrete example.
To avoid talking about abstracts, let's use qtsensors as a concrete example.


The qtsensors module repository has a module, QtSensors. The source code of the module lives under src/sensors and the master header is QtSensors/QtSensors. Since this module specifies <kbd>QT = core</kbd> in its .pro file and since sync.profile specifies some mastercontent for core, that content goes into the master header before any of the generated include lines.
: The qtsensors module repository has a module, QtSensors. The source code of the module lives under src/sensors and the master header is QtSensors/QtSensors. Since this module specifies <kbd>QT = core</kbd> in its .pro file and since sync.profile specifies some mastercontent for core, that content goes into the master header before any of the generated include lines.
<code>
<code>
#ifndef QT_QTSENSORS_MODULE_H
#ifndef QT_QTSENSORS_MODULE_H
Line 213: Line 205:
</code>
</code>
It's not completely clear why this is important.
: It's not completely clear why this is important. It possibly makes some sense when you have pre-compiled headers in use.
It possibly makes some sense when you have pre-compiled headers in use.
 
=== modulepris ===


* <kbd>%modulepris</kbd> - contains the module master include name, and the path to the module's qmake include file.  For example:
;<kbd>%modulepris</kbd>: contains the module master include name, and the path to the module's qmake include file.  For example:
<code>%modulepris = (
<code>%modulepris = (
  "QtScript" => "$basedir/modules/qt_script.pri",
  "QtScript" => "$basedir/modules/qt_script.pri",
Line 224: Line 213:
);</code>
);</code>


===  dependencies ===
;<kbd>%dependencies</kbd>: contains the other module repositories that are required to build this module repository, as well as the refs or SHA1s which should be used in them. Note that this should be all module repos needed to build this module repo, not just direct dependencies. For example:
 
<code>
* <kbd>%dependencies</kbd> - contains the other module repositories that are required to build this module repository, as well as the refs or SHA1s which should be used in them.
Note that this should be all module repos needed to build this module repo, not just direct dependencies.
ex: <code>
%dependencies = (
%dependencies = (
  "qtbase" => "refs/heads/branchWithExperimentalStuff",
  "qtbase" => "refs/heads/branchWithExperimentalStuff",
Line 240: Line 226:
=== other fields ===
=== other fields ===


* <kbd>@ignore_for_master_contents</kbd> - list of files to not check for any master content. For example: <kbd>@ignore_for_master_contents = ( "qt.h", "qpaintdevicedefs.h" );</kbd>
;<kbd>@ignore_for_master_contents</kbd>: list of files to not check for any master content. For example: <kbd>@ignore_for_master_contents = ( "qt.h", "qpaintdevicedefs.h" );</kbd>
* <kbd>@ignore_for_include_check</kbd> - list of files to not process at all.  For example: <kbd>@ignore_for_include_check = ( "qatomic.h" );</kbd>
;<kbd>@ignore_for_include_check</kbd>: list of files to not process at all.  For example: <kbd>@ignore_for_include_check = ( "qatomic.h" );</kbd>
* <kbd>@ignore_for_qt_begin_header_check</kbd>- list of files to not check for a begin header.  For example: <kbd>@ignore_for_qt_begin_header_check = ( "qconfig.h", "qfeatures.h", "qt_windows.h" );</kbd>
;<kbd>@ignore_for_qt_begin_header_check</kbd>: list of files to not check for a begin header.  For example: <kbd>@ignore_for_qt_begin_header_check = ( "qconfig.h", "qfeatures.h", "qt_windows.h" );</kbd>
* <kbd>@ignore_for_qt_begin_namespace_check</kbd> - list of files to not check for begin namespace.  For example: <kbd>@ignore_for_qt_begin_namespace_check = ( "qconfig.h", "qfeatures.h", "qt_windows.h", "qatomic_arch.h" );</kbd>
;<kbd>@ignore_for_qt_begin_namespace_check</kbd>: list of files to not check for begin namespace.  For example: <kbd>@ignore_for_qt_begin_namespace_check = ( "qconfig.h", "qfeatures.h", "qt_windows.h", "qatomic_arch.h" );</kbd>
* <kbd>@ignore_for_qt_module_check</kbd> - list of paths to avoid checking for module. For example: <kbd>@ignore_for_qt_module_check = ( "$modules{QtCore}/arch", "$modules{QtSql}/drivers", "$modules{phonon}" );</kbd>
;<kbd>@ignore_for_qt_module_check</kbd>: list of paths to avoid checking for module. For example: <kbd>@ignore_for_qt_module_check = ( "$modules{QtCore}/arch", "$modules{QtSql}/drivers", "$modules{phonon}" );</kbd>


== Library specific .pro files ==
== Library specific .pro files ==

Revision as of 17:01, 14 September 2016


Warning: This page is significantly outdated in many details

Getting started with new ideas on Qt Project's Playground.

It's easy to kick off a new module or tool in the Qt project. With the approval of a Qt Maintainer, you can request a new project to be added to the Qt Playground area of codereview.qt-project.org. We want to keep the barrier low so please don't hesitate to get started with your new idea in the Playground even if you're not sure whether the project will lead into anything real.

Here are the steps:

  1. Write a short description of your project
  2. Choose a descriptive playground project name. The name should not include "Qt". For example "Extra Effects", "Mime Types". The reason for not including the Qt name is that the good descriptive Qt prefixed names are reserved for projects that are actual Qt modules or tools. The playground modules do not have the status of being closely associated with Qt yet.
  3. Send your request for a new Playground project (including project name and description) to the "Qt Development List":mailto:development@qt-project.org mailing list
  4. Get approval from one Qt maintainer for your new playground project on the mailing list
  5. After a Qt maintainer has confirmed the approval, create a task in the Qt Project bug tracker (QTQAINFRA project, Gerrit component) requesting a new Gerrit project for you. Refer to the mailing list archives for the approval from a Qt Maintainer
  6. Keep calm and hack on

In your playground project, you use the

Playground

QML import path. If your Playground project is called "Extra Effects", then it is imported by

import Playground.ExtraEffects 0.1

Moving an existing project to the Qt Project.

If your project has already been started outside the Qt Project, it can still be moved to the Qt Project, either as a new Playground project or as a new Qt Add-On module or tool.

If you want to move your existing project to the Qt Project, then follow these steps:

  1. Send your request for moving an existing project to the Qt Project (including project name and description) to the "Qt Development List":mailto:development@qt.io mailing list
  2. If you want the project to be moved to the Playground, then you need to get an approval from one Qt maintainer on the mailing list
  3. If your project is well established and mature, you can alternatively request the project to be moved to the Qt Project as a new Qt Add-On module or tool. This requires discussion on the "Qt Development List":development@qt.io mailing list and the approval of the Chief Maintainer for the technical fit and spirit fit to Qt. Other technical reviews may be needed as well (TO BE CLARIFIED)
  4. After you have the approval from the mailing list, create a task in the Qt Project bug tracker ("QTQAINFRA"::https://bugreports.qt.io/browse/QTQAINFRA/component/19470 project, Gerrit component) requesting a new Gerrit project for you. Refer to the mailing list archives for the approval from a Qt Maintainer (for Playground projects) or Chief Maintainer (for new Qt modules and tools). Remember to mention that this is an existing project that will be moved to the Qt Project
  5. A special contribution agreement will be created for your project. All existing contributors need to accept the contribution agreement before the project can be moved (see Qt Project Legal Aspects)

Automated testing for Playground projects.

To be added. How to provide automated testing and test results for Playground projects?

Graduating from the Playground.

Once your project becomes more mature, it can be moved out of the playground, and become a Qt module or tool. This decision is done on the qt-development mailing list, based on the technical and spirit fit to Qt, and it requires the approval of the Chief Maintainer.

When your project is moved from the playground to the Qt project area, the playground name needs to be changed to a descriptive Qt module or tool name.

Guidelines for choosing good module and tool names.

Generally, module and tool names should be descriptive. The names describe the core of the function or benefit. Branded names are generally not recommended. Examples of good descriptive names include Qt Designer, Qt Core, Qt Location, Qt Sensors, and Qt Document Gallery.

If a proposed new name is not a simple descriptive term, then Legal and connotation checks are needed. These checks would have to be done on a national level for the regions where Qt is used, so they are complex and expensive. Therefore, names that require such checks are discouraged. If a name that requires Legal and connotation checks is still desired, then the maintainer should escalate to the Chief Maintainer.

General name related criteria:

  • Names fit the existing name and terminology range. For example for a new tool, consider following the example of the existing names Qt Designer, Qt Linguist, Qt Creator.
  • Difficult terminology is avoided and names are factually correct
  • Names should be chosen for long-term use
  • Try to avoid acronyms. Do not follow the example of Qt JSON DB. See this wiki for the spelling of module names.
  • Names work well in documentation and communications
  • Names are easy to understand and remember. Prefer short and simple names.
  • Names are free of negative meanings and connotations in different cultures and languages
  • Names are available (if legal consultation needed please see Qt Project legal contact information from: Qt Project Legal Aspects)

Don't use:

  • Third party technology names or trademarks or industry standard names as part of the name. Names such as "Qt V8" do not work. In a possible trademark enforcement action, we might be forced to remove the trademark from our code, which would break compatibility. Therefore, you should avoid using trademarks anywhere in the code (file names, class names, methods and so on). Sometimes, it is necessary to call a 3rd party product or technology with its real name; in these cases, use of a 3rd party trademark may be possible under "fair use" guidelines. In such cases, please discuss with Qt Project Legal (Qt Project Legal Aspects).
  • Any play on names. For example don't alter, derivate, conjugate or combine words to others. Don't follow the example of "ActiveQt" or "Qt MultimediaKit".
  • Slang in names

Using the module name in application code and documentation.

Once you have selected a name for your new module, you need to start using the name of the module in the code consistently. Be always consistent with your module name: choose just one name and spell it always in the same way. Use the same name in the C++ context and in QML: talk about the C++ API of your module or the QML API of your module.

In QML, applications should be able to start using any Qt module with the following QML import statement: import <module name>.<extension> <version>

For example:

import QtContacts 5.0
import QtQuick.Particles 2.0
import QtExample.UseCamelCaseHere 5.0

Since the module repository structure should not be exposed to the user of Qt (see below), we use import statements like

import QtContacts 5.0

instead of -

import QtPim.Contacts 5.0

-. Qt modules are recommended to wrap their public API in a C++ namespace, to avoid clashes in symbol naming with other Qt libraries. The C++ namespace is the module name in camel-case format, for example:

QtFeedback

,

QtJsonDb

,

QtContacts

and

QtBluetooth

. Namespaces are especially recommended for Qt Add-On modules. However, former Qt 4 modules do not use a namespace for source compatibility reasons. If the module doesn't have a namespace, then the usual conventions for naming classes and functions apply (

QMyClass

etc.). When naming classes of a module that uses a namespace, a good practice is use simple non-prefixed class names within the C++ namespace. Naming classes like

QMyClass

is also OK within a namespace.

Include directives work similarly for all Qt modules:

//modules are added to the include path, so these include directives work:
#include <QtFoo> /* include all classes of the module */
#include <QBar> /''' include one class */

//if two modules use the same class name, you can do this:
#include <QtFoo/QBar>

Libraries are named libqtfoo.so.5.0, QtFoo5.dll etc.

The qmake .pro file usage does not change from Qt 4. Both Qt Essentials and Qt Add-On modules need to provide a .pri file so that Qt applications can add the module to a project with the familiar way (more about this below):

QT += module

It is important to be consistent and use the same name for the module in all these places, and in the documentation.

The structure of a new module repository.

A module is a collection of library/-ies, documentation, examples, demos and tests.

Sometimes several modules share a source code repository. The qtbase, qtsystems, and qtpim repos are examples of such module repositories. In these cases, the name of the module repository is an implementation detail. The modules should be named and treated independently in the documentation.

It is recommended that a module repository follows the following structure:

README
  • LICENSE
    
  • bin/
    
    - Where all binaries of the module is/will be located
  • examples/
    
    - Where the examples of the module will be located
  • lib/
    
    - Where the libraries of a module will be located (for non-local install prefixes)
  • plugins/
    
    - Where the plugins of a module will be located (for non-local install prefixes)
  • imports/
    
    - Where the QML imports of a module will be located (for non-local install prefixes)
  • src/
    
    - Source code for all libraries of the module
  • src/[modulename]/doc/
    
    - Where the documentation of the module will be located.
    [modulename]
    
    is optional when the repository only contains one module.
  • modules/qt_<module>.pri
    
    for all modules
  • tests/auto/
    
    - All the auto-tests for all the modules
  • tests/benchmarks/
    
    - All the benchmarking tests for all the modules
  • <repository>.pro
    
    - A module repository's qmake top-level project file, which is responsible for compiling the complete project, with targets to generate the module's documentation.
  • sync.profile
    

The qt_<module>.pri files.

qt_<module>.pri

is a module specific file, of which a module repository may have several. The typical location for this file is under the

modules/

directory of a repository, but the location can be arbitrary, as it is referred to by the sync.profile file. The

qt_<module>.pri

file is a normal qmake include file, and is loaded before a projects .pro file is parsed. This means that all the variables defined by a module is available to any project. Due to this, the variables should be scoped under

QT.<module>

Each module requires a certain set of variables to be defined:

  • QT.<module>.name
    
    - Full name of module, f.ex. QtScriptTools
  • QT.<module>.bins
    
    - Path of bin/ directory, typically
    $$QT_MODULE_BIN_BASE
    
  • QT.<module>.includes
    
    - Path of include/, typically
    $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/$$QT.<module>.name
    
  • QT.<module>.private_includes
    
    - Path of private includes. typically
    $$QT_MODULE_INCLUDE_BASE/$$QT.<library>.name/private
    
    . The new sanctioned way is using the version, i.e.
    $$QT_MODULE_INCLUDE_BASE/<module>/$$QT.<module>.VERSION
    
  • QT.<module>.sources
    
    - Path of source code, typically
    $$QT_MODULE_BASE/src
    
  • QT.<module>.libs
    
    - Path of lib/. typically
    $$QT_MODULE_LIB_BASE
    
  • QT.<module>.plugins
    
    - Path of plugins/. typically
    $$QT_MODULE_PLUGIN_BASE
    
  • QT.<module>.imports
    
    - Path of imports/. typically
    $$QT_MODULE_IMPORT_BASE
    
  • QT.<module>.depends
    
    - The modules listed here should be all dependencies required to use <module>.

A module should be listed here if <module> uses its includes, symbols or macro definitions in its own public API and headers. For example, if public headers of a dependency are used in the public headers of <module>, that dependency should be listed here. Similarly, if a preprocessor macro or compiler flag is required to use the dependency, and that macro is used in the public headers of <module>, then that is a public dependency that should be listed here.

Optional:

  • QT.<module>.CONFIG
    
    - CONFIG Options to add to project when this module is used
  • QT.<module>.DEFINES
    
    - Defines to add to the project when this module is used

If Qt is not a system install, syncqt will create forwarding .pri's in

mkspecs/modules/

, which populates the variables

QT_MODULE_BASE

,

QT_MODULE_BIN_BASE

,

QT_MODULE_INCLUDE_BASE

,

QT_MODULE_LIB_BASE

with the appropriate paths before including the module pri file. In a system install Qt, the

mkspecs/modules/

pri files are the original, and the above variables contain the paths of which Qt has been configured with. This means that for a developer build of Qt (where prefix points to the build directory), modules can be used without running 'make install' as soon as it's built. However, system install Qt requires you to

make install

every time you do a recompile in the module repository.

The sync.profile script

The sync.profile file is a Perl script which contains settings for the module repository. syncqt uses this file to create forward include files, and forwarding qmake-include (pri) files.

The %dependencies variable is also used by build-bots to determine what other module repositories, and at which revision, are needed to build the module repository.

It may contain the following Perl hashes, and arrays.

%modules
contains a module's master include name, and the path for the sources, based on $basedir, which points to the module's base path. For example:
%modules = ( # path to module name map
 "QtScript" => "$basedir/src/script",
 "QtScriptTools" => "$basedir/src/scripttools",
);
%moduleheaders
restricts the module headers to only those found in these relative paths.
Not really used (used by -separate-module command line option), use above variable for individual modules.
%classnames
contains a header file, and its C++ filename equivalent. (To be used if the file do not really have a C++ class with that name.) For example:
%classnames = (
 "qglobal.h" => "QtGlobal",
 "qnamespace.h" => "Qt",
 "qdebug.h" => "QtDebug"
);
  • Under %classnames, there is one line like "qtmoduleversion.h" => "QtModuleVersion"
Here the qtmoduleversion.h was generated by syncqt, just to get a new name based on above rules.
For this qtmoduleversion.h, it was based on the info from the module .pri file.
  • For example:
for QtDeclarative module in qtdeclarative repo,
based on QT.declarative.MAJOR_VERSION, QT.declarative.MINOR_VERSION and QT.declarative.PATCH_VERSION in modules/qt_declarative.pri file
it will generate a src/declarative/qtdeclarativeversion.h
Please remember to add this file in qtdeclarative repo .gitignore file.
%mastercontent
contains extra content for a library's master include. For example:
%mastercontent = (
 "core" => "#include <QtCore/QtCore>",
 "gui" => "#include <QtGui/QtGui>",
 "scripttools" => "#include <QtScriptTools/QtScriptTools>",
);
There are a few things going on here that should be explained further. To avoid talking about abstracts, let's use qtsensors as a concrete example.
The qtsensors module repository has a module, QtSensors. The source code of the module lives under src/sensors and the master header is QtSensors/QtSensors. Since this module specifies QT = core in its .pro file and since sync.profile specifies some mastercontent for core, that content goes into the master header before any of the generated include lines.
#ifndef QT_QTSENSORS_MODULE_H
#define QT_QTSENSORS_MODULE_H
#include <QtCore/QtCore>
#include "qaccelerometer.h"

It's not completely clear why this is important. It possibly makes some sense when you have pre-compiled headers in use.
%modulepris
contains the module master include name, and the path to the module's qmake include file. For example:
%modulepris = (
 "QtScript" => "$basedir/modules/qt_script.pri",
 "QtScriptTools" => "$basedir/modules/qt_scripttools.pri",
);
%dependencies
contains the other module repositories that are required to build this module repository, as well as the refs or SHA1s which should be used in them. Note that this should be all module repos needed to build this module repo, not just direct dependencies. For example:
%dependencies = (
 "qtbase" => "refs/heads/branchWithExperimentalStuff",
 "qtscript" => "refs/heads/master",
 "qtsvg" => "refs/heads/master",
 "qtxmlpatterns" => "refs/heads/master",
 "qttools" => "01c57f35feac99ce910a56d0d1906717d27e2a62",
);

other fields

@ignore_for_master_contents
list of files to not check for any master content. For example: @ignore_for_master_contents = ( "qt.h", "qpaintdevicedefs.h" );
@ignore_for_include_check
list of files to not process at all. For example: @ignore_for_include_check = ( "qatomic.h" );
@ignore_for_qt_begin_header_check
list of files to not check for a begin header. For example: @ignore_for_qt_begin_header_check = ( "qconfig.h", "qfeatures.h", "qt_windows.h" );
@ignore_for_qt_begin_namespace_check
list of files to not check for begin namespace. For example: @ignore_for_qt_begin_namespace_check = ( "qconfig.h", "qfeatures.h", "qt_windows.h", "qatomic_arch.h" );
@ignore_for_qt_module_check
list of paths to avoid checking for module. For example: @ignore_for_qt_module_check = ( "$modules{QtCore}/arch", "$modules{QtSql}/drivers", "$modules{phonon}" );

Library specific .pro files

A module library/appliction can start its .pro file with a

load(qt_module)

to expose critical Qt configuration variables, such as

QMAKE_MOC

,

QMAKE_LFLAGS

,

QT_CFLAGS''<subsystem>

,

QMAKESPEC

, etc.

Getting a module repository integrated with the Qt 5 build and repository system

To get your module repository integrated as part of the Qt5 build and repo system follow these steps, and submit the changes.

  • Add the new submodule (replace qt-quick3d with your module details):
cd ~/depot
git clone git@gitorious.org:qt/qt5.git
cd qt5
git submodule add git://gitorious.org/qt-quick3d/qt-quick3d.git qtquick3d

' This should create a new directory inside~/depot/qt5 named after your module, and also

cat .gitmodule

should show your module.

  • Edit
    qt.pro
    
    and
    init-repository
    
    scripts
    • Do a
      git show f7225b87a9e9e8379c627c6771ee5b2bc6492f73
      
      for an example
    • First add your module to qt.pro so that it can be built by typing
      make module-qtquick3d
      
      for example, but is not built by default
    • Add the gerrit and/or gitorious repos for your module to the list
  • Suggest debugging your new qt5 changes to check they work
mkdir -p ~/test_depot && cd~/test_depot
git clone ~/depot/qt5 && cd qt5
./init-repository no-webkit nokia-developer brisbane codereview-username sarasmit
    • check that the script successfully checks out your project and the other projects