diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fe4ab2..556c09e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,8 @@ -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.19) include(cmake/Utilities.cmake) include(cmake/GetGitRevisionDescription.cmake) include(cmake/ProjectVersion.cmake) +include(cmake/ReproducibleBuild.cmake) project( MMU @@ -95,12 +96,8 @@ add_compile_options(-g) # optimizations if(CMAKE_CROSSCOMPILING) - # Reproducible build support - add_link_options(-fdebug-prefix-map=${CMAKE_SOURCE_DIR}=) - add_link_options(-fdebug-prefix-map=${CMAKE_BINARY_DIR}=) - if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "8") - add_compile_options(-ffile-prefix-map=${CMAKE_SOURCE_DIR}=) - endif() + # TODO: get date from the last git commit to set as epoch + set_source_epoch(0) # default optimization flags set(CMAKE_CXX_FLAGS_DEBUG "-Og -g") @@ -203,7 +200,9 @@ target_compile_options(firmware PRIVATE -Wdouble-promotion) add_subdirectory(src) -if(NOT CMAKE_CROSSCOMPILING) +if(CMAKE_CROSSCOMPILING) + set_all_targets_reproducible() +else() # do not build the firmware by default (tests are the focus if not crosscompiling) set_target_properties(firmware PROPERTIES EXCLUDE_FROM_ALL YES) diff --git a/cmake/ReproducibleBuild.cmake b/cmake/ReproducibleBuild.cmake new file mode 100644 index 0000000..bdc7995 --- /dev/null +++ b/cmake/ReproducibleBuild.cmake @@ -0,0 +1,66 @@ +# +# Functions and utilities for build reproducibility +# + +# Set a target to be reproducible +function(set_reproducible_target target) + # properties for static libraries + set_target_properties(${target} PROPERTIES STATIC_LIBRARY_OPTIONS "-D") + + # properties on executables + target_link_options(${target} PRIVATE -fdebug-prefix-map=${CMAKE_SOURCE_DIR}=) + target_link_options(${target} PRIVATE -fdebug-prefix-map=${CMAKE_BINARY_DIR}=) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "8") + target_compile_options(${target} PRIVATE -ffile-prefix-map=${CMAKE_SOURCE_DIR}=) + endif() + + # properties on sources + get_target_property(sources ${target} SOURCES) + get_target_property(source_dir ${target} SOURCE_DIR) + foreach(file IN LISTS sources) + cmake_path(ABSOLUTE_PATH file BASE_DIRECTORY ${source_dir}) + cmake_path(RELATIVE_PATH file BASE_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE rpath) + set_property( + SOURCE ${file} + DIRECTORY ${source_dir} + APPEND + PROPERTY COMPILE_OPTIONS "-frandom-seed=${rpath}" + ) + endforeach() +endfunction() + +# Get the list of targets for all directories +function(get_all_targets _result _dir) + get_property( + _subdirs + DIRECTORY "${_dir}" + PROPERTY SUBDIRECTORIES + ) + foreach(_subdir IN LISTS _subdirs) + get_all_targets(${_result} "${_subdir}") + endforeach() + get_directory_property(_sub_targets DIRECTORY "${_dir}" BUILDSYSTEM_TARGETS) + set(${_result} + ${${_result}} ${_sub_targets} + PARENT_SCOPE + ) +endfunction() + +# Make every target reproducible +function(set_all_targets_reproducible) + get_all_targets(targets ${CMAKE_SOURCE_DIR}) + foreach(target IN LISTS targets) + set_reproducible_target(${target}) + endforeach() +endfunction() + +# Set source epoch +function(set_source_epoch epoch) + set(ENV{SOURCE_DATE_EPOCH} ${epoch}) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8") + string(TIMESTAMP SOURCE_DATE_EPOCH "%Y-%m-%d") + add_compile_definitions(SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH}") + string(TIMESTAMP SOURCE_TIME_EPOCH "%H:%M:%S") + add_compile_definitions(SOURCE_TIME_EPOCH="${SOURCE_TIME_EPOCH}") + endif() +endfunction()