pro2cmake: Handle QT += core-private correctly for modules
If a module project (Quick) contains QT += core-private, the qmake semantics translated to CMake would mean the following: target_link_libraries(Quick PUBLIC Core) target_link_libraries(Quick PRIVATE CorePrivate) target_link_libraries(QuickPrivate INTERFACE CorePrivate) Whereas a QT_PRIVATE += core-private only means target_link_libraries(Quick PRIVATE CorePrivate) without adding any public dependencies to QuickPrivate. To achieve that, we need a few modifications to both pro2cmake and QtBuild.cmake - pro2cmake doesn't automagically add public and private dependencies to targets when encountering a private module assigned to QT. Instead it generates the logic described above by passing correct LIBRARIES, PUBLIC_LIBRARIES, and PRIVATE_MODULE_INTERFACE values. - pro2cmake doesn't do any dependency magic for non-module targets anymore, like executables, plugins, internal_modules. This means that QT assignments are now regular public dependencies. - qt_add_module and qt_extend_target now accept a new PRIVATE_MODULE_INTERFACE option. - qt_extend_target does not automagically make private modules be public dependencies on other private modules. - qt_extend_target correctly assigns PRIVATE_MODULE_INTERFACE values to Private module only. For other target types, it's a no-op. The change requires regeneration of all projects. When we fix pro2cmake and QtBuild.cmake to properly handle internal_modules (create only Private modules without creating a non-Private counter part), we will need another project regeneration to correctly assign dependencies. Change-Id: I4c21f26b3ef3b2a4ed208b58bccb65a5b7312f81 Task-number: QTBUG-81780 Reviewed-by: Leander Beernaert <leander.beernaert@qt.io> Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
parent
4ddd4bf1aa
commit
c5b61d2e90
@ -946,7 +946,7 @@ endfunction()
|
|||||||
set(__default_private_args "SOURCES;LIBRARIES;INCLUDE_DIRECTORIES;DEFINES;DBUS_ADAPTOR_BASENAME;DBUS_ADAPTOR_FLAGS;DBUS_ADAPTOR_SOURCES;DBUS_INTERFACE_BASENAME;DBUS_INTERFACE_FLAGS;DBUS_INTERFACE_SOURCES;FEATURE_DEPENDENCIES;COMPILE_OPTIONS;LINK_OPTIONS;MOC_OPTIONS;DISABLE_AUTOGEN_TOOLS;ENABLE_AUTOGEN_TOOLS;PLUGIN_TYPES")
|
set(__default_private_args "SOURCES;LIBRARIES;INCLUDE_DIRECTORIES;DEFINES;DBUS_ADAPTOR_BASENAME;DBUS_ADAPTOR_FLAGS;DBUS_ADAPTOR_SOURCES;DBUS_INTERFACE_BASENAME;DBUS_INTERFACE_FLAGS;DBUS_INTERFACE_SOURCES;FEATURE_DEPENDENCIES;COMPILE_OPTIONS;LINK_OPTIONS;MOC_OPTIONS;DISABLE_AUTOGEN_TOOLS;ENABLE_AUTOGEN_TOOLS;PLUGIN_TYPES")
|
||||||
|
|
||||||
set(__default_public_args "PUBLIC_LIBRARIES;PUBLIC_INCLUDE_DIRECTORIES;PUBLIC_DEFINES;PUBLIC_COMPILE_OPTIONS;PUBLIC_LINK_OPTIONS")
|
set(__default_public_args "PUBLIC_LIBRARIES;PUBLIC_INCLUDE_DIRECTORIES;PUBLIC_DEFINES;PUBLIC_COMPILE_OPTIONS;PUBLIC_LINK_OPTIONS")
|
||||||
|
set(__default_private_module_args "PRIVATE_MODULE_INTERFACE")
|
||||||
|
|
||||||
option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF)
|
option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF)
|
||||||
|
|
||||||
@ -1085,7 +1085,7 @@ function(qt_extend_target target)
|
|||||||
message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".")
|
message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".")
|
||||||
endif()
|
endif()
|
||||||
qt_parse_all_arguments(arg "qt_extend_target" "HEADER_MODULE" "PRECOMPILED_HEADER"
|
qt_parse_all_arguments(arg "qt_extend_target" "HEADER_MODULE" "PRECOMPILED_HEADER"
|
||||||
"CONDITION;${__default_public_args};${__default_private_args};COMPILE_FLAGS;NO_PCH_SOURCES" ${ARGN})
|
"CONDITION;${__default_public_args};${__default_private_args};${__default_private_module_args};COMPILE_FLAGS;NO_PCH_SOURCES" ${ARGN})
|
||||||
if ("x${arg_CONDITION}" STREQUAL x)
|
if ("x${arg_CONDITION}" STREQUAL x)
|
||||||
set(arg_CONDITION ON)
|
set(arg_CONDITION ON)
|
||||||
endif()
|
endif()
|
||||||
@ -1193,7 +1193,8 @@ function(qt_extend_target target)
|
|||||||
|
|
||||||
set(target_private "${target}Private")
|
set(target_private "${target}Private")
|
||||||
if(TARGET "${target_private}")
|
if(TARGET "${target_private}")
|
||||||
target_link_libraries("${target_private}" INTERFACE "${target}" "${qt_libs_private}")
|
target_link_libraries("${target_private}"
|
||||||
|
INTERFACE "${target}" ${arg_PRIVATE_MODULE_INTERFACE})
|
||||||
endif()
|
endif()
|
||||||
qt_register_target_dependencies("${target}"
|
qt_register_target_dependencies("${target}"
|
||||||
"${arg_PUBLIC_LIBRARIES}"
|
"${arg_PUBLIC_LIBRARIES}"
|
||||||
@ -1533,7 +1534,7 @@ function(qt_add_module target)
|
|||||||
qt_parse_all_arguments(arg "qt_add_module"
|
qt_parse_all_arguments(arg "qt_add_module"
|
||||||
"NO_MODULE_HEADERS;STATIC;DISABLE_TOOLS_EXPORT;EXCEPTIONS;INTERNAL_MODULE;NO_SYNC_QT;NO_PRIVATE_MODULE;HEADER_MODULE;GENERATE_METATYPES"
|
"NO_MODULE_HEADERS;STATIC;DISABLE_TOOLS_EXPORT;EXCEPTIONS;INTERNAL_MODULE;NO_SYNC_QT;NO_PRIVATE_MODULE;HEADER_MODULE;GENERATE_METATYPES"
|
||||||
"CONFIG_MODULE_NAME;PRECOMPILED_HEADER"
|
"CONFIG_MODULE_NAME;PRECOMPILED_HEADER"
|
||||||
"${__default_private_args};${__default_public_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES;NO_PCH_SOURCES" ${ARGN})
|
"${__default_private_args};${__default_public_args};${__default_private_module_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES;NO_PCH_SOURCES" ${ARGN})
|
||||||
|
|
||||||
if(NOT DEFINED arg_CONFIG_MODULE_NAME)
|
if(NOT DEFINED arg_CONFIG_MODULE_NAME)
|
||||||
set(arg_CONFIG_MODULE_NAME "${module_lower}")
|
set(arg_CONFIG_MODULE_NAME "${module_lower}")
|
||||||
@ -1751,6 +1752,7 @@ function(qt_add_module target)
|
|||||||
"${deprecation_define}"
|
"${deprecation_define}"
|
||||||
PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
|
PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
|
||||||
LIBRARIES ${arg_LIBRARIES} Qt::PlatformModuleInternal
|
LIBRARIES ${arg_LIBRARIES} Qt::PlatformModuleInternal
|
||||||
|
PRIVATE_MODULE_INTERFACE ${arg_PRIVATE_MODULE_INTERFACE}
|
||||||
FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
|
FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
|
||||||
DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES}
|
DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES}
|
||||||
DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
|
DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
|
||||||
|
@ -904,6 +904,8 @@ class Scope(object):
|
|||||||
self._visited_keys = set() # type: Set[str]
|
self._visited_keys = set() # type: Set[str]
|
||||||
self._total_condition = None # type: Optional[str]
|
self._total_condition = None # type: Optional[str]
|
||||||
self._parent_include_line_no = parent_include_line_no
|
self._parent_include_line_no = parent_include_line_no
|
||||||
|
self._is_public_module = False
|
||||||
|
self._has_private_module = False
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (
|
return (
|
||||||
@ -935,6 +937,14 @@ class Scope(object):
|
|||||||
def currentdir(self) -> str:
|
def currentdir(self) -> str:
|
||||||
return self._currentdir
|
return self._currentdir
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_public_module(self) -> bool:
|
||||||
|
return self._is_public_module
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_private_module(self) -> bool:
|
||||||
|
return self._has_private_module
|
||||||
|
|
||||||
def can_merge_condition(self):
|
def can_merge_condition(self):
|
||||||
if self._condition == "else":
|
if self._condition == "else":
|
||||||
return False
|
return False
|
||||||
@ -1826,16 +1836,9 @@ def extract_cmake_libraries(
|
|||||||
private_dependencies += [map_qt_library(q) for q in scope.expand(key)]
|
private_dependencies += [map_qt_library(q) for q in scope.expand(key)]
|
||||||
|
|
||||||
for key in ["QT"]:
|
for key in ["QT"]:
|
||||||
# Qt public libs: These may include FooPrivate in which case we get
|
|
||||||
# a private dependency on FooPrivate as well as a public dependency on Foo
|
|
||||||
for lib in scope.expand(key):
|
for lib in scope.expand(key):
|
||||||
mapped_lib = map_qt_library(lib)
|
mapped_lib = map_qt_library(lib)
|
||||||
|
public_dependencies.append(mapped_lib)
|
||||||
if mapped_lib.endswith("Private"):
|
|
||||||
private_dependencies.append(mapped_lib)
|
|
||||||
public_dependencies.append(mapped_lib[:-7])
|
|
||||||
else:
|
|
||||||
public_dependencies.append(mapped_lib)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
_map_libraries_to_cmake(public_dependencies, known_libraries, is_example=is_example),
|
_map_libraries_to_cmake(public_dependencies, known_libraries, is_example=is_example),
|
||||||
@ -1972,8 +1975,41 @@ def write_library_section(
|
|||||||
scope, known_libraries=known_libraries
|
scope, known_libraries=known_libraries
|
||||||
)
|
)
|
||||||
|
|
||||||
write_list(cm_fh, private_dependencies, "LIBRARIES", indent + 1)
|
is_public_module = scope.is_public_module
|
||||||
write_list(cm_fh, public_dependencies, "PUBLIC_LIBRARIES", indent + 1)
|
current_scope = scope
|
||||||
|
while not is_public_module and current_scope.parent:
|
||||||
|
current_scope = current_scope.parent
|
||||||
|
is_public_module = current_scope.is_public_module
|
||||||
|
|
||||||
|
# When handling module dependencies, handle QT += foo-private magic.
|
||||||
|
# This implies:
|
||||||
|
# target_link_libraries(Module PUBLIC Qt::Foo)
|
||||||
|
# target_link_libraries(Module PRIVATE Qt::FooPrivate)
|
||||||
|
# target_link_libraries(ModulePrivate INTERFACE Qt::FooPrivate)
|
||||||
|
if is_public_module:
|
||||||
|
private_module_dep_pattern = re.compile(r"^(Qt::(.+))Private$")
|
||||||
|
|
||||||
|
public_module_public_deps = []
|
||||||
|
public_module_private_deps = private_dependencies
|
||||||
|
private_module_interface_deps = []
|
||||||
|
|
||||||
|
for dep in public_dependencies:
|
||||||
|
match = re.match(private_module_dep_pattern, dep)
|
||||||
|
if match:
|
||||||
|
if match[1] not in public_module_public_deps:
|
||||||
|
public_module_public_deps.append(match[1])
|
||||||
|
private_module_interface_deps.append(dep)
|
||||||
|
if dep not in public_module_private_deps:
|
||||||
|
public_module_private_deps.append(dep)
|
||||||
|
else:
|
||||||
|
if dep not in public_module_public_deps:
|
||||||
|
public_module_public_deps.append(dep)
|
||||||
|
write_list(cm_fh, public_module_private_deps, "LIBRARIES", indent + 1)
|
||||||
|
write_list(cm_fh, public_module_public_deps, "PUBLIC_LIBRARIES", indent + 1)
|
||||||
|
write_list(cm_fh, private_module_interface_deps, "PRIVATE_MODULE_INTERFACE", indent + 1)
|
||||||
|
else:
|
||||||
|
write_list(cm_fh, private_dependencies, "LIBRARIES", indent + 1)
|
||||||
|
write_list(cm_fh, public_dependencies, "PUBLIC_LIBRARIES", indent + 1)
|
||||||
|
|
||||||
|
|
||||||
def write_autogen_section(cm_fh: IO[str], scope: Scope, *, indent: int = 0):
|
def write_autogen_section(cm_fh: IO[str], scope: Scope, *, indent: int = 0):
|
||||||
@ -2827,9 +2863,12 @@ def write_module(cm_fh: IO[str], scope: Scope, *, indent: int = 0) -> str:
|
|||||||
# or when option(host_build) is used, as described in qt_module.prf.
|
# or when option(host_build) is used, as described in qt_module.prf.
|
||||||
is_static = "static" in scope.get("CONFIG") or "host_build" in scope.get("_OPTION")
|
is_static = "static" in scope.get("CONFIG") or "host_build" in scope.get("_OPTION")
|
||||||
|
|
||||||
|
is_public_module = True
|
||||||
|
|
||||||
if is_static:
|
if is_static:
|
||||||
extra.append("STATIC")
|
extra.append("STATIC")
|
||||||
if "internal_module" in scope.get("CONFIG"):
|
if "internal_module" in scope.get("CONFIG"):
|
||||||
|
is_public_module = False
|
||||||
extra.append("INTERNAL_MODULE")
|
extra.append("INTERNAL_MODULE")
|
||||||
if "no_module_headers" in scope.get("CONFIG"):
|
if "no_module_headers" in scope.get("CONFIG"):
|
||||||
extra.append("NO_MODULE_HEADERS")
|
extra.append("NO_MODULE_HEADERS")
|
||||||
@ -2837,6 +2876,8 @@ def write_module(cm_fh: IO[str], scope: Scope, *, indent: int = 0) -> str:
|
|||||||
extra.append("NO_SYNC_QT")
|
extra.append("NO_SYNC_QT")
|
||||||
if "no_private_module" in scope.get("CONFIG"):
|
if "no_private_module" in scope.get("CONFIG"):
|
||||||
extra.append("NO_PRIVATE_MODULE")
|
extra.append("NO_PRIVATE_MODULE")
|
||||||
|
else:
|
||||||
|
scope._has_private_module = True
|
||||||
if "header_module" in scope.get("CONFIG"):
|
if "header_module" in scope.get("CONFIG"):
|
||||||
extra.append("HEADER_MODULE")
|
extra.append("HEADER_MODULE")
|
||||||
if "metatypes" in scope.get("CONFIG") or "qmltypes" in scope.get("CONFIG"):
|
if "metatypes" in scope.get("CONFIG") or "qmltypes" in scope.get("CONFIG"):
|
||||||
@ -2850,6 +2891,8 @@ def write_module(cm_fh: IO[str], scope: Scope, *, indent: int = 0) -> str:
|
|||||||
if module_plugin_types:
|
if module_plugin_types:
|
||||||
extra.append(f"PLUGIN_TYPES {' '.join(module_plugin_types)}")
|
extra.append(f"PLUGIN_TYPES {' '.join(module_plugin_types)}")
|
||||||
|
|
||||||
|
scope._is_public_module = is_public_module
|
||||||
|
|
||||||
target_name = module_name[2:]
|
target_name = module_name[2:]
|
||||||
write_main_part(
|
write_main_part(
|
||||||
cm_fh,
|
cm_fh,
|
||||||
|
Loading…
Reference in New Issue
Block a user