Skip to content
Snippets Groups Projects
Select Git revision
  • df45f35d6f29c2ebe6ef8a10c418a4a2eb739de7
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/201911
  • release/releaseWindowsTestOne
  • release/releaseTest
  • release/releaseWindowsTest
  • release/windowsReleaseTest
  • release/201910
  • release/qt/201910
  • release/windows-test/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • 1.0.0
  • 0.3.0
  • 0.2.1
  • 0.2.0
  • 0.1.0
26 results

make-lrc.py

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    make-lrc.py 8.77 KiB
    import tempfile
    import re
    import sys
    import os
    import subprocess
    import platform
    import argparse
    import multiprocessing
    import shutil
    import fileinput
    import re
    from enum import Enum
    
    # vs help
    win_sdk_default = '10.0.16299.0'
    win_toolset_default = '142'
    qt_version_default = '5.15.0'
    
    vs_where_path = os.path.join(
        os.environ['ProgramFiles(x86)'], 'Microsoft Visual Studio', 'Installer', 'vswhere.exe'
    )
    
    host_is_64bit = (False, True)[platform.machine().endswith('64')]
    this_dir = os.path.dirname(os.path.realpath(__file__))
    build_dir = this_dir + '\\build'
    
    class QtVerison(Enum):
        Major = 0
        Minor = 1
        Micro = 2
    
    def getLatestVSVersion():
        args = [
            '-latest',
            '-products *',
            '-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
            '-property installationVersion'
        ]
        cmd = [vs_where_path] + args
        output = subprocess.check_output(' '.join(cmd)).decode('utf-8')
        if output:
            return output.splitlines()[0].split('.')[0]
        else:
            return
    
    
    def findVSLatestDir():
        args = [
            '-latest',
            '-products *',
            '-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
            '-property installationPath'
        ]
        cmd = [vs_where_path] + args
        output = subprocess.check_output(' '.join(cmd)).decode('utf-8')
        if output:
            return output.splitlines()[0]
        else:
            return
    
    
    def findMSBuild():
        filename = 'MSBuild.exe'
        for root, _, files in os.walk(findVSLatestDir() + r'\\MSBuild'):
            if filename in files:
                return os.path.join(root, filename)
    
    
    def getVSEnv(arch='x64', platform='', version=''):
        env_cmd = 'set path=%path:"=% && ' + \
            getVSEnvCmd(arch, platform, version) + ' && set'
        p = subprocess.Popen(env_cmd,
                             shell=True,
                             stdout=subprocess.PIPE)
        stdout, _ = p.communicate()
        out = stdout.decode('utf-8').split("\r\n")[5:-1]
        return dict(s.split('=', 1) for s in out)
    
    
    def getCMakeGenerator(vs_version):
        if vs_version == '15':
            return 'Visual Studio 15 2017 Win64'
        else:
            return 'Visual Studio ' + vs_version + ' 2019'
    
    
    def getQtVersionNumber(qt_version, version_type):
        version_list = qt_version.split('.')
        return version_list[version_type.value]
    
    
    def getVSEnvCmd(arch='x64', platform='', version=''):
        vcEnvInit = [findVSLatestDir() + r'\VC\Auxiliary\Build\"vcvarsall.bat']
        if platform != '':
            args = [arch, platform, version]
        else:
            args = [arch, version]
        if args:
            vcEnvInit.extend(args)
        vcEnvInit = 'call \"' + ' '.join(vcEnvInit)
        return vcEnvInit
    
    
    def build_project(msbuild, msbuild_args, proj, env_vars):
        args = []
        args.extend(msbuild_args)
        args.append(proj)
        cmd = [msbuild]
        cmd.extend(args)
        p = subprocess.Popen(cmd, shell=True,
                             stdout=sys.stdout,
                             env=env_vars)
        _, _ = p.communicate()
        if p.returncode:
            print("Build failed when building ", proj)
            sys.exit(1)
    
    
    def purge_dir(build_dir):
        if os.path.exists(build_dir):
            try:
                shutil.rmtree(build_dir)
            except Exception as e:
                print('Error while removing directory: ' + str(e))
                sys.exit(1)
    
    
    def generate(force, qtver, sdk, toolset, arch):
        # check build dir
        if os.path.exists(build_dir):
            if not force:
                print("Skipping generate, build directory already exists!")
                return
            purge_dir(build_dir)
        print('Generating lrc with Qt-' + qtver + ' ' +
              arch + ' ' + sdk + ' ' + toolset)
        daemon_dir = os.path.dirname(this_dir) + '\\daemon'
        daemon_bin = daemon_dir + '\\build\\x64\\ReleaseLib_win32\\bin\\dring.lib'
        if not os.path.exists(daemon_bin):
            print("Daemon library not found!")
            sys.exit(1)
        # we just assume Qt is installed in the default folder
        qt_dir = 'C:\\Qt\\' + qtver
        cmake_gen = getCMakeGenerator(getLatestVSVersion())
        qt_minor_version = getQtVersionNumber(qtver, QtVerison.Minor)
    
        qt_cmake_dir = qt_dir + (
            '\\msvc2017_64' if int(qt_minor_version) <= 14 else '\\msvc2019_64') + '\\lib\\cmake\\'
        cmake_options = [
            '-DQt5_DIR=' + qt_cmake_dir + 'Qt5',
            '-DQt5Core_DIR=' + qt_cmake_dir + 'Qt5Core',
            '-DQt5Sql_DIR=' + qt_cmake_dir + 'Qt5Sql',
            '-DQt5LinguistTools_DIR=' + qt_cmake_dir + 'Qt5LinguistTools',
            '-DQt5Concurrent_DIR=' + qt_cmake_dir + 'Qt5Concurrent',
            '-DQt5Gui_DIR=' + qt_cmake_dir + 'Qt5Gui',
            '-Dring_BIN=' + daemon_bin,
            '-DRING_INCLUDE_DIR=' + daemon_dir + '\\src\\dring',
            '-DCMAKE_SYSTEM_VERSION=' + sdk
        ]
        if not os.path.exists(build_dir):
            os.makedirs(build_dir)
        os.chdir(build_dir)
        cmd = ['cmake', '..', '-G', cmake_gen]
        cmd.extend(cmake_options)
        p = subprocess.Popen(cmd, shell=True,
                             stdout=subprocess.PIPE)
        _, _ = p.communicate()
        if p.returncode:
            print("Couldn't generate!")
            sys.exit(1)
    
        qtwrapper_proj_path = build_dir + '\\src\\qtwrapper\\qtwrapper.vcxproj'
        lrc_proj_path = build_dir + '\\ringclient_static.vcxproj'
    
        # force toolset
        replace_vs_prop(qtwrapper_proj_path,
                        'PlatformToolset',
                        toolset)
        replace_vs_prop(lrc_proj_path,
                        'PlatformToolset',
                        toolset)
        # force unicode
        replace_vs_prop(qtwrapper_proj_path,
                        'CharacterSet',
                        'Unicode')
        replace_vs_prop(lrc_proj_path,
                        'CharacterSet',
                        'Unicode')
        os.chdir(this_dir)
    
    
    def replace_vs_prop(filename, prop, val):
        p = re.compile(r'(?s)<' + prop + r'\s?.*?>(.*?)<\/' + prop + r'>')
        val = r'<' + prop + r'>' + val + r'</' + prop + r'>'
        with fileinput.FileInput(filename, inplace=True) as file:
            for line in file:
                print(re.sub(p, val, line), end='')
    
    
    def build(arch, toolset):
        print('Building lrc Release|' + arch)
        vs_env_vars = {}
        vs_env_vars.update(getVSEnv())
        qtwrapper_proj_path = build_dir + '\\src\\qtwrapper\\qtwrapper.vcxproj'
        lrc_proj_path = build_dir + '\\ringclient_static.vcxproj'
        msbuild = findMSBuild()
        if not os.path.isfile(msbuild):
            raise IOError('msbuild.exe not found. path=' + msbuild)
        msbuild_args = [
            '/nologo',
            '/verbosity:minimal',
            '/maxcpucount:' + str(multiprocessing.cpu_count()),
            '/p:Platform=' + arch,
            '/p:Configuration=' + 'Release',
            '/p:useenv=true',
            '/p:PlatformToolset=' + toolset]
        build_project(msbuild, msbuild_args, qtwrapper_proj_path, vs_env_vars)
        build_project(msbuild, msbuild_args, lrc_proj_path, vs_env_vars)
    
    
    def parse_args():
        ap = argparse.ArgumentParser(description="Windows Jami-lrc build tool")
        ap.add_argument(
            '-b', '--build', action='store_true',
            help='Build lrc')
        ap.add_argument(
            '-f', '--force', action='store_true',
            help='Force action')
        ap.add_argument(
            '-p', '--purge', action='store_true',
            help='Purges the build directory')
        ap.add_argument(
            '-q', '--qtver', default=qt_version_default,
            help='Sets the Qt version to build with')
        ap.add_argument(
            '-g', '--gen', action='store_true',
            help='Generates vs project files for lrc using CMake')
        ap.add_argument(
            '-a', '--arch', default='x64',
            help='Sets the build architecture')
        ap.add_argument(
            '-s', '--sdk', default=win_sdk_default, type=str,
            help='Use specified windows sdk version')
        ap.add_argument(
            '-t', '--toolset', default=win_toolset_default, type=str,
            help='Use specified platform toolset version')
    
        parsed_args = ap.parse_args()
    
        if parsed_args.toolset:
            if parsed_args.toolset[0] != 'v':
                parsed_args.toolset = 'v' + parsed_args.toolset
    
        return parsed_args
    
    
    def main():
        if not host_is_64bit:
            print('These scripts will only run on a 64-bit Windows system for now!')
            sys.exit(1)
    
        if int(getLatestVSVersion()) < 15:
            print('These scripts require at least Visual Studio v15 2017!')
            sys.exit(1)
    
        parsed_args = parse_args()
    
        if parsed_args.purge:
            print('Purging build dir')
            purge_dir(build_dir)
    
        if parsed_args.gen:
            generate(parsed_args.force, parsed_args.qtver,
                     parsed_args.sdk, parsed_args.toolset, parsed_args.arch)
    
        if parsed_args.build:
            build(parsed_args.arch, parsed_args.toolset)
    
    
    if __name__ == '__main__':
        main()