Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
build-plugin.py 6.18 KiB
#!/usr/bin/env python3
#
# Copyright (C) 2020-2021 Savoir-faire Linux Inc.
#
# Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Creates packaging targets for a distribution and architecture.
# This helps reduce the length of the top Makefile.
#

# This script must unify the Plugins build for
# every project and Operational System

import os
import sys
import json
import platform
import argparse
import subprocess
import multiprocessing

IOS_DISTRIBUTION_NAME = "ios"
OSX_DISTRIBUTION_NAME = "osx"
ANDROID_DISTRIBUTION_NAME = "android"
WIN32_DISTRIBUTION_NAME = "win32"
UBUNTU_DISTRIBUTION_NAME = "ubuntu"

# vs vars
win_sdk_default = '10.0.16299.0'
win_toolset_default = 'v142'


def parse():
    parser = argparse.ArgumentParser(description='Builds Plugins projects')
    parser.add_argument('--projects', type=str,
                        help='Select plugins to be build.')
    parser.add_argument('--distribution')
    parser.add_argument('--processor', type=str, default="GPU",
                        help='Runtime plugin CPU/GPU setting.')
    parser.add_argument('--buildOptions', default='', type=str,
                        help="Type all build optionsto pass to package.json 'defines' property.\nThis argument consider that you're using cmake.")

    dist = choose_distribution()

    if dist == WIN32_DISTRIBUTION_NAME:
        parser.add_argument('--toolset', default=win_toolset_default, type=str,
                            help='Windows use only, specify Visual Studio toolset version')
        parser.add_argument('--sdk', default=win_sdk_default, type=str,
                            help='Windows use only, specify Windows SDK version')

    args = parser.parse_args()
    args.projects = args.projects.split(',')
    args.processor = args.processor.split(',')

    if (args.distribution is not None):
        args.distribution = args.distribution.lower()
    else:
        args.distribution = dist

    if (len(args.processor) == 1):
        args.processor *= len(args.projects)

    validate_args(args)

    if dist != WIN32_DISTRIBUTION_NAME:
        args.toolset = ''
        args.sdk = ''
    return args


def validate_args(parsed_args):
    """Validate the args values, exit if error is found"""

    # Filter unsupported distributions.
    supported_distros = [
        ANDROID_DISTRIBUTION_NAME, UBUNTU_DISTRIBUTION_NAME,
        WIN32_DISTRIBUTION_NAME, OSX_DISTRIBUTION_NAME
    ]

    if parsed_args.distribution not in supported_distros:
        print('Distribution \'{0}\' not supported.\nChoose one of: {1}'.format(
            parsed_args.distribution, ', '.join(supported_distros)
        ))
        sys.exit(1)

    if (len(parsed_args.processor) != len(parsed_args.projects)):
        sys.exit('Processor must be single or the same size as projects.')

    for processor in parsed_args.processor:
        if (processor not in ['GPU', 'CPU']):
            sys.exit('Processor can only be GPU or CPU.')

    if (parsed_args.buildOptions):
        parsed_args.buildOptions = parsed_args.buildOptions.split(',')


def choose_distribution():
    system = platform.system().lower()

    if system == "linux" or system == "linux2":
        if os.path.isfile("/etc/arch-release"):
            return "arch"
        with open("/etc/os-release") as f:
            for line in f:
                k, v = line.split("=")
                if k.strip() == 'ID':
                    return v.strip().replace('"', '').split(' ')[0]
    elif system == "darwin":
        return OSX_DISTRIBUTION_NAME
    elif system == "windows":
        return WIN32_DISTRIBUTION_NAME

    return 'Unknown'


def buildPlugin(pluginPath, processor, distribution, toolset='', sdk='', buildOptions=''):
    if distribution == WIN32_DISTRIBUTION_NAME:
        if (buildOptions):
            with open(f"{pluginPath}/package.json") as f:
                defaultPackage = json.load(f)
                package = defaultPackage.copy()
                package['defines'] = []
                for option in buildOptions:
                    package['defines'].append(option)
                f.close()
            with open(f"{pluginPath}/package.json", 'w') as f:
                json.dump(package, f, indent=4)
                f.close()
        subprocess.run([
            sys.executable, os.path.join(
                os.getcwd(), "../../daemon/compat/msvc/winmake.py"),
            "-P",
            "--toolset", toolset,
            "--sdk", sdk,
            "-fb", pluginPath.split('/')[-1]
        ], check=True)
        if (buildOptions):
            with open(f"{pluginPath}/package.json", "w") as f:
                json.dump(defaultPackage, f, indent=4)
                f.close()
        return

    environ = os.environ.copy()

    install_args = []

    if distribution == ANDROID_DISTRIBUTION_NAME:
        install_args.append('-t')
        install_args.append(ANDROID_DISTRIBUTION_NAME)
    if processor:
        install_args.append('-c')
        install_args.append(processor)
    install_args.append('-p')
    install_args.append(str(multiprocessing.cpu_count()))

    subprocess.check_call(['chmod', '+x', pluginPath + "/build.sh"])
    return subprocess.run([pluginPath + "/build.sh"] +
                          install_args, env=environ, check=True)


def main():
    args = parse()
    currentDir = os.getcwd()

    for i, plugin in enumerate(args.projects):
        os.chdir(currentDir + "/" + plugin)
        buildPlugin(
            currentDir + "/" + plugin,
            args.processor[i],
            args.distribution,
            args.toolset,
            args.sdk,
            args.buildOptions)


if __name__ == "__main__":
    main()