initial commit

This commit is contained in:
2026-09-21 13:41:40 +09:00
commit 855c7328df
411 changed files with 85352 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
# Verify the complete inventory before installation and again at the destination.
include("${CMAKE_CURRENT_LIST_DIR}/WriteWindowsRuntimeManifest.cmake")
function(docview_verify_windows_worker executable output_files)
docview_runtime_file_info("${executable}" EXE worker_name worker_size)
get_filename_component(worker_directory "${executable}" DIRECTORY)
set(manifest "${executable}.runtime.json")
if(NOT EXISTS "${manifest}" OR IS_SYMLINK "${manifest}" OR IS_DIRECTORY "${manifest}")
message(FATAL_ERROR "Build the worker runtime manifest before installing: ${manifest}")
endif()
file(SIZE "${manifest}" manifest_size)
if(manifest_size LESS 1 OR manifest_size GREATER 131072)
message(FATAL_ERROR "Worker runtime manifest exceeds its size limit or is empty")
endif()
file(READ "${manifest}" inventory)
string(JSON root_type TYPE "${inventory}")
string(JSON fields LENGTH "${inventory}")
string(JSON version_type TYPE "${inventory}" schemaVersion)
string(JSON executable_type TYPE "${inventory}" executable)
string(JSON files_type TYPE "${inventory}" files)
string(JSON version GET "${inventory}" schemaVersion)
string(JSON declared_executable GET "${inventory}" executable)
string(JSON count LENGTH "${inventory}" files)
if(NOT root_type STREQUAL "OBJECT" OR NOT fields EQUAL 3 OR
NOT version_type STREQUAL "NUMBER" OR NOT version STREQUAL "1" OR
NOT executable_type STREQUAL "STRING" OR NOT declared_executable STREQUAL worker_name OR
NOT files_type STREQUAL "ARRAY" OR count LESS 1 OR count GREATER 128)
message(FATAL_ERROR "Invalid worker runtime inventory schema")
endif()
math(EXPR last "${count} - 1")
set(files)
set(names)
set(total 0)
set(found_executable FALSE)
foreach(index RANGE 0 ${last})
string(JSON entry_type TYPE "${inventory}" files ${index})
string(JSON fields LENGTH "${inventory}" files ${index})
string(JSON name_type TYPE "${inventory}" files ${index} path)
string(JSON hash_type TYPE "${inventory}" files ${index} sha256)
string(JSON size_type TYPE "${inventory}" files ${index} size)
string(JSON name GET "${inventory}" files ${index} path)
string(JSON expected_hash GET "${inventory}" files ${index} sha256)
string(JSON expected_size GET "${inventory}" files ${index} size)
string(LENGTH "${expected_hash}" hash_length)
if(NOT entry_type STREQUAL "OBJECT" OR NOT fields EQUAL 3 OR
NOT name_type STREQUAL "STRING" OR NOT hash_type STREQUAL "STRING" OR
NOT size_type STREQUAL "NUMBER" OR NOT expected_size MATCHES "^[1-9][0-9]*$" OR
NOT hash_length EQUAL 64 OR NOT expected_hash MATCHES "^[0-9a-f]+$")
message(FATAL_ERROR "Invalid worker runtime file record")
endif()
if(name STREQUAL worker_name)
set(kind EXE)
set(found_executable TRUE)
else()
set(kind DLL)
endif()
get_filename_component(basename "${name}" NAME)
if(NOT name STREQUAL basename)
message(FATAL_ERROR "Runtime manifest contains a non-basename path")
endif()
set(path "${worker_directory}/${name}")
docview_runtime_file_info("${path}" "${kind}" checked_name size)
string(TOLOWER "${name}" folded)
if(folded IN_LIST names)
message(FATAL_ERROR "Runtime manifest has a duplicate name")
endif()
list(APPEND names "${folded}")
math(EXPR total "${total} + ${size}")
if(NOT size EQUAL expected_size OR total GREATER 536870912)
message(FATAL_ERROR "Runtime file size no longer matches its build inventory: ${name}")
endif()
file(SHA256 "${path}" actual_hash)
if(NOT actual_hash STREQUAL expected_hash)
message(FATAL_ERROR "Runtime file no longer matches its build inventory: ${name}")
endif()
list(APPEND files "${path}")
endforeach()
if(NOT found_executable)
message(FATAL_ERROR "Runtime manifest is missing its worker executable")
endif()
set(${output_files} "${files}" PARENT_SCOPE)
endfunction()
docview_verify_windows_worker("${WORKER_EXECUTABLE}" verified_files)
if(NOT WORKER_VERIFY_ONLY)
if(NOT IS_ABSOLUTE "${WORKER_INSTALL_DIRECTORY}")
message(FATAL_ERROR "An absolute worker installation directory is required")
endif()
# file(INSTALL) applies DESTDIR itself. Its input must retain the unstaged
# install prefix; native tools and the verification below need the real path.
file(INSTALL DESTINATION "${WORKER_INSTALL_DIRECTORY}" TYPE FILE
FILES ${verified_files} "${WORKER_EXECUTABLE}.runtime.json")
get_filename_component(worker_name "${WORKER_EXECUTABLE}" NAME)
docview_verify_windows_worker("$ENV{DESTDIR}${WORKER_INSTALL_DIRECTORY}/${worker_name}" installed_files)
endif()
+16
View File
@@ -0,0 +1,16 @@
# Local Arch development packaging is explicit; normal builds do not package.
include_guard(GLOBAL)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
return()
endif()
find_package(Python3 3.11 COMPONENTS Interpreter QUIET)
if(Python3_Interpreter_FOUND)
set(DOCVIEW_LINUX_PACKAGE_OUTPUT "${CMAKE_BINARY_DIR}/linux-development-package" CACHE PATH
"New output directory for the local Arch development package")
add_custom_target(linux-development-package
COMMAND "${Python3_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/tools/package_linux_development.py"
--build-dir "${CMAKE_BINARY_DIR}" --output "${DOCVIEW_LINUX_PACKAGE_OUTPUT}"
DEPENDS docview docview-pdf-worker docview-archive-worker
USES_TERMINAL VERBATIM
COMMENT "Packaging the local Arch development build with dependency notices")
endif()
+10
View File
@@ -0,0 +1,10 @@
# The non-V8 build never executes PDF JavaScript or dynamic XFA.
set(DOCVIEW_PDFIUM_ROOT "${CMAKE_SOURCE_DIR}/.deps/pdfium" CACHE PATH "Pinned PDFium installation")
find_path(DOCVIEW_PDFIUM_INCLUDE_DIR fpdfview.h HINTS "${DOCVIEW_PDFIUM_ROOT}/include" REQUIRED)
find_library(DOCVIEW_PDFIUM_LIBRARY NAMES pdfium pdfium.dll HINTS "${DOCVIEW_PDFIUM_ROOT}/lib" REQUIRED)
add_library(PDFium::PDFium SHARED IMPORTED GLOBAL)
set_target_properties(PDFium::PDFium PROPERTIES IMPORTED_LOCATION "${DOCVIEW_PDFIUM_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${DOCVIEW_PDFIUM_INCLUDE_DIR}")
if(WIN32)
find_file(DOCVIEW_PDFIUM_RUNTIME pdfium.dll HINTS "${DOCVIEW_PDFIUM_ROOT}/bin" NO_DEFAULT_PATH REQUIRED)
set_target_properties(PDFium::PDFium PROPERTIES IMPORTED_IMPLIB "${DOCVIEW_PDFIUM_LIBRARY}" IMPORTED_LOCATION "${DOCVIEW_PDFIUM_RUNTIME}")
endif()
+83
View File
@@ -0,0 +1,83 @@
# Extra notices tied to the exact inspected Linux PDFium library and source pin.
# These are install data; no application code or PDF rendering option changes.
set(_notice_root "${CMAKE_CURRENT_SOURCE_DIR}/resources/licenses/pdfium-supplemental")
file(READ "${_notice_root}/sources.json" _notice_manifest)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/pdfium.lock.json" _pdfium_lock)
foreach(_pair "pdfiumVersion;version" "pdfiumUpstreamCommit;upstreamCommit")
list(GET _pair 0 _notice_key)
list(GET _pair 1 _lock_key)
string(JSON _notice_value GET "${_notice_manifest}" "${_notice_key}")
string(JSON _lock_value GET "${_pdfium_lock}" "${_lock_key}")
if(NOT _notice_value STREQUAL _lock_value)
message(FATAL_ERROR "PDFium supplemental notices need review for this source pin")
endif()
endforeach()
string(JSON _notice_binary GET "${_notice_manifest}" pdfiumLibrarySha256)
file(SHA256 "${DOCVIEW_PDFIUM_LIBRARY}" _actual_binary)
if(NOT _notice_binary STREQUAL _actual_binary OR EXISTS "${DOCVIEW_PDFIUM_ROOT}/BUILDINFO.json")
# Only the separately reviewed v2 tuple may differ from the original
# provider. There is deliberately no user-supplied trust/hash override.
find_package(Python3 3.11 REQUIRED COMPONENTS Interpreter)
set(_candidate_verifier "${CMAKE_CURRENT_SOURCE_DIR}/tools/verify_pdfium_candidate.py")
set(_candidate_notice "${CMAKE_CURRENT_BINARY_DIR}/pdfium-candidate-notices/sources.json")
execute_process(COMMAND "${Python3_EXECUTABLE}" "${_candidate_verifier}"
--prefix "${DOCVIEW_PDFIUM_ROOT}" --library "${DOCVIEW_PDFIUM_LIBRARY}"
--include-dir "${DOCVIEW_PDFIUM_INCLUDE_DIR}" --notice-output "${_candidate_notice}"
RESULT_VARIABLE _candidate_result OUTPUT_VARIABLE _candidate_record ERROR_VARIABLE _candidate_error)
if(NOT _candidate_result EQUAL 0)
message(FATAL_ERROR "PDFium supplemental notices need review for this binary: ${_candidate_error}")
endif()
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${DOCVIEW_PDFIUM_ROOT}/BUILDINFO.json"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/pdfium-candidate-v2.lock.json"
"${_candidate_verifier}")
# Recheck at install as well: configure success is not permission to install
# a prefix whose library, headers, or correspondence subsequently changed.
install(CODE "
execute_process(COMMAND \"${Python3_EXECUTABLE}\" \"${_candidate_verifier}\"
--prefix \"${DOCVIEW_PDFIUM_ROOT}\" --library \"${DOCVIEW_PDFIUM_LIBRARY}\"
--include-dir \"${DOCVIEW_PDFIUM_INCLUDE_DIR}\" --notice-output \"${_candidate_notice}\"
RESULT_VARIABLE candidate_result OUTPUT_QUIET ERROR_VARIABLE candidate_error)
if(NOT candidate_result EQUAL 0)
message(FATAL_ERROR \"PDFium candidate changed before install: \${candidate_error}\")
endif()")
string(JSON _candidate_files LENGTH "${_candidate_record}" installFiles)
math(EXPR _candidate_last "${_candidate_files} - 1")
foreach(_index RANGE 0 ${_candidate_last})
string(JSON _source GET "${_candidate_record}" installFiles ${_index} source)
string(JSON _destination GET "${_candidate_record}" installFiles ${_index} destination)
get_filename_component(_directory "${_destination}" DIRECTORY)
install(FILES "${DOCVIEW_PDFIUM_ROOT}/${_source}" DESTINATION "${_directory}")
endforeach()
install(FILES "${_candidate_notice}" DESTINATION share/doc/docview/pdfium/supplemental)
install(FILES "${DOCVIEW_PDFIUM_ROOT}/licenses/libcxx-LICENSE.txt"
"${DOCVIEW_PDFIUM_ROOT}/licenses/libcxxabi-LICENSE.txt"
DESTINATION share/doc/docview/pdfium/supplemental)
return()
endif()
string(JSON _notice_count LENGTH "${_notice_manifest}" files)
string(JSON _notice_schema GET "${_notice_manifest}" schemaVersion)
if(NOT _notice_schema EQUAL 1)
message(FATAL_ERROR "Unsupported PDFium supplemental notice schema")
endif()
if(NOT _notice_count EQUAL 2)
message(FATAL_ERROR "Expected the two audited PDFium supplemental notices")
endif()
set(_notice_names)
foreach(_index RANGE 0 1)
string(JSON _name GET "${_notice_manifest}" files ${_index} name)
string(JSON _hash GET "${_notice_manifest}" files ${_index} sha256)
if(NOT _name MATCHES "^(libcxx|libcxxabi)-LICENSE[.]txt$")
message(FATAL_ERROR "Unexpected PDFium supplemental notice filename")
endif()
if(_name IN_LIST _notice_names)
message(FATAL_ERROR "Duplicate PDFium supplemental notice filename")
endif()
list(APPEND _notice_names "${_name}")
file(SHA256 "${_notice_root}/${_name}" _actual)
if(NOT _actual STREQUAL _hash)
message(FATAL_ERROR "PDFium supplemental notice digest mismatch")
endif()
install(FILES "${_notice_root}/${_name}" DESTINATION share/doc/docview/pdfium/supplemental)
endforeach()
install(FILES "${_notice_root}/sources.json" DESTINATION share/doc/docview/pdfium/supplemental)
+255
View File
@@ -0,0 +1,255 @@
# Native script/include inputs: WORKER_EXECUTABLE, RUNTIME_LIBRARIES,
# SEARCH_DIRECTORIES and EXTRA_RUNTIME_LIBRARIES (explicit MSVC redistributables).
# No input is resolved through PATH. CMake's PE scanner searches the importing
# binary's directory, OS directories and the explicit DIRECTORIES list.
cmake_minimum_required(VERSION 3.24)
include("${CMAKE_CURRENT_LIST_DIR}/WriteWindowsRuntimeManifest.cmake")
function(docview_runtime_actual_path input output)
if(NOT IS_ABSOLUTE "${input}" OR NOT EXISTS "${input}" OR IS_SYMLINK "${input}")
message(FATAL_ERROR "Invalid worker runtime source: ${input}")
endif()
set(actual "${input}")
if(WIN32)
# CMake before 3.27 lowercases DLL result names. Recover on-disk casing
# before comparing an imported target against the scanner's result.
get_filename_component(parent "${input}" DIRECTORY)
get_filename_component(name "${input}" NAME)
string(TOLOWER "${name}" wanted)
file(GLOB siblings LIST_DIRECTORIES FALSE "${parent}/*")
set(matches)
foreach(sibling IN LISTS siblings)
get_filename_component(candidate "${sibling}" NAME)
string(TOLOWER "${candidate}" folded)
if(folded STREQUAL wanted)
list(APPEND matches "${sibling}")
endif()
endforeach()
list(LENGTH matches count)
if(NOT count EQUAL 1)
message(FATAL_ERROR "Ambiguous case-insensitive runtime source: ${input}")
endif()
list(GET matches 0 actual)
endif()
set(${output} "${actual}" PARENT_SCOPE)
endfunction()
# Pure package-copy step is independently testable with synthetic MZ fixtures.
# It does not claim that these files passed the native PE dependency scanner.
function(docview_stage_runtime_files executable sources)
docview_runtime_file_info("${executable}" EXE executable_name executable_size)
get_filename_component(directory "${executable}" DIRECTORY)
file(LOCK "${directory}/.docview-worker-runtime.lock" GUARD FUNCTION TIMEOUT 60 RESULT_VARIABLE locked)
if(NOT locked STREQUAL "0")
message(FATAL_ERROR "Cannot lock the worker runtime package directory: ${locked}")
endif()
set(names)
set(paths)
set(digests)
set(sizes)
set(total "${executable_size}")
foreach(input IN LISTS sources)
docview_runtime_actual_path("${input}" source)
docview_runtime_file_info("${source}" DLL name size)
string(TOLOWER "${name}" key)
list(FIND names "${key}" existing)
file(SHA256 "${source}" digest)
if(NOT existing EQUAL -1)
list(GET paths ${existing} previous)
get_filename_component(previous_name "${previous}" NAME)
list(GET digests ${existing} previous_digest)
if(NOT name STREQUAL previous_name OR NOT digest STREQUAL previous_digest)
message(FATAL_ERROR "Conflicting worker runtime DLL sources: ${previous};${source}")
endif()
continue()
endif()
list(APPEND names "${key}")
list(APPEND paths "${source}")
list(APPEND digests "${digest}")
list(APPEND sizes "${size}")
list(LENGTH names count)
math(EXPR total "${total} + ${size}")
if(count GREATER 127 OR total GREATER 536870912)
message(FATAL_ERROR "Worker runtime exceeds 128 files or 512 MiB")
endif()
endforeach()
# Inspect existing names case-insensitively, including on case-sensitive
# build hosts. Never overwrite a different DLL shared by another worker.
file(GLOB existing_entries LIST_DIRECTORIES TRUE "${directory}/*")
set(runtime_files "${executable}")
list(LENGTH paths count)
if(count GREATER 0)
math(EXPR last "${count} - 1")
foreach(index RANGE 0 ${last})
list(GET paths ${index} source)
list(GET names ${index} key)
list(GET digests ${index} digest)
list(GET sizes ${index} size)
get_filename_component(name "${source}" NAME)
set(destination "${directory}/${name}")
foreach(entry IN LISTS existing_entries)
get_filename_component(existing_name "${entry}" NAME)
string(TOLOWER "${existing_name}" existing_key)
if(existing_key STREQUAL key AND NOT existing_name STREQUAL name)
message(FATAL_ERROR "Case-insensitive runtime destination collision: ${name}")
endif()
endforeach()
if(EXISTS "${destination}" OR IS_SYMLINK "${destination}")
docview_runtime_file_info("${destination}" DLL old_name old_size)
file(SHA256 "${destination}" old_digest)
if(NOT old_size EQUAL size OR NOT old_digest STREQUAL digest)
message(FATAL_ERROR "Refusing to replace a different runtime DLL: ${destination}")
endif()
else()
string(RANDOM LENGTH 24 ALPHABET 0123456789abcdef nonce)
set(temporary "${destination}.${nonce}.tmp")
if(EXISTS "${temporary}" OR IS_SYMLINK "${temporary}")
message(FATAL_ERROR "Runtime copy temporary path already exists")
endif()
file(COPY_FILE "${source}" "${temporary}" RESULT copied)
if(NOT copied STREQUAL "0")
file(REMOVE "${temporary}")
message(FATAL_ERROR "Cannot copy runtime DLL: ${copied}")
endif()
file(SHA256 "${temporary}" copied_digest)
file(SIZE "${temporary}" copied_size)
if(NOT copied_digest STREQUAL digest OR NOT copied_size EQUAL size)
file(REMOVE "${temporary}")
message(FATAL_ERROR "Runtime DLL changed while copying: ${source}")
endif()
file(RENAME "${temporary}" "${destination}" NO_REPLACE RESULT renamed)
if(NOT renamed STREQUAL "0")
file(REMOVE "${temporary}")
message(FATAL_ERROR "Cannot publish runtime DLL: ${renamed}")
endif()
# Older CMake on POSIX can publish NO_REPLACE with a hard link
# while leaving the source name behind. Remove only our own
# temporary name after successful publication, preserving the
# destination and NO_REPLACE's collision protection.
file(REMOVE "${temporary}")
if(EXISTS "${temporary}" OR IS_SYMLINK "${temporary}")
message(FATAL_ERROR "Cannot remove the runtime copy temporary path")
endif()
endif()
list(APPEND runtime_files "${destination}")
endforeach()
endif()
docview_write_windows_runtime_manifest("${executable}" "${runtime_files}")
endfunction()
function(docview_regex_case_path path output)
string(REPLACE "\\" "/" normalized "${path}")
string(LENGTH "${normalized}" length)
math(EXPR last "${length} - 1")
set(regex)
set(metacharacters "." "[" "]" "(" ")" "+" "*" "?" "^" "$" "|" "{" "}")
foreach(index RANGE 0 ${last})
string(SUBSTRING "${normalized}" ${index} 1 character)
if(character MATCHES "[A-Za-z]")
string(TOUPPER "${character}" upper)
string(TOLOWER "${character}" lower)
string(APPEND regex "[${upper}${lower}]")
elseif(character IN_LIST metacharacters)
string(APPEND regex "\\${character}")
else()
string(APPEND regex "${character}")
endif()
endforeach()
set(${output} "${regex}" PARENT_SCOPE)
endfunction()
function(docview_is_windows_os_runtime path system_root output)
string(REPLACE "\\" "/" normalized "${path}")
string(REPLACE "\\" "/" root "${system_root}")
string(REGEX REPLACE "/+$" "" root "${root}")
string(TOLOWER "${normalized}" normalized)
string(TOLOWER "${root}/" root)
string(FIND "${normalized}" "${root}" prefix)
set(result FALSE)
if(prefix EQUAL 0)
string(LENGTH "${root}" length)
string(SUBSTRING "${normalized}" ${length} -1 relative)
if(relative MATCHES "^(system32|syswow64)/" OR relative MATCHES "^[^/]+[.]dll$")
set(result TRUE)
endif()
endif()
set(${output} "${result}" PARENT_SCOPE)
endfunction()
function(docview_stage_windows_worker)
if(NOT CMAKE_HOST_WIN32)
message(FATAL_ERROR "Native Windows PE runtime dependency scanning requires a Windows host")
endif()
docview_runtime_file_info("${WORKER_EXECUTABLE}" EXE executable_name executable_size)
file(TO_CMAKE_PATH "$ENV{SystemRoot}" system_root)
if(NOT IS_ABSOLUTE "${system_root}" OR NOT IS_DIRECTORY "${system_root}/System32")
message(FATAL_ERROR "Cannot locate the Windows OS runtime directories")
endif()
docview_regex_case_path("${system_root}" os_regex)
set(os_exclusions "^${os_regex}/[Ss][Yy][Ss][Tt][Ee][Mm]32/"
"^${os_regex}/[Ss][Yy][Ss][Ww][Oo][Ww]64/"
"^${os_regex}/[^/]+[.][Dd][Ll][Ll]$")
set(explicit_libraries)
set(directories ${SEARCH_DIRECTORIES})
foreach(input IN LISTS RUNTIME_LIBRARIES EXTRA_RUNTIME_LIBRARIES)
docview_runtime_actual_path("${input}" source)
docview_runtime_file_info("${source}" DLL name size)
string(TOLOWER "${name}" folded)
if(folded MATCHES "^(api|ext)-ms-win-.*[.]dll$")
message(FATAL_ERROR "API-set DLLs belong to Windows and must not be copied: ${name}")
endif()
docview_is_windows_os_runtime("${source}" "${system_root}" os_file)
if(os_file)
message(FATAL_ERROR "Do not package DLLs from Windows OS directories: ${source}")
endif()
list(APPEND explicit_libraries "${source}")
get_filename_component(parent "${source}" DIRECTORY)
list(APPEND directories "${parent}")
endforeach()
list(REMOVE_DUPLICATES explicit_libraries)
list(REMOVE_DUPLICATES directories)
foreach(directory IN LISTS directories)
if(NOT IS_ABSOLUTE "${directory}" OR NOT IS_DIRECTORY "${directory}")
message(FATAL_ERROR "DLL search directories must be explicit existing absolute paths: ${directory}")
endif()
endforeach()
set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM "windows+pe")
if(DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND AND
(NOT IS_ABSOLUTE "${CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND}" OR
NOT EXISTS "${CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND}"))
message(FATAL_ERROR "The PE inspection tool must have an existing absolute path")
endif()
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES "${WORKER_EXECUTABLE}"
LIBRARIES ${explicit_libraries}
DIRECTORIES ${directories}
RESOLVED_DEPENDENCIES_VAR resolved
UNRESOLVED_DEPENDENCIES_VAR unresolved
CONFLICTING_DEPENDENCIES_PREFIX conflicting
PRE_EXCLUDE_REGEXES "^api-ms-win-.*[.]dll$" "^ext-ms-win-.*[.]dll$"
POST_EXCLUDE_REGEXES ${os_exclusions})
if(unresolved)
message(FATAL_ERROR "Unresolved worker runtime DLL dependencies: ${unresolved}")
endif()
if(conflicting_FILENAMES)
message(FATAL_ERROR "Conflicting worker runtime DLL dependencies: ${conflicting_FILENAMES}")
endif()
set(package_dependencies)
foreach(dependency IN LISTS resolved)
docview_runtime_actual_path("${dependency}" dependency)
docview_is_windows_os_runtime("${dependency}" "${system_root}" os_file)
get_filename_component(name "${dependency}" NAME)
string(TOLOWER "${name}" folded)
if(NOT os_file AND NOT folded MATCHES "^(api|ext)-ms-win-.*[.]dll$")
list(APPEND package_dependencies "${dependency}")
endif()
endforeach()
# Explicit redistributables are included even if a matching import resolved
# to a Windows OS DLL that the scanner correctly excluded.
set(package_sources ${explicit_libraries} ${package_dependencies})
docview_stage_runtime_files("${WORKER_EXECUTABLE}" "${package_sources}")
endfunction()
if(DEFINED WORKER_EXECUTABLE)
docview_stage_windows_worker()
endif()
+61
View File
@@ -0,0 +1,61 @@
# Windows SDK tools and matching Qt binaries are required on the build host.
include_guard(GLOBAL)
if(NOT WIN32)
return()
endif()
set(DOCVIEW_EXTRA_WORKER_RUNTIME_DLLS "" CACHE STRING
"Explicit additional redistributable DLLs approved for worker packaging")
find_program(DOCVIEW_DUMPBIN_EXECUTABLE NAMES dumpbin REQUIRED)
find_program(DOCVIEW_WINDEPLOYQT_EXECUTABLE NAMES windeployqt
HINTS "${Qt6_DIR}/../../../bin" REQUIRED)
function(docview_configure_windows_worker target)
set(script "${CMAKE_CURRENT_BINARY_DIR}/stage-${target}-$<CONFIG>.cmake")
file(GENERATE OUTPUT "${script}" CONTENT "
set(WORKER_EXECUTABLE [==[$<TARGET_FILE:${target}>]==])
set(RUNTIME_LIBRARIES [==[$<TARGET_RUNTIME_DLLS:${target}>]==])
set(SEARCH_DIRECTORIES [==[$<TARGET_FILE_DIR:Qt6::Core>;$<TARGET_FILE_DIR:${DOCVIEW_ZIP_TARGET}>;$<TARGET_FILE_DIR:qpdf::libqpdf>;${DOCVIEW_PDFIUM_ROOT}/bin]==])
set(EXTRA_RUNTIME_LIBRARIES [==[${DOCVIEW_EXTRA_WORKER_RUNTIME_DLLS}]==])
set(CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL dumpbin)
set(CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND [==[${DOCVIEW_DUMPBIN_EXECUTABLE}]==])
include([==[${CMAKE_CURRENT_FUNCTION_LIST_DIR}/StageWindowsWorker.cmake]==])
")
add_custom_command(TARGET ${target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -P "${script}" VERBATIM
COMMENT "Collecting and hashing the restricted runtime for ${target}")
endfunction()
function(docview_install_windows_worker target)
set(script "${CMAKE_CURRENT_BINARY_DIR}/install-${target}-$<CONFIG>.cmake")
file(GENERATE OUTPUT "${script}" CONTENT "
set(WORKER_EXECUTABLE [==[$<TARGET_FILE:${target}>]==])
set(WORKER_INSTALL_DIRECTORY \"\${CMAKE_INSTALL_PREFIX}/bin\")
set(WORKER_VERIFY_ONLY FALSE)
include([==[${CMAKE_CURRENT_FUNCTION_LIST_DIR}/InstallWindowsWorker.cmake]==])
")
install(SCRIPT "${script}")
endfunction()
function(docview_install_windows_gui target)
set(script "${CMAKE_CURRENT_BINARY_DIR}/deploy-${target}-$<CONFIG>.cmake")
file(GENERATE OUTPUT "${script}" CONTENT "
set(destination \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin\")
execute_process(COMMAND [==[${DOCVIEW_WINDEPLOYQT_EXECUTABLE}]==]
--$<IF:$<CONFIG:Debug>,debug,release> --no-compiler-runtime --nopatchqt
--dir \"\${destination}\" --plugindir \"\${destination}/plugins\"
--qml-deploy-dir \"\${destination}/qml\" --translationdir \"\${destination}/translations\"
--qmldir [==[${CMAKE_SOURCE_DIR}/qml]==] \"\${destination}/$<TARGET_FILE_NAME:${target}>\"
RESULT_VARIABLE deployed)
if(NOT deployed EQUAL 0)
message(FATAL_ERROR \"windeployqt failed: \${deployed}\")
endif()
file(WRITE \"\${destination}/qt.conf\" \"[Paths]\\nPrefix=.\\nPlugins=plugins\\nQmlImports=qml\\nLibraryExecutables=.\\nData=.\\nTranslations=translations\\n\")
# windeployqt must not patch or replace any hashed worker dependency.
set(WORKER_VERIFY_ONLY TRUE)
foreach(name docview-pdf-worker.exe docview-archive-worker.exe)
set(WORKER_EXECUTABLE \"\${destination}/\${name}\")
include([==[${CMAKE_CURRENT_FUNCTION_LIST_DIR}/InstallWindowsWorker.cmake]==])
endforeach()
")
install(SCRIPT "${script}")
endfunction()
+123
View File
@@ -0,0 +1,123 @@
# Script API: -DWORKER_EXECUTABLE=<absolute exe> -DRUNTIME_FILES=<absolute list>
# Include API: docview_write_windows_runtime_manifest(executable "${files}").
# This writer validates the package inventory, not the PE import table. The
# native dependency scanner is StageWindowsWorker.cmake.
cmake_minimum_required(VERSION 3.24)
include_guard(GLOBAL)
function(docview_runtime_file_info path kind out_name out_size)
if(NOT IS_ABSOLUTE "${path}" OR NOT EXISTS "${path}" OR IS_DIRECTORY "${path}" OR IS_SYMLINK "${path}")
message(FATAL_ERROR "Worker runtime requires an absolute regular file: ${path}")
endif()
get_filename_component(name "${path}" NAME)
string(LENGTH "${name}" length)
string(TOLOWER "${name}" folded)
if(length GREATER 128 OR NOT name MATCHES "^[A-Za-z0-9][A-Za-z0-9._-]*$" OR
name MATCHES "[.]$" OR folded MATCHES "^(con|prn|aux|nul|com[1-9]|lpt[1-9])([.]|$)")
message(FATAL_ERROR "Invalid Windows runtime filename: ${name}")
endif()
if((kind STREQUAL "EXE" AND NOT folded MATCHES "[.]exe$") OR
(kind STREQUAL "DLL" AND NOT folded MATCHES "[.]dll$"))
message(FATAL_ERROR "Only the worker executable and DLLs may enter its runtime: ${name}")
endif()
file(SIZE "${path}" size)
if(size LESS 2 OR size GREATER 268435456)
message(FATAL_ERROR "Worker runtime file exceeds the 256 MiB limit or is empty: ${name}")
endif()
file(READ "${path}" signature LIMIT 2 HEX)
if(NOT signature STREQUAL "4d5a")
message(FATAL_ERROR "Worker runtime file has no MZ signature: ${name}")
endif()
set(${out_name} "${name}" PARENT_SCOPE)
set(${out_size} "${size}" PARENT_SCOPE)
endfunction()
function(docview_write_windows_runtime_manifest executable files)
docview_runtime_file_info("${executable}" EXE executable_name executable_size)
file(REAL_PATH "${executable}" executable_real)
get_filename_component(directory "${executable_real}" DIRECTORY)
if(WIN32)
string(TOLOWER "${directory}" directory)
endif()
list(LENGTH files count)
if(count LESS 1 OR count GREATER 128)
message(FATAL_ERROR "Worker runtime inventory must contain 1..128 files")
endif()
set(seen)
set(total 0)
set(has_executable FALSE)
# Check every limit before hashing potentially large files or changing an
# existing manifest. File order does not affect the serialized inventory.
foreach(path IN LISTS files)
get_filename_component(name "${path}" NAME)
if(name STREQUAL executable_name)
set(kind EXE)
else()
set(kind DLL)
endif()
docview_runtime_file_info("${path}" "${kind}" name size)
file(REAL_PATH "${path}" real)
get_filename_component(parent "${real}" DIRECTORY)
if(WIN32)
string(TOLOWER "${parent}" parent)
endif()
if(NOT parent STREQUAL directory)
message(FATAL_ERROR "Manifest entries must already be beside the worker: ${name}")
endif()
string(TOLOWER "${name}" key)
if(key IN_LIST seen)
message(FATAL_ERROR "Case-insensitive duplicate worker runtime filename: ${name}")
endif()
list(APPEND seen "${key}")
if(name STREQUAL executable_name)
if(NOT real STREQUAL executable_real)
message(FATAL_ERROR "Manifest executable does not match its worker")
endif()
set(has_executable TRUE)
endif()
math(EXPR total "${total} + ${size}")
if(total GREATER 536870912)
message(FATAL_ERROR "Worker runtime exceeds the 512 MiB aggregate limit")
endif()
endforeach()
if(NOT has_executable)
message(FATAL_ERROR "Worker runtime manifest must include its executable")
endif()
list(SORT files CASE INSENSITIVE)
set(entries)
foreach(path IN LISTS files)
get_filename_component(name "${path}" NAME)
file(SIZE "${path}" size)
file(SHA256 "${path}" digest)
string(TOLOWER "${digest}" digest)
list(APPEND entries " {\"path\":\"${name}\",\"sha256\":\"${digest}\",\"size\":${size}}")
endforeach()
list(JOIN entries ",\n" entries_json)
set(json "{\n \"schemaVersion\":1,\n \"executable\":\"${executable_name}\",\n \"files\":[\n${entries_json}\n ]\n}\n")
string(LENGTH "${json}" json_size)
if(json_size GREATER 131072)
message(FATAL_ERROR "Worker runtime manifest exceeds its 128 KiB limit")
endif()
set(output "${executable}.runtime.json")
if(IS_SYMLINK "${output}" OR IS_DIRECTORY "${output}")
message(FATAL_ERROR "Refusing a non-regular worker runtime manifest destination")
endif()
string(RANDOM LENGTH 24 ALPHABET 0123456789abcdef nonce)
set(temporary "${output}.${nonce}.tmp")
if(EXISTS "${temporary}" OR IS_SYMLINK "${temporary}")
message(FATAL_ERROR "Worker runtime manifest temporary path already exists")
endif()
file(WRITE "${temporary}" "${json}")
file(RENAME "${temporary}" "${output}" RESULT renamed)
if(NOT renamed STREQUAL "0")
file(REMOVE "${temporary}")
message(FATAL_ERROR "Cannot atomically publish worker runtime manifest: ${renamed}")
endif()
endfunction()
if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE)
if(NOT DEFINED WORKER_EXECUTABLE OR NOT DEFINED RUNTIME_FILES)
message(FATAL_ERROR "WORKER_EXECUTABLE and RUNTIME_FILES are required")
endif()
docview_write_windows_runtime_manifest("${WORKER_EXECUTABLE}" "${RUNTIME_FILES}")
endif()
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""Fetch the hash-pinned non-V8 PDFium dependency for Linux or Windows x64."""
from pathlib import Path
import argparse
import hashlib
import json
import platform
import tarfile
import tempfile
import urllib.request
root = Path(__file__).resolve().parent.parent
lock = json.loads((root / 'cmake/pdfium.lock.json').read_text())
host = {'Linux': 'linux-x64', 'Windows': 'windows-x64'}.get(platform.system())
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--platform', choices=['linux-x64', 'windows-x64'], default=host)
parser.add_argument('--destination', type=Path)
args = parser.parse_args()
if args.platform is None or (args.platform == host and platform.machine() not in ('x86_64', 'AMD64')):
raise SystemExit('A supported x64 platform is required; specify --platform for a cross-platform download.')
prefix = 'windowsX64' if args.platform == 'windows-x64' else 'linuxX64'
destination = args.destination or root / '.deps' / ('pdfium' if args.platform == host else 'pdfium-' + args.platform.split('-')[0])
with tempfile.TemporaryDirectory(prefix='docview-pdfium-') as temporary:
archive = Path(temporary) / 'pdfium.tgz'
urllib.request.urlretrieve(lock[prefix + 'Archive'], archive)
if hashlib.sha256(archive.read_bytes()).hexdigest() != lock[prefix + 'Sha256']:
raise SystemExit('PDFium archive hash mismatch; dependency not installed.')
destination.mkdir(parents=True, exist_ok=True)
with tarfile.open(archive) as bundle:
bundle.extractall(destination, filter='data')
print(f'Installed pinned PDFium {lock["version"]} in {destination}')
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
{
"schemaVersion": 1,
"candidateId": "reviewed-v2",
"sourceRevision": "a5a7089234f121990b336b3841008009dca143bf",
"librarySha256": "cb049fe434f4c911b5eb047c0aca572d4dd9f5e405dde329b76c05a6aa771403",
"buildInfoSha256": "6fbb6f24a7ca241150f8abf8d9ad031c76d9cfffc809026a61068c357d47ae18",
"anchorRecordPath": "provenance/master6.json",
"anchorRecordSha256": "80af72b06d5c9a6a3ab8b9311373e6a23e8df28668ce575e1124350e69aa160b",
"patchSha256": "470ca6dd5c83e06ee82c788d1e34b19766f7c592473b80607f0d7bb09d761616",
"gnArgsSha256": "5a2e04e1c0bb3eb05dc415dfa005a917804be8f63ade2365016c148e8efd8197",
"supplementalSourceSha256": "97d75f0b50e5ad8114229ec4e5cece147272563dfed4fd434087b70d871a114a"
}
+28
View File
@@ -0,0 +1,28 @@
{
"version": "155.0.8057.0",
"branch": "chromium/8057",
"upstreamCommit": "a5a7089234f121990b336b3841008009dca143bf",
"upstream": "https://pdfium.googlesource.com/pdfium/+/a5a7089234f121990b336b3841008009dca143bf",
"binaryProvider": "https://github.com/bblanchon/pdfium-binaries",
"linuxX64Archive": "https://github.com/bblanchon/pdfium-binaries/releases/download/chromium%2F8057/pdfium-linux-x64.tgz",
"linuxX64Sha256": "7788fa57a2996ebd21afc4090eb0a42b9f95ef3a72e7ef4c0756f1ea703c0415",
"windowsX64Archive": "https://github.com/bblanchon/pdfium-binaries/releases/download/chromium%2F8057/pdfium-win-x64.tgz",
"windowsX64Sha256": "e307d519e42f2e69b1b531f0c2a32dffcdf3891ec0eba60328ba51a57cec01ed",
"windowsBuildOptions": {
"pdf_enable_v8": false,
"pdf_enable_xfa": false,
"target_cpu": "x64",
"target_os": "win"
},
"buildOptions": {
"pdf_enable_v8": false,
"pdf_enable_xfa": false,
"pdf_is_standalone": true,
"is_debug": false,
"pdf_use_partition_alloc": false,
"target_cpu": "x64",
"target_os": "linux"
},
"licenses": [".deps/pdfium/LICENSE", ".deps/pdfium/licenses/"],
"apiNotes": "Structure tree, MCID and page-object access use experimental public APIs, compiled against these exact headers. No private Qt or PDFium API is used."
}