Files
Phoenix/buildtools/builder.py
Scott Talbert 5abeba2f5d
Some checks failed
ci-build / build-source-dist (push) Has been cancelled
ci-build / Build wxPython documentation (push) Has been cancelled
ci-build / build-wheels (x64, macos-13, 3.10) (push) Has been cancelled
ci-build / build-wheels (x64, macos-13, 3.11) (push) Has been cancelled
ci-build / build-wheels (x64, macos-13, 3.12) (push) Has been cancelled
ci-build / build-wheels (x64, macos-13, 3.13) (push) Has been cancelled
ci-build / build-wheels (x64, macos-13, 3.9) (push) Has been cancelled
ci-build / build-wheels (x64, ubuntu-22.04, 3.10) (push) Has been cancelled
ci-build / build-wheels (x64, ubuntu-22.04, 3.11) (push) Has been cancelled
ci-build / build-wheels (x64, ubuntu-22.04, 3.12) (push) Has been cancelled
ci-build / build-wheels (x64, ubuntu-22.04, 3.13) (push) Has been cancelled
ci-build / build-wheels (x64, ubuntu-22.04, 3.9) (push) Has been cancelled
ci-build / build-wheels (x64, windows-2022, 3.10) (push) Has been cancelled
ci-build / build-wheels (x64, windows-2022, 3.11) (push) Has been cancelled
ci-build / build-wheels (x64, windows-2022, 3.12) (push) Has been cancelled
ci-build / build-wheels (x64, windows-2022, 3.13) (push) Has been cancelled
ci-build / build-wheels (x64, windows-2022, 3.9) (push) Has been cancelled
ci-build / build-wheels (x86, windows-2022, 3.10) (push) Has been cancelled
ci-build / build-wheels (x86, windows-2022, 3.11) (push) Has been cancelled
ci-build / build-wheels (x86, windows-2022, 3.12) (push) Has been cancelled
ci-build / build-wheels (x86, windows-2022, 3.13) (push) Has been cancelled
ci-build / build-wheels (x86, windows-2022, 3.9) (push) Has been cancelled
ci-build / Publish Python distribution to PyPI (push) Has been cancelled
ci-build / Create GitHub Release and upload source (push) Has been cancelled
ci-build / Upload wheels to snapshot-builds on wxpython.org (push) Has been cancelled
Fix bundled wxWidgets build on OpenSUSE
OpenSUSE has defined its libdir to be 'lib64', which is mismatched with
wxWidgets' in-place wx-config, which expects 'lib.'  Work around this by
unsetting the CONFIG_SITE envvar (which enables the OpenSUSE customizations)
when configuring wxWidgets.

Fixes: https://github.com/wxWidgets/Phoenix/issues/558
Fixes: https://github.com/wxWidgets/Phoenix/issues/1067
Fixes: https://github.com/wxWidgets/Phoenix/issues/2422
Fixes: https://github.com/wxWidgets/Phoenix/issues/2532
2025-02-01 19:47:12 -05:00

258 lines
7.8 KiB
Python

import os
import subprocess
import sys
import time
class BuildError(Exception):
def __init__(self, value):
self.value = value
def __repr__(self):
return repr(self.value)
def runInDir(command, dir=None, verbose=True):
if dir:
olddir = os.getcwd()
os.chdir(dir)
commandStr = " ".join(command)
if verbose:
print(commandStr)
result = os.system(commandStr)
if dir:
os.chdir(olddir)
return result
class Builder:
"""
Base class exposing the Builder interface.
"""
def __init__(self, formatName="", commandName="", programDir=None):
"""
formatName = human readable name for project format (should correspond with Bakefile names)
commandName = name of command line program used to invoke builder
programDir = directory program is located in, if not on the path
"""
self.dir = dir
self.name = commandName
self.formatName = formatName
self.programDir = programDir
self.doSetup()
def doSetup(self):
"""
Do anything special needed to configure the environment to build with this builder.
"""
pass
def isAvailable(self):
"""
Run sanity checks before attempting to build with this format
"""
# Make sure the builder program exists
programPath = self.getProgramPath()
if os.path.exists(programPath):
return True
else:
# check the PATH for the program
# TODO: How do we check if we're in Cygwin?
if sys.platform.startswith("win"):
result = os.system(self.name)
if result == 0:
return True
dirs = os.environ["PATH"].split(":")
for dir in dirs:
if os.path.isfile(os.path.join(dir, self.name)):
return True
else:
result = os.system("which %s" % self.name)
if result == 0:
return True
return False
def getProgramPath(self):
if self.programDir:
path = os.path.join(self.programDir, self.name)
if sys.platform.startswith("win"):
path = '"%s"' % path
return path
return self.name
def getProjectFileArg(self, projectFile = None):
result = []
if projectFile:
result.append(projectFile)
return result
def clean(self, dir=None, projectFile=None, options=[]):
"""
dir = the directory containing the project file
projectFile = Some formats need to explicitly specify the project file's name
"""
if self.isAvailable():
args = [self.getProgramPath()]
pfArg = self.getProjectFileArg(projectFile)
if pfArg:
args.extend(pfArg)
args.append("clean")
if options:
args.extend(options)
result = runInDir(args, dir)
return result
return False
def configure(self, dir=None, options=[]):
# if we don't have configure, just report success
return 0
def build(self, dir=None, projectFile=None, targets=None, options=[]):
if self.isAvailable():
args = [self.getProgramPath()]
pfArg = self.getProjectFileArg(projectFile)
if pfArg:
args.extend(pfArg)
# Important Note: if extending args, check it first!
# NoneTypes are not iterable and will crash the clean, build, or install!
# Very very irritating when this happens right at the end.
if options:
args.extend(options)
result = runInDir(args, dir)
return result
return 1
def install(self, dir=None, projectFile=None, options=[]):
if self.isAvailable():
args = [self.getProgramPath()]
pfArg = self.getProjectFileArg(projectFile)
if pfArg:
args.extend(pfArg)
args.append("install")
if options:
args.extend(options)
result = runInDir(args, dir)
return result
return 1
# Concrete subclasses of abstract Builder interface
class GNUMakeBuilder(Builder):
def __init__(self, commandName=None, formatName="GNUMake"):
if commandName is None:
commandName = os.environ.get("MAKE", "make")
Builder.__init__(self, commandName=commandName, formatName=formatName)
class XcodeBuilder(Builder):
def __init__(self, commandName="xcodebuild", formatName="Xcode"):
Builder.__init__(self, commandName=commandName, formatName=formatName)
class AutoconfBuilder(GNUMakeBuilder):
def __init__(self, formatName="autoconf"):
GNUMakeBuilder.__init__(self, formatName=formatName)
def configure(self, dir=None, options=None, env=None):
#olddir = os.getcwd()
#os.chdir(dir)
configdir = dir
if not dir:
configdir = os.getcwd()
configure_cmd = ""
while os.path.exists(configdir):
config_cmd = os.path.join(configdir, "configure")
if not os.path.exists(config_cmd):
parentdir = os.path.abspath(os.path.join(configdir, ".."))
if configdir == parentdir:
break
configdir = parentdir
else:
configure_cmd = config_cmd
break
if not configure_cmd:
sys.stderr.write("Could not find configure script at %r. Have you run autoconf?\n" % dir)
return 1
optionsStr = " ".join(options) if options else ""
command = "%s %s" % (configure_cmd, optionsStr)
print(command)
result = subprocess.run(command, shell=True, env=env)
#os.chdir(olddir)
return result.returncode
class MSVCBuilder(Builder):
def __init__(self, commandName="nmake.exe"):
Builder.__init__(self, commandName=commandName, formatName="msvc")
def isAvailable(self):
PATH = os.environ['PATH'].split(os.path.pathsep)
for p in PATH:
if os.path.exists(os.path.join(p, self.name)):
return True
return False
def getProjectFileArg(self, projectFile = None):
result = []
if projectFile:
result.extend(['-f', projectFile])
return result
class MSVCProjectBuilder(Builder):
def __init__(self):
Builder.__init__(self, commandName="VCExpress.exe", formatName="msvcProject")
for key in ["VS90COMNTOOLS", "VC80COMNTOOLS", "VC71COMNTOOLS"]:
if os.environ.has_key(key):
self.programDir = os.path.join(os.environ[key], "..", "IDE")
if self.programDir is None:
for version in ["9.0", "8", ".NET 2003"]:
msvcDir = "C:\\Program Files\\Microsoft Visual Studio %s\\Common7\\IDE" % version
if os.path.exists(msvcDir):
self.programDir = msvcDir
def isAvailable(self):
if self.programDir:
path = os.path.join(self.programDir, self.name)
if os.path.exists(path):
return True
else:
# I don't have commercial versions of MSVC so I can't test this
name = "devenv.com"
path = os.path.join(self.programDir, name)
if os.path.exists(path):
self.name = "devenv.com"
return True
return False
builders = [GNUMakeBuilder, XcodeBuilder, AutoconfBuilder, MSVCBuilder, MSVCProjectBuilder]
def getAvailableBuilders():
availableBuilders = {}
for symbol in builders:
thisBuilder = symbol()
if thisBuilder.isAvailable():
availableBuilders[thisBuilder.formatName] = symbol
return availableBuilders