Package: gnat-7 Followup-For: Bug #856042 Control: tags 856042 + patch This new source-date-epoch.diff applies to 7-20170226-1 and builds with DEB_BUILD_OPTIONS="lang=ada nocheck noopt nostrap nolang=...". The test is more extensive, but I have not been able to run it on the build result (for unrelated reasons).
--- a/debian/rules.patch +++ b/debian/rules.patch @@ -145,6 +145,7 @@ debian_patches += ada-arm #endif debian_patches += ada-link-shlib + debian_patches += ada-lib-info-source-date-epoch #endif --- /dev/null +++ b/debian/patches/ada-lib-info-source-date-epoch.diff @@ -0,0 +1,174 @@ +# DP: When the SOURCE_DATE_EPOCH environment variable is set, +# DP: replace timestamps more recent than its value with its value +# DP: when writing Ada Library Information (ALI) files. +# DP: This allow reproducible builds from generated or patched Ada sources. +# DP: https://reproducible-builds.org/specs/source-date-epoch/ + +--- a/src/gcc/ada/lib-writ.adb ++++ b/src/gcc/ada/lib-writ.adb +@@ -54,6 +54,7 @@ + with Uname; use Uname; + + with System.Case_Util; use System.Case_Util; ++with System.OS_Lib; + with System.WCh_Con; use System.WCh_Con; + + package body Lib.Writ is +@@ -62,6 +63,15 @@ + -- Local Subprograms -- + ----------------------- + ++ procedure Truncate_To_Source_Date_Epoch (T : in out Time_Stamp_Type); ++ pragma Inline (Truncate_To_Source_Date_Epoch); ++ -- If SOURCE_DATE_EPOCH is defined in the environment and ++ -- represents an UNIX epoch, T is truncated to this date. ++ ++ -- This allows reproducible ALI contents even for sources patched ++ -- or generated at build time. ++ -- https://reproducible-builds.org/specs/source-date-epoch/ ++ + procedure Write_Unit_Name (N : Node_Id); + -- Used to write out the unit name for R (pragma Restriction) lines + -- for uses of Restriction (No_Dependence => unit-name). +@@ -175,6 +185,65 @@ + end; + end Ensure_System_Dependency; + ++ ----------------------------------- ++ -- Truncate_To_Source_Date_Epoch -- ++ ----------------------------------- ++ ++ -- An internal state caches the result of the getenv() system call ++ -- during first execution. The Source_Date_Unset case could be ++ -- replaced with a Source_Date far in the future, but we want to ++ -- avoid Time_Stamp_Type comparisons in the most common case. ++ ++ type A_Source_Date_State is ++ (Source_Date_Unknown, Source_Date_Unset, Source_Date_Set); ++ Source_Date_State : A_Source_Date_State := Source_Date_Unknown; ++ Source_Date : Time_Stamp_Type; ++ ++ procedure Truncate_To_Source_Date_Epoch (T : in out Time_Stamp_Type) is ++ begin ++ case Source_Date_State is ++ when Source_Date_Unset => ++ null; ++ when Source_Date_Set => ++ if Source_Date < T then ++ T := Source_Date; ++ end if; ++ when Source_Date_Unknown => ++ declare ++ use System.OS_Lib; ++ Env_Var : String_Access; ++ Get_OK : Boolean; ++ Epoch : OS_Time; ++ Y : Year_Type; ++ Mo : Month_Type; ++ D : Day_Type; ++ H : Hour_Type; ++ Mn : Minute_Type; ++ S : Second_Type; ++ begin ++ Env_Var := Getenv ("SOURCE_DATE_EPOCH"); ++ Get_OS_Time_From_String (Env_Var.all, Get_OK, Epoch); ++ Free (Env_Var); ++ if Get_OK then ++ GM_Split (Epoch, Y, Mo, D, H, Mn, S); ++ Make_Time_Stamp (Year => Nat (Y), ++ Month => Nat (Mo), ++ Day => Nat (D), ++ Hour => Nat (H), ++ Minutes => Nat (Mn), ++ Seconds => Nat (S), ++ TS => Source_Date); ++ Source_Date_State := Source_Date_Set; ++ if Source_Date < T then ++ T := Source_Date; ++ end if; ++ else ++ Source_Date_State := Source_Date_Unset; ++ end if; ++ end; ++ end case; ++ end Truncate_To_Source_Date_Epoch; ++ + --------------- + -- Write_ALI -- + --------------- +@@ -1471,7 +1540,14 @@ + + Write_Info_Name_May_Be_Quoted (Fname); + Write_Info_Tab (25); +- Write_Info_Str (String (Time_Stamp (Sind))); ++ ++ declare ++ T : Time_Stamp_Type := Time_Stamp (Sind); ++ begin ++ Truncate_To_Source_Date_Epoch (T); ++ Write_Info_Str (String (T)); ++ end; ++ + Write_Info_Char (' '); + Write_Info_Str (Get_Hex_String (Source_Checksum (Sind))); + +--- a/src/gcc/ada/s-os_lib.adb ++++ b/src/gcc/ada/s-os_lib.adb +@@ -1153,6 +1153,41 @@ + return Result; + end Get_Object_Suffix; + ++ ----------------------------- ++ -- Get_OS_Time_From_String -- ++ ----------------------------- ++ ++ procedure Get_OS_Time_From_String (Arg : String; ++ Success : out Boolean; ++ Result : out OS_Time) is ++ -- Calling System.Val_LLI breaks the bootstrap sequence. ++ Digit : OS_Time; ++ begin ++ Result := 0; ++ if Arg'Length = 0 then ++ Success := False; ++ return; ++ end if; ++ for I in Arg'Range loop ++ if Arg (I) not in '0' .. '9' then ++ Success := False; ++ return; ++ end if; ++ Digit := OS_Time (Character'Pos (Arg (I)) - Character'Pos ('0')); ++ if OS_Time'Last / 10 < Result then ++ Success := False; ++ return; ++ end if; ++ Result := Result * 10; ++ if OS_Time'Last - Digit < Result then ++ Success := False; ++ return; ++ end if; ++ Result := Result + Digit; ++ end loop; ++ Success := True; ++ end Get_OS_Time_From_String; ++ + ---------------------------------- + -- Get_Target_Debuggable_Suffix -- + ---------------------------------- +--- a/src/gcc/ada/s-os_lib.ads ++++ b/src/gcc/ada/s-os_lib.ads +@@ -164,6 +164,13 @@ + -- component parts to be interpreted in the local time zone, and returns + -- an OS_Time. Returns Invalid_Time if the creation fails. + ++ procedure Get_OS_Time_From_String (Arg : String; ++ Success : out Boolean; ++ Result : out OS_Time); ++ -- Success is set if Arg is not empty, only contains decimal ++ -- digits and represents an integer within OS_Time range. Result ++ -- is then affected with the represented value. ++ + ---------------- + -- File Stuff -- + ----------------
#!/bin/sh set -C -e -f -u
cat > p.ads <<EOF package P is N : constant := 42; end P; EOF mtime=20 touch --date=@$mtime p.ads to_gnat () { date --utc --date=@$1 +%Y%m%d%H%M%S } check () { expected=`to_gnat $1` gnatgcc -c p.ads found=`sed -n '/^D p\.ads\t\+\([0-9]\{14\}\) .*/{s//\1/;p;q}' p.ali` rm -f p.ali p.o if test "$found" != $expected ; then echo "Test failed" echo " SOURCE_DATE_EPOCH: '${SOURCE_DATE_EPOCH:-}'" echo " Source file mtime:`to_gnat $mtime` ($mtime)" echo " Expected in ALI :$expected ($1)" echo " Found in ALI :$found" rm -f p.ads exit 1 fi } # SOURCE_DATE_EPOCH is not defined check $mtime # SOURCE_DATE_EPOCH is invalid or more recent than mtime. for d in "" a " 1" -0 -1 30 030 ; do SOURCE_DATE_EPOCH=$d check $mtime done # SOURCE_DATE_EPOCH is valid and older than mtime. for d in 0 10 010 ; do SOURCE_DATE_EPOCH=$d check $d done rm -f p.ads echo "SOURCE_DATE_EPOCH tests OK"