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:
parent
6cd1e7d908
commit
7e2be76681
6 changed files with 95 additions and 24 deletions
|
@ -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
|
||||
|
|
|
@ -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, '')
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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')
|
||||
|
|
41
SConstruct
41
SConstruct
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue