mirror of
https://github.com/stenzek/duckstation.git
synced 2026-10-11 22:49:58 +00:00
CMake: Improve reproducibility
Relative build RPATH, rcc mtime pinning.
This commit is contained in:
+14
-7
@@ -65,20 +65,27 @@ endif()
|
||||
# We don't need exceptions, disable them to save a bit of code size.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
|
||||
|
||||
# Rewrite paths in macros to be relative to the source directory.
|
||||
# Helpful for reproducible builds.
|
||||
# Rewrite paths in macros and debug info to fixed names, so that the output does not depend
|
||||
# on where the source and build directories are located. Helpful for reproducible builds.
|
||||
# The build directory is mapped last, so it takes precedence when it is inside the source directory.
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT CMAKE_GENERATOR MATCHES "Xcode" AND
|
||||
(COMPILER_CLANG OR COMPILER_CLANG_CL OR COMPILER_GCC))
|
||||
file(RELATIVE_PATH source_dir_remap "${CMAKE_BINARY_DIR}" "${CMAKE_SOURCE_DIR}")
|
||||
string(REGEX REPLACE "\/+$" "" source_dir_remap "${source_dir_remap}")
|
||||
set(source_dir_remap_str "\"${CMAKE_SOURCE_DIR}\"=\"${source_dir_remap}\"")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffile-prefix-map=${source_dir_remap_str}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffile-prefix-map=${source_dir_remap_str}")
|
||||
set(dir_remap_str "-ffile-prefix-map=\"${CMAKE_SOURCE_DIR}\"=. -ffile-prefix-map=\"${CMAKE_BINARY_DIR}\"=build")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${dir_remap_str}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${dir_remap_str}")
|
||||
endif()
|
||||
|
||||
# Write binaries to a seperate directory.
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
|
||||
|
||||
# Locate the prebuilt dependencies relative to the binary, instead of using the absolute
|
||||
# paths that CMake adds to the RUNPATH by default, which leak the source directory.
|
||||
if(LINUX)
|
||||
get_origin_relative_path(deps_rpath "${DEPS_PATH}/lib")
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set(CMAKE_INSTALL_RPATH "${deps_rpath}")
|
||||
endif()
|
||||
|
||||
# Enable large file support on Linux 32-bit platforms.
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
add_definitions("-D_FILE_OFFSET_BITS=64")
|
||||
|
||||
@@ -412,14 +412,23 @@ function(add_runtime_libraries TARGET)
|
||||
)
|
||||
else()
|
||||
# Linux, and macOS when using the Xcode generator/not using bundles.
|
||||
if(LINUX)
|
||||
get_origin_relative_path(dyn_lib_dir "${dyn_lib_dir}")
|
||||
endif()
|
||||
list(APPEND LIBRARY_RPATHS "${dyn_lib_dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Add the required library directories to the target's existing
|
||||
# build RPATH, without adding duplicate entries.
|
||||
# Linux is built with the install RPATH, see the top-level CMakeLists.txt.
|
||||
if(LINUX)
|
||||
set(rpath_property INSTALL_RPATH)
|
||||
else()
|
||||
set(rpath_property BUILD_RPATH)
|
||||
endif()
|
||||
if(LIBRARY_RPATHS)
|
||||
get_target_property(existing_rpath ${TARGET} BUILD_RPATH)
|
||||
get_target_property(existing_rpath ${TARGET} ${rpath_property})
|
||||
if(NOT existing_rpath)
|
||||
set(existing_rpath "")
|
||||
endif()
|
||||
@@ -428,7 +437,58 @@ function(add_runtime_libraries TARGET)
|
||||
list(REMOVE_DUPLICATES existing_rpath)
|
||||
set_target_properties(
|
||||
${TARGET}
|
||||
PROPERTIES BUILD_RPATH "${existing_rpath}"
|
||||
PROPERTIES ${rpath_property} "${existing_rpath}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Returns an RPATH entry for DIR that is relative to the directory binaries are written to.
|
||||
function(get_origin_relative_path OUTVAR DIR)
|
||||
# $ORIGIN is the real location of the binary, so symlinks have to be resolved first.
|
||||
file(MAKE_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
file(REAL_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" binary_dir)
|
||||
file(REAL_PATH "${DIR}" real_dir)
|
||||
file(RELATIVE_PATH relative_dir "${binary_dir}" "${real_dir}")
|
||||
set(${OUTVAR} "$ORIGIN/${relative_dir}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Compiles a .qrc file to a binary .rcc file, without embedding file modification times.
|
||||
function(add_binary_resources TARGET QRC_FILE OUTPUT_FILE)
|
||||
get_filename_component(qrc_path "${QRC_FILE}" ABSOLUTE)
|
||||
get_filename_component(qrc_dir "${qrc_path}" DIRECTORY)
|
||||
|
||||
# Pick up the files listed in the .qrc as dependencies, re-running CMake if the list changes.
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${qrc_path}")
|
||||
file(READ "${qrc_path}" qrc_contents)
|
||||
string(REGEX MATCHALL "<file[^>]*>[^<]+</file>" qrc_entries "${qrc_contents}")
|
||||
set(qrc_depends)
|
||||
foreach(entry IN LISTS qrc_entries)
|
||||
string(REGEX REPLACE "<file[^>]*>([^<]+)</file>" "\\1" entry "${entry}")
|
||||
list(APPEND qrc_depends "${qrc_dir}/${entry}")
|
||||
endforeach()
|
||||
|
||||
# rcc stamps every entry with the mtime of its source file, i.e. the checkout time.
|
||||
# Pin it to the commit date instead, unless the caller has already provided a date.
|
||||
set(source_date "$ENV{SOURCE_DATE_EPOCH}")
|
||||
if(NOT source_date)
|
||||
find_package(Git)
|
||||
if(EXISTS "${PROJECT_SOURCE_DIR}/.git" AND GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} log -1 --format=%ct
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE source_date
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
set(rcc_env)
|
||||
if(source_date)
|
||||
set(rcc_env "${CMAKE_COMMAND}" -E env "SOURCE_DATE_EPOCH=${source_date}")
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT "${OUTPUT_FILE}"
|
||||
COMMAND ${rcc_env} "$<TARGET_FILE:Qt6::rcc>" -no-compress --binary --name ${TARGET} --output "${OUTPUT_FILE}" "${qrc_path}"
|
||||
DEPENDS Qt6::rcc "${qrc_path}" ${qrc_depends}
|
||||
VERBATIM)
|
||||
add_custom_target(${TARGET} ALL DEPENDS "${OUTPUT_FILE}")
|
||||
endfunction()
|
||||
|
||||
@@ -283,14 +283,14 @@ if(NOT BUILD_MACOS_BUNDLE)
|
||||
set(RCC_FILENAME "duckstation-qt.rcc")
|
||||
set(RCC_BUILD_PATH "${CMAKE_CURRENT_BINARY_DIR}/${RCC_FILENAME}")
|
||||
set(RCC_OUTPUT_DIR "$<TARGET_FILE_DIR:duckstation-qt>/resources")
|
||||
qt_add_binary_resources(duckstation-qt-rcc resources/duckstation-qt.qrc DESTINATION ${RCC_BUILD_PATH} OPTIONS -no-compress)
|
||||
add_binary_resources(duckstation-qt-rcc resources/duckstation-qt.qrc "${RCC_BUILD_PATH}")
|
||||
add_dependencies(duckstation-qt duckstation-qt-rcc)
|
||||
|
||||
add_custom_command(TARGET duckstation-qt POST_BUILD COMMAND "${CMAKE_COMMAND}" -E make_directory "${RCC_OUTPUT_DIR}")
|
||||
add_custom_command(TARGET duckstation-qt POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${RCC_BUILD_PATH}" "${RCC_OUTPUT_DIR}/${RCC_FILENAME}")
|
||||
else()
|
||||
set(RCC_FILE "${CMAKE_CURRENT_BINARY_DIR}/duckstation-qt.rcc")
|
||||
qt_add_binary_resources(duckstation-qt-rcc resources/duckstation-qt.qrc DESTINATION ${RCC_FILE} OPTIONS -no-compress)
|
||||
add_binary_resources(duckstation-qt-rcc resources/duckstation-qt.qrc "${RCC_FILE}")
|
||||
add_dependencies(duckstation-qt duckstation-qt-rcc)
|
||||
target_sources(duckstation-qt PRIVATE ${RCC_FILE})
|
||||
set_source_files_properties(${RCC_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
Reference in New Issue
Block a user