View Issue Details

IDProjectCategoryView StatusLast Update
0004808The Dark ModDesign/Codingpublic01.02.2020 09:43
ReporterStefanB Assigned Tostgatilov  
PrioritynormalSeveritytrivialReproducibilityalways
Status resolvedResolutionwon't fix 
PlatformLinux 
Product VersionTDM 2.06 
Target VersionTDM 2.08Fixed in VersionTDM 2.08 
Summary0004808: Make SCons Python3 compatible (Patch included)
DescriptionThe current SCons scripts are not compatible with Python3. Python2 will go out of maintenance in 2020 (https://pythonclock.org/)

The scripts can be made compatible with both Python3 and Python 2.7 without to much effort.
Steps To ReproduceBuild on a modern Linux distribution
TagsNo tags attached.
Attached Files
0001-SConstruct-Use-print-as-a-function-for-python3-compa.patch (5,488 bytes)   
From db89790e355ec79d25196e03ec7f7f44cbe3b302 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
Date: Tue, 29 May 2018 20:18:01 +0200
Subject: [PATCH 1/5] SConstruct: Use print as a function for python3
 compatibility

---
 SConstruct               | 12 ++++++------
 sys/scons/SConscript.gl  |  2 +-
 sys/scons/scons_utils.py | 20 ++++++++++----------
 tdm_update/SConstruct    |  4 ++--
 4 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/SConstruct b/SConstruct
index be36d16..b244cb6 100644
--- a/SConstruct
+++ b/SConstruct
@@ -147,13 +147,13 @@ if ( not ARGUMENTS.has_key( 'NOCONF' ) or ARGUMENTS['NOCONF'] != '1' ):
 		site_file = open(conf_filename, 'r')
 		p = pickle.Unpickler(site_file)
 		site_dict = p.load()
-		print 'Loading build configuration from ' + conf_filename + ':'
+		print('Loading build configuration from ' + conf_filename + ':')
 		for k, v in site_dict.items():
 			exec_cmd = k + '=\'' + v + '\''
-			print '  ' + exec_cmd
+			print('  ' + exec_cmd)
 			exec(exec_cmd)
 else:
-	print 'Site settings ignored'
+	print('Site settings ignored')
 
 # end site settings ------------------------------
 
@@ -161,7 +161,7 @@ else:
 
 for k in ARGUMENTS.keys():
 	exec_cmd = k + '=\'' + ARGUMENTS[k] + '\''
-	print 'Command line: ' + exec_cmd
+	print('Command line: ' + exec_cmd)
 	exec( exec_cmd )
 
 # stgatilov: avoid annoying human errors when you set target='x32'
@@ -279,7 +279,7 @@ elif ( BUILD == 'release' ):
 	if ( ID_MCHECK == '0' ):
 		ID_MCHECK = '2'
 else:
-	print 'Unknown build configuration ' + BUILD
+	print('Unknown build configuration ' + BUILD)
 	sys.exit(0)
 
 if ( GL_HARDLINK != '0' ):
@@ -313,7 +313,7 @@ g_env_base['LINKFLAGS'] += CORELINKFLAGS
 
 
 #if ( int(JOBS) > 1 ):
-#	print 'Using buffered process output'
+#	print('Using buffered process output')
 #	silent = False
 #	if ( SILENT == '1' ):
 #		silent = True
diff --git a/sys/scons/SConscript.gl b/sys/scons/SConscript.gl
index 20237a2..0dc96d6 100644
--- a/sys/scons/SConscript.gl
+++ b/sys/scons/SConscript.gl
@@ -46,7 +46,7 @@ def build_logfuncs(env, target, source):
 	
 	f_out.close()
 	
-	print 'Generated %s' % target[0]
+	print('Generated {0}'.format(target[0]))
 
 gl_env = g_env_base.Clone()
 gl_env.Append( CPPPATH = '#' )
diff --git a/sys/scons/scons_utils.py b/sys/scons/scons_utils.py
index 377562c..c2050e1 100644
--- a/sys/scons/scons_utils.py
+++ b/sys/scons/scons_utils.py
@@ -19,9 +19,9 @@ class idBuffering:
 		except OSError, x:
 			if x.errno != 10:
 				raise x
-			print 'OSError ignored on command: %s' % command_string
+			print('OSError ignored on command: {0}'.format(command_string))
 			retval = 0
-		print command_string
+		print(command_string)
 		if ( retval != 0 or not self.silent ):
 			sys.stdout.write( stdout.getvalue() )
 			sys.stderr.write( stderr.getvalue() )
@@ -30,7 +30,7 @@ class idBuffering:
 class idSetupBase:
 	
 	def SimpleCommand( self, cmd ):
-		print cmd
+		print(cmd)
 		ret = commands.getstatusoutput( cmd )
 		if ( len( ret[ 1 ] ) ):
 			sys.stdout.write( ret[ 1 ] )
@@ -40,7 +40,7 @@ class idSetupBase:
 		return ret[ 1 ]
 
 	def TrySimpleCommand( self, cmd ):
-		print cmd
+		print(cmd)
 		ret = commands.getstatusoutput( cmd )
 		sys.stdout.write( ret[ 1 ] )
 
@@ -101,17 +101,17 @@ class idSetupBase:
 def checkLDD( target, source, env ):
 	file = target[0]
 	if (not os.path.isfile(file.abspath)):
-		print('ERROR: CheckLDD: target %s not found\n' % target[0])
+		print('ERROR: CheckLDD: target {0} not found\n'.format(target[0]))
 		Exit(1)
 	( status, output ) = commands.getstatusoutput( 'ldd -r %s' % file )
 	if ( status != 0 ):
-		print 'ERROR: ldd command returned with exit code %d' % ldd_ret
+		print('ERROR: ldd command returned with exit code {0}'.format(ldd_ret))
 		os.system( 'rm %s' % target[ 0 ] )
 		sys.exit(1)
 	lines = string.split( output, '\n' )
 	have_undef = 0
 	for i_line in lines:
-		#print repr(i_line)
+		#print(repr(i_line))
 		regex = re.compile('undefined symbol: (.*)\t\\((.*)\\)')
 		if ( regex.match(i_line) ):
 			symbol = regex.sub('\\1', i_line)
@@ -120,8 +120,8 @@ def checkLDD( target, source, env ):
 			except:
 				have_undef = 1
 	if ( have_undef ):
-		print output
-		print "ERROR: undefined symbols"
+		print(output)
+		print("ERROR: undefined symbols")
 		os.system('rm %s' % target[0])
 		sys.exit(1)
 
@@ -131,7 +131,7 @@ def SharedLibrarySafe( env, target, source ):
 	return ret
 
 def NotImplementedStub( *whatever ):
-	print 'Not Implemented'
+	print('Not Implemented')
 	sys.exit( 1 )
 
 # --------------------------------------------------------------------
diff --git a/tdm_update/SConstruct b/tdm_update/SConstruct
index c01983c..48ca68d 100644
--- a/tdm_update/SConstruct
+++ b/tdm_update/SConstruct
@@ -105,7 +105,7 @@ MACOSX_TARGET_ARCH = 'i386'
 
 for k in ARGUMENTS.keys():
 	exec_cmd = k + '=\'' + ARGUMENTS[k] + '\''
-	print 'Command line: ' + exec_cmd
+	print('Command line: ' + exec_cmd)
 	exec( exec_cmd )
 
 # end command line settings ----------------------
@@ -188,7 +188,7 @@ elif ( BUILD == 'release' ):
 	# no-unsafe-math-optimizations: that should be on by default really. hit some wonko bugs in physics code because of that
 	OPTCPPFLAGS = [ '-O3', '-ffast-math', '-fno-unsafe-math-optimizations', '-fomit-frame-pointer' ]
 else:
-	print 'Unknown build configuration ' + BUILD
+	print('Unknown build configuration ' + BUILD)
 	sys.exit(0)
 
 # create the build environements
-- 
2.17.0

0002-SConstruct-Replace-deprecated-syntax-modules-with-fo.patch (9,577 bytes)   
From 62fce580600a14a0e7f79fc1c81b80b2fd489ca5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
Date: Tue, 29 May 2018 20:34:33 +0200
Subject: [PATCH 2/5] SConstruct: Replace deprecated syntax/modules with
 forwards compatible ones

The subprocess module is available since python 2.4 and replaces the
commands module, which is deprecated since 2.6 and has been removed in 3.0.
Remove unused popen2 and StringIO imports.
Use 'except ... as e:' syntax, which is supported since python 2.6.
dict().has_key is deprecated and can be replace by 'key in dict' or,
for lookup, with get(key, default).
The pickle load/dump methos need a binary file in python3, use the binary
flag for opening.
split no longer is a method of the string module, but of the str() class.
---
 SConstruct                          | 19 ++++++++-------
 sys/gllog/logfunc.py                |  6 ++---
 sys/gllog/read.py                   |  4 ++--
 sys/scons/scons_utils.py            | 36 +++++++++++++++--------------
 tdm_update/SConscript.libtdm_update |  2 +-
 tdm_update/SConscript.minizip       |  2 +-
 tdm_update/SConscript.tdm_update    |  2 +-
 tdm_update/SConstruct               |  9 ++++----
 8 files changed, 40 insertions(+), 40 deletions(-)

diff --git a/SConstruct b/SConstruct
index b244cb6..27823dd 100644
--- a/SConstruct
+++ b/SConstruct
@@ -3,7 +3,7 @@
 # TTimo <ttimo@idsoftware.com>
 # http://scons.sourceforge.net
 
-import sys, os, time, commands, re, pickle, StringIO, popen2, commands, pdb, zipfile, string
+import sys, os, time, re, pickle, subprocess, pdb, zipfile, string
 import SCons
 
 sys.path.append( 'sys/scons' )
@@ -104,13 +104,12 @@ EnsureSConsVersion( 0, 96 )
 # system detection -------------------------------
 
 # CPU type
-cpu = commands.getoutput('uname -m')
-exp = re.compile('.*i?86.*')
-if exp.match(cpu):
+cpu = subprocess.check_output(["uname", "-m"])
+if re.match(b'.*i?86.*', cpu):
 	cpu = 'x86'
 else:
-	cpu = commands.getoutput('uname -p')
-	if ( cpu == 'powerpc' ):
+	cpu = subprocess.check_output(["uname", "-p"])
+	if ( cpu == b'powerpc' ):
 		cpu = 'ppc'
 	else:
 		cpu = 'cpu'
@@ -141,10 +140,10 @@ TARGET_ARCH = 'x86'
 
 # site settings ----------------------------------
 
-if ( not ARGUMENTS.has_key( 'NOCONF' ) or ARGUMENTS['NOCONF'] != '1' ):
+if ( ARGUMENTS.get('NOCONF', 0) != '1' ):
 	site_dict = {}
 	if (os.path.exists(conf_filename)):
-		site_file = open(conf_filename, 'r')
+		site_file = open(conf_filename, 'rb')
 		p = pickle.Unpickler(site_file)
 		site_dict = p.load()
 		print('Loading build configuration from ' + conf_filename + ':')
@@ -173,12 +172,12 @@ if TARGET_ARCH == 'x32':
 
 # save site configuration ----------------------
 
-if ( not ARGUMENTS.has_key( 'NOCONF' ) or ARGUMENTS['NOCONF'] != '1' ):
+if ( ARGUMENTS.get('NOCONF', 0) != '1' ):
 	for k in serialized:
 		exec_cmd = 'site_dict[\'' + k + '\'] = ' + k
 		exec(exec_cmd)
 
-	site_file = open(conf_filename, 'w')
+	site_file = open(conf_filename, 'wb')
 	p = pickle.Pickler(site_file)
 	p.dump(site_dict)
 	site_file.close()
diff --git a/sys/gllog/logfunc.py b/sys/gllog/logfunc.py
index 3a9e46f..e38de5d 100644
--- a/sys/gllog/logfunc.py
+++ b/sys/gllog/logfunc.py
@@ -12,10 +12,10 @@ def do_logfunc(f_in, f_out):
 	for l in (gl, glX):
 		for t in l:
 			# process ret type to strip trailing spaces
-			t[0] = string.strip(t[0])
+			t[0] = t[0].strip()
 			f_out.write('static %s APIENTRY log%s(%s) {\n' % ( t[0], t[2], t[3] ))
 			# work on parameters
-			base_params = string.split(t[3], ',')
+			base_params = t[3].split(',')
 			#f_out.write('// %s\n' % repr(base_params))
 			# init format string and parameter list
 			params = []
@@ -26,7 +26,7 @@ def do_logfunc(f_in, f_out):
 			for i in base_params:
 				regex = re.compile('([a-zA-Z0-9]*)$')
 				name = regex.search(i).group(1)
-				type = string.strip(i[0:len(i)-len(name)])				
+				type = i[0:len(i)-len(name)].strip()
 				# catch type with no name
 				if (len(type) == 0):
 					type = name
diff --git a/sys/gllog/read.py b/sys/gllog/read.py
index 502322d..04b8d50 100644
--- a/sys/gllog/read.py
+++ b/sys/gllog/read.py
@@ -4,7 +4,7 @@ import sys, string
 
 def read_gl(f_in):
 	buffer = f_in.read()
-	lines = string.split(buffer, '\n')
+	lines = buffer.split('\n')
 
 	gl = []
 	wgl = []
@@ -12,7 +12,7 @@ def read_gl(f_in):
 
 	for line in lines:
 		if ( len(line) ): # drop empty lines
-			tokens = string.split(line, ';')
+			tokens = line.split(';')
 			if ( tokens[1] == 'qgl' ):
 				gl.append(tokens)
 			elif ( tokens[1] == 'qwgl' ):
diff --git a/sys/scons/scons_utils.py b/sys/scons/scons_utils.py
index c2050e1..9af5926 100644
--- a/sys/scons/scons_utils.py
+++ b/sys/scons/scons_utils.py
@@ -1,5 +1,5 @@
 # -*- mode: python -*-
-import sys, os, string, time, commands, re, pickle, StringIO, popen2, commands, pdb, zipfile, tempfile
+import sys, os, subprocess, string, time, re, pickle, pdb, zipfile, tempfile
 import SCons
 
 # need an Environment and a matching buffered_spawn API .. encapsulate
@@ -16,7 +16,7 @@ class idBuffering:
 			command_string += i
 		try:
 			retval = self.env['PSPAWN']( sh, escape, cmd, args, env, stdout, stderr )
-		except OSError, x:
+		except OSError as x:
 			if x.errno != 10:
 				raise x
 			print('OSError ignored on command: {0}'.format(command_string))
@@ -31,18 +31,19 @@ class idSetupBase:
 	
 	def SimpleCommand( self, cmd ):
 		print(cmd)
-		ret = commands.getstatusoutput( cmd )
-		if ( len( ret[ 1 ] ) ):
-			sys.stdout.write( ret[ 1 ] )
+		ret = subprocess.check_output( cmd )
+		if ( len( ret ) ):
+			sys.stdout.write( ret.decode('utf-8') )
 			sys.stdout.write( '\n' )
-		if ( ret[ 0 ] != 0 ):
-			raise 'command failed'
-		return ret[ 1 ]
+		return ret.decode('utf-8')
 
 	def TrySimpleCommand( self, cmd ):
 		print(cmd)
-		ret = commands.getstatusoutput( cmd )
-		sys.stdout.write( ret[ 1 ] )
+		try:
+			ret = subprocess.check_output( cmd )
+		except:
+			pass
+		sys.stdout.write( ret.decode('utf-8') )
 
 	def M4Processing( self, file, d ):
 		file_out = file[:-3]
@@ -95,20 +96,21 @@ class idSetupBase:
 		f = open( 'framework/BuildVersion.h' )
 		l = f.readlines()[ 4 ]
 		f.close()
-		pat = re.compile( '.* = (.*);\n' )
-		return pat.split( l )[ 1 ]
+		return re.split( '.* = (.*);\n', l )[ 1 ]
 
 def checkLDD( target, source, env ):
 	file = target[0]
 	if (not os.path.isfile(file.abspath)):
 		print('ERROR: CheckLDD: target {0} not found\n'.format(target[0]))
 		Exit(1)
-	( status, output ) = commands.getstatusoutput( 'ldd -r %s' % file )
-	if ( status != 0 ):
-		print('ERROR: ldd command returned with exit code {0}'.format(ldd_ret))
+	try:
+		output = subprocess.check_output( 'ldd -r %s' % file )
+		output = output.decode('utf-8')
+	except CalledProcessError as e:
+		print('ERROR: ldd command returned with exit code {0}: {1}'.format(e.returncode, e.output))
 		os.system( 'rm %s' % target[ 0 ] )
 		sys.exit(1)
-	lines = string.split( output, '\n' )
+	lines = output.split( '\n' )
 	have_undef = 0
 	for i_line in lines:
 		#print(repr(i_line))
@@ -171,7 +173,7 @@ def SetupUtils( env ):
 	env.BuildSetup = NotImplementedStub
 
 def BuildList( s_prefix, s_string ):
-	s_list = string.split( s_string )
+	s_list = s_string.split( )
 	for i in range( len( s_list ) ):
 		s_list[i] = os.path.join(s_prefix, s_list[i])
 	return s_list
diff --git a/tdm_update/SConscript.libtdm_update b/tdm_update/SConscript.libtdm_update
index 8143c41..8a038fd 100644
--- a/tdm_update/SConscript.libtdm_update
+++ b/tdm_update/SConscript.libtdm_update
@@ -19,7 +19,7 @@
 import string
 
 def BuildList( s_prefix, s_string ):
-	s_list = string.split( s_string )
+	s_list = s_string.split( )
 	for i in range( len( s_list ) ):
 		s_list[ i ] = s_prefix + '/' + s_list[ i ]
 	return s_list
diff --git a/tdm_update/SConscript.minizip b/tdm_update/SConscript.minizip
index 9a0cdb3..04f95f5 100644
--- a/tdm_update/SConscript.minizip
+++ b/tdm_update/SConscript.minizip
@@ -19,7 +19,7 @@
 import string
 
 def BuildList( s_prefix, s_string ):
-	s_list = string.split( s_string )
+	s_list = s_string.split( )
 	for i in range( len( s_list ) ):
 		s_list[ i ] = s_prefix + '/' + s_list[ i ]
 	return s_list
diff --git a/tdm_update/SConscript.tdm_update b/tdm_update/SConscript.tdm_update
index 92ffbdd..3c39073 100644
--- a/tdm_update/SConscript.tdm_update
+++ b/tdm_update/SConscript.tdm_update
@@ -31,7 +31,7 @@ if ( g_os == 'Linux' ):
 	g_env.Append( CPPFLAGS = '-D_GLIBCXX_USE_CXX11_ABI=0' )
 
 def BuildList( s_prefix, s_string ):
-	s_list = string.split( s_string )
+	s_list = s_string.split( )
 	for i in range( len( s_list ) ):
 		s_list[ i ] = s_prefix + '/' + s_list[ i ]
 	return s_list
diff --git a/tdm_update/SConstruct b/tdm_update/SConstruct
index 48ca68d..853af53 100644
--- a/tdm_update/SConstruct
+++ b/tdm_update/SConstruct
@@ -20,7 +20,7 @@
 # Based on id's game sconscript
 # Author: greebo
 
-import sys, os, time, commands, re, pickle, StringIO, commands, pdb, string
+import sys, os, time, re, pickle, subprocess, pdb, string
 import SCons
 
 # choose configuration variables which should be saved between runs
@@ -72,12 +72,11 @@ EnsureSConsVersion( 0, 98 )
 # system detection -------------------------------
 
 # CPU type
-cpu = commands.getoutput('uname -m')
-exp = re.compile('.*i?86.*')
-if exp.match(cpu):
+cpu = subprocess.check_output(["uname", "-m"])
+if re.match(b'.*i?86.*', cpu):
 	cpu = 'x86'
 else:
-	cpu = commands.getoutput('uname -p')
+	cpu = subprocess.check_output(["uname", "-p"])
 	if ( cpu == 'powerpc' ):
 		cpu = 'ppc'
 	else:
-- 
2.17.0

Relationships

related to 0005075 resolvedcabalistic Switch Linux build of TDM from SCons to CMake 

Activities

stgatilov

stgatilov

01.06.2018 13:14

administrator   ~0010488

Wow... they finally did it =)
Half a year since python 3 release --- not much.

I'll use your patches and make scons scripts compatible with both Python 3 and Python 2.
stgatilov

stgatilov

01.02.2020 09:43

administrator   ~0012165

Since we are migrating from SCons to CMake, this is no longer a problem.

Issue History

Date Modified Username Field Change
31.05.2018 17:56 StefanB New Issue
31.05.2018 17:56 StefanB File Added: 0001-SConstruct-Use-print-as-a-function-for-python3-compa.patch
31.05.2018 17:58 StefanB File Added: 0002-SConstruct-Replace-deprecated-syntax-modules-with-fo.patch
01.06.2018 13:14 stgatilov Note Added: 0010488
01.06.2018 13:15 stgatilov Assigned To => stgatilov
01.06.2018 13:15 stgatilov Severity normal => trivial
01.06.2018 13:15 stgatilov Status new => assigned
01.06.2018 13:15 stgatilov Target Version => TDM 2.07
11.06.2018 10:00 stgatilov Target Version TDM 2.07 =>
20.01.2019 07:18 stgatilov Target Version => TDM 2.08
12.12.2019 14:23 stgatilov Relationship added related to 0005075
01.02.2020 09:43 stgatilov Note Added: 0012165
01.02.2020 09:43 stgatilov Status assigned => resolved
01.02.2020 09:43 stgatilov Resolution open => won't fix
01.02.2020 09:43 stgatilov Fixed in Version => TDM 2.08