summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominik Holland <dominik.holland@qt.io>2019-10-07 16:38:48 +0200
committerDominik Holland <dominik.holland@qt.io>2019-10-29 17:26:28 +0100
commit25ba2939cace6bfbc065f3c8ea8cfe6d72eb5c17 (patch)
treed2475a26e8ed1332ee9abd83f70b17d05f52234a
parent25b1d344d1f5b5fe791f9c9893adfc59a8db60e5 (diff)
downloadqtivi-25ba2939cace6bfbc065f3c8ea8cfe6d72eb5c17.tar.gz
ivigenerator: Add support to import other modules
When importing another module from within a QFace file, the generator now searches within the QFace import path. If this module is found, the information is then used to generate code that includes types from this module. The QFace import path can be set in the autogenerator similar to qmlscene by using the -I option; in qmake it can be set using QFACE_IMPORT_PATH. The generator makes sure to generate correct code, but the developer still needs to setup the .pro files correctly to add the imported module to the INCLUDEPATH and also link to the generated library. Fixes: AUTOSUITE-1158 Change-Id: I0e9fa714d4c893a4bf17c5f7db34c62d84932c94 Reviewed-by: Robert Griebl <robert.griebl@qt.io>
-rw-r--r--mkspecs/features/ivigenerator.prf10
-rw-r--r--src/ivicore/doc/src/ivigenerator/generator-usage.qdoc7
-rw-r--r--src/ivicore/doc/src/ivigenerator/ivigenerator.qdoc1
-rw-r--r--src/ivicore/doc/src/ivigenerator/qmake-integration.qdoc4
-rwxr-xr-xsrc/tools/ivigenerator/generate.py65
-rw-r--r--src/tools/ivigenerator/templates_frontend/module.cpp.tpl13
-rw-r--r--src/tools/ivigenerator/templates_frontend/module.h.tpl14
-rw-r--r--src/tools/ivigenerator/templates_frontend/struct.h.tpl4
-rw-r--r--tests/auto/core/ivigenerator/include-test.qface115
-rw-r--r--tests/auto/core/ivigenerator/ivigenerator.pro3
-rw-r--r--tests/auto/core/ivigenerator/projects/include-test/backend_qtro/backend_qtro.pro16
-rw-r--r--tests/auto/core/ivigenerator/projects/include-test/backend_simulator/backend_simulator.pro16
-rw-r--r--tests/auto/core/ivigenerator/projects/include-test/common/common.pro14
-rw-r--r--tests/auto/core/ivigenerator/projects/include-test/frontend/frontend.pro17
-rw-r--r--tests/auto/core/ivigenerator/projects/include-test/include-test.pro22
-rw-r--r--tests/auto/core/ivigenerator/projects/include-test/qmlplugin/qmlplugin.pro12
-rw-r--r--tests/auto/core/ivigenerator/projects/include-test/simulation_server_qtro/simulation_server_qtro.pro16
-rw-r--r--tests/auto/core/ivigenerator/projects/include-test/test/test.pro15
-rw-r--r--tests/auto/core/ivigenerator/projects/projects.pro1
-rw-r--r--tests/auto/core/ivigenerator/qface imports/common.qface20
20 files changed, 360 insertions, 25 deletions
diff --git a/mkspecs/features/ivigenerator.prf b/mkspecs/features/ivigenerator.prf
index 90f04c5..3330fdc 100644
--- a/mkspecs/features/ivigenerator.prf
+++ b/mkspecs/features/ivigenerator.prf
@@ -79,17 +79,23 @@ IVI_GENERATOR_OPTIONS = --format=$$QFACE_FORMAT --force
for (ANNOTATION, QFACE_ANNOTATIONS) {
file = $$absolute_path($$ANNOTATION, $$_PRO_FILE_PWD_)
- IVI_GENERATOR_OPTIONS += -A $$system_path($$file)
+ IVI_GENERATOR_OPTIONS += -A $$system_quote($$system_path($$file))
qface_sources.depends += $$file
OTHER_FILES += $$file
}
+for (IMPORT, QFACE_IMPORT_PATH) {
+ dir = $$absolute_path($$IMPORT, $$_PRO_FILE_PWD_)
+
+ IVI_GENERATOR_OPTIONS += -I $$system_quote($$system_path($$dir))
+}
+
# Windows doesn't offer any other way to sleep for a time inside non-interactive scripts
equals(QMAKE_HOST.os, Windows): SLEEP = ping -n 2 127.0.0.1 >nul
else: SLEEP = sleep 1
qface_sources.target = $$relative_path($$PRI, $$OUT_PWD)
-qface_sources.commands = $$SLEEP && $$ENV $$system_path($$IVI_GENERATOR) $$IVI_GENERATOR_OPTIONS $$system_path($$QFACE_ABS_PWD/$${QFACE_FILE}) $$system_path($$QFACE_OUTPUT_DIR)
+qface_sources.commands = $$SLEEP && $$ENV $$system_path($$IVI_GENERATOR) $$IVI_GENERATOR_OPTIONS $$system_quote($$system_path($$QFACE_ABS_PWD/$${QFACE_FILE})) $$system_quote($$system_path($$QFACE_OUTPUT_DIR))
qface_sources.depends = $$IVI_GENERATOR_PATH/generate.py
qface_sources.depends += $$QFACE_ABS_PWD/$${QFACE_FILE}
qface_sources.depends += $$files($$IVI_GENERATOR_PATH/common/*)
diff --git a/src/ivicore/doc/src/ivigenerator/generator-usage.qdoc b/src/ivicore/doc/src/ivigenerator/generator-usage.qdoc
index ba45323..287dc99 100644
--- a/src/ivicore/doc/src/ivigenerator/generator-usage.qdoc
+++ b/src/ivicore/doc/src/ivigenerator/generator-usage.qdoc
@@ -77,6 +77,13 @@
overrides the previously set value. This option can be used multiple times. For
more information, see \l{merge-annotations}{Merge Annotations}.
\row
+ \target import-option
+ \li -I, --import <import-path>
+ \li Adds the given path to the list of import paths. All directories in this list are
+ scanned recursively for QFace files. The QFace files found are then used to resolve
+ the information required when importing a module; this is similar to how C++ include
+ paths work.
+ \row
\li source
\li Path or paths to the IDL source files. If there are multiple entries, each one is
handled. If a directory path is provided, it's scanned for IDL files.
diff --git a/src/ivicore/doc/src/ivigenerator/ivigenerator.qdoc b/src/ivicore/doc/src/ivigenerator/ivigenerator.qdoc
index 2d62ed5..5ff1c97 100644
--- a/src/ivicore/doc/src/ivigenerator/ivigenerator.qdoc
+++ b/src/ivicore/doc/src/ivigenerator/ivigenerator.qdoc
@@ -50,7 +50,6 @@ QFace library, that provides a generic autogeneration framework.
Currently, Qt IVI generator has the following limitations:
\list
- \li It's not possible to import other QFace modules using the \c import command.
\li There's no support for external C++ types, outside of the IDL, such as reusing a
QGeoCoordinate inside a QFace IDL.
\li The \c map<> type is not supported.
diff --git a/src/ivicore/doc/src/ivigenerator/qmake-integration.qdoc b/src/ivicore/doc/src/ivigenerator/qmake-integration.qdoc
index 7b79d1e..f4f2d16 100644
--- a/src/ivicore/doc/src/ivigenerator/qmake-integration.qdoc
+++ b/src/ivicore/doc/src/ivigenerator/qmake-integration.qdoc
@@ -71,6 +71,10 @@ The following qmake variables are available:
\li QFACE_ANNOTATIONS
\li A list of additional annotation files in YAML format. For more information, see the
\l{annotations-option}{Annotations Option}.
+ \row
+ \li QFACE_IMPORT_PATH
+ \li A list of import paths, which are considered when an IDL file uses an import statement.
+ For more information, see the \l{imports-option}{Import Option}.
\endtable
For more details on the generator's command line arguments, see \l {Use the Generator}.
diff --git a/src/tools/ivigenerator/generate.py b/src/tools/ivigenerator/generate.py
index b792797..e2b0b6c 100755
--- a/src/tools/ivigenerator/generate.py
+++ b/src/tools/ivigenerator/generate.py
@@ -44,6 +44,7 @@ import click
import logging.config
import yaml
import json
+import sys
from path import Path
from qface.generator import FileSystem, Generator
@@ -175,7 +176,7 @@ def default_type_value(symbol):
nested = Filters.returnType(symbol.type.nested)
return 'QVariantList()'.format(nested)
elif symbol.type.is_struct:
- return '{0}{1}()'.format(prefix, symbol.type)
+ return '{0}{1}()'.format(prefix, symbol.type.reference.name)
elif symbol.type.is_model:
return 'nullptr'
jinja_error('default_type_value: Unknown parameter {0} of type {1}'.format(symbol, symbol.type))
@@ -214,7 +215,7 @@ def test_type_value(symbol):
return 'QVariantList({{{0}}})'.format(value)
elif symbol.type.is_struct:
values_string = ', '.join(test_type_value(e) for e in symbol.type.reference.fields)
- return '{0}{1}({2})'.format(prefix, symbol.type, values_string)
+ return '{0}{1}({2})'.format(prefix, symbol.type.reference.name, values_string)
elif symbol.type.is_model:
return 'new QIviPagingModel()'
jinja_error('test_type_value: Unknown parameter {0} of type {1}'.format(symbol, symbol.type))
@@ -279,7 +280,7 @@ def parameter_type_default(symbol):
"""
prefix = Filters.classPrefix
if symbol.type.is_enum or symbol.type.is_flag:
- return '{0}{1}Module::{2} {3}={4}'.format(prefix, upper_first(symbol.module.module_name), flag_type(symbol), symbol, default_type_value(symbol))
+ return '{0}{1}Module::{2} {3}={4}'.format(prefix, upper_first(symbol.type.reference.module.module_name), flag_type(symbol), symbol, default_type_value(symbol))
if symbol.type.is_void or symbol.type.is_primitive:
if symbol.type.name == 'string':
return 'const QString &{0}=QString()'.format(symbol)
@@ -298,7 +299,7 @@ def parameter_type_default(symbol):
elif nested.is_complex:
return 'QIviPagingModel *{0}=nullptr'.format(symbol)
else:
- return 'const {0}{1} &{2}={0}{1}()'.format(prefix, symbol.type, symbol)
+ return 'const {0}{1} &{2}={0}{1}()'.format(prefix, symbol.type.reference.name, symbol)
jinja_error('parameter_type_default: Unknown parameter {0} of type {1}'.format(symbol, symbol.type))
def parameter_type(symbol):
@@ -307,7 +308,7 @@ def parameter_type(symbol):
"""
prefix = Filters.classPrefix
if symbol.type.is_enum or symbol.type.is_flag:
- return '{0}{1}Module::{2} {3}'.format(prefix, upper_first(symbol.module.module_name), flag_type(symbol), symbol)
+ return '{0}{1}Module::{2} {3}'.format(prefix, upper_first(symbol.type.reference.module.module_name), flag_type(symbol), symbol)
if symbol.type.is_void or symbol.type.is_primitive:
if symbol.type.name == 'string':
return 'const QString &{0}'.format(symbol)
@@ -326,7 +327,7 @@ def parameter_type(symbol):
elif nested.is_complex:
return 'QIviPagingModel *{0}'.format(symbol)
else:
- return 'const {0}{1} &{2}'.format(prefix, symbol.type, symbol)
+ return 'const {0}{1} &{2}'.format(prefix, symbol.type.reference.name, symbol)
jinja_error('parameter_type: Unknown parameter {0} of type {1}'.format(symbol, symbol.type))
@@ -336,7 +337,7 @@ def return_type(symbol):
"""
prefix = Filters.classPrefix
if symbol.type.is_enum or symbol.type.is_flag:
- return('{0}{1}Module::{2}'.format(prefix, upper_first(symbol.module.module_name), flag_type(symbol)))
+ return('{0}{1}Module::{2}'.format(prefix, upper_first(symbol.type.reference.module.module_name), flag_type(symbol)))
if symbol.type.is_void or symbol.type.is_primitive:
if symbol.type.name == 'string':
return 'QString'
@@ -355,7 +356,7 @@ def return_type(symbol):
elif nested.is_complex:
return 'QIviPagingModel *'
else:
- return '{0}{1}'.format(prefix, symbol.type)
+ return '{0}{1}'.format(prefix, symbol.type.reference.name)
jinja_error('return_type: Unknown symbol {0} of type {1}'.format(symbol, symbol.type))
@@ -679,24 +680,25 @@ def model_type(symbol):
def struct_includes(symbol):
includesSet = set()
tpl = '#include \"{0}.h\"'
+
if isinstance(symbol, Struct):
for val in symbol.fields:
if val.type.is_struct:
- includesSet.add(tpl.format(val.type).lower())
+ includesSet.add(tpl.format(val.type.reference.name).lower())
elif isinstance(symbol, Interface):
for val in symbol.properties:
if val.type.is_struct:
- includesSet.add(tpl.format(val.type).lower())
+ includesSet.add(tpl.format(val.type.reference.name).lower())
for op in symbol.operations:
for param in op.parameters:
if param.type.is_struct:
- includesSet.add(tpl.format(param.type).lower())
+ includesSet.add(tpl.format(param.type.reference.name).lower())
if op.type.is_struct:
- includesSet.add(tpl.format(op.type).lower())
+ includesSet.add(tpl.format(op.type.reference.name).lower())
for op in symbol.signals:
for param in op.parameters:
if param.type.is_struct:
- includesSet.add(tpl.format(param.type).lower())
+ includesSet.add(tpl.format(param.type.reference.name).lower())
return includesSet
@@ -726,11 +728,20 @@ def comment_text(comment):
processed.append(line)
return processed
-def generate(tplconfig, moduleConfig, annotations, src, dst):
+def generate(tplconfig, moduleConfig, annotations, imports, src, dst):
log.debug('run {0} {1}'.format(src, dst))
FileSystem.strict = True
Generator.strict = True
+
+ # First run without imports to know the name of the modules we want to generate
+ module_names = []
system = FileSystem.parse(src)
+ for module in system.modules:
+ module_names.append(module.name)
+
+ # Second run with imports to resolve all needed type information
+ all_files = imports + src
+ system = FileSystem.parse(all_files)
for annotations_file in annotations:
log.debug('{0}'.format(annotations_file))
if not os.path.isabs(annotations_file):
@@ -801,8 +812,19 @@ def generate(tplconfig, moduleConfig, annotations, src, dst):
for member in enum.members:
member.add_tag('config')
+ ctx.update({'modules': system.modules})
for module in system.modules:
+ # Only generate files for the modules detected from the first parse run
+ if not module.name in module_names:
+ continue
+
log.debug('generate code for module %s', module)
+
+ # Report early if we cannot find the imported modules
+ for imp in module._importMap:
+ if imp not in system._moduleMap:
+ sys.exit("{0}: Couldn't resolve import '{1}'".format(currentQFaceSrcFile, imp))
+
for val, key in moduleConfig.items():
module.add_attribute('config', val, key)
ctx.update({'module': module})
@@ -832,13 +854,13 @@ def generate(tplconfig, moduleConfig, annotations, src, dst):
generator.write(rule['dest_file'], rule['template_file'], ctx, preserve, force)
-def run(format, moduleConfig, annotations, src, dst):
+def run(format, moduleConfig, annotations, imports, src, dst):
if format in IVI_DEFAULT_TEMPLATES:
tplConfig = 'templates_{0}'.format(format)
- generate(here / tplConfig, moduleConfig, annotations, src, dst)
+ generate(here / tplConfig, moduleConfig, annotations, imports, src, dst)
else:
if os.path.exists(format):
- generate(format, moduleConfig, annotations, src, dst)
+ generate(format, moduleConfig, annotations, imports, src, dst)
else:
print('Format "{0}" is invalid. Should be one of {1} or an existing template folder'.format(format, IVI_DEFAULT_TEMPLATES))
exit(1)
@@ -854,10 +876,15 @@ def run(format, moduleConfig, annotations, src, dst):
'implicit annotation file. The annotation files will be merged in the order they are passed '
'to the generator. Providing a duplicate key in the YAML file will override the previously '
'set value. This option can be used multiple times.')
+@click.option('--import', '-I', 'imports' , multiple=True, default=False, help=
+ 'Adds the given path to the list of import paths. All directories in this list are '
+ 'scanned recursively for QFace files. The QFace files found are then used to resolve '
+ 'the information required when importing a module; this is similar to how C++ include '
+ 'paths work.')
@click.argument('src', nargs=-1, type=click.Path(exists=True))
@click.argument('dst', nargs=1, type=click.Path(exists=True))
-def app(src, dst, format, reload, module, force, annotations):
+def app(src, dst, format, reload, module, force, annotations, imports):
"""
The QtIvi Autogenerator (ivigenerator)
@@ -881,7 +908,7 @@ def app(src, dst, format, reload, module, force, annotations):
"module": module,
"force": force
}
- run(format, moduleConfig, annotations, src, dst)
+ run(format, moduleConfig, annotations, imports, src, dst)
if __name__ == '__main__':
diff --git a/src/tools/ivigenerator/templates_frontend/module.cpp.tpl b/src/tools/ivigenerator/templates_frontend/module.cpp.tpl
index ac3f6d8..1e17757 100644
--- a/src/tools/ivigenerator/templates_frontend/module.cpp.tpl
+++ b/src/tools/ivigenerator/templates_frontend/module.cpp.tpl
@@ -113,6 +113,19 @@ QObject* {{class|lower}}_singletontype_provider(QQmlEngine*, QJSEngine*)
/*! \internal */
void {{class}}::registerTypes()
{
+{% for import in module.imports %}
+{# All imports are provided including their imported version e.g. "Common 1.0". Because we need
+ to access the Module type, we first need to split the version and then search for the name.
+ See https://github.com/Pelagicore/qface/issues/87
+#}
+{% set name = import.split(' ')[0] %}
+{% for mod in modules %}
+{% if mod.name == name %}
+ {{mod.module_name|upperfirst}}Module::registerTypes();
+{% endif %}
+{% endfor %}
+{% endfor %}
+
{% for enum in module.enums %}
qRegisterMetaType<{{class}}::{{enum|flag_type}}>();
qRegisterMetaTypeStreamOperators<{{class}}::{{enum|flag_type}}>();
diff --git a/src/tools/ivigenerator/templates_frontend/module.h.tpl b/src/tools/ivigenerator/templates_frontend/module.h.tpl
index b9efded..a203e92 100644
--- a/src/tools/ivigenerator/templates_frontend/module.h.tpl
+++ b/src/tools/ivigenerator/templates_frontend/module.h.tpl
@@ -50,6 +50,20 @@
{% else %}
#include "{{module.module_name|lower}}global.h"
{% endif %}
+
+{% for import in module.imports %}
+{# All imports are provided including their imported version e.g. "Common 1.0". Because we need
+ to access the Module type, we first need to split the version and then search for the name.
+ See https://github.com/Pelagicore/qface/issues/87
+#}
+{% set name = import.split(' ')[0] %}
+{% for mod in modules %}
+{% if mod.name == name %}
+#include <{{mod.module_name|lower}}module.h>
+{% endif %}
+{% endfor %}
+{% endfor %}
+
#include <QObject>
QT_BEGIN_NAMESPACE
diff --git a/src/tools/ivigenerator/templates_frontend/struct.h.tpl b/src/tools/ivigenerator/templates_frontend/struct.h.tpl
index 76639c2..c9d4ea4 100644
--- a/src/tools/ivigenerator/templates_frontend/struct.h.tpl
+++ b/src/tools/ivigenerator/templates_frontend/struct.h.tpl
@@ -47,8 +47,8 @@
#ifndef {{oncedefine}}
#define {{oncedefine}}
-{% if interface.module.tags.config.module %}
-#include <{{interface.module.tags.config.module}}/{{module.module_name|lower}}module.h>
+{% if module.tags.config.module %}
+#include <{{module.tags.config.module}}/{{module.module_name|lower}}module.h>
{% else %}
#include "{{module.module_name|lower}}module.h"
{% endif %}
diff --git a/tests/auto/core/ivigenerator/include-test.qface b/tests/auto/core/ivigenerator/include-test.qface
new file mode 100644
index 0000000..dd13fe3
--- /dev/null
+++ b/tests/auto/core/ivigenerator/include-test.qface
@@ -0,0 +1,115 @@
+/**
+ * module
+ */
+module include.test 1.0
+
+import Common 1.0
+
+/**
+ * \brief the brief
+ * the description
+ * continues \l http://qt.io
+ */
+interface IncludeTester {
+ readonly string lastMessage;
+ int intValue;
+ var varValue;
+ @config_simulator: {minimum: 10.}
+ real floatValue1;
+ @config_simulator: {maximum: 10.}
+ real floatValue2;
+ string stringValue;
+
+ model<NestedStruct> nestedStructModel;
+ model<NestedImportedStruct> nestedImportedStructModel;
+ list<int> intList;
+ list<Common.CommonStruct> commonStructList;
+ list<NestedImportedStruct> nestedImportedStructList;
+ TestEnum testEnum;
+ Common.CommonEnum commonEnum;
+
+ string echo(string msg);
+ string id() const;
+ NestedStruct getNestedStruct();
+ NestedImportedStruct getNestedImportedStruct();
+ Common.CommonStruct getCommonStruct();
+ void voidSlot();
+ void voidSlot2(int param);
+ void timer(int interval);
+ Common.CommonFlag flagMethod(Common.CommonFlag testFlag);
+ Common.CommonEnum enumMethod(Common.CommonEnum testEnum);
+
+ signal anotherChanged(NestedImportedStruct another);
+ signal foobar(string foo);
+ signal somethingHappened();
+ signal newValueAvailable(var newValue);
+}
+
+@config: { zoned: true }
+interface IncludeTesterZoned {
+ readonly string lastMessage;
+ int intValue;
+ var varValue;
+ @config_simulator: {minimum: 10.}
+ real floatValue1;
+ @config_simulator: {maximum: 10.}
+ real floatValue2;
+ string stringValue;
+
+ model<NestedStruct> nestedStructModel;
+ model<NestedImportedStruct> nestedImportedStructModel;
+ list<int> intList;
+ list<Common.CommonStruct> commonStructList;
+ list<NestedImportedStruct> nestedImportedStructList;
+ TestEnum testEnum;
+ Common.CommonEnum commonEnum;
+
+ string echo(string msg);
+ string id() const;
+ NestedStruct getNestedStruct();
+ NestedImportedStruct getNestedImportedStruct();
+ Common.CommonStruct getCommonStruct();
+ void voidSlot();
+ void voidSlot2(int param);
+ void timer(int interval);
+ Common.CommonFlag flagMethod(Common.CommonFlag testFlag);
+ Common.CommonEnum enumMethod(Common.CommonEnum testEnum);
+
+ signal anotherChanged(NestedImportedStruct another);
+ signal foobar(string foo);
+ signal somethingHappened();
+ signal newValueAvailable(var newValue);
+}
+
+/**
+ * \brief A TestFlag
+ */
+flag TestFlag {
+ /**
+ * \brief The first value
+ */
+ TestFlagValue = 1,
+ /**
+ * \brief The second value
+ */
+ TestFlagValue = 2,
+}
+
+enum TestEnum {
+ FirstEnumValue = 1,
+ SecondEnumValue = 2
+}
+
+struct NestedStruct {
+ AnotherStruct anotherStruct;
+ TestEnum testEnum;
+}
+
+struct AnotherStruct {
+ int justANumber;
+}
+
+struct NestedImportedStruct {
+ Common.CommonStruct commonStruct;
+ TestFlag testFlag;
+}
diff --git a/tests/auto/core/ivigenerator/ivigenerator.pro b/tests/auto/core/ivigenerator/ivigenerator.pro
index 00f5307..26f1401 100644
--- a/tests/auto/core/ivigenerator/ivigenerator.pro
+++ b/tests/auto/core/ivigenerator/ivigenerator.pro
@@ -6,4 +6,5 @@ SUBDIRS = projects \
OTHER_FILES = org.example.echo.qface \
org.example.echo.yaml \
org.example.echo.noannotation.qface \
- no-private.yaml
+ no-private.yaml \
+ include-test.qface \
diff --git a/tests/auto/core/ivigenerator/projects/include-test/backend_qtro/backend_qtro.pro b/tests/auto/core/ivigenerator/projects/include-test/backend_qtro/backend_qtro.pro
new file mode 100644
index 0000000..ce0da0f
--- /dev/null
+++ b/tests/auto/core/ivigenerator/projects/include-test/backend_qtro/backend_qtro.pro
@@ -0,0 +1,16 @@
+TEMPLATE=lib
+TARGET = $$qtLibraryTarget(include_test_qtro)
+LIBS += -L$$OUT_PWD/.. -l$$qtLibraryTarget(include_test_frontend) -l$$qtLibraryTarget(include_test_common)
+DESTDIR = ../qtivi
+
+CONFIG += warn_off ivigenerator plugin
+
+INCLUDEPATH += $$OUT_PWD/../frontend $$OUT_PWD/../common
+PLUGIN_TYPE = qtivi
+PLUGIN_CLASS_NAME = IncludeTestPlugin
+
+QT += core ivicore
+
+QFACE_FORMAT = backend_qtro
+QFACE_SOURCES = ../../../include-test.qface
+QFACE_IMPORT_PATH += "../../../qface imports"
diff --git a/tests/auto/core/ivigenerator/projects/include-test/backend_simulator/backend_simulator.pro b/tests/auto/core/ivigenerator/projects/include-test/backend_simulator/backend_simulator.pro
new file mode 100644
index 0000000..819898e
--- /dev/null
+++ b/tests/auto/core/ivigenerator/projects/include-test/backend_simulator/backend_simulator.pro
@@ -0,0 +1,16 @@
+TEMPLATE=lib
+TARGET = $$qtLibraryTarget(include_test_simulator)
+LIBS += -L$$OUT_PWD/.. -l$$qtLibraryTarget(include_test_frontend) -l$$qtLibraryTarget(include_test_common)
+DESTDIR = ../qtivi
+
+CONFIG += warn_off ivigenerator plugin
+
+INCLUDEPATH += $$OUT_PWD/../frontend $$OUT_PWD/../common
+PLUGIN_TYPE = qtivi
+PLUGIN_CLASS_NAME = IncludeTestPlugin
+
+QT += core ivicore
+
+QFACE_FORMAT = backend_simulator
+QFACE_SOURCES = ../../../include-test.qface
+QFACE_IMPORT_PATH += "../../../qface imports"
diff --git a/tests/auto/core/ivigenerator/projects/include-test/common/common.pro b/tests/auto/core/ivigenerator/projects/include-test/common/common.pro
new file mode 100644
index 0000000..306669a
--- /dev/null
+++ b/tests/auto/core/ivigenerator/projects/include-test/common/common.pro
@@ -0,0 +1,14 @@
+TEMPLATE=lib
+TARGET= $$qtLibraryTarget(include_test_common)
+DESTDIR = ../
+
+CONFIG += ivigenerator
+
+QT += ivicore ivicore-private qml quick
+
+DEFINES += QT_BUILD_COMMON_LIB
+
+macos: QMAKE_SONAME_PREFIX = @rpath
+
+QFACE_SOURCES = "../../../qface imports/common.qface"
+
diff --git a/tests/auto/core/ivigenerator/projects/include-test/frontend/frontend.pro b/tests/auto/core/ivigenerator/projects/include-test/frontend/frontend.pro
new file mode 100644
index 0000000..e287e47
--- /dev/null
+++ b/tests/auto/core/ivigenerator/projects/include-test/frontend/frontend.pro
@@ -0,0 +1,17 @@
+TEMPLATE=lib
+TARGET= $$qtLibraryTarget(include_test_frontend)
+DESTDIR = ../
+
+CONFIG += ivigenerator
+
+QT += ivicore ivicore-private qml quick
+
+DEFINES += QT_BUILD_INCLUDE_TEST_LIB
+INCLUDEPATH += $$OUT_PWD/../common
+LIBS += -L$$OUT_PWD/.. -l$$qtLibraryTarget(include_test_common)
+
+macos: QMAKE_SONAME_PREFIX = @rpath
+
+QFACE_SOURCES = ../../../include-test.qface
+QFACE_IMPORT_PATH += "../../../qface imports"
+
diff --git a/tests/auto/core/ivigenerator/projects/include-test/include-test.pro b/tests/auto/core/ivigenerator/projects/include-test/include-test.pro
new file mode 100644
index 0000000..3febe98
--- /dev/null
+++ b/tests/auto/core/ivigenerator/projects/include-test/include-test.pro
@@ -0,0 +1,22 @@
+TEMPLATE = subdirs
+
+SUBDIRS = common \
+ frontend \
+ qmlplugin \
+ backend_simulator \
+ test \
+
+frontend.depends = common
+backend_simulator.depends = frontend
+test.depends = frontend
+qmlplugin.depends = frontend
+
+QT_FOR_CONFIG += ivicore
+
+qtConfig(remoteobjects) {
+ SUBDIRS += backend_qtro \
+ simulation_server_qtro
+
+ backend_qtro.depends = frontend
+ simulation_server_qtro.depends = frontend
+}
diff --git a/tests/auto/core/ivigenerator/projects/include-test/qmlplugin/qmlplugin.pro b/tests/auto/core/ivigenerator/projects/include-test/qmlplugin/qmlplugin.pro
new file mode 100644
index 0000000..b0a45d8
--- /dev/null
+++ b/tests/auto/core/ivigenerator/projects/include-test/qmlplugin/qmlplugin.pro
@@ -0,0 +1,12 @@
+TEMPLATE = lib
+QT = ivicore
+CONFIG += c++11 plugin
+
+INCLUDEPATH += $$OUT_PWD/../frontend $$OUT_PWD/../common
+LIBS += -L$$OUT_PWD/.. -l$$qtLibraryTarget(include_test_frontend) -l$$qtLibraryTarget(include_test_common)
+
+QFACE_FORMAT = qmlplugin
+QFACE_SOURCES = ../../../include-test.qface
+QFACE_IMPORT_PATH += "../../../qface imports"
+
+load(ivigenerator)
diff --git a/tests/auto/core/ivigenerator/projects/include-test/simulation_server_qtro/simulation_server_qtro.pro b/tests/auto/core/ivigenerator/projects/include-test/simulation_server_qtro/simulation_server_qtro.pro
new file mode 100644
index 0000000..2618076
--- /dev/null
+++ b/tests/auto/core/ivigenerator/projects/include-test/simulation_server_qtro/simulation_server_qtro.pro
@@ -0,0 +1,16 @@
+TEMPLATE = app
+TARGET = org-example-echo-qtro-simulation-server
+LIBS += -L$$OUT_PWD/.. -l$$qtLibraryTarget(include_test_frontend) -l$$qtLibraryTarget(include_test_common)
+
+DESTDIR = ..
+
+CONFIG += c++11 ivigenerator
+CONFIG -= app_bundle
+
+INCLUDEPATH += $$OUT_PWD/../frontend $$OUT_PWD/../common
+
+QT += qml quick core ivicore
+
+QFACE_FORMAT = server_qtro_simulator
+QFACE_SOURCES = ../../../include-test.qface
+QFACE_IMPORT_PATH += "../../../qface imports"
diff --git a/tests/auto/core/ivigenerator/projects/include-test/test/test.pro b/tests/auto/core/ivigenerator/projects/include-test/test/test.pro
new file mode 100644
index 0000000..6b7e344
--- /dev/null
+++ b/tests/auto/core/ivigenerator/projects/include-test/test/test.pro
@@ -0,0 +1,15 @@
+TARGET = tst_include
+QMAKE_PROJECT_NAME = $$TARGET
+DESTDIR = ../
+
+QT += testlib core ivicore
+CONFIG += c++11 ivigenerator testcase
+
+INCLUDEPATH += $$OUT_PWD/../frontend $$OUT_PWD/../common
+LIBS += -L$$OUT_PWD/.. -l$$qtLibraryTarget(include_test_frontend) -l$$qtLibraryTarget(include_test_common)
+
+QMAKE_RPATHDIR += $$OUT_PWD/..
+
+QFACE_FORMAT = test
+QFACE_SOURCES = ../../../include-test.qface
+QFACE_IMPORT_PATH += "../../../qface imports"
diff --git a/tests/auto/core/ivigenerator/projects/projects.pro b/tests/auto/core/ivigenerator/projects/projects.pro
index bc349a5..eb8d2b7 100644
--- a/tests/auto/core/ivigenerator/projects/projects.pro
+++ b/tests/auto/core/ivigenerator/projects/projects.pro
@@ -5,6 +5,7 @@ QT_FOR_CONFIG += ivicore
SUBDIRS = org-example-echo \
org-example-echo-noprivate \
org-example-echo-noannotation \
+ include-test \
qtConfig(remoteobjects) {
SUBDIRS += org-example-echo-qtro
diff --git a/tests/auto/core/ivigenerator/qface imports/common.qface b/tests/auto/core/ivigenerator/qface imports/common.qface
new file mode 100644
index 0000000..b9cee0c
--- /dev/null
+++ b/tests/auto/core/ivigenerator/qface imports/common.qface
@@ -0,0 +1,20 @@
+module Common 1.0;
+
+struct CommonStruct {
+ string name
+ OtherCommonStruct otherStruct
+}
+
+struct OtherCommonStruct {
+ bool checked
+}
+
+enum CommonEnum {
+ CommonValue1,
+ CommonValue2
+}
+
+flag CommonFlag {
+ FlagValue1 = 1,
+ FlagValue2 = 2
+}