Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 1 | import tempfile |
| 2 | import re |
| 3 | import sys |
| 4 | import os |
| 5 | import subprocess |
| 6 | import platform |
| 7 | import argparse |
| 8 | import multiprocessing |
| 9 | import fileinput |
| 10 | import re |
| 11 | |
| 12 | # vs help |
| 13 | win_sdk_default = '10.0.16299.0' |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 14 | win_toolset_default = 'v142' |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 15 | |
| 16 | vs_where_path = os.path.join( |
| 17 | os.environ['ProgramFiles(x86)'], 'Microsoft Visual Studio', 'Installer', 'vswhere.exe' |
| 18 | ) |
| 19 | |
| 20 | host_is_64bit = (False, True)[platform.machine().endswith('64')] |
| 21 | |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 22 | |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 23 | def execute_cmd(cmd, with_shell=False, env_vars={}): |
| 24 | if(bool(env_vars)): |
| 25 | p = subprocess.Popen(cmd, shell=with_shell, |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 26 | stdout=sys.stdout, |
| 27 | env=env_vars) |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 28 | else: |
| 29 | p = subprocess.Popen(cmd, shell=with_shell) |
| 30 | _, _ = p.communicate() |
| 31 | return p.returncode |
| 32 | |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 33 | |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 34 | def getLatestVSVersion(): |
| 35 | args = [ |
| 36 | '-latest', |
| 37 | '-products *', |
| 38 | '-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64', |
| 39 | '-property installationVersion' |
| 40 | ] |
| 41 | cmd = [vs_where_path] + args |
| 42 | output = subprocess.check_output(' '.join(cmd)).decode('utf-8') |
| 43 | if output: |
| 44 | return output.splitlines()[0].split('.')[0] |
| 45 | else: |
| 46 | return |
| 47 | |
| 48 | |
| 49 | def findVSLatestDir(): |
| 50 | args = [ |
| 51 | '-latest', |
| 52 | '-products *', |
| 53 | '-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64', |
| 54 | '-property installationPath' |
| 55 | ] |
| 56 | cmd = [vs_where_path] + args |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 57 | output = subprocess.check_output( |
| 58 | ' '.join(cmd)).decode('utf-8', errors='ignore') |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 59 | if output: |
| 60 | return output.splitlines()[0] |
| 61 | else: |
| 62 | return |
| 63 | |
| 64 | |
| 65 | def findMSBuild(): |
| 66 | filename = 'MSBuild.exe' |
| 67 | for root, _, files in os.walk(findVSLatestDir() + r'\\MSBuild'): |
| 68 | if filename in files: |
| 69 | return os.path.join(root, filename) |
| 70 | |
| 71 | |
| 72 | def getVSEnv(arch='x64', platform='', version=''): |
| 73 | env_cmd = 'set path=%path:"=% && ' + \ |
| 74 | getVSEnvCmd(arch, platform, version) + ' && set' |
| 75 | p = subprocess.Popen(env_cmd, |
| 76 | shell=True, |
| 77 | stdout=subprocess.PIPE) |
| 78 | stdout, _ = p.communicate() |
| 79 | out = stdout.decode('utf-8', errors='ignore').split("\r\n")[5:-1] |
| 80 | return dict(s.split('=', 1) for s in out) |
| 81 | |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 82 | |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 83 | def getVSEnvCmd(arch='x64', platform='', version=''): |
| 84 | vcEnvInit = [findVSLatestDir() + r'\VC\Auxiliary\Build\"vcvarsall.bat'] |
| 85 | if platform != '': |
| 86 | args = [arch, platform, version] |
| 87 | else: |
| 88 | args = [arch, version] |
| 89 | if args: |
| 90 | vcEnvInit.extend(args) |
| 91 | vcEnvInit = 'call \"' + ' '.join(vcEnvInit) |
| 92 | return vcEnvInit |
| 93 | |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 94 | |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 95 | def build_project(msbuild, msbuild_args, proj, env_vars): |
| 96 | args = [] |
| 97 | args.extend(msbuild_args) |
| 98 | args.append(proj) |
| 99 | cmd = [msbuild] |
| 100 | cmd.extend(args) |
| 101 | if (execute_cmd(cmd, True, env_vars)): |
| 102 | print("Build failed when building ", proj) |
| 103 | sys.exit(1) |
| 104 | |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 105 | |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 106 | def replace_vs_prop(filename, prop, val): |
| 107 | p = re.compile(r'(?s)<' + prop + r'\s?.*?>(.*?)<\/' + prop + r'>') |
| 108 | val = r'<' + prop + r'>' + val + r'</' + prop + r'>' |
| 109 | with fileinput.FileInput(filename, inplace=True) as file: |
| 110 | for line in file: |
| 111 | print(re.sub(p, val, line), end='') |
| 112 | |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 113 | |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 114 | def deps(arch, toolset, qtver): |
| 115 | print('Deps Qt Client Release|' + arch) |
| 116 | |
| 117 | # Fetch QRencode |
| 118 | print('Generate QRencode') |
| 119 | apply_cmd = "git apply --reject --ignore-whitespace --whitespace=fix" |
| 120 | qrencode_path = 'qrencode-win32' |
| 121 | if (os.path.isdir(qrencode_path)): |
| 122 | os.system('rmdir qrencode-win32 /s /q') |
| 123 | if (execute_cmd("git clone https://github.com/BlueDragon747/qrencode-win32.git", True)): |
| 124 | print("Git clone failed when cloning from https://github.com/BlueDragon747/qrencode-win32.git") |
| 125 | sys.exit(1) |
| 126 | if(execute_cmd("cd qrencode-win32 && git checkout d6495a2aa74d058d54ae0f1b9e9e545698de66ce && " + apply_cmd + ' ..\\qrencode-win32.patch', True)): |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 127 | print("qrencode-win32 set up error") |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 128 | sys.exit(1) |
| 129 | |
| 130 | print('Building qrcodelib') |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 131 | build(arch, '', '', 'Release-Lib', |
| 132 | '\\qrencode-win32\\qrencode-win32\\vc8\\qrcodelib\\qrcodelib.vcxproj', qtver, False) |
| 133 | |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 134 | |
| 135 | def build(arch, toolset, sdk_version, config_str, project_path_under_current_path, qtver, force_option=True): |
| 136 | configuration_type = 'StaticLibrary' |
| 137 | |
| 138 | qtFolderDir = "msvc2017_64" |
| 139 | qtverSplit = qtver.split('.') |
| 140 | |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 141 | if((int(qtverSplit[0]) >= 6) or ((int(qtverSplit[0]) == 5) and (int(qtverSplit[1]) >= 15))): |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 142 | qtFolderDir = "msvc2019_64" |
| 143 | |
| 144 | if (config_str == 'Release'): |
| 145 | print('Generating project using qmake ' + config_str + '|' + arch) |
| 146 | if(execute_cmd("C:\\Qt\\" + qtver + "\\" + qtFolderDir + "\\bin\\qmake.exe " + "-tp vc jami-qt.pro -o jami-qt.vcxproj")): |
| 147 | print("Qmake vcxproj file generate error") |
| 148 | sys.exit(1) |
| 149 | configuration_type = 'Application' |
| 150 | elif (config_str == 'Beta'): |
| 151 | print('Generating project using qmake ' + config_str + '|' + arch) |
| 152 | if(execute_cmd("C:\\Qt\\" + qtver + "\\" + qtFolderDir + "\\bin\\qmake.exe " + "-tp vc jami-qt.pro -o jami-qt.vcxproj CONFIG+=Beta")): |
| 153 | print("Beat: Qmake vcxproj file generate error") |
| 154 | sys.exit(1) |
| 155 | config_str = 'Release' |
| 156 | configuration_type = 'Application' |
| 157 | elif (config_str == 'ReleaseCompile'): |
| 158 | print('Generating project using qmake ' + config_str + '|' + arch) |
| 159 | if(execute_cmd("C:\\Qt\\" + qtver + "\\" + qtFolderDir + "\\bin\\qmake.exe " + "-tp vc jami-qt.pro -o jami-qt.vcxproj CONFIG+=ReleaseCompile")): |
| 160 | print("ReleaseCompile: Qmake vcxproj file generate error") |
| 161 | sys.exit(1) |
| 162 | config_str = 'Release' |
| 163 | |
| 164 | # Note: If project is configured to Beta or ReleaseCompile, the configuration name is still release, |
| 165 | # but will be outputted into x64/Beta folder (for Beta Only) |
| 166 | |
| 167 | print('Building projects in ' + config_str + '|' + arch) |
| 168 | vs_env_vars = {} |
| 169 | vs_env_vars.update(getVSEnv()) |
| 170 | this_dir = os.path.dirname(os.path.realpath(__file__)) |
| 171 | qt_client_proj_path = this_dir + project_path_under_current_path |
| 172 | |
| 173 | msbuild = findMSBuild() |
| 174 | if not os.path.isfile(msbuild): |
| 175 | raise IOError('msbuild.exe not found. path=' + msbuild) |
| 176 | msbuild_args = [ |
| 177 | '/nologo', |
| 178 | '/verbosity:minimal', |
| 179 | '/maxcpucount:' + str(multiprocessing.cpu_count()), |
| 180 | '/p:Platform=' + arch, |
| 181 | '/p:Configuration=' + config_str, |
| 182 | '/p:ConfigurationType=' + configuration_type, |
| 183 | '/p:useenv=true'] |
| 184 | if (toolset != ''): |
| 185 | msbuild_args.append('/p:PlatformToolset=' + toolset) |
| 186 | if (force_option): |
| 187 | # force toolset |
| 188 | replace_vs_prop(qt_client_proj_path, |
| 189 | 'PlatformToolset', |
| 190 | toolset) |
| 191 | # force unicode |
| 192 | replace_vs_prop(qt_client_proj_path, |
| 193 | 'CharacterSet', |
| 194 | 'Unicode') |
| 195 | # force sdk_version |
| 196 | replace_vs_prop(qt_client_proj_path, |
| 197 | 'WindowsTargetPlatformVersion', |
| 198 | sdk_version) |
| 199 | |
| 200 | build_project(msbuild, msbuild_args, qt_client_proj_path, vs_env_vars) |
| 201 | |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 202 | |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 203 | def parse_args(): |
| 204 | ap = argparse.ArgumentParser(description="Windows Jami-lrc build tool") |
| 205 | ap.add_argument( |
| 206 | '-b', '--build', action='store_true', |
| 207 | help='Build Qt Client') |
| 208 | ap.add_argument( |
| 209 | '-a', '--arch', default='x64', |
| 210 | help='Sets the build architecture') |
| 211 | ap.add_argument( |
| 212 | '-d', '--deps', action='store_true', |
| 213 | help='Build Deps for Qt Client') |
| 214 | ap.add_argument( |
| 215 | '-bt', '--beta', action='store_true', |
| 216 | help='Build Qt Client in Beta Config') |
| 217 | ap.add_argument( |
| 218 | '-c', '--releasecompile', action='store_true', |
| 219 | help='Build Qt Client in ReleaseCompile Config') |
| 220 | ap.add_argument( |
| 221 | '-s', '--sdk', default=win_sdk_default, type=str, |
| 222 | help='Use specified windows sdk version') |
| 223 | ap.add_argument( |
| 224 | '-t', '--toolset', default=win_toolset_default, type=str, |
| 225 | help='Use specified platform toolset version') |
| 226 | ap.add_argument( |
| 227 | '-q', '--qtver', default='5.9.4', |
| 228 | help='Sets the version of Qmake') |
| 229 | |
| 230 | parsed_args = ap.parse_args() |
| 231 | |
| 232 | return parsed_args |
| 233 | |
| 234 | |
| 235 | def main(): |
| 236 | if not host_is_64bit: |
| 237 | print('These scripts will only run on a 64-bit Windows system for now!') |
| 238 | sys.exit(1) |
| 239 | |
| 240 | if int(getLatestVSVersion()) < 15: |
| 241 | print('These scripts require at least Visual Studio v15 2017!') |
| 242 | sys.exit(1) |
| 243 | |
| 244 | parsed_args = parse_args() |
| 245 | |
| 246 | if parsed_args.deps: |
| 247 | deps(parsed_args.arch, parsed_args.toolset, parsed_args.qtver) |
| 248 | |
| 249 | if parsed_args.build: |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 250 | build(parsed_args.arch, parsed_args.toolset, parsed_args.sdk, |
| 251 | 'Release', '\\jami-qt.vcxproj', parsed_args.qtver) |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 252 | |
| 253 | if parsed_args.beta: |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 254 | build(parsed_args.arch, parsed_args.toolset, parsed_args.sdk, |
| 255 | 'Beta', '\\jami-qt.vcxproj', parsed_args.qtver) |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 256 | |
| 257 | if parsed_args.releasecompile: |
Andreas Traczyk | 1b25907 | 2020-08-10 10:22:07 -0400 | [diff] [blame] | 258 | build(parsed_args.arch, parsed_args.toolset, parsed_args.sdk, |
| 259 | 'ReleaseCompile', '\\jami-qt.vcxproj', parsed_args.qtver) |
| 260 | |
Sébastien Blin | 1f91576 | 2020-08-03 13:27:42 -0400 | [diff] [blame] | 261 | |
| 262 | if __name__ == '__main__': |
| 263 | main() |