#!python3
# Copyright 2007-2017 Gemr. All Rights Reserved.
# Licensed to MIT see LICENSE.txt
import distutils
import os
import pathlib
import warnings
import gdeps as GDeps
__author__ = 'Suryavarman (http://sourceforge.net/u/suryavarman/profile/)'
[docs]class Bakefile125(GDeps.Make):
def __init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers=[], inIdes=[], inExePath="", inTypeName=""):
"""
Implementation of Bakefile project. See http://bakefile.org/
Version 1.2.5 :
https://github.com/vslavik/bakefile/releases/tag/v1.2.5.1
:param inConfigFile:
:param inSectionName: Can be empty for the maker include in the
folder directory.
:param inFolderDir: The working dir.
example:
os.path.normpath(project.m_FolderDir + r'\\include\\wx\\msw\\')
:param inSolutionName: makefile without the wildcard like «.gcc» and «.vc»
:param inArgs:
:param inTargetsArgs:
:param inCompilers:
:param inIdes:
:param inExePath:
:param inTypeName:
"""
GDeps.Make.__init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers, inIdes, inExePath, Bakefile125.getTypeName())
assert False, 'GDeps.Bakefile125 is not yet ready.'
def getTypeName():
return "Bakefile125"
def make(self):
pass
[docs]class Bakefile029(GDeps.Make):
def __init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers=[], inIdes=[], inExePath="", inTypeName=""):
"""
Implementation of Bakefile project. See http://bakefile.org/
Version 0.2.9 :
https://github.com/vslavik/bakefile/releases/tag/v0.2.9
:param inConfigFile:
:param inSectionName: Can be empty for the maker include in the
folder directory.
:param inFolderDir: The working dir.
**Example**
c:\\working\\libs\\boost_1-58
:param inSolutionName: makefile without the wildcard like «.gcc» and «.vc»
:param inArgs: OUTPUT_FOLDERS Represent a list of folders where the generated files are located.
You can use GDeps.Keys.ms_BakeFile029OutputFolders to retrieve the value : 'OUTPUT_FOLDERS'
**Example**
'OUTPUT_FOLDERS' : aFolderDir + r'\\build\\msw;' + aFolderDir + r'\\lib;'
process for each targets
1) copy the folder name into the parent folder with a temporary name
2) build the solution
3) rename FOLDER_NAME
4) rename the copy to the original name FOLDER_NAME
USE_SAME_OUTPUT_FOLDER is a boolean. If true we use the same folders. We avoid the
OUTPUT_FOLDERS.
process for each targets
2) build the solution
:param inTargetsArgs:
:param inCompilers:
:param inIdes:
:param inExePath:
:param inTypeName:
"""
GDeps.Make.__init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers, inIdes, inExePath, Bakefile029.getTypeName())
@staticmethod
[docs] def getTypeName():
return "Bakefile029"
[docs] def make(self):
aMacroReporting = GDeps.Make.make(self)
# aMakeLogFilePath = self.m_FolderDir + "\\bakefile029.log"
for aCompiler in self.m_Compilers:
if self.isCompatible(aCompiler):
# the compiler generate the log file
self.m_ErrorRegexp = aCompiler.m_ErrorRegexp
self.m_WarningRegexp = aCompiler.m_WarningRegexp
self.m_SplitRegexp = aCompiler.m_SplitRegexp
aCompiler.setvars()
assert self.m_TargetsArgs, self.m_TypeName + " ERROR : There are no targets"
for aTargetArgs in self.m_TargetsArgs:
aBuildType = self.getBuildType(aTargetArgs.m_TargetType)
aCurrentDir = os.getcwd()
os.chdir(self.m_FolderDir)
aProjectWildcard = self.getProjectWildcard(aCompiler)
if aProjectWildcard:
def pathExist(inPath):
return os.path.exists(inPath) and os.path.isdir(inPath)
aSolutionPath = '"' + os.path.normpath(self.m_FolderDir + '/' + self.m_SolutionName + aProjectWildcard) + '"'
aMakePath = '"' + os.path.normpath(aCompiler.getMakeDir()) + '"'
aOutputFolders = self.getOutputFolders()
aUseSameOutputFolder = self.useOuputFolders()
if not aOutputFolders:
aPath = pathlib.Path(self.m_FolderDir)
aOutputFolders.append([aPath.name, self.m_FolderDir[:-len(aPath.name)]])
aBuildId = self.m_TypeName + '_' + aCompiler.m_TypeName + '_' + aBuildType
aLogFilePath = os.path.normpath(GDeps.getParentDir(self.m_FolderDir) + r'\\' + aBuildId + '.log')
GDeps.clearLogFile(aLogFilePath)
if aUseSameOutputFolder:
for aItem in aOutputFolders:
aBuildParentDir = aItem[1]
aBuildFolderName = aItem[0]
aBuildParentDir = os.path.abspath(aBuildParentDir)
aFolderPath = os.path.normpath(aBuildParentDir + r'\\' + aBuildFolderName)
aBackupFolderPath = os.path.normpath(aBuildParentDir + r'\\' + aBuildFolderName + '_GDeps_tmp')
if aBuildFolderName and aBuildParentDir:
if pathExist(aFolderPath):
"""
Process for each targets:
1) copy the folder name into the parent folder with a temporary name
2) build the solution
3) rename FOLDER_NAME
4) copy the backup with the original name FOLDER_NAME
"""
# 1) copy the folder name into the parent folder with a temporary name
assert aBackupFolderPath != aFolderPath, "The backup and the original folders have the same name."
if pathExist(aBackupFolderPath):
warnings.warn('The folder ' + aBackupFolderPath + ' already exist. To prevent an issue we will try to remove it.')
GDeps.rmdir(aBackupFolderPath, aLogFilePath, True)
assert not pathExist(aBackupFolderPath), 'The folder ' + aBackupFolderPath + ' cannot be delete.'
GDeps.copy(aFolderPath, aBackupFolderPath, aLogFilePath, True)
else:
assert False, 'The folder ' + aFolderPath + " doesn't exist. Please be sure to have " + \
GDeps.Keys.ms_BakeFile029UseSameOutputFolder + ' with a correct values.' \
' The current value is ' + aBuildFolderName + ' and ' + \
aBuildParentDir
# 2) build the solution
if self.isMingw(aCompiler):
self.buildMingw(aMakePath, aSolutionPath, aBuildType, aCompiler, aTargetArgs, aLogFilePath)
elif self.isDigitalMars(aCompiler):
self.buildDigitalMars(aMakePath, aSolutionPath, aBuildType, aCompiler, aTargetArgs, aLogFilePath)
elif self.isVC(aCompiler):
self.buildVisualCPP(aMakePath, aSolutionPath, aBuildType, aCompiler, aTargetArgs, aLogFilePath)
if aUseSameOutputFolder:
for aItem in aOutputFolders:
aBuildParentDir = aItem[1]
aBuildFolderName = aItem[0]
aBuildParentDir = os.path.abspath(aBuildParentDir)
aFolderPath = os.path.normpath(aBuildParentDir + r'\\' + aBuildFolderName)
aBackupFolderPath = os.path.normpath(aBuildParentDir + r'\\' + aBuildFolderName + '_GDeps_tmp')
# 3) rename FOLDER_NAME
if aBuildFolderName and aBuildParentDir and pathExist(aFolderPath):
aRenameName = aBuildFolderName + '_GDeps_build_' + aBuildId
aRenamePath = os.path.normpath(aBuildParentDir + r'\\' + aRenameName)
if pathExist(aRenamePath):
GDeps.rmdir(aRenamePath, aLogFilePath)
GDeps.copy(aFolderPath, aRenamePath, aLogFilePath, True)
GDeps.rmdir(aFolderPath, aLogFilePath, True)
# 4) copy the backup with the original name FOLDER_NAME
if aBuildFolderName and aBuildParentDir:
if pathExist(aBackupFolderPath):
if pathExist(aFolderPath):
warnings.warn('The folder ' + aFolderPath + ' already exist, it has to be rename before that step. We will try to remove it.')
GDeps.rmdir(aFolderPath, aLogFilePath)
GDeps.copy(aBackupFolderPath, aFolderPath, aLogFilePath, True)
else:
assert False, 'The folder ' + aBackupFolderPath + "doesn't exist"
aMacroReporting.append(aCompiler, aBuildId, aLogFilePath, False)
aMacroReporting.append(GDeps.call_Report(), aBuildId, aLogFilePath, False)
aMacroReporting.append(GDeps.copy_Report(), aBuildId, aLogFilePath, False)
aMacroReporting.append(GDeps.call_Report(), aBuildId, aLogFilePath, False)
os.chdir(aCurrentDir)
else:
warnings.warn('The compiler ' + aCompiler.m_TypeName + ' is not compatible with ' + self.m_TypeName)
return aMacroReporting
[docs] def useOuputFolders(self):
return (True if self.m_Args[GDeps.Keys.ms_BakeFile029UseSameOutputFolder] == 'True' else False) if GDeps.Keys.ms_BakeFile029UseSameOutputFolder in self.m_Args else False
# return distutils.util.strtobool(self.m_Args[GDeps.Keys.ms_BakeFile029UseSameOutputFolder]) if GDeps.Keys.ms_BakeFile029UseSameOutputFolder in self.m_Args else False
[docs] def getOutputFolders(self):
"""
If OUTPUT_FOLDERS is define. This function return a list of folders where the generated files are located.
:return: a list of pair : first = parent folder, second = folder name
:rtype: array of [str, str]
"""
aSeparator = ';'
aStr = self.m_Args[GDeps.Keys.ms_BakeFile029OutputFolders] if GDeps.Keys.ms_BakeFile029OutputFolders in self.m_Args else ''
aList = aStr.split(aSeparator)
if aStr and aStr[-1] == aSeparator and aList[-1] == '':
aList.pop()
aResult = []
if aStr:
for aItem in aList:
aPath = pathlib.Path(aItem)
aName = aPath.name
aParentDir = aItem[:-len(aName)]
aResult.append([aName, aParentDir])
return aResult
[docs] def cleanArgs(self, inArgs):
"""
The args has to begin with a space
.. todo:: has to be remove and use getParams
"""
aArgs = inArgs
if aArgs and aArgs[0] != ' ':
aArgs = ' ' + aArgs
return aArgs
[docs] def buildMingw(self, inMakePath, inSolutionPath, inBuildType, inCompiler, inTarget, inLogFilePath):
aArgs = self.getParams(inTarget, inCompiler)
print(' The arguments for the compilation will be : ' + aArgs)
GDeps.callWithLogFile(inMakePath + ' -f ' + inSolutionPath + self.cleanArgs(aArgs) + ' BUILD=' + inBuildType + ' clean', inLogFilePath)
GDeps.callWithLogFile(inMakePath + ' -f ' + inSolutionPath + self.cleanArgs(aArgs) + ' BUILD=' + inBuildType, inLogFilePath)
[docs] def buildDigitalMars(self, inMakePath, inSolutionPath, inBuildType, inCompiler, inTarget, inLogFilePath):
aBatFilePath = os.path.normpath(self.m_FolderDir + r'\\Gdeps_' + inCompiler.m_TypeName + '_bakefile.bat')
if os.path.exists(aBatFilePath):
if not os.path.isfile(aBatFilePath):
warnings.warn('The path ' + aBatFilePath + 'already exist and is a directory')
GDeps.rmdir(aBatFilePath, inLogFilePath)
with open(aBatFilePath, 'w') as aBat:
aBat.write(inCompiler.getUpdateEnvarBatch())
aBat.write(os.linesep)
aArgs = self.getParams(inTarget, inCompiler, ' ', '')
# aCompilerArgs = inTarget.getCompilerArgs(inCompiler)
# aArgs = inArgs
# for aKey, aValue in aCompilerArgs.items():
# aArgs += ' ' + aKey + aValue
aBat.write('CALL ' + inMakePath + ' -f ' + inSolutionPath + self.cleanArgs(aArgs) + ' BUILD=' + inBuildType + ' clean')
aBat.write(os.linesep)
aBat.write('CALL ' + inMakePath + ' -f ' + inSolutionPath + self.cleanArgs(aArgs) + ' BUILD=' + inBuildType)
GDeps.callWithLogFile(aBatFilePath, inLogFilePath)
[docs] def buildVisualCPP(self, inMakePath, inSolutionPath, inBuildType, inCompiler, inTarget, inLogFilePath):
# to by pass nMake issues with the environment variables
aBatFilePath = os.path.normpath(self.m_FolderDir + r'\\Gdeps_' + inCompiler.m_TypeName + '_bakefile.bat')
if os.path.exists(aBatFilePath):
if not os.path.isfile(aBatFilePath):
warnings.warn('The path ' + aBatFilePath + 'already exist and is a directory')
GDeps.rmdir(aBatFilePath, inLogFilePath)
with open(aBatFilePath, 'w') as aBat:
if inCompiler.m_TypeName == GDeps.VC90_32.getTypeName():
aBat.write('CALL "' + inCompiler.getvarsScriptPath() + '" x86')
else:
aBat.write('CALL "' + inCompiler.getvarsScriptPath())
aBat.write(os.linesep)
aArgs = self.getParams(inTarget, inCompiler)
aBat.write('CALL ' + inMakePath + ' -f ' + inSolutionPath + self.cleanArgs(aArgs) + ' BUILD=' + inBuildType + ' clean')
aBat.write(os.linesep)
aBat.write('CALL ' + inMakePath + ' -f ' + inSolutionPath + self.cleanArgs(aArgs) + ' BUILD=' + inBuildType)
# http://www.robvanderwoude.com/battech_redirection.php 2>&1 to redirect all the output.
GDeps.callWithLogFile(aBatFilePath, inLogFilePath)
[docs] def getBuildType(self, inTargetType):
if inTargetType == GDeps.Target.release_static:
return "release"
if inTargetType == GDeps.Target.release_dynamic:
return "release"
if inTargetType == GDeps.Target.debug_static:
return "debug"
if inTargetType == GDeps.Target.debug_dynamic:
return "debug"
[docs] def getParams(self, inTargetArgs, inCompiler, inSeparator=' ', inEqualSign='='):
""" :return: the arguments to call the maker
:rtype: str
Example with wxWidgets:
>>> 'SHARED=1 MONOLITHIC=1 UNICODE=1'
"""
aArgs = {}
aKeyHasToBeRemove = [GDeps.Keys.ms_BakeFile029OutputFolders, GDeps.Keys.ms_BakeFile029UseSameOutputFolder]
for aKey, aValue in self.m_Args.items():
if aKey not in aKeyHasToBeRemove:
aArgs[aKey] = aValue
aParams = GDeps.getAllParamsString(aArgs, inTargetArgs, inCompiler, inSeparator, inEqualSign, True,
inMultipleValueSeparator=inSeparator,
inMultipleValueBegin='"',
inMultipleValueEnd='"')
print(aParams)
return aParams + ((' ' if aParams and aParams[-1] != ' ' else '') + 'TARGET_CPU=X64' if inCompiler.m_AdressModel == GDeps.AdressModel.x64 else '')
[docs] def isVC(self, inCompiler):
"""
:param inCompiler: A compiler instance to retrieve the compiler type.
:type inCompiler: GDeps.Compiler
:return: True if microsoft visual c++ compiler
:rtype: bool
"""
return inCompiler.m_TypeName == GDeps.VC140_32.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC140_64.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC120_32.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC120_64.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC110_32.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC110_64.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC100_32.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC100_64.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC90_32.getTypeName()
[docs] def isMingw(self, inCompiler):
return inCompiler.m_TypeName == GDeps.Mingw_32.getTypeName() or\
inCompiler.m_TypeName == GDeps.Mingw_64.getTypeName()
[docs] def isDigitalMars(self, inCompiler):
return inCompiler.m_TypeName == GDeps.Dm_32.getTypeName()
[docs] def getProjectWildcard(self, inCompiler):
""" :return : The wildcard of associate solution. """
if self.isMingw(inCompiler):
return '.gcc'
if self.isVC(inCompiler):
return '.vc'
if self.isDigitalMars(inCompiler):
return '.dmc'
warnings.warn('There are no associate wildcard for this compiler : ' + inCompiler.m_TypeName)
return ''
[docs] def isCompatible(self, inCompiler):
return inCompiler.m_TypeName == GDeps.VC120_32.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC120_64.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC110_32.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC110_64.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC100_32.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC100_64.getTypeName() or \
inCompiler.m_TypeName == GDeps.VC90_32.getTypeName() or \
inCompiler.m_TypeName == GDeps.Mingw_32.getTypeName() or \
inCompiler.m_TypeName == GDeps.Mingw_64.getTypeName() or \
inCompiler.m_TypeName == GDeps.Dm_32.getTypeName()