summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Edelev <[email protected]>2021-12-29 18:00:52 +0100
committerAlexey Edelev <[email protected]>2022-02-10 02:31:05 +0100
commit2201934efa1b9889d474347e705784bf6925e120 (patch)
tree450a4b8dbb3777668be075790421de77733337f7
parent06e7b5168e269f913f03ecb9d77fc82db4d9dfd6 (diff)
Use 'copy' but not 'copy_if_different' on Windows platforms
Use custom script to copy big Android artifacts on Windows platforms. The script uses 'copy' but not 'copy_if_different' when source file size is bigger than 2GB. 'cmake -E copy_if_different' only compares first 2GB of files because of cmake issue, so this step only workaround the problem. Pick-to: 6.2 6.3 Task-number: QTBUG-99491 Change-Id: Id076734700e334dfc3330da412462c2b53829b33 Reviewed-by: Alexandru Croitor <[email protected]> Reviewed-by: Qt CI Bot <[email protected]>
-rw-r--r--cmake/QtBaseGlobalTargets.cmake2
-rw-r--r--cmake/QtConfig.cmake.in1
-rw-r--r--cmake/QtCopyFileIfDifferent.cmake15
-rw-r--r--cmake/QtPublicCMakeHelpers.cmake20
-rw-r--r--src/corelib/Qt6AndroidMacros.cmake20
-rw-r--r--tests/manual/cmake/test_copy_file_if_different_command/CMakeLists.txt73
-rw-r--r--tests/manual/cmake/test_copy_file_if_different_command/main.cpp61
7 files changed, 183 insertions, 9 deletions
diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake
index cae5ec8bf64..e9d93705103 100644
--- a/cmake/QtBaseGlobalTargets.cmake
+++ b/cmake/QtBaseGlobalTargets.cmake
@@ -218,6 +218,7 @@ qt_copy_or_install(FILES
cmake/QtCompilerFlags.cmake
cmake/QtCompilerOptimization.cmake
cmake/QtConfigDependencies.cmake.in
+ cmake/QtCopyFileIfDifferent.cmake
cmake/QtDeferredDependenciesHelpers.cmake
cmake/QtDbusHelpers.cmake
cmake/QtDocsHelpers.cmake
@@ -299,6 +300,7 @@ qt_copy_or_install(DIRECTORY
set(__public_cmake_helpers
cmake/QtFeature.cmake
cmake/QtFeatureCommon.cmake
+ cmake/QtPublicCMakeHelpers.cmake
cmake/QtPublicCMakeVersionHelpers.cmake
cmake/QtPublicFinalizerHelpers.cmake
cmake/QtPublicPluginHelpers.cmake
diff --git a/cmake/QtConfig.cmake.in b/cmake/QtConfig.cmake.in
index dd39ff648e6..822224d2dbd 100644
--- a/cmake/QtConfig.cmake.in
+++ b/cmake/QtConfig.cmake.in
@@ -92,6 +92,7 @@ include("${CMAKE_CURRENT_LIST_DIR}/QtPublicWalkLibsHelpers.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicFindPackageHelpers.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicDependencyHelpers.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicToolHelpers.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/QtPublicCMakeHelpers.cmake")
if(NOT DEFINED QT_CMAKE_EXPORT_NAMESPACE)
set(QT_CMAKE_EXPORT_NAMESPACE @QT_CMAKE_EXPORT_NAMESPACE@)
diff --git a/cmake/QtCopyFileIfDifferent.cmake b/cmake/QtCopyFileIfDifferent.cmake
new file mode 100644
index 00000000000..4c64895b534
--- /dev/null
+++ b/cmake/QtCopyFileIfDifferent.cmake
@@ -0,0 +1,15 @@
+# copy_if_different works incorrect in Windows if file size if bigger than 2GB.
+# See https://gitlab.kitware.com/cmake/cmake/-/issues/23052 and QTBUG-99491 for details.
+
+cmake_minimum_required(VERSION 3.16)
+
+set(copy_strategy "copy_if_different")
+if(CMAKE_HOST_WIN32)
+ file(SIZE "${SRC_FILE_PATH}" size)
+ # If file size is bigger than 2GB copy it unconditionally
+ if(size GREATER_EQUAL 2147483648)
+ set(copy_strategy "copy")
+ endif()
+endif()
+
+execute_process(COMMAND ${CMAKE_COMMAND} -E ${copy_strategy} "${SRC_FILE_PATH}" "${DST_FILE_PATH}")
diff --git a/cmake/QtPublicCMakeHelpers.cmake b/cmake/QtPublicCMakeHelpers.cmake
new file mode 100644
index 00000000000..86b8edacd49
--- /dev/null
+++ b/cmake/QtPublicCMakeHelpers.cmake
@@ -0,0 +1,20 @@
+# copy_if_different works incorrect in Windows if file size if bigger than 2GB.
+# See https://gitlab.kitware.com/cmake/cmake/-/issues/23052 and QTBUG-99491 for details.
+function(_qt_internal_copy_file_if_different_command out_var src_file dst_file)
+ # The CMake version higher than 3.23 doesn't contain the issue
+ if(CMAKE_HOST_WIN32 AND CMAKE_VERSION VERSION_LESS 3.23)
+ set(${out_var} "${CMAKE_COMMAND}"
+ "-DSRC_FILE_PATH=${src_file}"
+ "-DDST_FILE_PATH=${dst_file}"
+ -P "${_qt_6_config_cmake_dir}/QtCopyFileIfDifferent.cmake"
+ PARENT_SCOPE
+ )
+ else()
+ set(${out_var} "${CMAKE_COMMAND}"
+ -E copy_if_different
+ "${src_file}"
+ "${dst_file}"
+ PARENT_SCOPE
+ )
+ endif()
+endfunction()
diff --git a/src/corelib/Qt6AndroidMacros.cmake b/src/corelib/Qt6AndroidMacros.cmake
index 3313975022c..7b7f56041f1 100644
--- a/src/corelib/Qt6AndroidMacros.cmake
+++ b/src/corelib/Qt6AndroidMacros.cmake
@@ -381,11 +381,13 @@ function(qt6_android_add_apk_target target)
# in case DEPFILEs are not supported.
# Also the target is used to copy the library that belongs to ${target} when building multi-abi
# apk to the abi-specific directory.
+ _qt_internal_copy_file_if_different_command(copy_command
+ "$<TARGET_FILE:${target}>"
+ "${apk_final_dir}/${target_file_copy_relative_path}"
+ )
add_custom_target(${target}_prepare_apk_dir ALL
DEPENDS ${target} ${extra_deps}
- COMMAND ${CMAKE_COMMAND}
- -E copy_if_different $<TARGET_FILE:${target}>
- "${apk_final_dir}/${target_file_copy_relative_path}"
+ COMMAND ${copy_command}
COMMENT "Copying ${target} binary to apk folder"
)
@@ -478,6 +480,10 @@ function(qt6_android_add_apk_target target)
file(RELATIVE_PATH androiddeployqt_output_path "${CMAKE_BINARY_DIR}" "${apk_final_dir}")
set(androiddeployqt_output_path
"${QT_INTERNAL_ANDROID_MULTI_ABI_BINARY_DIR}/${androiddeployqt_output_path}")
+ _qt_internal_copy_file_if_different_command(copy_command
+ "$<TARGET_FILE:${target}>"
+ "${androiddeployqt_output_path}/${target_file_copy_relative_path}"
+ )
if(has_depfile_support)
set(deploy_android_deps_dir "${apk_final_dir}/${target}_deploy_android")
set(timestamp_file "${deploy_android_deps_dir}/timestamp")
@@ -486,9 +492,7 @@ function(qt6_android_add_apk_target target)
DEPENDS ${target} ${extra_deps}
COMMAND ${CMAKE_COMMAND} -E make_directory "${deploy_android_deps_dir}"
COMMAND ${CMAKE_COMMAND} -E touch "${timestamp_file}"
- COMMAND ${CMAKE_COMMAND}
- -E copy_if_different $<TARGET_FILE:${target}>
- "${androiddeployqt_output_path}/${target_file_copy_relative_path}"
+ COMMAND ${copy_command}
COMMAND ${deployment_tool}
--input ${deployment_file}
--output ${androiddeployqt_output_path}
@@ -504,9 +508,7 @@ function(qt6_android_add_apk_target target)
else()
add_custom_target(qt_internal_${target}_copy_apk_dependencies
DEPENDS ${target} ${extra_deps}
- COMMAND ${CMAKE_COMMAND}
- -E copy_if_different $<TARGET_FILE:${target}>
- "${androiddeployqt_output_path}/${target_file_copy_relative_path}"
+ COMMAND ${copy_command}
COMMAND ${deployment_tool}
--input ${deployment_file}
--output ${androiddeployqt_output_path}
diff --git a/tests/manual/cmake/test_copy_file_if_different_command/CMakeLists.txt b/tests/manual/cmake/test_copy_file_if_different_command/CMakeLists.txt
new file mode 100644
index 00000000000..c6486111267
--- /dev/null
+++ b/tests/manual/cmake/test_copy_file_if_different_command/CMakeLists.txt
@@ -0,0 +1,73 @@
+# How to run the test:
+# 1. Create the build directory, e.g. /home/user/build_test_copy_file_if_different
+# 2. cd /home/user/build_test_copy_file_if_different
+# 3. /path/to/Qt/bin/qt-cmake /path/to/Qt/Sources/qtbase/tests/manual/cmake/test_copy_file_if_different_command
+# 4. cmake --build . --parallel
+# 5. ctest
+cmake_minimum_required(VERSION 3.16)
+
+project(test_copy_file_if_different_command
+ LANGUAGES CXX
+)
+
+if(NOT CMAKE_HOST_WIN32)
+ message("Test only applicable for WIN32 platform. Nothing to do.")
+ return()
+endif()
+
+if(CMAKE_CROSSCOMPILING)
+ message("Test should only be run on host system. Crosscompiling is not supported.")
+ return()
+endif()
+
+find_program(fsutil NAMES fsutil fsutil.exe)
+if(NOT fsutil)
+ message(WARNING "Unable to find 'fsutil' executable. Skipping the test")
+ return()
+endif()
+
+find_package(Qt6 REQUIRED COMPONENTS Core)
+
+function(test_copy_file_command output_file test_data_base_name size)
+ set(testdatasrc1 "${CMAKE_CURRENT_BINARY_DIR}/${test_data_base_name}1.bin")
+ set(testdatasrc2 "${CMAKE_CURRENT_BINARY_DIR}/${test_data_base_name}2.bin")
+ set(testdatadst "${CMAKE_CURRENT_BINARY_DIR}/${test_data_base_name}.bin")
+
+ # Remove existing data first
+ file(REMOVE "${testdatasrc1}" "${testdatasrc2}" "${testdatadst}")
+
+ file(TO_NATIVE_PATH "${testdatasrc1}" native_testdatasrc)
+ execute_process(COMMAND ${fsutil} file createNew "${native_testdatasrc}" ${size}
+ RESULT_VARIABLE result)
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Unable to allocate file ${native_testdatasrc}"
+ " of size ${size} for test"
+ )
+ endif()
+
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${testdatasrc1}" "${testdatasrc2}"
+ RESULT_VARIABLE result)
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Unable to copy test data from ${testdatasrc1} to ${testdatasrc2}")
+ endif()
+
+ foreach(src_file_num RANGE 1 2)
+ set(src_file "${testdatasrc${src_file_num}}")
+ file(APPEND "${src_file}" "${src_file_num}")
+ _qt_internal_copy_file_if_different_command(copy_command "${src_file}" "${testdatadst}")
+ execute_process(COMMAND ${copy_command} RESULT_VARIABLE result)
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Unable to execute the copy command ${copy_command}")
+ endif()
+ endforeach()
+
+ set(${output_file} "${testdatadst}" PARENT_SCOPE)
+endfunction()
+
+test_copy_file_command(output_file1K testdata1K 1024)
+test_copy_file_command(output_file2GB testdata2GB 2147483648)
+
+add_executable(test_copy_if_different_command main.cpp)
+
+enable_testing()
+add_test(NAME "test_copy_if_different_command" COMMAND test_copy_if_different_command "${output_file1K}" "${output_file2GB}")
diff --git a/tests/manual/cmake/test_copy_file_if_different_command/main.cpp b/tests/manual/cmake/test_copy_file_if_different_command/main.cpp
new file mode 100644
index 00000000000..6248692efb0
--- /dev/null
+++ b/tests/manual/cmake/test_copy_file_if_different_command/main.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite 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 <fstream>
+#include <iostream>
+
+int checkFileLastByte(const std::string &filename, std::fstream::off_type offset)
+{
+ std::ifstream file(filename, std::ios_base::in);
+ if (!file.is_open()) {
+ std::cerr << "Unable to open test data file: " << filename << std::endl;
+ return 1;
+ }
+ file.seekg(offset, std::ios_base::beg);
+ char data = 0;
+ file.read(&data, sizeof(data));
+ if (data != '2') { // We always expect it's the second copy of the file
+ std::cerr << "Invalid data inside the file: " << filename << std::endl;
+ return 2;
+ }
+
+ return 0;
+};
+
+int main(int argc, char *argv[])
+{
+ if (argc != 3) {
+ std::cerr << "Test requires exact 2 arguments that point to the test data" << std::endl;
+ return 1;
+ }
+
+ int result = checkFileLastByte(argv[1], 1024);
+ if (result != 0)
+ return result;
+ return checkFileLastByte(argv[2], 2147483648);
+}