CMake: Use AUTOMOC/AUTOUIC/AUTORCC
Change-Id: I0235ca4f227623e5937348b4b010637921dbf154 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
parent
07dfa3013c
commit
e57a94cbd8
@ -222,43 +222,6 @@ function(qt_internal_add_linker_version_script target)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Generates the necessary rules to run moc on the sources specified after the MOC parameter.
|
||||
# The resulting moc files are added to the target.
|
||||
function(qt_internal_wrap_cpp target)
|
||||
# get include dirs
|
||||
qt_get_moc_flags(moc_flags)
|
||||
qt_parse_all_arguments(arg "qt_internal_wrap_cpp" "" "HEADER_FILE_ONLY" "OPTIONS;DEPENDS;MOC" ${ARGN})
|
||||
|
||||
set(outfiles)
|
||||
|
||||
get_target_property(binary_dir "${target}" BINARY_DIR)
|
||||
get_target_property(source_dir "${target}" SOURCE_DIR)
|
||||
|
||||
foreach(it ${arg_MOC})
|
||||
get_filename_component(moc_file_extension ${it} EXT)
|
||||
|
||||
if("x${moc_file_extension}" STREQUAL "x.h")
|
||||
set(file_prefix "moc_")
|
||||
set(file_extension ".cpp")
|
||||
else()
|
||||
set(file_prefix "")
|
||||
set(file_extension ".moc")
|
||||
endif()
|
||||
|
||||
qt_make_output_file("${it}" "${file_prefix}" "${file_extension}" "${source_dir}" "${binary_dir}" outfile)
|
||||
|
||||
qt_create_moc_command("${target}" "${source_dir}" "${it}" "${outfile}" "${moc_flags}" "${arg_OPTIONS}" "${arg_DEPENDS}")
|
||||
set_source_files_properties("${outfile}" PROPERTIES HEADER_FILE_ONLY ${arg_HEADER_FILE_ONLY})
|
||||
if (arg_HEADER_FILE_ONLY)
|
||||
get_filename_component(directory "${outfile}" DIRECTORY)
|
||||
target_include_directories("${target}" PRIVATE "${directory}")
|
||||
endif()
|
||||
|
||||
list(APPEND outfiles "${outfile}")
|
||||
endforeach()
|
||||
target_sources("${target}" PRIVATE "${outfiles}")
|
||||
endfunction()
|
||||
|
||||
|
||||
# Get a set of Qt module related values based on the target name.
|
||||
# When doing qt_internal_module_info(foo Core) this method will set
|
||||
@ -280,157 +243,6 @@ function(qt_internal_module_info result target)
|
||||
endfunction()
|
||||
|
||||
|
||||
# This function takes a target as a parameter, followed by a list of sources.
|
||||
# The sources are scanned for Q_OBJECT/Q_GADGET use as well as the inclusion of
|
||||
# moc_*.cpp/*.moc. Rules are created to call moc accordingly at build time and
|
||||
# add the generated sources to the target, if the generated code is not
|
||||
# directly included otherwise.
|
||||
function(qt_internal_automoc target)
|
||||
if ("x${ARGN}" STREQUAL "x")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED QT_MOCSCANNER)
|
||||
get_target_property(mocPath "Qt::moc" LOCATION)
|
||||
get_filename_component(binDirectory "${mocPath}" DIRECTORY)
|
||||
set(QT_MOCSCANNER "${binDirectory}/qmocscanner${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" "\n" sources "${ARGN}")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/moc_sources_and_headers.txt" ${sources})
|
||||
execute_process(COMMAND "${QT_MOCSCANNER}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/moc_sources_and_headers.txt"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/moc_files_included.txt"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/moc_files_to_build.txt"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/moc_files_included.txt" moc_files_included)
|
||||
file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/moc_files_to_build.txt" moc_files_to_build)
|
||||
|
||||
file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/moc_sources_and_headers.txt")
|
||||
file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/moc_files_included.txt")
|
||||
file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/moc_files_to_build.txt")
|
||||
|
||||
qt_internal_wrap_cpp("${target}" MOC ${moc_files_included} HEADER_FILE_ONLY ON)
|
||||
qt_internal_wrap_cpp("${target}" MOC ${moc_files_to_build} HEADER_FILE_ONLY OFF)
|
||||
endfunction()
|
||||
|
||||
|
||||
# This function takes a target as a parameter, followed by a list of sources.
|
||||
# Any sources with the .ui extension are passed on to uic and the generated output
|
||||
# is added to the target sources.
|
||||
function(qt_internal_autouic target)
|
||||
set(outfiles "")
|
||||
|
||||
get_target_property(source_dir "${target}" SOURCE_DIR)
|
||||
get_target_property(binary_dir "${target}" BINARY_DIR)
|
||||
|
||||
foreach(infile ${ARGN})
|
||||
get_filename_component(ext "${infile}" EXT)
|
||||
if("${ext}" STREQUAL ".ui")
|
||||
qt_make_output_file("${infile}" "ui_" ".h" "${source_dir}" "${binary_dir}" outfile)
|
||||
qt_create_uic_command("${infile}" "${source_dir}" "${outfile}")
|
||||
list(APPEND outfiles "${outfile}")
|
||||
|
||||
get_filename_component(outfile_path "${outfile}" PATH)
|
||||
target_include_directories("${target}" PRIVATE "${outfile_path}")
|
||||
endif()
|
||||
endforeach()
|
||||
target_sources("${target}" PRIVATE "${outfiles}")
|
||||
endfunction()
|
||||
|
||||
|
||||
# This function attempts to (poorly) parse the given resourceFile (.qrc) and
|
||||
# determine the dependencies, i.e. which files are intended for inclusion into
|
||||
# the Qt resource.
|
||||
function(qt_extract_qrc_dependencies resourceFile out_depends_ rc_depends_)
|
||||
get_filename_component(rc_path ${resourceFile} PATH)
|
||||
|
||||
if(EXISTS "${infile}")
|
||||
# parse file for dependencies
|
||||
# all files are absolute paths or relative to the location of the qrc file
|
||||
file(READ "${infile}" RC_FILE_CONTENTS)
|
||||
string(REGEX MATCHALL "<file[^<]+" RC_FILES "${RC_FILE_CONTENTS}")
|
||||
set(RC_DEPENDS "")
|
||||
foreach(RC_FILE ${RC_FILES})
|
||||
string(REGEX REPLACE "^<file[^>]*>" "" RC_FILE "${RC_FILE}")
|
||||
if(NOT IS_ABSOLUTE "${RC_FILE}")
|
||||
set(RC_FILE "${rc_path}/${RC_FILE}")
|
||||
endif()
|
||||
set(RC_DEPENDS ${RC_DEPENDS} "${RC_FILE}")
|
||||
endforeach()
|
||||
# Since this cmake function is doing the dependency scanning for these files,
|
||||
# let's make a configured file and add it as a dependency so cmake is run
|
||||
# again when dependencies need to be recomputed.
|
||||
qt_make_output_file("${infile}" "" ".qrc.depends" "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" out_depends)
|
||||
configure_file("${infile}" "${out_depends}" COPYONLY)
|
||||
else()
|
||||
# The .qrc file does not exist (yet). Let's add a dependency and hope
|
||||
# that it will be generated later
|
||||
set(out_depends)
|
||||
endif()
|
||||
|
||||
set(${out_depends_} ${out_depends} PARENT_SCOPE)
|
||||
set(${rc_depends_} ${RC_DEPENDS} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
# This function creates the necessary rule to call rcc on the given
|
||||
# resource file and stores the name of the to-be generated C++ source
|
||||
# file (created by rcc) in the outCppFile variable.
|
||||
function(qt_create_rcc_command resourceFile source_dir binary_dir outfile)
|
||||
qt_extract_qrc_dependencies("${infile}" out_depends rc_depends "${source_dir}" "${binary_dir}")
|
||||
set_source_files_properties("${infile}" PROPERTIES SKIP_AUTORCC ON)
|
||||
|
||||
get_filename_component(outfilename "${resourceFile}" NAME_WE)
|
||||
add_custom_command(OUTPUT "${outfile}"
|
||||
COMMAND "Qt::rcc" --name "${outfilename}" --output "${outfile}" "${resourceFile}"
|
||||
MAIN_DEPENDENCY "${infile}"
|
||||
DEPENDS "${rc_depends}" "${out_depends}"
|
||||
WORKING_DIRECTORY "${source_dir}" VERBATIM)
|
||||
set_source_files_properties("${outfile}" PROPERTIES SKIP_AUTOMOC ON)
|
||||
set_source_files_properties("${outfile}" PROPERTIES SKIP_AUTOUIC ON)
|
||||
endfunction()
|
||||
|
||||
|
||||
# This function takes a target as a parameter, followed by a list of sources.
|
||||
# Any sources ending with the .qrc extension are treated as Qt resources and rules
|
||||
# to call rcc are generated. The source files rcc generates are added to the target.
|
||||
function(qt_internal_autorcc target)
|
||||
get_target_property(binary_dir "${target}" BINARY_DIR)
|
||||
get_target_property(source_dir "${target}" SOURCE_DIR)
|
||||
|
||||
set(qrc_outfiles "")
|
||||
|
||||
foreach(infile ${ARGN})
|
||||
get_filename_component(ext "${infile}" EXT)
|
||||
if("${ext}" STREQUAL ".qrc")
|
||||
qt_make_output_file("${infile}" "qrc_" ".cpp" "${source_dir}" "${binary_dir}" outfile)
|
||||
list(FIND all_sources "${outfile}" known_result)
|
||||
if (known_result GREATER -1)
|
||||
continue()
|
||||
endif()
|
||||
|
||||
qt_create_rcc_command("${infile}" "${source_dir}" "${binary_dir}" "${outfile}")
|
||||
list(APPEND qrc_outfiles "${outfile}")
|
||||
endif()
|
||||
endforeach()
|
||||
target_sources("${target}" PRIVATE "${qrc_outfiles}")
|
||||
endfunction()
|
||||
|
||||
|
||||
# This function takes a target as a parameter, followed by a list of sources.
|
||||
# The sources are scanned for .ui and .qrc as well as Q_OBJECT/Q_GADGET use
|
||||
# and rules to call uic/rcc/moc are created. Any generated sources are added
|
||||
# as private sources to the specified target.
|
||||
function(qt_internal_process_automatic_sources target)
|
||||
qt_internal_automoc("${target}" ${ARGN})
|
||||
qt_internal_autouic("${target}" ${ARGN})
|
||||
qt_internal_autorcc("${target}" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
|
||||
set(__default_private_args "SOURCES;LIBRARIES;INCLUDE_DIRECTORIES;DEFINES;DBUS_ADAPTOR_FLAGS;DBUS_ADAPTOR_SOURCES;DBUS_INTERFACE_FLAGS;DBUS_INTERFACE_SOURCES;FEATURE_DEPENDENCIES")
|
||||
set(__default_public_args "PUBLIC_LIBRARIES;PUBLIC_INCLUDE_DIRECTORIES;PUBLIC_DEFINES")
|
||||
|
||||
@ -459,7 +271,6 @@ function(extend_target target)
|
||||
qt_create_qdbusxml2cpp_command("${target}" "${interface}" INTERFACE FLAGS "${arg_DBUS_INTERFACE_FLAGS}")
|
||||
list(APPEND dbus_sources "${sources}")
|
||||
endforeach()
|
||||
qt_internal_process_automatic_sources("${target}" "${arg_SOURCES}")
|
||||
|
||||
# Import features
|
||||
if(NOT "${target}" STREQUAL "Core")
|
||||
@ -487,6 +298,15 @@ function(extend_target target)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set_target_properties("${target}" PROPERTIES
|
||||
AUTOMOC ON
|
||||
AUTOMOC_EXECUTABLE "$<TARGET_FILE:Qt::moc>"
|
||||
AUTORCC ON
|
||||
AUTORCC_EXECUTABLE "$<TARGET_FILE:Qt::rcc>"
|
||||
AUTOUIC ON
|
||||
AUTOUIC_EXECUTABLE "$<TARGET_FILE:Qt::uic>"
|
||||
)
|
||||
|
||||
target_sources("${target}" PRIVATE ${arg_SOURCES} ${dbus_sources})
|
||||
if (arg_COMPILE_FLAGS)
|
||||
set_source_files_properties(${arg_SOURCES} PROPERTIES COMPILE_FLAGS "${arg_COMPILE_FLAGS}")
|
||||
@ -882,19 +702,14 @@ function(add_qt_tool name)
|
||||
endif()
|
||||
|
||||
add_qt_executable("${name}" OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_BINDIR}"
|
||||
# Do not pass sources here: They may not get processed when BOOTSTRAP is set!
|
||||
SOURCES ${arg_SOURCES}
|
||||
INCLUDE_DIRECTORIES
|
||||
${arg_INCLUDE_DIRECTORIES}
|
||||
DEFINES ${arg_DEFINES}
|
||||
LIBRARIES ${corelib} ${arg_LIBRARIES}
|
||||
)
|
||||
target_sources("${name}" PRIVATE "${arg_SOURCES}")
|
||||
qt_internal_add_target_aliases("${name}")
|
||||
|
||||
if (NOT arg_BOOTSTRAP)
|
||||
qt_internal_process_automatic_sources("${name}" ${arg_SOURCES})
|
||||
endif()
|
||||
|
||||
install(TARGETS "${name}" EXPORT "Qt${PROJECT_VERSION_MAJOR}ToolsTargets" DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
qt_push_features_into_parent_scope()
|
||||
endfunction()
|
||||
@ -968,75 +783,28 @@ function(qt_make_output_file infile prefix suffix source_dir binary_dir result)
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(qt_get_moc_flags moc_flags)
|
||||
set(${moc_flags})
|
||||
get_directory_property(inc_DIRS INCLUDE_DIRECTORIES)
|
||||
# Complete manual moc invocation with full control.
|
||||
# Use AUTOMOC whenever possible.
|
||||
function(qt_manual_moc result)
|
||||
cmake_parse_arguments(arg "" "" "FLAGS" ${ARGN})
|
||||
set(moc_files)
|
||||
foreach(infile ${arg_UNPARSED_ARGUMENTS})
|
||||
qt_make_output_file("${infile}" "moc_" ".cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" outfile)
|
||||
list(APPEND moc_files "${outfile}")
|
||||
|
||||
if(CMAKE_INCLUDE_CURRENT_DIR)
|
||||
list(APPEND inc_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
set(moc_parameters_file "${outfile}_parameters$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>")
|
||||
set(moc_parameters ${arg_FLAGS} -o "${outfile}" "${infile}")
|
||||
string (REPLACE ";" "\n" moc_parameters "${moc_parameters}")
|
||||
|
||||
foreach(current ${inc_DIRS})
|
||||
if("${current}" MATCHES "\\.framework/?$")
|
||||
string(REGEX REPLACE "/[^/]+\\.framework" "" framework_path "${current}")
|
||||
set(${moc_flags} ${${moc_flags}} "-F${framework_path}")
|
||||
else()
|
||||
set(${moc_flags} ${${moc_flags}} "-I${current}")
|
||||
endif()
|
||||
file(GENERATE OUTPUT "${moc_parameters_file}" CONTENT "${moc_parameters}\n")
|
||||
|
||||
add_custom_command(OUTPUT "${outfile}"
|
||||
COMMAND Qt::moc "@${moc_parameters_file}"
|
||||
DEPENDS "${infile}" ${moc_depends} Qt::moc
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM)
|
||||
endforeach()
|
||||
|
||||
get_directory_property(defines COMPILE_DEFINITIONS)
|
||||
foreach(current ${defines})
|
||||
set(${moc_flags} ${${moc_flags}} "-D${current}")
|
||||
endforeach()
|
||||
|
||||
if(WIN32)
|
||||
set(${moc_flags} ${${moc_flags}} -DWIN32)
|
||||
endif()
|
||||
if (MSVC)
|
||||
set(${moc_flags} ${${moc_flags}} --compiler-flavor=msvc)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
# helper to set up a moc rule
|
||||
function(qt_create_moc_command target source_dir infile outfile moc_flags moc_options moc_depends)
|
||||
# Pass the parameters in a file. Set the working directory to
|
||||
# be that containing the parameters file and reference it by
|
||||
# just the file name. This is necessary because the moc tool on
|
||||
# MinGW builds does not seem to handle spaces in the path to the
|
||||
# file given with the @ syntax.
|
||||
set (moc_parameters_file "${outfile}_parameters")
|
||||
set (moc_parameters ${moc_flags} ${moc_options} -o "${outfile}" "${infile}")
|
||||
string (REPLACE ";" "\n" moc_parameters "${moc_parameters}")
|
||||
|
||||
set(moc_parameters_file "${moc_parameters_file}$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>")
|
||||
set(targetincludes "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>")
|
||||
set(targetdefines "$<TARGET_PROPERTY:${target},COMPILE_DEFINITIONS>")
|
||||
set(targetincludes "$<$<BOOL:${targetincludes}>:-I$<JOIN:${targetincludes},\n-I>\n>")
|
||||
set(targetdefines "$<$<BOOL:${targetdefines}>:-D$<JOIN:${targetdefines},\n-D>\n>")
|
||||
|
||||
file (GENERATE
|
||||
OUTPUT "${moc_parameters_file}"
|
||||
CONTENT "${targetdefines}${targetincludes}${moc_parameters}\n"
|
||||
)
|
||||
|
||||
set(moc_extra_parameters_file @${moc_parameters_file})
|
||||
add_custom_command(OUTPUT "${outfile}"
|
||||
COMMAND "Qt::moc" "${moc_extra_parameters_file}"
|
||||
DEPENDS "${infile}" ${moc_depends}
|
||||
WORKING_DIRECTORY "${source_dir}" VERBATIM)
|
||||
endfunction()
|
||||
|
||||
|
||||
# helper to set up a uic rule
|
||||
function(qt_create_uic_command infile source_dir outfile)
|
||||
add_custom_command(OUTPUT "${outfile}"
|
||||
COMMAND "Qt::uic" "${infile}" -o "${outfile}"
|
||||
DEPENDS "${infile}"
|
||||
COMMENT "Running UIC on ${infile}."
|
||||
WORKING_DIRECTORY "${source_dir}" VERBATIM)
|
||||
set_source_files_properties("${outfile}" PROPERTIES HEADER_FILE_ONLY ON)
|
||||
set("${result}" ${moc_files} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
@ -1066,10 +834,7 @@ function(qt_create_qdbusxml2cpp_command target infile)
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
VERBATIM)
|
||||
|
||||
# Moc the header:
|
||||
qt_internal_wrap_cpp("${target}" MOC "${header_file}" HEADER_FILE_ONLY OFF)
|
||||
|
||||
target_sources("${target}" PRIVATE "${header_file}" "${source_file}" "${moc_sources}")
|
||||
target_sources("${target}" PRIVATE "${header_file}" "${source_file}")
|
||||
endfunction()
|
||||
|
||||
|
||||
|
@ -4,6 +4,8 @@ Initial port is on-going. Some modules of QtBase are ported, incl. some of the p
|
||||
|
||||
Basic functionality is there (moc, uic, etc.), but documentation, translations, qdbusxml2cpp, etc. are missing.
|
||||
|
||||
NOTE: YOU WILL NEED CMAKE 3.14 or later (if that is not released yet you will need to have
|
||||
https://gitlab.kitware.com/cmake/cmake/merge_requests/2679 applied).
|
||||
|
||||
# Intro
|
||||
|
||||
|
@ -45,7 +45,4 @@ macro(add_cmake_test_generate name)
|
||||
endmacro()
|
||||
|
||||
add_cmake_test_generate(features)
|
||||
add_cmake_test_generate(moc)
|
||||
add_cmake_test_generate(qrc)
|
||||
add_cmake_test_generate(qt_make_output_file)
|
||||
add_cmake_test_generate(uic)
|
||||
|
@ -1,34 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.12.0)
|
||||
|
||||
project(MocTest
|
||||
VERSION 1.0.0
|
||||
DESCRIPTION "Moc test"
|
||||
HOMEPAGE_URL "https://qt.io/"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
## Add some paths to check for cmake modules:
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../;${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/extra-cmake-modules/find-modules;${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/kwin")
|
||||
|
||||
## Qt specific setup common for all modules:
|
||||
include(QtSetup)
|
||||
|
||||
include(../test.cmake)
|
||||
|
||||
fake_moc_results(MOC foo.cpp sub2/foobar.h MOC_AND_BUILD main.cpp sub/bar.h)
|
||||
add_qt_executable(test_executable
|
||||
SOURCES
|
||||
../main.cpp
|
||||
sub/bar.h
|
||||
sub2/foobar.h
|
||||
foo.cpp
|
||||
)
|
||||
|
||||
test_source_file(test_executable "${CMAKE_CURRENT_BINARY_DIR}/main.moc" BUILD)
|
||||
test_source_file(test_executable "${CMAKE_CURRENT_BINARY_DIR}/sub/moc_bar.cpp" BUILD)
|
||||
test_source_file(test_executable "${CMAKE_CURRENT_BINARY_DIR}/sub2/moc_foobar.cpp")
|
||||
test_source_file(test_executable "${CMAKE_CURRENT_BINARY_DIR}/foo.moc")
|
||||
|
||||
test_include_directory(test_executable "${CMAKE_CURRENT_BINARY_DIR}/sub" UNKNOWN)
|
||||
test_include_directory(test_executable "${CMAKE_CURRENT_BINARY_DIR}/sub2")
|
||||
|
@ -1,31 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.12.0)
|
||||
|
||||
project(QrcTest
|
||||
VERSION 1.0.0
|
||||
DESCRIPTION "Qrc test"
|
||||
HOMEPAGE_URL "https://qt.io/"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
## Add some paths to check for cmake modules:
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../;${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/extra-cmake-modules/find-modules;${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/kwin")
|
||||
|
||||
## Qt specific setup common for all modules:
|
||||
include(QtSetup)
|
||||
|
||||
include(../test.cmake)
|
||||
|
||||
fake_moc_results()
|
||||
add_qt_executable(test_executable
|
||||
SOURCES
|
||||
../main.cpp
|
||||
qrc.qrc
|
||||
)
|
||||
|
||||
fake_moc_results()
|
||||
extend_target(test_executable SOURCES dialog/dialog.qrc)
|
||||
|
||||
test_source_file(test_executable "${CMAKE_CURRENT_BINARY_DIR}/qrc_qrc.cpp" BUILD)
|
||||
test_source_file(test_executable "${CMAKE_CURRENT_BINARY_DIR}/dialog/qrc_dialog.cpp" BUILD)
|
||||
|
||||
test_include_directory(test_executable "${CMAKE_CURRENT_BINARY_DIR}/dialog" UNKNOWN)
|
@ -1,31 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.12.0)
|
||||
|
||||
project(UicTest
|
||||
VERSION 1.0.0
|
||||
DESCRIPTION "Uic test"
|
||||
HOMEPAGE_URL "https://qt.io/"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
## Add some paths to check for cmake modules:
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../;${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/extra-cmake-modules/find-modules;${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/kwin")
|
||||
|
||||
## Qt specific setup common for all modules:
|
||||
include(QtSetup)
|
||||
|
||||
include(../test.cmake)
|
||||
|
||||
fake_moc_results()
|
||||
add_qt_executable(test_executable
|
||||
SOURCES
|
||||
../main.cpp
|
||||
window.ui
|
||||
)
|
||||
|
||||
fake_moc_results()
|
||||
extend_target(test_executable SOURCES dialog/dialog.ui)
|
||||
|
||||
test_source_file(test_executable "${CMAKE_CURRENT_BINARY_DIR}/ui_window.h")
|
||||
test_source_file(test_executable "${CMAKE_CURRENT_BINARY_DIR}/dialog/ui_dialog.h")
|
||||
|
||||
test_include_directory(test_executable "${CMAKE_CURRENT_BINARY_DIR}/dialog")
|
@ -1,18 +1,6 @@
|
||||
# Generated from rasterwindow.pro.
|
||||
|
||||
#####################################################################
|
||||
## None Binary:
|
||||
#####################################################################
|
||||
|
||||
set(sources main.cpp
|
||||
rasterwindow.cpp rasterwindow.h)
|
||||
add_executable(rasterwindow
|
||||
${sources}
|
||||
add_qt_executable(rasterwindow
|
||||
SOURCES
|
||||
main.cpp
|
||||
rasterwindow.cpp rasterwindow.h
|
||||
LIBRARIES Qt::Core Qt::Test Qt::Gui
|
||||
)
|
||||
qt_internal_automoc(rasterwindow ${sources})
|
||||
target_include_directories(rasterwindow
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
target_link_libraries(rasterwindow PRIVATE Qt::Core Qt::Test Qt::Gui)
|
||||
|
@ -23,7 +23,6 @@ function(find_or_build_bootstrap_names)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
find_or_build_bootstrap_tool(qmocscanner)
|
||||
if (_build_tools)
|
||||
add_subdirectory(tools/bootstrap) # bootstrap library
|
||||
endif()
|
||||
@ -32,10 +31,6 @@ function(find_or_build_bootstrap_names)
|
||||
find_or_build_bootstrap_tool(qfloat16-tables)
|
||||
find_or_build_bootstrap_tool(tracegen)
|
||||
|
||||
# $<TARGET_FILE:Qt::qmocscanner> does not work during configure run, so export into a plain variable:
|
||||
get_target_property(_mocscanner "Qt::qmocscanner" IMPORTED_LOCATION)
|
||||
set(QT_MOCSCANNER "${_mocscanner}" CACHE INTERNAL "Qt moc scanner")
|
||||
|
||||
if (_build_tools)
|
||||
install(EXPORT "Qt${PROJECT_VERSION_MAJOR}ToolsTargets" NAMESPACE "Qt::" DESTINATION "${INSTALL_LIBDIR}/cmake/Qt${PROJECT_VERSION_MAJOR}")
|
||||
endif()
|
||||
@ -76,4 +71,5 @@ endif()
|
||||
if (QT_FEATURE_testlib)
|
||||
add_subdirectory(testlib)
|
||||
endif()
|
||||
add_subdirectory(printsupport)
|
||||
add_subdirectory(plugins)
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
find_package(Threads)
|
||||
find_package(WrapDoubleConversion REQUIRED)
|
||||
|
||||
@ -51,7 +50,6 @@ add_qt_module(Core
|
||||
global/qlibraryinfo.cpp global/qlibraryinfo.h
|
||||
global/qlogging.cpp global/qlogging.h
|
||||
global/qmalloc.cpp
|
||||
global/qnamespace.h
|
||||
global/qnumeric.cpp global/qnumeric.h global/qnumeric_p.h
|
||||
global/qoperatingsystemversion.cpp global/qoperatingsystemversion.h global/qoperatingsystemversion_p.h
|
||||
global/qprocessordetection.h
|
||||
@ -117,7 +115,6 @@ add_qt_module(Core
|
||||
kernel/qmetatype.cpp kernel/qmetatype.h kernel/qmetatype_p.h
|
||||
kernel/qmetatypeswitcher_p.h
|
||||
kernel/qmimedata.cpp kernel/qmimedata.h
|
||||
kernel/qobject.cpp kernel/qobject.h kernel/qobject_p.h
|
||||
kernel/qobject_impl.h
|
||||
kernel/qobjectcleanuphandler.cpp kernel/qobjectcleanuphandler.h
|
||||
kernel/qobjectdefs.h
|
||||
@ -229,6 +226,8 @@ add_qt_module(Core
|
||||
tools/qvector.h
|
||||
tools/qversionnumber.cpp tools/qversionnumber.h
|
||||
tools/qvsnprintf.cpp
|
||||
INCLUDE_DIRECTORIES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/global # For qconfig.cpp
|
||||
LIBRARIES
|
||||
WrapDoubleConversion
|
||||
WrapRt
|
||||
@ -240,6 +239,28 @@ add_qt_module(Core
|
||||
QT_NO_FOREACH
|
||||
)
|
||||
|
||||
# Handle QObject: Automoc does not work for this as it would
|
||||
# require to spill internals into users:
|
||||
add_library(Core_qobject OBJECT)
|
||||
qt_manual_moc(qobject_moc_files kernel/qobject.h global/qnamespace.h)
|
||||
set_source_files_properties(${qobject_moc_files} PROPERTIES HEADER_FILE_ONLY ON)
|
||||
target_sources(Core_qobject PRIVATE
|
||||
global/qnamespace.h
|
||||
kernel/qobject.cpp kernel/qobject.h kernel/qobject_p.h ${qobject_moc_files})
|
||||
target_include_directories(Core_qobject PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/global"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/kernel"
|
||||
"${PROJECT_BINARY_DIR}/include"
|
||||
"${PROJECT_BINARY_DIR}/include/QtCore"
|
||||
"${PROJECT_BINARY_DIR}/include/QtCore/${PROJECT_VERSION}"
|
||||
"${PROJECT_BINARY_DIR}/include/QtCore/${PROJECT_VERSION}/QtCore")
|
||||
target_link_libraries(Core_qobject PRIVATE Qt::Platform)
|
||||
target_link_libraries(Core PRIVATE Core_qobject)
|
||||
|
||||
# Comments trigger moc for these, so skip automoc:
|
||||
set_source_files_properties( tools/qsharedpointer.cpp PROPERTIES SKIP_AUTOMOC ON)
|
||||
|
||||
set_property(TARGET Core APPEND PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/global/qconfig.h")
|
||||
set_property(TARGET Core APPEND PROPERTY PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/global/qconfig_p.h")
|
||||
|
||||
@ -738,6 +759,7 @@ extend_target(Core CONDITION QT_FEATURE_statemachine
|
||||
statemachine/qsignaltransition.cpp statemachine/qsignaltransition.h statemachine/qsignaltransition_p.h
|
||||
statemachine/qstate.cpp statemachine/qstate.h statemachine/qstate_p.h
|
||||
statemachine/qstatemachine.cpp statemachine/qstatemachine.h statemachine/qstatemachine_p.h
|
||||
INCLUDE_DIRECTORIES statemachine
|
||||
)
|
||||
|
||||
# qeventtransition:
|
||||
@ -756,6 +778,7 @@ extend_target(Core CONDITION QT_FEATURE_mimetype
|
||||
mimetypes/qmimeprovider.cpp mimetypes/qmimeprovider_p.h
|
||||
mimetypes/qmimetype.cpp mimetypes/qmimetype.h mimetypes/qmimetype_p.h
|
||||
mimetypes/qmimetypeparser.cpp mimetypes/qmimetypeparser_p.h
|
||||
INCLUDE_DIRECTORIES mimetypes
|
||||
)
|
||||
|
||||
# Enable Evaluation based on QT_EVAL variable being set from the outside:
|
||||
|
@ -4215,8 +4215,8 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
|
||||
If the QVariant contains a pointer to a type derived from QObject then
|
||||
\c{T} may be any QObject type. If the pointer stored in the QVariant can be
|
||||
qobject_cast to T, then that result is returned. Otherwise a null pointer is
|
||||
returned. Note that this only works for QObject subclasses which use the
|
||||
Q_OBJECT macro.
|
||||
returned. Note that this only works for QObject subclasses which use
|
||||
the Q_OBJECT macro.
|
||||
|
||||
If the QVariant contains a sequential container and \c{T} is QVariantList, the
|
||||
elements of the container will be converted into \l {QVariant}s and returned as a QVariantList.
|
||||
|
@ -235,6 +235,14 @@ add_qt_module(Gui
|
||||
Qt::Core
|
||||
)
|
||||
|
||||
set_source_files_properties(
|
||||
# Comment triggering moc:
|
||||
opengl/qopenglfunctions.cpp
|
||||
PROPERTIES
|
||||
SKIP_AUTOMOC ON
|
||||
SKIP_AUTOUIC ON
|
||||
SKIP_AUTORCC ON)
|
||||
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
@ -59,7 +59,8 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QShaderLanguage
|
||||
{
|
||||
Q_GUI_EXPORT Q_NAMESPACE
|
||||
Q_GUI_EXPORT
|
||||
Q_NAMESPACE
|
||||
|
||||
enum StorageQualifier : char {
|
||||
Const = 1,
|
||||
|
@ -58,6 +58,14 @@ add_qt_module(Network
|
||||
Qt::CorePrivate
|
||||
)
|
||||
|
||||
set_source_files_properties(
|
||||
# Comment triggering moc:
|
||||
access/qnetworkaccessdebugpipebackend_p.h
|
||||
PROPERTIES
|
||||
SKIP_AUTOMOC ON
|
||||
SKIP_AUTOUIC ON
|
||||
SKIP_AUTORCC ON)
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
||||
|
@ -31,6 +31,12 @@ add_qt_module(OpenGL
|
||||
Qt::GuiPrivate
|
||||
Qt::WidgetsPrivate
|
||||
)
|
||||
set_source_files_properties(qglfunctions.cpp qgraphicsshadereffect.cpp PROPERTIES
|
||||
SKIP_AUTOMOC ON
|
||||
SKIP_AUTOUIC ON
|
||||
SKIP_AUTORCC ON
|
||||
)
|
||||
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
@ -1,6 +1,11 @@
|
||||
# FIXME Add the rest of the stuff
|
||||
|
||||
add_qt_module(PlatformHeaders SOURCES fake.cpp)
|
||||
set_source_files_properties(fake.cpp PROPERTIES
|
||||
SKIP_AUTOMOC ON
|
||||
SKIP_AUTOUIC ON
|
||||
SKIP_AUTORCC ON
|
||||
)
|
||||
|
||||
extend_target(PlatformHeaders CONDITION APPLE SOURCES cocoafunctions/qcocoawindowfunctions.h)
|
||||
|
||||
|
@ -20,6 +20,11 @@ add_qt_module(FontDatabaseSupport
|
||||
Qt::CorePrivate
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
set_source_files_properties(fake.cpp PROPERTIES
|
||||
SKIP_AUTOMOC ON
|
||||
SKIP_AUTOUIC ON
|
||||
SKIP_AUTORCC ON
|
||||
)
|
||||
|
||||
extend_target(FontDatabaseSupport CONDITION APPLE
|
||||
SOURCES
|
||||
|
@ -1,10 +0,0 @@
|
||||
set(_mocscanner "${PROJECT_BINARY_DIR}/${INSTALL_BINDIR}/qmocscanner${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
try_compile(mocscanner_built "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" COPY_FILE "${_mocscanner}")
|
||||
|
||||
add_executable(qmocscanner IMPORTED GLOBAL)
|
||||
set_target_properties(qmocscanner PROPERTIES IMPORTED_LOCATION "${_mocscanner}")
|
||||
|
||||
install(PROGRAMS "${_mocscanner}" DESTINATION "${INSTALL_BINDIR}")
|
||||
add_executable("Qt::qmocscanner" ALIAS "qmocscanner")
|
||||
|
||||
# FIXME: This should get exported to ToolsTargets!
|
@ -1,623 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Intel Corporation.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the qmocscanner application of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** 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.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
struct ScanResult
|
||||
{
|
||||
std::string fileName;
|
||||
bool foundMocRelevantMacro = false;
|
||||
std::vector<std::string> includedMocFiles;
|
||||
};
|
||||
|
||||
struct Option
|
||||
{
|
||||
static int debug_level;
|
||||
};
|
||||
int Option::debug_level = 0;
|
||||
|
||||
static void debug_msg(int level, const char *fmt, ...)
|
||||
{
|
||||
if (level < 3)
|
||||
return;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#define qmake_endOfLine(c) (c == '\r' || c == '\n')
|
||||
|
||||
static int skipEscapedLineEnds(const char *buffer, int buffer_len, int offset, int *lines)
|
||||
{
|
||||
// Join physical lines to make logical lines, as in the C preprocessor
|
||||
while (offset + 1 < buffer_len
|
||||
&& buffer[offset] == '\\'
|
||||
&& qmake_endOfLine(buffer[offset + 1])) {
|
||||
offset += 2;
|
||||
++*lines;
|
||||
if (offset < buffer_len
|
||||
&& buffer[offset - 1] == '\r'
|
||||
&& buffer[offset] == '\n') // CRLF
|
||||
offset++;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static bool matchWhileUnsplitting(const char *buffer, int buffer_len, int start,
|
||||
const char *needle, int needle_len,
|
||||
int *matchlen, int *lines)
|
||||
{
|
||||
int x = start;
|
||||
for (int n = 0; n < needle_len;
|
||||
n++, x = skipEscapedLineEnds(buffer, buffer_len, x + 1, lines)) {
|
||||
if (x >= buffer_len || buffer[x] != needle[n])
|
||||
return false;
|
||||
}
|
||||
// That also skipped any remaining BSNLs immediately after the match.
|
||||
|
||||
// Tell caller how long the match was:
|
||||
*matchlen = x - start;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Advance from an opening quote at buffer[offset] to the matching close quote. */
|
||||
static int scanPastString(char *buffer, int buffer_len, int offset, int *lines)
|
||||
{
|
||||
// http://en.cppreference.com/w/cpp/language/string_literal
|
||||
// It might be a C++11 raw string.
|
||||
bool israw = false;
|
||||
if (buffer[offset] == '"' && offset > 0) {
|
||||
int explore = offset - 1;
|
||||
bool prefix = false; // One of L, U, u or u8 may appear before R
|
||||
bool saw8 = false; // Partial scan of u8
|
||||
while (explore >= 0) {
|
||||
// Cope with backslash-newline interruptions of the prefix:
|
||||
if (explore > 0
|
||||
&& qmake_endOfLine(buffer[explore])
|
||||
&& buffer[explore - 1] == '\\') {
|
||||
explore -= 2;
|
||||
} else if (explore > 1
|
||||
&& buffer[explore] == '\n'
|
||||
&& buffer[explore - 1] == '\r'
|
||||
&& buffer[explore - 2] == '\\') {
|
||||
explore -= 3;
|
||||
// Remaining cases can only decrement explore by one at a time:
|
||||
} else if (saw8 && buffer[explore] == 'u') {
|
||||
explore--;
|
||||
saw8 = false;
|
||||
prefix = true;
|
||||
} else if (saw8 || prefix) {
|
||||
break;
|
||||
} else if (explore > 1 && buffer[explore] == '8') {
|
||||
explore--;
|
||||
saw8 = true;
|
||||
} else if (buffer[explore] == 'L'
|
||||
|| buffer[explore] == 'U'
|
||||
|| buffer[explore] == 'u') {
|
||||
explore--;
|
||||
prefix = true;
|
||||
} else if (buffer[explore] == 'R') {
|
||||
if (israw)
|
||||
break;
|
||||
explore--;
|
||||
israw = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check the R (with possible prefix) isn't just part of an identifier:
|
||||
if (israw && explore >= 0
|
||||
&& (isalnum(buffer[explore]) || buffer[explore] == '_')) {
|
||||
israw = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (israw) {
|
||||
#define SKIP_BSNL(pos) skipEscapedLineEnds(buffer, buffer_len, (pos), lines)
|
||||
|
||||
offset = SKIP_BSNL(offset + 1);
|
||||
const char *const delim = buffer + offset;
|
||||
int clean = offset;
|
||||
while (offset < buffer_len && buffer[offset] != '(') {
|
||||
if (clean < offset)
|
||||
buffer[clean++] = buffer[offset];
|
||||
else
|
||||
clean++;
|
||||
|
||||
offset = SKIP_BSNL(offset + 1);
|
||||
}
|
||||
/*
|
||||
Not checking correctness (trust real compiler to do that):
|
||||
- no controls, spaces, '(', ')', '\\' or (presumably) '"' in delim;
|
||||
- at most 16 bytes in delim
|
||||
|
||||
Raw strings are surely defined after phase 2, when BSNLs are resolved;
|
||||
so the delimiter's exclusion of '\\' and space (including newlines)
|
||||
applies too late to save us the need to cope with BSNLs in it.
|
||||
*/
|
||||
|
||||
const int delimlen = buffer + clean - delim;
|
||||
int matchlen = delimlen, extralines = 0;
|
||||
while ((offset = SKIP_BSNL(offset + 1)) < buffer_len
|
||||
&& (buffer[offset] != ')'
|
||||
|| (delimlen > 0 &&
|
||||
!matchWhileUnsplitting(buffer, buffer_len,
|
||||
offset + 1, delim, delimlen,
|
||||
&matchlen, &extralines))
|
||||
|| buffer[offset + 1 + matchlen] != '"')) {
|
||||
// skip, but keep track of lines
|
||||
if (qmake_endOfLine(buffer[offset]))
|
||||
++*lines;
|
||||
extralines = 0;
|
||||
}
|
||||
*lines += extralines; // from the match
|
||||
// buffer[offset] is ')'
|
||||
offset += 1 + matchlen; // 1 for ')', then delim
|
||||
// buffer[offset] is '"'
|
||||
|
||||
#undef SKIP_BSNL
|
||||
} else { // Traditional string or char literal:
|
||||
const char term = buffer[offset];
|
||||
while (++offset < buffer_len && buffer[offset] != term) {
|
||||
if (buffer[offset] == '\\')
|
||||
++offset;
|
||||
else if (qmake_endOfLine(buffer[offset]))
|
||||
++*lines;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static std::vector<std::string> findIncludes(const char *fileName, char *buffer, int buffer_len)
|
||||
{
|
||||
std::vector<std::string> includes;
|
||||
int line_count = 1;
|
||||
enum {
|
||||
/*
|
||||
States of C preprocessing (for TYPE_C only), after backslash-newline
|
||||
elimination and skipping comments and spaces (i.e. in ANSI X3.159-1989
|
||||
section 2.1.1.2's phase 4). We're about to study buffer[x] to decide
|
||||
on which transition to do.
|
||||
*/
|
||||
AtStart, // start of logical line; a # may start a preprocessor directive
|
||||
HadHash, // saw a # at start, looking for preprocessor keyword
|
||||
WantName, // saw #include or #import, waiting for name
|
||||
InCode // after directive, parsing non-#include directive or in actual code
|
||||
} cpp_state = AtStart;
|
||||
|
||||
int x = 0;
|
||||
if (buffer_len >= 3) {
|
||||
const unsigned char *p = (unsigned char *)buffer;
|
||||
// skip UTF-8 BOM, if present
|
||||
if (p[0] == 0xEF && p[1] == 0xBB && p[2] == 0xBF)
|
||||
x += 3;
|
||||
}
|
||||
for (; x < buffer_len; ++x) {
|
||||
bool try_local = true;
|
||||
char *inc = nullptr;
|
||||
// We've studied all buffer[i] for i < x
|
||||
for (; x < buffer_len; ++x) {
|
||||
// How to handle backslash-newline (BSNL) pairs:
|
||||
#define SKIP_BSNL(pos) skipEscapedLineEnds(buffer, buffer_len, (pos), &line_count)
|
||||
|
||||
// Seek code or directive, skipping comments and space:
|
||||
for (; (x = SKIP_BSNL(x)) < buffer_len; ++x) {
|
||||
if (buffer[x] == ' ' || buffer[x] == '\t') {
|
||||
// keep going
|
||||
} else if (buffer[x] == '/') {
|
||||
int extralines = 0;
|
||||
int y = skipEscapedLineEnds(buffer, buffer_len, x + 1, &extralines);
|
||||
if (y >= buffer_len) {
|
||||
x = y;
|
||||
break;
|
||||
} else if (buffer[y] == '/') { // C++-style comment
|
||||
line_count += extralines;
|
||||
x = SKIP_BSNL(y + 1);
|
||||
while (x < buffer_len && !qmake_endOfLine(buffer[x]))
|
||||
x = SKIP_BSNL(x + 1); // skip
|
||||
|
||||
cpp_state = AtStart;
|
||||
++line_count;
|
||||
} else if (buffer[y] == '*') { // C-style comment
|
||||
line_count += extralines;
|
||||
x = y;
|
||||
while ((x = SKIP_BSNL(++x)) < buffer_len) {
|
||||
if (buffer[x] == '*') {
|
||||
extralines = 0;
|
||||
y = skipEscapedLineEnds(buffer, buffer_len,
|
||||
x + 1, &extralines);
|
||||
if (y < buffer_len && buffer[y] == '/') {
|
||||
line_count += extralines;
|
||||
x = y; // for loop shall step past this
|
||||
break;
|
||||
}
|
||||
} else if (qmake_endOfLine(buffer[x])) {
|
||||
++line_count;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// buffer[x] is the division operator
|
||||
break;
|
||||
}
|
||||
} else if (qmake_endOfLine(buffer[x])) {
|
||||
++line_count;
|
||||
cpp_state = AtStart;
|
||||
} else {
|
||||
/* Drop out of phases 1, 2, 3, into phase 4 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Phase 4 study of buffer[x]:
|
||||
|
||||
if (x >= buffer_len)
|
||||
break;
|
||||
|
||||
switch (cpp_state) {
|
||||
case HadHash:
|
||||
{
|
||||
// Read keyword; buffer[x] starts first preprocessing token after #
|
||||
const char *const keyword = buffer + x;
|
||||
int clean = x;
|
||||
while (x < buffer_len && buffer[x] >= 'a' && buffer[x] <= 'z') {
|
||||
// skip over keyword, consolidating it if it contains BSNLs
|
||||
// (see WantName's similar code consolidating inc, below)
|
||||
if (clean < x)
|
||||
buffer[clean++] = buffer[x];
|
||||
else
|
||||
clean++;
|
||||
|
||||
x = SKIP_BSNL(x + 1);
|
||||
}
|
||||
const int keyword_len = buffer + clean - keyword;
|
||||
x--; // Still need to study buffer[x] next time round for loop.
|
||||
|
||||
cpp_state =
|
||||
((keyword_len == 7 && !strncmp(keyword, "include", 7)) // C & Obj-C
|
||||
|| (keyword_len == 6 && !strncmp(keyword, "import", 6))) // Obj-C
|
||||
? WantName : InCode;
|
||||
break;
|
||||
}
|
||||
|
||||
case WantName:
|
||||
{
|
||||
char term = buffer[x];
|
||||
if (term == '<') {
|
||||
try_local = false;
|
||||
term = '>';
|
||||
} else if (term != '"') {
|
||||
/*
|
||||
Possibly malformed, but this may be something like:
|
||||
#include IDENTIFIER
|
||||
which does work, if #define IDENTIFIER "filename" is
|
||||
in effect. This is beyond this noddy preprocessor's
|
||||
powers of tracking. So give up and resume searching
|
||||
for a directive. We haven't made sense of buffer[x],
|
||||
so back up to ensure we do study it (now as code) next
|
||||
time round the loop.
|
||||
*/
|
||||
x--;
|
||||
cpp_state = InCode;
|
||||
continue;
|
||||
}
|
||||
|
||||
x = SKIP_BSNL(x + 1);
|
||||
inc = buffer + x;
|
||||
int clean = x; // offset if we need to clear \-newlines
|
||||
for (; x < buffer_len && buffer[x] != term; x = SKIP_BSNL(x + 1)) {
|
||||
if (qmake_endOfLine(buffer[x])) { // malformed
|
||||
cpp_state = AtStart;
|
||||
++line_count;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
If we do skip any BSNLs, we need to consolidate the
|
||||
surviving text by copying to lower indices. For that
|
||||
to be possible, we also have to keep 'clean' advanced
|
||||
in step with x even when we've yet to see any BSNLs.
|
||||
*/
|
||||
if (clean < x)
|
||||
buffer[clean++] = buffer[x];
|
||||
else
|
||||
clean++;
|
||||
}
|
||||
if (cpp_state == WantName)
|
||||
buffer[clean] = '\0';
|
||||
else // i.e. malformed
|
||||
inc = nullptr;
|
||||
|
||||
cpp_state = InCode; // hereafter
|
||||
break;
|
||||
}
|
||||
|
||||
case AtStart:
|
||||
// Preprocessor directive?
|
||||
if (buffer[x] == '#') {
|
||||
cpp_state = HadHash;
|
||||
break;
|
||||
}
|
||||
cpp_state = InCode;
|
||||
// ... and fall through to handle buffer[x] as such.
|
||||
case InCode:
|
||||
// matching quotes (string literals and character literals)
|
||||
if (buffer[x] == '\'' || buffer[x] == '"') {
|
||||
x = scanPastString(buffer, buffer_len, x, &line_count);
|
||||
// for loop's ++x shall step over the closing quote.
|
||||
}
|
||||
// else: buffer[x] is just some code; move on.
|
||||
break;
|
||||
}
|
||||
|
||||
if (inc) // We were in WantName and found a name.
|
||||
break;
|
||||
#undef SKIP_BSNL
|
||||
}
|
||||
if (x >= buffer_len)
|
||||
break;
|
||||
|
||||
if (inc) {
|
||||
includes.push_back(inc);
|
||||
}
|
||||
}
|
||||
return includes;
|
||||
}
|
||||
|
||||
static bool isCWordChar(char c) {
|
||||
return c == '_'
|
||||
|| (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
static bool scanBufferForMocRelevantMacros(const char *fileName, char *buffer, int buffer_len)
|
||||
{
|
||||
int line_count = 1;
|
||||
bool ignore[3] = { false, false, false }; // [0] for Q_OBJECT, [1] for Q_GADGET, [2] for Q_NAMESPACE
|
||||
/* qmake ignore Q_GADGET */
|
||||
/* qmake ignore Q_OBJECT */
|
||||
/* qmake ignore Q_NAMESPACE */
|
||||
for (int x = 0; x < buffer_len; x++) {
|
||||
#define SKIP_BSNL(pos) skipEscapedLineEnds(buffer, buffer_len, (pos), &line_count)
|
||||
x = SKIP_BSNL(x);
|
||||
if (buffer[x] == '/') {
|
||||
int extralines = 0;
|
||||
int y = skipEscapedLineEnds(buffer, buffer_len, x + 1, &extralines);
|
||||
if (buffer_len > y) {
|
||||
// If comment, advance to the character that ends it:
|
||||
if (buffer[y] == '/') { // C++-style comment
|
||||
line_count += extralines;
|
||||
x = y;
|
||||
do {
|
||||
x = SKIP_BSNL(x + 1);
|
||||
} while (x < buffer_len && !qmake_endOfLine(buffer[x]));
|
||||
|
||||
} else if (buffer[y] == '*') { // C-style comment
|
||||
line_count += extralines;
|
||||
x = SKIP_BSNL(y + 1);
|
||||
for (; x < buffer_len; x = SKIP_BSNL(x + 1)) {
|
||||
if (buffer[x] == 't' || buffer[x] == 'q') { // ignore
|
||||
if (buffer_len >= (x + 20) &&
|
||||
!strncmp(buffer + x + 1, "make ignore Q_OBJECT", 20)) {
|
||||
debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_OBJECT\"",
|
||||
fileName, line_count);
|
||||
x += 20;
|
||||
ignore[0] = true;
|
||||
} else if (buffer_len >= (x + 20) &&
|
||||
!strncmp(buffer + x + 1, "make ignore Q_GADGET", 20)) {
|
||||
debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_GADGET\"",
|
||||
fileName, line_count);
|
||||
x += 20;
|
||||
ignore[1] = true;
|
||||
} else if (buffer_len >= (x + 23) &&
|
||||
!strncmp(buffer + x + 1, "make ignore Q_NAMESPACE", 23)) {
|
||||
debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_NAMESPACE\"",
|
||||
fileName, line_count);
|
||||
x += 23;
|
||||
ignore[2] = true;
|
||||
}
|
||||
} else if (buffer[x] == '*') {
|
||||
extralines = 0;
|
||||
y = skipEscapedLineEnds(buffer, buffer_len, x + 1, &extralines);
|
||||
if (buffer_len > y && buffer[y] == '/') {
|
||||
line_count += extralines;
|
||||
x = y;
|
||||
break;
|
||||
}
|
||||
} else if (Option::debug_level && qmake_endOfLine(buffer[x])) {
|
||||
++line_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
// else: don't update x, buffer[x] is just the division operator.
|
||||
}
|
||||
} else if (buffer[x] == '\'' || buffer[x] == '"') {
|
||||
x = scanPastString(buffer, buffer_len, x, &line_count);
|
||||
// Leaves us on closing quote; for loop's x++ steps us past it.
|
||||
}
|
||||
|
||||
if (x < buffer_len && Option::debug_level && qmake_endOfLine(buffer[x]))
|
||||
++line_count;
|
||||
if (buffer_len > x + 8 && !isCWordChar(buffer[x])) {
|
||||
int morelines = 0;
|
||||
int y = skipEscapedLineEnds(buffer, buffer_len, x + 1, &morelines);
|
||||
if (buffer[y] == 'Q') {
|
||||
static const char interesting[][12] = { "Q_OBJECT", "Q_GADGET", "Q_NAMESPACE"};
|
||||
for (int interest = 0; interest < 3; ++interest) {
|
||||
if (ignore[interest])
|
||||
continue;
|
||||
|
||||
int matchlen = 0, extralines = 0;
|
||||
size_t needle_len = strlen(interesting[interest]);
|
||||
assert(needle_len <= INT_MAX);
|
||||
if (matchWhileUnsplitting(buffer, buffer_len, y,
|
||||
interesting[interest],
|
||||
static_cast<int>(needle_len),
|
||||
&matchlen, &extralines)
|
||||
&& y + matchlen < buffer_len
|
||||
&& !isCWordChar(buffer[y + matchlen])) {
|
||||
if (Option::debug_level) {
|
||||
buffer[y + matchlen] = '\0';
|
||||
debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s",
|
||||
fileName,
|
||||
line_count + morelines, buffer + y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef SKIP_BSNL
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool startsWith(const std::string &str, const char *needle)
|
||||
{
|
||||
return str.find(needle) == 0;
|
||||
}
|
||||
|
||||
static bool endsWith(const std::string &str, const char *needle)
|
||||
{
|
||||
return str.rfind(needle) == str.size() - strlen(needle);
|
||||
}
|
||||
|
||||
static std::string fileNameFromPath(const std::string &path)
|
||||
{
|
||||
int separatorIndex = path.rfind("/");
|
||||
if (separatorIndex == -1)
|
||||
return path;
|
||||
return path.substr(separatorIndex + 1);
|
||||
}
|
||||
|
||||
static ScanResult scanFile(const std::string &fileName)
|
||||
{
|
||||
ScanResult result;
|
||||
result.fileName = fileName;
|
||||
|
||||
std::ifstream file(fileName, std::ios::binary);
|
||||
if (!file.is_open())
|
||||
return result;
|
||||
|
||||
file.seekg(0, std::ios_base::end);
|
||||
auto size = file.tellg();
|
||||
if (size == 0)
|
||||
return result;
|
||||
file.seekg(0, std::ios_base::beg);
|
||||
|
||||
std::vector<char> buffer;
|
||||
buffer.resize(size);
|
||||
char *bufferPtr = &(*buffer.begin());
|
||||
file.read(bufferPtr, size);
|
||||
|
||||
file.close();
|
||||
|
||||
result.foundMocRelevantMacro = scanBufferForMocRelevantMacros(fileName.c_str(), bufferPtr, size);
|
||||
|
||||
for (const auto &include: findIncludes(fileName.c_str(), bufferPtr, size)) {
|
||||
if (startsWith(include, "moc_") && endsWith(include, ".cpp")) {
|
||||
std::string mocHeader = include.substr(strlen("moc_"),
|
||||
include.size() - strlen("moc_") - strlen(".cpp"));
|
||||
mocHeader.append(".h");
|
||||
result.includedMocFiles.push_back(mocHeader);
|
||||
} else if (endsWith(include, ".moc")) {
|
||||
std::string mocHeader = include.substr(0, include.size() - strlen(".moc"));
|
||||
mocHeader.append(".cpp");
|
||||
result.includedMocFiles.push_back(mocHeader);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void writeSetToFile(const char *fileName, const std::set<std::string> &content)
|
||||
{
|
||||
std::ofstream file(fileName, std::ios::binary);
|
||||
for (const auto &entry: content) {
|
||||
const std::string &fileName = entry;
|
||||
file << fileName << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 4) {
|
||||
fprintf(stderr, "usage: %s <sources file> <included mocs output file> <built mocs output file>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::vector<std::string> sourcesAndHeaders;
|
||||
{
|
||||
std::ifstream file(argv[1]);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "failed to open input file " << argv[1] << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for (std::string line; std::getline(file, line);)
|
||||
sourcesAndHeaders.push_back(line);
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> mocCandidates;
|
||||
std::unordered_set<std::string> mocFilesInIncludeStatements;
|
||||
|
||||
for (const auto &sourceOrHeader: sourcesAndHeaders) {
|
||||
auto result = scanFile(sourceOrHeader);
|
||||
if (result.foundMocRelevantMacro)
|
||||
mocCandidates.insert(result.fileName);
|
||||
for (const auto &header: result.includedMocFiles)
|
||||
mocFilesInIncludeStatements.insert(header);
|
||||
}
|
||||
|
||||
std::set<std::string> mocFilesToInclude;
|
||||
std::set<std::string> mocFilesToBuild;
|
||||
|
||||
for (const auto &candidate: mocCandidates) {
|
||||
std::string fileName = fileNameFromPath(candidate);
|
||||
if (mocFilesInIncludeStatements.find(fileName) != mocFilesInIncludeStatements.end())
|
||||
mocFilesToInclude.insert(candidate);
|
||||
else
|
||||
mocFilesToBuild.insert(candidate);
|
||||
}
|
||||
|
||||
writeSetToFile(argv[2], mocFilesToInclude);
|
||||
writeSetToFile(argv[3], mocFilesToBuild);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -49,7 +49,7 @@ if (TARGET Qt::Widgets)
|
||||
add_subdirectory(widgets)
|
||||
endif()
|
||||
if (TARGET Qt::PrintSupport)
|
||||
# add_subdirectory(printsupport)
|
||||
add_subdirectory(printsupport)
|
||||
endif()
|
||||
# add_subdirectory(cmake) ## FIXME: Does this still make sense in this form?
|
||||
# add_subdirectory(installed_cmake) ## FIXME: Does this still make sense in this form?
|
||||
|
Loading…
Reference in New Issue
Block a user