Source code for gdeps.bakefile

#!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()