Primitive SOURCE_DATE_EPOCH support for reproducible builds (patches 294)

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@7188 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2020-06-26 22:52:09 +00:00
parent 6cd1e7d908
commit 7e2be76681
6 changed files with 95 additions and 24 deletions

View file

@ -36,6 +36,8 @@ Released on ? ?th, 2020
\S2{} Build System
\b Primitive SOURCE_DATE_EPOCH support (\W{http://sf.net/p/nsis/patches/294}{patch #294})
\b Python 3 fixes (\W{http://sf.net/p/nsis/patches/296}{patch #296})
\H{v3.05} 3.05

View file

@ -4,13 +4,13 @@ Import('defenv')
### imports
Import('FlagsConfigure GetOptionOrEnv')
Import('FlagsConfigure GetOptionOrEnv GetStdSysEnvVarList')
### HACKS!
if GetOptionOrEnv('NSIS_SCONS_GNU_ENVPATHHACK'):
import os
defenv['ENV']['PATH'] = os.getenv('PATH') # Major hack!
import_env = ['SystemDrive', 'SystemRoot', 'TEMP', 'TMP', 'PATHEXT']
import_env = GetStdSysEnvVarList(path=True, temp=True)
for var in import_env:
if var in os.environ:
defenv['ENV'][var] = os.environ.get(var, '')

View file

@ -290,7 +290,7 @@ def generate(env):
targ_arc = env.get('TARGET_ARCH', 'x86')
if "None" == env.get('MSVC_USE_SCRIPT', '!'):
for x in ['INCLUDE', 'LIB', 'PATH', 'CL', 'LINK', 'ML']: env['ENV'][x] = ""
for x in ['INCLUDE', 'LIB', 'PATH', 'CL', '_CL_', 'LINK', '_LINK_', 'ML']: env['ENV'][x] = ""
if not env.WhereIs('cl', os.environ['PATH']):
raise SCons.Errors.InternalError("CL not found in %s" % os.environ['PATH'])
include_path = os.environ['INCLUDE']
@ -312,6 +312,7 @@ def generate(env):
env.PrependENVPath('INCLUDE', include_path)
env.PrependENVPath('LIB', lib_path)
env.PrependENVPath('PATH', exe_path)
# 'LIBPATH' = ?
env['ENV']['CPU'] = (targ_arc.upper(), 'i386')['x86' in targ_arc.lower()] # AMD64/ARM64 or i386
env['ENV']['TARGETOS'] = 'BOTH'

View file

@ -1,3 +1,31 @@
def IsExecutingOnWindows():
import sys, os
if sys.platform.startswith('win') or os.name == 'nt': return True
return False
def GetWindowsStdSysEnvVarList(path=False, temp=True, user=True, os=True, shell=True, cpu=True):
ret = []
if os: ret += 'OS WINDIR SYSTEMDRIVE SYSTEMROOT ALLUSERSPROFILE Public ProgramData CommonProgramFiles CommonProgramFiles(x86) CommonProgramW6432 ProgramFiles ProgramFiles(x86) ProgramW6432'.split()
if cpu: ret += 'NUMBER_OF_PROCESSORS PROCESSOR_ARCHITECTURE PROCESSOR_ARCHITEW6432 PROCESSOR_IDENTIFIER PROCESSOR_LEVEL PROCESSOR_REVISION'.split()
if user: ret += 'COMPUTERNAME USERNAME USERPROFILE APPDATA LOCALAPPDATA HOMEDRIVE HOMESHARE HOMEPATH LOGONSERVER USERDNSDOMAIN USERDOMAIN USERDOMAIN_ROAMINGPROFILE ClientName SessionName'.split()
if shell: ret += 'COMSPEC PATHEXT PSModulePath'.split() # PROMPT
if temp: ret += 'TEMP TMP'.split()
if path: ret += 'PATH'.split()
return ret
def GetPosixStdSysEnvVarList(path=False, temp=True, user=True, os=True, shell=True, cpu=True):
ret = []
if os: ret += 'HOSTALIASES'.split()
if user: ret += 'HOME USER LOGNAME DATEMSK UID'.split() # XDG_* TZ LANGUAGE LANG LC_* NLSPATH
if shell: ret += 'SHELL TERM TERMCAP'.split()
if temp: ret += 'TMPDIR'.split()
if path: ret += 'PATH MANPATH'.split()
return ret
def GetStdSysEnvVarList(path=False, temp=True, user=True, os=True, shell=True, cpu=True):
func = GetPosixStdSysEnvVarList
if IsExecutingOnWindows(): func = GetWindowsStdSysEnvVarList
return func(path=path, temp=temp, user=user, os=os, shell=shell, cpu=cpu)
def AddAvailableLibs(env, libs):
"""
Scans through a list of libraries and adds
@ -145,10 +173,10 @@ def ReadU32LE(f, fpos=None, defval=None):
return FileUnpackRead("<I", 4, f, fpos, defval)
def WriteU16LE(f, v, fpos):
if not fpos is None: f.seek(fpos)
f.write(struct.pack("<H", v))
return f.write(struct.pack("<H", v))
def WriteU32LE(f, v, fpos):
if not fpos is None: f.seek(fpos)
f.write(struct.pack("<I", v))
return f.write(struct.pack("<I", v))
class MSPE:
def __init__(self, path=None, open_for_write=False):
@ -177,16 +205,24 @@ class MSPE:
self.IsPEP = 0x20b == self.NTOHMagic # IMAGE_NT_OPTIONAL_HDR64_MAGIC?
def ReadMachine(self):
return ReadU16LE(self._f, self.NTHOffset+4+0)
def WriteTimeDateStamp(self, value):
return WriteU32LE(self._f, value, self.NTHOffset+4+4)
def ReadCharacteristics(self):
return ReadU16LE(self._f, self.NTHOffset+4+18)
def WriteCharacteristics(self, value):
WriteU16LE(self._f, value, self.NTHOffset+4+18)
return WriteU16LE(self._f, value, self.NTHOffset+4+18)
def ReadDllCharacteristics(self):
return ReadU16LE(self._f, self.NTHOffset+4+20+70)
def WriteDllCharacteristics(self, value):
WriteU16LE(self._f, value, self.NTHOffset+4+20+70)
return WriteU16LE(self._f, value, self.NTHOffset+4+20+70)
def WriteChecksum(self, value):
WriteU32LE(self._f, value, self.NTHOffset+4+20+64)
return WriteU32LE(self._f, value, self.NTHOffset+4+20+64)
def InvalidateChecksum(self):
return self.WriteChecksum(0) and 0
def IsPE(pe):
if not isinstance(pe, MSPE): pe = MSPE(pe)
if not pe.NTOHMagic is None: return True
def IsPEExecutable(pe):
if not isinstance(pe, MSPE): pe = MSPE(pe)
@ -211,8 +247,25 @@ def SetPESecurityFlagsWorker(filepath):
ioh_dc |= 0x0040 # +IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE (ASLR)
if pe.IsPEP: ioh_dc |= 0x0020 # +IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA (HEASLR)
pe.WriteDllCharacteristics(ioh_dc)
pe.WriteChecksum(0)
pe.InvalidateChecksum()
finally:
return
Export('AddAvailableLibs AddZLib FlagsConfigure GetAvailableLibs GetOptionOrEnv IsPEExecutable SetPESecurityFlagsWorker')
def SetPETimestamp(filepath, timestamp):
pe = MSPE(filepath, open_for_write=True)
try:
if not IsPE(pe): return
pe.WriteTimeDateStamp(int(timestamp or 0))
pe.InvalidateChecksum()
return True
finally:
return
def MakeReproducibleAction(target, source, env):
if env.get('SOURCE_DATE_EPOCH','') is not '':
SetPETimestamp(target[0].path, env['SOURCE_DATE_EPOCH'])
def SilentActionEcho(target, source, env):
return None
Export('GetStdSysEnvVarList AddAvailableLibs AddZLib FlagsConfigure GetAvailableLibs GetOptionOrEnv SilentActionEcho IsPEExecutable SetPESecurityFlagsWorker MakeReproducibleAction')

View file

@ -64,20 +64,20 @@ doctypes = [
####### Build Environment ###
######################################################################
import os
path = ARGUMENTS.get('PATH', '')
toolset = ARGUMENTS.get('TOOLSET', '')
arch = ARGUMENTS.get('TARGET_ARCH', 'x86')
if toolset and path:
defenv = Environment(TARGET_ARCH = arch, ENV = {'PATH' : path}, TOOLS = toolset.split(',') + ['zip'])
else:
if path:
defenv = Environment(TARGET_ARCH = arch, ENV = {'PATH' : path})
if toolset:
defenv = Environment(TARGET_ARCH = arch, TOOLS = toolset.split(',') + ['zip'])
if not toolset and not path:
defenv = Environment(TARGET_ARCH = arch)
defenv = {
'TARGET_ARCH': ARGUMENTS.get('TARGET_ARCH', 'x86'),
'ENV': {}
}
if path: defenv['ENV']['PATH'] = path
if toolset: defenv['TOOLS'] = toolset.split(',') + ['zip']
if len(defenv['ENV']) == 0: del defenv['ENV']
defenv = Environment(**defenv)
Export('defenv')
######################################################################
@ -85,12 +85,12 @@ Export('defenv')
######################################################################
SConscript('SCons/utils.py')
Import('GetOptionOrEnv')
######################################################################
####### Options ###
######################################################################
import os
default_doctype = 'html'
if defenv.WhereIs('hhc', os.environ['PATH']):
default_doctype = 'chm'
@ -195,6 +195,8 @@ opts.Add(('PREFIX_DATA', 'Path to install nsis data to (plugins, includes, stubs
opts.Add(('PREFIX_DOC','Path to install nsis README / INSTALL / TODO files to.', dirs['doc']))
opts.Add(('PREFIX_PLUGINAPI_INC','Path to install plugin API headers to.', None))
opts.Add(('PREFIX_PLUGINAPI_LIB','Path to install plugin static library to.', None))
# reproducible builds
opts.Add(('SOURCE_DATE_EPOCH', 'UNIX timestamp (in seconds)', os.environ.get('SOURCE_DATE_EPOCH')))
opts.Update(defenv)
Help(opts.GenerateHelpText(defenv))
@ -211,6 +213,10 @@ if 'NSIS_CONFIG_CONST_DATA_PATH' in defenv['NSIS_CPPDEFINES']:
defenv.Append(NSIS_CPPDEFINES = [('PREFIX_DATA', '"%s"' % defenv.subst('$PREFIX_DATA'))])
defenv.Append(NSIS_CPPDEFINES = [('PREFIX_DOC', '"%s"' % defenv.subst('$PREFIX_DOC'))])
if defenv.get('SOURCE_DATE_EPOCH','') is not '':
defenv['ENV']['SOURCE_DATE_EPOCH'] = defenv['SOURCE_DATE_EPOCH'] = int(defenv['SOURCE_DATE_EPOCH'], 0) # Normalize and apply to ENV for child processes
defenv.Append(NSIS_CPPDEFINES = [('NSIS_SOURCE_DATE_EPOCH', '%s' % defenv['SOURCE_DATE_EPOCH'])]) # Display in /HDRINFO
# Need this early for the config header files to be placed in
if defenv['UNICODE']:
if defenv['DEBUG']:
@ -441,7 +447,7 @@ def Sign(targets):
a = defenv.Action('$CODESIGNER "%s"' % t.path)
defenv.AddPostAction(t, a)
Import('IsPEExecutable SetPESecurityFlagsWorker')
Import('SilentActionEcho IsPEExecutable SetPESecurityFlagsWorker MakeReproducibleAction')
def SetPESecurityFlagsAction(target, source, env):
for t in target:
SetPESecurityFlagsWorker(t.path)
@ -454,6 +460,10 @@ def SetPESecurityFlags(targets):
a = defenv.Action(SetPESecurityFlagsAction, strfunction=SetPESecurityFlagsActionEcho)
defenv.AddPostAction(t, a)
def MakeReproducible(targets):
for t in targets:
defenv.AddPostAction(t, defenv.Action(MakeReproducibleAction, strfunction=SilentActionEcho))
def TestScript(scripts):
defenv.Install('$TESTDISTDIR/Tests', scripts)
@ -471,6 +481,7 @@ defenv.DistributeDocs = DistributeDocs
defenv.DistributeExamples = DistributeExamples
defenv.Sign = Sign
defenv.SetPESecurityFlags = SetPESecurityFlags
defenv.MakeReproducible = MakeReproducible
defenv.TestScript = TestScript
def DistributeExtras(env, target, examples, docs):
@ -484,7 +495,6 @@ def DistributeExtras(env, target, examples, docs):
######################################################################
if defenv['MSTOOLKIT']:
Import('GetOptionOrEnv')
if GetOptionOrEnv('MSVC_USE_SCRIPT', '!') != '!':
defenv['MSVC_USE_SCRIPT'] = GetOptionOrEnv('MSVC_USE_SCRIPT')
defenv.Tool('mstoolkit', toolpath = [Dir('SCons/Tools').rdir()])
@ -559,6 +569,7 @@ if defenv['PLATFORM'] == 'win32':
nsis_menu_target = defenv.Command(os.path.join('$ZIPDISTDIR', 'NSIS.exe'),
os.path.join('$ZIPDISTDIR', 'Examples', 'NSISMenu.nsi'),
build_nsis_menu_for_zip)
defenv.MakeReproducible(nsis_menu_target)
defenv.Sign(nsis_menu_target)
dist_zip = 'nsis-${VERSION}${DISTSUFFIX}.zip'
@ -641,6 +652,7 @@ def BuildStub(compression, solid, unicode):
target = defenv.SConscript(dirs = 'Source/exehead', variant_dir = build_dir, duplicate = False, exports = exports)
env.SideEffect('%s/stub_%s.map' % (build_dir, stub), target)
env.MakeReproducible(target)
env.DistributeStubs(target, names=compression+suffix)
defenv.Alias(compression, target)
@ -672,6 +684,7 @@ makensis = defenv.SConscript(dirs = 'Source', variant_dir = build_dir, duplicate
makensis_env.SideEffect('%s/makensis.map' % build_dir, makensis)
defenv.MakeReproducible(makensis)
defenv.Alias('makensis', makensis)
if defenv['PLATFORM'] == 'win32':
@ -709,6 +722,7 @@ def BuildPluginWorker(target, source, libs, examples = None, docs = None,
defenv.Alias('plugins', plugin)
defenv.SetPESecurityFlags(plugin)
defenv.MakeReproducible(plugin)
defenv.Sign(plugin)
CleanMap(env, plugin, target)
@ -803,6 +817,7 @@ def BuildUtil(target, source, libs, entry = None, res = None,
defenv.Alias(target, util)
defenv.Alias('utils', util)
defenv.MakeReproducible(util)
defenv.Sign(util)
CleanMap(env, util, target)

View file

@ -3624,7 +3624,7 @@ bool CEXEBuild::hostapi_request_data(MakensisAPI::datatransfer_e operation, UINT
return data && ((HOSTAPIREQUESTDATAPROC)data[0])((void*) data[1], hWnd, Msg, wParam, lParam); // We don't set DWLP_MSGRESULT nor care about the return value
}
};
if (!notify_hwnd || (minver && SendMessage(notify_hwnd, QUERYHOST, QH_SUPPORTEDVERSION, 0) < minver)) return false;
if (!notify_hwnd || (minver && (UINT) SendMessage(notify_hwnd, QUERYHOST, QH_SUPPORTEDVERSION, 0) < minver)) return false;
size_t data[] = { (size_t) proc, (size_t) cookie };
COPYDATASTRUCT cds = { (DWORD) operation, inputsize, (void*) input };
HWND hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, WC_DIALOG, NULL, WS_POPUP|WS_DISABLED, 0, 0, 0, 0, NULL, NULL, NULL, NULL);