diff --git a/CMakeLists.txt b/CMakeLists.txt
index 357ee6954..6fe98c90f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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")
diff --git a/CMakeModules/DuckStationUtils.cmake b/CMakeModules/DuckStationUtils.cmake
index 2bd7d72ed..29e45ff5f 100644
--- a/CMakeModules/DuckStationUtils.cmake
+++ b/CMakeModules/DuckStationUtils.cmake
@@ -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 "]*>[^<]+" qrc_entries "${qrc_contents}")
+ set(qrc_depends)
+ foreach(entry IN LISTS qrc_entries)
+ string(REGEX REPLACE "]*>([^<]+)" "\\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} "$" -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()
diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt
index 118c35ae9..2a7f72619 100644
--- a/src/duckstation-qt/CMakeLists.txt
+++ b/src/duckstation-qt/CMakeLists.txt
@@ -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 "$/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)